[RFC for-next 1/2] IB/{core,uverbs}: ib_uverbs callback registration in ib_core

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: shamir rabinovitch <shamir.rabinovitch@xxxxxxxxxx>

next patch will add dependency from ib_umem_get to ib_uverbs.
this require ib_uverbs callback registartion to prevent circular
dependecy of the form ib_core -> ib_uverbs -> ib_core that fail
in depmod check.

Signed-off-by: shamir rabinovitch <shamir.rabinovitch@xxxxxxxxxx>
---
 drivers/infiniband/core/device.c      | 51 +++++++++++++++++++++++++++
 drivers/infiniband/core/uverbs_main.c | 11 ++++++
 include/rdma/ib_verbs.h               | 12 +++++++
 3 files changed, 74 insertions(+)

diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 47ab34ee1a9d..416180805a6a 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -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);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 9f9172eb1512..e0574cd5e850 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -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,
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 0ec15d673d92..cd8c5886a1e6 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -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);
-- 
2.17.2




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux