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>
This commit is contained in:
Родитель
8ddc7c5326
Коммит
fd60ae404f
|
@ -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 @@
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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:
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче