@@ -789,6 +789,56 @@ void ib_unregister_client(struct ib_client *client)
}
EXPORT_SYMBOL(ib_unregister_client);
+static DEFINE_MUTEX(uverbs_lock);
+static struct ib_uverbs __rcu *ib_core_uverbs;
+
+int ib_register_uverbs(struct ib_uverbs *uverbs)
+{
+ struct ib_uverbs *core_uverbs;
+ int ret = 0;
+
+ mutex_lock(&uverbs_lock);
+ if (ib_core_uverbs) {
+ ret = -EEXIST;
+ goto unlock;
+ }
+
+ core_uverbs = kzalloc(sizeof(*core_uverbs), GFP_KERNEL);
+ if (!core_uverbs) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ *core_uverbs = *uverbs;
+ rcu_assign_pointer(ib_core_uverbs, core_uverbs);
+unlock:
+ mutex_unlock(&uverbs_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(ib_register_uverbs);
+
+void ib_unregister_uverbs(void)
+{
+ struct ib_uverbs *core_uverbs;
+
+ mutex_lock(&uverbs_lock);
+ if (!ib_core_uverbs)
+ goto unlock;
+ core_uverbs = ib_core_uverbs;
+ rcu_assign_pointer(ib_core_uverbs, NULL);
+ synchronize_rcu();
+ kfree(core_uverbs);
+unlock:
+ mutex_unlock(&uverbs_lock);
+}
+EXPORT_SYMBOL(ib_unregister_uverbs);
+
+struct ib_uverbs *ib_get_uverbs(void)
+{
+ return rcu_dereference(ib_core_uverbs);
+}
+
/**
* ib_get_client_data - Get IB client context
* @device:Device to get context for
@@ -1435,6 +1485,7 @@ static void __exit ib_core_cleanup(void)
destroy_workqueue(ib_comp_wq);
/* Make sure that any pending umem accounting work is done. */
destroy_workqueue(ib_wq);
+ ib_unregister_uverbs();
}
MODULE_ALIAS_RDMA_NETLINK(RDMA_NL_LS, 4);
@@ -1370,6 +1370,7 @@ static char *uverbs_devnode(struct device *dev, umode_t *mode)
static int __init ib_uverbs_init(void)
{
+ struct ib_uverbs uverbs = {0};
int ret;
ret = register_chrdev_region(IB_UVERBS_BASE_DEV,
@@ -1409,8 +1410,17 @@ static int __init ib_uverbs_init(void)
goto out_class;
}
+ ret = ib_register_uverbs(&uverbs);
+ if (ret) {
+ pr_err("user_verbs: couldn't register uverbs\n");
+ goto out_client;
+ }
+
return 0;
+out_client:
+ ib_unregister_client(&uverbs_client);
+
out_class:
class_destroy(uverbs_class);
@@ -1428,6 +1438,7 @@ static int __init ib_uverbs_init(void)
static void __exit ib_uverbs_cleanup(void)
{
+ ib_unregister_uverbs();
ib_unregister_client(&uverbs_client);
class_destroy(uverbs_class);
unregister_chrdev_region(IB_UVERBS_BASE_DEV,
@@ -2617,6 +2617,10 @@ struct ib_client {
struct list_head list;
};
+struct ib_uverbs {
+ /* uverbs callbacks used by ib_core */
+};
+
struct ib_device *ib_alloc_device(size_t size);
void ib_dealloc_device(struct ib_device *device);
@@ -2630,6 +2634,14 @@ void ib_unregister_device(struct ib_device *device);
int ib_register_client (struct ib_client *client);
void ib_unregister_client(struct ib_client *client);
+int ib_register_uverbs(struct ib_uverbs *uverbs);
+void ib_unregister_uverbs(void);
+/*
+ * return uverbs callbacks or NULL.
+ * rcu read lock must be held as long as uverbs callbacks are in use.
+ */
+struct ib_uverbs *ib_get_uverbs(void);
+
void *ib_get_client_data(struct ib_device *device, struct ib_client *client);
void ib_set_client_data(struct ib_device *device, struct ib_client *client,
void *data);