[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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



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>
---
V2:
- remove stale spin_unlock() (Oleksandr Tyshchenko)
---
 drivers/xen/pvcalls-front.c | 46 +++++++++++++++++++++----------------
 1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index d5d589bda243..b72ee9379d77 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -227,22 +227,30 @@ 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 +441,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 +828,27 @@ 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) {
-               clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
-                         (void *)&map->passive.flags);
-               spin_unlock(&bedata->socket_lock);
                free_active_ring(map2);
                kfree(map2);
+               clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
+                         (void *)&map->passive.flags);
                pvcalls_exit_sock(sock);
                return ret;
        }
 
-       ret = create_active(map2, &evtchn);
+       spin_lock(&bedata->socket_lock);
+       ret = get_request(bedata, &req_id);
        if (ret < 0) {
-               free_active_ring(map2);
-               kfree(map2);
                clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
                          (void *)&map->passive.flags);
                spin_unlock(&bedata->socket_lock);
+               pvcalls_front_free_map(bedata, map2);
                pvcalls_exit_sock(sock);
                return ret;
        }
+
        list_add_tail(&map2->list, &bedata->socket_mappings);
 
        req = RING_GET_REQUEST(&bedata->ring, req_id);
-- 
2.35.3




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.