IB/uverbs: Avoid a crash on device hot remove
authorJack Morgenstein <jackm@mellanox.co.il>
Thu, 3 Aug 2006 17:56:42 +0000 (10:56 -0700)
committerRoland Dreier <rolandd@cisco.com>
Thu, 3 Aug 2006 17:56:42 +0000 (10:56 -0700)
Wait until all users have closed their device context before allowing
device unregistration to complete.  This prevents a crash caused by
referring to stale data structures.

A better solution would be to have a way to revoke contexts rather
than waiting for userspace to close the context, but that's a much
bigger change that will have to wait.  For now let's at least avoid
the crash.

Signed-off-by: Jack Morgenstein <jackm@mellanox.co.il>
Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_main.c

index bb9bee56a824a9ea5b1da2417a882a12aab11f16..102a59c033ff9fe3b0f79b8aedc66ced43515eb4 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/kref.h>
 #include <linux/idr.h>
 #include <linux/mutex.h>
+#include <linux/completion.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_user_verbs.h>
@@ -69,6 +70,7 @@
 
 struct ib_uverbs_device {
        struct kref                             ref;
+       struct completion                       comp;
        int                                     devnum;
        struct cdev                            *dev;
        struct class_device                    *class_dev;
index e725cccc7cde245803a10791fec5c31c212a1b36..4e16314e8e6dd8bec8e9aabb4917a841f441695f 100644 (file)
@@ -122,7 +122,7 @@ static void ib_uverbs_release_dev(struct kref *ref)
        struct ib_uverbs_device *dev =
                container_of(ref, struct ib_uverbs_device, ref);
 
-       kfree(dev);
+       complete(&dev->comp);
 }
 
 void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
@@ -740,6 +740,7 @@ static void ib_uverbs_add_one(struct ib_device *device)
                return;
 
        kref_init(&uverbs_dev->ref);
+       init_completion(&uverbs_dev->comp);
 
        spin_lock(&map_lock);
        uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -793,6 +794,8 @@ err_cdev:
 
 err:
        kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
+       wait_for_completion(&uverbs_dev->comp);
+       kfree(uverbs_dev);
        return;
 }
 
@@ -812,7 +815,10 @@ static void ib_uverbs_remove_one(struct ib_device *device)
        spin_unlock(&map_lock);
 
        clear_bit(uverbs_dev->devnum, dev_map);
+
        kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
+       wait_for_completion(&uverbs_dev->comp);
+       kfree(uverbs_dev);
 }
 
 static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags,