Commit fd60ae40 authored by Jack Morgenstein's avatar Jack Morgenstein Committed by Roland Dreier

IB/uverbs: Avoid a crash on device hot remove

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: default avatarJack Morgenstein <jackm@mellanox.co.il>
Signed-off-by: default avatarMichael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 8ddc7c53
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/completion.h>
#include <rdma/ib_verbs.h> #include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h> #include <rdma/ib_user_verbs.h>
...@@ -69,6 +70,7 @@ ...@@ -69,6 +70,7 @@
struct ib_uverbs_device { struct ib_uverbs_device {
struct kref ref; struct kref ref;
struct completion comp;
int devnum; int devnum;
struct cdev *dev; struct cdev *dev;
struct class_device *class_dev; struct class_device *class_dev;
......
...@@ -122,7 +122,7 @@ static void ib_uverbs_release_dev(struct kref *ref) ...@@ -122,7 +122,7 @@ static void ib_uverbs_release_dev(struct kref *ref)
struct ib_uverbs_device *dev = struct ib_uverbs_device *dev =
container_of(ref, struct ib_uverbs_device, ref); container_of(ref, struct ib_uverbs_device, ref);
kfree(dev); complete(&dev->comp);
} }
void ib_uverbs_release_ucq(struct ib_uverbs_file *file, void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
...@@ -740,6 +740,7 @@ static void ib_uverbs_add_one(struct ib_device *device) ...@@ -740,6 +740,7 @@ static void ib_uverbs_add_one(struct ib_device *device)
return; return;
kref_init(&uverbs_dev->ref); kref_init(&uverbs_dev->ref);
init_completion(&uverbs_dev->comp);
spin_lock(&map_lock); spin_lock(&map_lock);
uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
...@@ -793,6 +794,8 @@ err_cdev: ...@@ -793,6 +794,8 @@ err_cdev:
err: err:
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
wait_for_completion(&uverbs_dev->comp);
kfree(uverbs_dev);
return; return;
} }
...@@ -812,7 +815,10 @@ static void ib_uverbs_remove_one(struct ib_device *device) ...@@ -812,7 +815,10 @@ static void ib_uverbs_remove_one(struct ib_device *device)
spin_unlock(&map_lock); spin_unlock(&map_lock);
clear_bit(uverbs_dev->devnum, dev_map); clear_bit(uverbs_dev->devnum, dev_map);
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); 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, static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment