Re: [PATCH] xen/pvcalls: don't call bind_evtchn_to_irqhandler() under lock

From: Juergen Gross
Date: Tue Mar 28 2023 - 06:58:44 EST


On 28.03.23 12:34, Oleksandr Tyshchenko wrote:


On 28.03.23 12:39, Juergen Gross wrote:

Hello Juergen


bind_evtchn_to_irqhandler() shouldn't be called under spinlock, as it
can sleep.

This requires to move the calls of create_active() out of the locked
regions. This is no problem, as the worst which could happen would be
a spurious call of the interrupt handler, causing a spurious wake_up().

Reported-by: Dan Carpenter <error27@xxxxxxxxx>
Link: https://lore.kernel.org/lkml/Y+JUIl64UDmdkboh@kadam/
Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
---
  drivers/xen/pvcalls-front.c | 46 ++++++++++++++++++++++---------------
  1 file changed, 27 insertions(+), 19 deletions(-)

diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index d5d589bda243..6e5d712e3115 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -227,22 +227,31 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
  static void free_active_ring(struct sock_mapping *map);
-static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
-                   struct sock_mapping *map)
+static void pvcalls_front_destroy_active(struct pvcalls_bedata *bedata,
+                     struct sock_mapping *map)
  {
      int i;
      unbind_from_irqhandler(map->active.irq, map);
-    spin_lock(&bedata->socket_lock);
-    if (!list_empty(&map->list))
-        list_del_init(&map->list);
-    spin_unlock(&bedata->socket_lock);
+    if (bedata) {
+        spin_lock(&bedata->socket_lock);
+        if (!list_empty(&map->list))
+            list_del_init(&map->list);
+        spin_unlock(&bedata->socket_lock);
+    }
      for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++)
          gnttab_end_foreign_access(map->active.ring->ref[i], NULL);
      gnttab_end_foreign_access(map->active.ref, NULL);
+
      free_active_ring(map);
+}
+
+static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
+                   struct sock_mapping *map)
+{
+    pvcalls_front_destroy_active(bedata, map);
      kfree(map);
  }
@@ -433,19 +442,18 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
          pvcalls_exit_sock(sock);
          return ret;
      }
-
-    spin_lock(&bedata->socket_lock);
-    ret = get_request(bedata, &req_id);
+    ret = create_active(map, &evtchn);
      if (ret < 0) {
-        spin_unlock(&bedata->socket_lock);
          free_active_ring(map);
          pvcalls_exit_sock(sock);
          return ret;
      }
-    ret = create_active(map, &evtchn);
+
+    spin_lock(&bedata->socket_lock);
+    ret = get_request(bedata, &req_id);
      if (ret < 0) {
          spin_unlock(&bedata->socket_lock);
-        free_active_ring(map);
+        pvcalls_front_destroy_active(NULL, map);
          pvcalls_exit_sock(sock);
          return ret;
      }
@@ -821,28 +829,28 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
          pvcalls_exit_sock(sock);
          return ret;
      }
-    spin_lock(&bedata->socket_lock);
-    ret = get_request(bedata, &req_id);
+    ret = create_active(map2, &evtchn);
      if (ret < 0) {
+        free_active_ring(map2);
+        kfree(map2);
          clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
                (void *)&map->passive.flags);
          spin_unlock(&bedata->socket_lock);


Looks like we also need to remove spin_unlock() above, correct?

Thanks for catching!


Juergen

Attachment: OpenPGP_0xB0DE9DD628BF132F.asc
Description: OpenPGP public key

Attachment: OpenPGP_signature
Description: OpenPGP digital signature