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: Jack Morgenstein <jackm@mellanox.co.il>
Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: Roland Dreier <rolandd@cisco.com>

authored by Jack Morgenstein and committed by Roland Dreier fd60ae40 8ddc7c53

+9 -1
+2
drivers/infiniband/core/uverbs.h
··· 42 42 #include <linux/kref.h> 43 43 #include <linux/idr.h> 44 44 #include <linux/mutex.h> 45 + #include <linux/completion.h> 45 46 46 47 #include <rdma/ib_verbs.h> 47 48 #include <rdma/ib_user_verbs.h> ··· 70 69 71 70 struct ib_uverbs_device { 72 71 struct kref ref; 72 + struct completion comp; 73 73 int devnum; 74 74 struct cdev *dev; 75 75 struct class_device *class_dev;
+7 -1
drivers/infiniband/core/uverbs_main.c
··· 122 122 struct ib_uverbs_device *dev = 123 123 container_of(ref, struct ib_uverbs_device, ref); 124 124 125 - kfree(dev); 125 + complete(&dev->comp); 126 126 } 127 127 128 128 void ib_uverbs_release_ucq(struct ib_uverbs_file *file, ··· 740 740 return; 741 741 742 742 kref_init(&uverbs_dev->ref); 743 + init_completion(&uverbs_dev->comp); 743 744 744 745 spin_lock(&map_lock); 745 746 uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); ··· 794 793 795 794 err: 796 795 kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); 796 + wait_for_completion(&uverbs_dev->comp); 797 + kfree(uverbs_dev); 797 798 return; 798 799 } 799 800 ··· 815 812 spin_unlock(&map_lock); 816 813 817 814 clear_bit(uverbs_dev->devnum, dev_map); 815 + 818 816 kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); 817 + wait_for_completion(&uverbs_dev->comp); 818 + kfree(uverbs_dev); 819 819 } 820 820 821 821 static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags,