All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH for-next 0/7] Change IDR usage and locking in uverbs
@ 2017-01-11 10:53 Matan Barak
       [not found] ` <1484132033-3346-1-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-11 10:53 UTC (permalink / raw)
  To: Doug Ledford
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

Hi Doug,

This series is the first part of introducing the new ABI.
It changes the IDR and locking mechanism in ib_uverbs.
This will allow handling all types in the same way, both IB/core
standard types and driver specific types. In that case, type is
referred to either IDR (such as QP, CQ, etc.) or FD such as
completion channel based uobjects.

Previously, we had global IDR tables per type and a per-type list on
the user context, which implied that the type system was fixed.
This patch series changes that into a per-device IDR table (since
in the new proposed ABI each device could have a different type
system) and a unified per-context objects list. Objects in this list
could either be IDR based objects or FD based objects.

A type is represented by an identifier, an allocation size, a free
function which is used in the context tear down and a release order.
The allocation function is actually the handler (for example,
create_qp). The release order determines the relations between objects.
Some relations are set in the hardware or user-space. For example,
you can create a MW before MR, but if this MW is bounded to the MR,
the MW should be released before the MR.
Later on, we'll add actions in an object-oriented programming manner
to each type. So, a type contains all required information for
allocating its size and freeing it.

The locking mechanism is changed as well. Previously, the uverbs_cmd
handlers created new objects themselves and dealt with the internals
of locking/unlocking them. This is now moved to a separate code which
either creates a new object, destroys an object or locks it for
read/write. This is possible since we have a descriptive type system.
Hence, we could have a shared code to create, lock and destroy types.

In contrast to the previous locking approach, we don't block the
user-space thread if an object is already locked, but we just return
-EBUSY and expect the user to handle this. In order to maintain
backward compatibility, we've added explicit locks to the uverbs_cmd
handlers (in non-racy scenarios of course), thus for sane flows the
behaviour should be the same as previous one.
The incentive here is to provide a robust infrastructure to add new
actions that can't create a dead-lock (e.g. two commands that try to
lock objects in AB-BA manner).
In addition, since objects creation and locking is dealt in a
centralized place, the new proposed ABI won't need to deal with it
explicitly in its handlers.

A typical flow of a handler will be:
1. Serialize the user-space command to kernel-space.
2. Get all objects the handle needs (through the new centralized
     mechanism).
3. Do the actual command.
4. Finalize objects (unlock/add/destroy/rollback) and write response
     to the user.

This patch-set is applied on top of Doug's k.o/for-4.11 branch.
The whole ABI proposal is available in my github [1] using the tag
abi-devel-latest.

Regards,
Matan

[1] https://github.com/matanb10/linux/

Leon Romanovsky (1):
  IB/core: Refactor IDR to be per-device

Matan Barak (6):
  IB/core: Add support for custom types
  IB/core: Add support for fd objects
  IB/core: Add generic ucontext initialization and teardown
  IB/core: Add macros for declaring types and type groups
  IB/core: Declare all common IB types
  IB/core: Use the new IDR and locking infrastructure in uverbs_cmd

 drivers/infiniband/core/Makefile             |    3 +-
 drivers/infiniband/core/device.c             |   14 +
 drivers/infiniband/core/rdma_core.c          |  496 ++++++++++++
 drivers/infiniband/core/rdma_core.h          |   89 ++
 drivers/infiniband/core/uverbs.h             |   28 +-
 drivers/infiniband/core/uverbs_cmd.c         | 1117 ++++++++------------------
 drivers/infiniband/core/uverbs_ioctl_cmd.c   |  212 +++++
 drivers/infiniband/core/uverbs_main.c        |  279 ++-----
 drivers/infiniband/hw/cxgb3/iwch_provider.c  |    4 +
 drivers/infiniband/hw/cxgb4/provider.c       |    4 +
 drivers/infiniband/hw/hns/hns_roce_main.c    |    4 +
 drivers/infiniband/hw/i40iw/i40iw_verbs.c    |    4 +
 drivers/infiniband/hw/mlx4/main.c            |    4 +
 drivers/infiniband/hw/mlx5/main.c            |    4 +
 drivers/infiniband/hw/mthca/mthca_provider.c |    4 +
 drivers/infiniband/hw/nes/nes_verbs.c        |    4 +
 drivers/infiniband/hw/ocrdma/ocrdma_main.c   |    4 +
 drivers/infiniband/hw/usnic/usnic_ib_main.c  |    4 +
 drivers/infiniband/sw/rdmavt/vt.c            |    4 +
 drivers/infiniband/sw/rxe/rxe_verbs.c        |    4 +
 include/rdma/ib_verbs.h                      |   33 +-
 include/rdma/uverbs_ioctl.h                  |  128 +++
 include/rdma/uverbs_ioctl_cmd.h              |   68 ++
 23 files changed, 1511 insertions(+), 1004 deletions(-)
 create mode 100644 drivers/infiniband/core/rdma_core.c
 create mode 100644 drivers/infiniband/core/rdma_core.h
 create mode 100644 drivers/infiniband/core/uverbs_ioctl_cmd.c
 create mode 100644 include/rdma/uverbs_ioctl.h
 create mode 100644 include/rdma/uverbs_ioctl_cmd.h

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH for-next 1/7] IB/core: Refactor IDR to be per-device
       [not found] ` <1484132033-3346-1-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
@ 2017-01-11 10:53   ` Matan Barak
       [not found]     ` <1484132033-3346-2-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  2017-01-11 10:53   ` [PATCH for-next 2/7] IB/core: Add support for custom types Matan Barak
                     ` (5 subsequent siblings)
  6 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-11 10:53 UTC (permalink / raw)
  To: Doug Ledford
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

From: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>

The current code creates an IDR per type. Since types are currently
common for all vendors and known in advance, this was good enough.
However, the proposed ioctl based infrastructure allows each vendor
to declare only some of the common types and declare its own specific
types.

Thus, we decided to implement IDR to be per device and refactor it to
use a new file.

Signed-off-by: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Signed-off-by: Haggai Eran <haggaie-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/core/device.c      |  14 +++
 drivers/infiniband/core/uverbs.h      |  16 +---
 drivers/infiniband/core/uverbs_cmd.c  | 157 ++++++++++++++++------------------
 drivers/infiniband/core/uverbs_main.c |  42 +++------
 include/rdma/ib_verbs.h               |   4 +
 5 files changed, 106 insertions(+), 127 deletions(-)

diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 571974c..2c4cc55 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -168,11 +168,23 @@ static int alloc_name(char *name)
 	return 0;
 }
 
+static void ib_device_allocate_idrs(struct ib_device *device)
+{
+	spin_lock_init(&device->idr_lock);
+	idr_init(&device->idr);
+}
+
+static void ib_device_destroy_idrs(struct ib_device *device)
+{
+	idr_destroy(&device->idr);
+}
+
 static void ib_device_release(struct device *device)
 {
 	struct ib_device *dev = container_of(device, struct ib_device, dev);
 
 	ib_cache_release_one(dev);
+	ib_device_destroy_idrs(dev);
 	kfree(dev->port_immutable);
 	kfree(dev);
 }
@@ -219,6 +231,8 @@ struct ib_device *ib_alloc_device(size_t size)
 	if (!device)
 		return NULL;
 
+	ib_device_allocate_idrs(device);
+
 	device->dev.class = &ib_class;
 	device_initialize(&device->dev);
 
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 455034a..6344b80 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -38,7 +38,6 @@
 #define UVERBS_H
 
 #include <linux/kref.h>
-#include <linux/idr.h>
 #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <linux/cdev.h>
@@ -176,20 +175,7 @@ struct ib_ucq_object {
 	u32			async_events_reported;
 };
 
-extern spinlock_t ib_uverbs_idr_lock;
-extern struct idr ib_uverbs_pd_idr;
-extern struct idr ib_uverbs_mr_idr;
-extern struct idr ib_uverbs_mw_idr;
-extern struct idr ib_uverbs_ah_idr;
-extern struct idr ib_uverbs_cq_idr;
-extern struct idr ib_uverbs_qp_idr;
-extern struct idr ib_uverbs_srq_idr;
-extern struct idr ib_uverbs_xrcd_idr;
-extern struct idr ib_uverbs_rule_idr;
-extern struct idr ib_uverbs_wq_idr;
-extern struct idr ib_uverbs_rwq_ind_tbl_idr;
-
-void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj);
+void idr_remove_uobj(struct ib_uobject *uobj);
 
 struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
 					struct ib_device *ib_dev,
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 7007822..9e3c7db 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -120,37 +120,36 @@ static void put_uobj_write(struct ib_uobject *uobj)
 	put_uobj(uobj);
 }
 
-static int idr_add_uobj(struct idr *idr, struct ib_uobject *uobj)
+static int idr_add_uobj(struct ib_uobject *uobj)
 {
 	int ret;
 
 	idr_preload(GFP_KERNEL);
-	spin_lock(&ib_uverbs_idr_lock);
+	spin_lock(&uobj->context->device->idr_lock);
 
-	ret = idr_alloc(idr, uobj, 0, 0, GFP_NOWAIT);
+	ret = idr_alloc(&uobj->context->device->idr, uobj, 0, 0, GFP_NOWAIT);
 	if (ret >= 0)
 		uobj->id = ret;
 
-	spin_unlock(&ib_uverbs_idr_lock);
+	spin_unlock(&uobj->context->device->idr_lock);
 	idr_preload_end();
 
 	return ret < 0 ? ret : 0;
 }
 
-void idr_remove_uobj(struct idr *idr, struct ib_uobject *uobj)
+void idr_remove_uobj(struct ib_uobject *uobj)
 {
-	spin_lock(&ib_uverbs_idr_lock);
-	idr_remove(idr, uobj->id);
-	spin_unlock(&ib_uverbs_idr_lock);
+	spin_lock(&uobj->context->device->idr_lock);
+	idr_remove(&uobj->context->device->idr, uobj->id);
+	spin_unlock(&uobj->context->device->idr_lock);
 }
 
-static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
-					 struct ib_ucontext *context)
+static struct ib_uobject *__idr_get_uobj(int id, struct ib_ucontext *context)
 {
 	struct ib_uobject *uobj;
 
 	rcu_read_lock();
-	uobj = idr_find(idr, id);
+	uobj = idr_find(&context->device->idr, id);
 	if (uobj) {
 		if (uobj->context == context)
 			kref_get(&uobj->ref);
@@ -162,12 +161,12 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
 	return uobj;
 }
 
-static struct ib_uobject *idr_read_uobj(struct idr *idr, int id,
-					struct ib_ucontext *context, int nested)
+static struct ib_uobject *idr_read_uobj(int id, struct ib_ucontext *context,
+					int nested)
 {
 	struct ib_uobject *uobj;
 
-	uobj = __idr_get_uobj(idr, id, context);
+	uobj = __idr_get_uobj(id, context);
 	if (!uobj)
 		return NULL;
 
@@ -183,12 +182,11 @@ static struct ib_uobject *idr_read_uobj(struct idr *idr, int id,
 	return uobj;
 }
 
-static struct ib_uobject *idr_write_uobj(struct idr *idr, int id,
-					 struct ib_ucontext *context)
+static struct ib_uobject *idr_write_uobj(int id, struct ib_ucontext *context)
 {
 	struct ib_uobject *uobj;
 
-	uobj = __idr_get_uobj(idr, id, context);
+	uobj = __idr_get_uobj(id, context);
 	if (!uobj)
 		return NULL;
 
@@ -201,18 +199,18 @@ static struct ib_uobject *idr_write_uobj(struct idr *idr, int id,
 	return uobj;
 }
 
-static void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context,
+static void *idr_read_obj(int id, struct ib_ucontext *context,
 			  int nested)
 {
 	struct ib_uobject *uobj;
 
-	uobj = idr_read_uobj(idr, id, context, nested);
+	uobj = idr_read_uobj(id, context, nested);
 	return uobj ? uobj->object : NULL;
 }
 
 static struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context)
 {
-	return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context, 0);
+	return idr_read_obj(pd_handle, context, 0);
 }
 
 static void put_pd_read(struct ib_pd *pd)
@@ -222,7 +220,7 @@ static void put_pd_read(struct ib_pd *pd)
 
 static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context, int nested)
 {
-	return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context, nested);
+	return idr_read_obj(cq_handle, context, nested);
 }
 
 static void put_cq_read(struct ib_cq *cq)
@@ -230,24 +228,24 @@ static void put_cq_read(struct ib_cq *cq)
 	put_uobj_read(cq->uobject);
 }
 
-static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
+static void put_ah_read(struct ib_ah *ah)
 {
-	return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context, 0);
+	put_uobj_read(ah->uobject);
 }
 
-static void put_ah_read(struct ib_ah *ah)
+static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
 {
-	put_uobj_read(ah->uobject);
+	return idr_read_obj(ah_handle, context, 0);
 }
 
 static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context)
 {
-	return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0);
+	return idr_read_obj(qp_handle, context, 0);
 }
 
 static struct ib_wq *idr_read_wq(int wq_handle, struct ib_ucontext *context)
 {
-	return idr_read_obj(&ib_uverbs_wq_idr, wq_handle, context, 0);
+	return idr_read_obj(wq_handle, context, 0);
 }
 
 static void put_wq_read(struct ib_wq *wq)
@@ -258,7 +256,7 @@ static void put_wq_read(struct ib_wq *wq)
 static struct ib_rwq_ind_table *idr_read_rwq_indirection_table(int ind_table_handle,
 							       struct ib_ucontext *context)
 {
-	return idr_read_obj(&ib_uverbs_rwq_ind_tbl_idr, ind_table_handle, context, 0);
+	return idr_read_obj(ind_table_handle, context, 0);
 }
 
 static void put_rwq_indirection_table_read(struct ib_rwq_ind_table *ind_table)
@@ -270,7 +268,7 @@ static struct ib_qp *idr_write_qp(int qp_handle, struct ib_ucontext *context)
 {
 	struct ib_uobject *uobj;
 
-	uobj = idr_write_uobj(&ib_uverbs_qp_idr, qp_handle, context);
+	uobj = idr_write_uobj(qp_handle, context);
 	return uobj ? uobj->object : NULL;
 }
 
@@ -286,7 +284,7 @@ static void put_qp_write(struct ib_qp *qp)
 
 static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context)
 {
-	return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context, 0);
+	return idr_read_obj(srq_handle, context, 0);
 }
 
 static void put_srq_read(struct ib_srq *srq)
@@ -297,7 +295,7 @@ static void put_srq_read(struct ib_srq *srq)
 static struct ib_xrcd *idr_read_xrcd(int xrcd_handle, struct ib_ucontext *context,
 				     struct ib_uobject **uobj)
 {
-	*uobj = idr_read_uobj(&ib_uverbs_xrcd_idr, xrcd_handle, context, 0);
+	*uobj = idr_read_uobj(xrcd_handle, context, 0);
 	return *uobj ? (*uobj)->object : NULL;
 }
 
@@ -305,7 +303,6 @@ static void put_xrcd_read(struct ib_uobject *uobj)
 {
 	put_uobj_read(uobj);
 }
-
 ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
 			      struct ib_device *ib_dev,
 			      const char __user *buf,
@@ -575,7 +572,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
 	atomic_set(&pd->usecnt, 0);
 
 	uobj->object = pd;
-	ret = idr_add_uobj(&ib_uverbs_pd_idr, uobj);
+	ret = idr_add_uobj(uobj);
 	if (ret)
 		goto err_idr;
 
@@ -599,7 +596,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
 	return in_len;
 
 err_copy:
-	idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
+	idr_remove_uobj(uobj);
 
 err_idr:
 	ib_dealloc_pd(pd);
@@ -622,7 +619,7 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(&ib_uverbs_pd_idr, cmd.pd_handle, file->ucontext);
+	uobj = idr_write_uobj(cmd.pd_handle, file->ucontext);
 	if (!uobj)
 		return -EINVAL;
 	pd = uobj->object;
@@ -640,7 +637,7 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
 	uobj->live = 0;
 	put_uobj_write(uobj);
 
-	idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
@@ -816,7 +813,7 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
 
 	atomic_set(&obj->refcnt, 0);
 	obj->uobject.object = xrcd;
-	ret = idr_add_uobj(&ib_uverbs_xrcd_idr, &obj->uobject);
+	ret = idr_add_uobj(&obj->uobject);
 	if (ret)
 		goto err_idr;
 
@@ -860,7 +857,7 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
 	}
 
 err_insert_xrcd:
-	idr_remove_uobj(&ib_uverbs_xrcd_idr, &obj->uobject);
+	idr_remove_uobj(&obj->uobject);
 
 err_idr:
 	ib_dealloc_xrcd(xrcd);
@@ -894,7 +891,7 @@ ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file,
 		return -EFAULT;
 
 	mutex_lock(&file->device->xrcd_tree_mutex);
-	uobj = idr_write_uobj(&ib_uverbs_xrcd_idr, cmd.xrcd_handle, file->ucontext);
+	uobj = idr_write_uobj(cmd.xrcd_handle, file->ucontext);
 	if (!uobj) {
 		ret = -EINVAL;
 		goto out;
@@ -927,7 +924,7 @@ ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file,
 	if (inode && !live)
 		xrcd_table_delete(file->device, inode);
 
-	idr_remove_uobj(&ib_uverbs_xrcd_idr, uobj);
+	idr_remove_uobj(uobj);
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
 	mutex_unlock(&file->mutex);
@@ -1020,7 +1017,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
 	atomic_inc(&pd->usecnt);
 
 	uobj->object = mr;
-	ret = idr_add_uobj(&ib_uverbs_mr_idr, uobj);
+	ret = idr_add_uobj(uobj);
 	if (ret)
 		goto err_unreg;
 
@@ -1048,7 +1045,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
 	return in_len;
 
 err_copy:
-	idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
+	idr_remove_uobj(uobj);
 
 err_unreg:
 	ib_dereg_mr(mr);
@@ -1093,8 +1090,7 @@ ssize_t ib_uverbs_rereg_mr(struct ib_uverbs_file *file,
 	     (cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK)))
 			return -EINVAL;
 
-	uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle,
-			      file->ucontext);
+	uobj = idr_write_uobj(cmd.mr_handle, file->ucontext);
 
 	if (!uobj)
 		return -EINVAL;
@@ -1163,7 +1159,7 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle, file->ucontext);
+	uobj = idr_write_uobj(cmd.mr_handle, file->ucontext);
 	if (!uobj)
 		return -EINVAL;
 
@@ -1178,7 +1174,7 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
 	if (ret)
 		return ret;
 
-	idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
@@ -1238,7 +1234,7 @@ ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file,
 	atomic_inc(&pd->usecnt);
 
 	uobj->object = mw;
-	ret = idr_add_uobj(&ib_uverbs_mw_idr, uobj);
+	ret = idr_add_uobj(uobj);
 	if (ret)
 		goto err_unalloc;
 
@@ -1265,7 +1261,7 @@ ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file,
 	return in_len;
 
 err_copy:
-	idr_remove_uobj(&ib_uverbs_mw_idr, uobj);
+	idr_remove_uobj(uobj);
 
 err_unalloc:
 	uverbs_dealloc_mw(mw);
@@ -1291,7 +1287,7 @@ ssize_t ib_uverbs_dealloc_mw(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof(cmd)))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(&ib_uverbs_mw_idr, cmd.mw_handle, file->ucontext);
+	uobj = idr_write_uobj(cmd.mw_handle, file->ucontext);
 	if (!uobj)
 		return -EINVAL;
 
@@ -1306,7 +1302,7 @@ ssize_t ib_uverbs_dealloc_mw(struct ib_uverbs_file *file,
 	if (ret)
 		return ret;
 
-	idr_remove_uobj(&ib_uverbs_mw_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
@@ -1420,7 +1416,7 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
 	atomic_set(&cq->usecnt, 0);
 
 	obj->uobject.object = cq;
-	ret = idr_add_uobj(&ib_uverbs_cq_idr, &obj->uobject);
+	ret = idr_add_uobj(&obj->uobject);
 	if (ret)
 		goto err_free;
 
@@ -1446,7 +1442,7 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
 	return obj;
 
 err_cb:
-	idr_remove_uobj(&ib_uverbs_cq_idr, &obj->uobject);
+	idr_remove_uobj(&obj->uobject);
 
 err_free:
 	ib_destroy_cq(cq);
@@ -1716,7 +1712,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext);
+	uobj = idr_write_uobj(cmd.cq_handle, file->ucontext);
 	if (!uobj)
 		return -EINVAL;
 	cq      = uobj->object;
@@ -1732,7 +1728,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
 	if (ret)
 		return ret;
 
-	idr_remove_uobj(&ib_uverbs_cq_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
@@ -1939,7 +1935,7 @@ static int create_qp(struct ib_uverbs_file *file,
 	qp->uobject = &obj->uevent.uobject;
 
 	obj->uevent.uobject.object = qp;
-	ret = idr_add_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
+	ret = idr_add_uobj(&obj->uevent.uobject);
 	if (ret)
 		goto err_destroy;
 
@@ -1987,7 +1983,7 @@ static int create_qp(struct ib_uverbs_file *file,
 
 	return 0;
 err_cb:
-	idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
+	idr_remove_uobj(&obj->uevent.uobject);
 
 err_destroy:
 	ib_destroy_qp(qp);
@@ -2173,7 +2169,7 @@ ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
 	qp->uobject = &obj->uevent.uobject;
 
 	obj->uevent.uobject.object = qp;
-	ret = idr_add_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
+	ret = idr_add_uobj(&obj->uevent.uobject);
 	if (ret)
 		goto err_destroy;
 
@@ -2202,7 +2198,7 @@ ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
 	return in_len;
 
 err_remove:
-	idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
+	idr_remove_uobj(&obj->uevent.uobject);
 
 err_destroy:
 	ib_destroy_qp(qp);
@@ -2498,7 +2494,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
 
 	memset(&resp, 0, sizeof resp);
 
-	uobj = idr_write_uobj(&ib_uverbs_qp_idr, cmd.qp_handle, file->ucontext);
+	uobj = idr_write_uobj(cmd.qp_handle, file->ucontext);
 	if (!uobj)
 		return -EINVAL;
 	qp  = uobj->object;
@@ -2521,7 +2517,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
 	if (obj->uxrcd)
 		atomic_dec(&obj->uxrcd->refcnt);
 
-	idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
@@ -2982,7 +2978,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
 	ah->uobject  = uobj;
 	uobj->object = ah;
 
-	ret = idr_add_uobj(&ib_uverbs_ah_idr, uobj);
+	ret = idr_add_uobj(uobj);
 	if (ret)
 		goto err_destroy;
 
@@ -3007,7 +3003,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
 	return in_len;
 
 err_copy:
-	idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
+	idr_remove_uobj(uobj);
 
 err_destroy:
 	ib_destroy_ah(ah);
@@ -3032,7 +3028,7 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(&ib_uverbs_ah_idr, cmd.ah_handle, file->ucontext);
+	uobj = idr_write_uobj(cmd.ah_handle, file->ucontext);
 	if (!uobj)
 		return -EINVAL;
 	ah = uobj->object;
@@ -3046,7 +3042,7 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
 	if (ret)
 		return ret;
 
-	idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
@@ -3345,7 +3341,7 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
 	atomic_inc(&cq->usecnt);
 	wq->uobject = &obj->uevent.uobject;
 	obj->uevent.uobject.object = wq;
-	err = idr_add_uobj(&ib_uverbs_wq_idr, &obj->uevent.uobject);
+	err = idr_add_uobj(&obj->uevent.uobject);
 	if (err)
 		goto destroy_wq;
 
@@ -3372,7 +3368,7 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
 	return 0;
 
 err_copy:
-	idr_remove_uobj(&ib_uverbs_wq_idr, &obj->uevent.uobject);
+	idr_remove_uobj(&obj->uevent.uobject);
 destroy_wq:
 	ib_destroy_wq(wq);
 err_put_cq:
@@ -3421,7 +3417,7 @@ int ib_uverbs_ex_destroy_wq(struct ib_uverbs_file *file,
 		return -EOPNOTSUPP;
 
 	resp.response_length = required_resp_len;
-	uobj = idr_write_uobj(&ib_uverbs_wq_idr, cmd.wq_handle,
+	uobj = idr_write_uobj(cmd.wq_handle,
 			      file->ucontext);
 	if (!uobj)
 		return -EINVAL;
@@ -3436,7 +3432,7 @@ int ib_uverbs_ex_destroy_wq(struct ib_uverbs_file *file,
 	if (ret)
 		return ret;
 
-	idr_remove_uobj(&ib_uverbs_wq_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
@@ -3604,7 +3600,7 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
 	for (i = 0; i < num_wq_handles; i++)
 		atomic_inc(&wqs[i]->usecnt);
 
-	err = idr_add_uobj(&ib_uverbs_rwq_ind_tbl_idr, uobj);
+	err = idr_add_uobj(uobj);
 	if (err)
 		goto destroy_ind_tbl;
 
@@ -3632,7 +3628,7 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
 	return 0;
 
 err_copy:
-	idr_remove_uobj(&ib_uverbs_rwq_ind_tbl_idr, uobj);
+	idr_remove_uobj(uobj);
 destroy_ind_tbl:
 	ib_destroy_rwq_ind_table(rwq_ind_tbl);
 err_uobj:
@@ -3675,7 +3671,7 @@ int ib_uverbs_ex_destroy_rwq_ind_table(struct ib_uverbs_file *file,
 	if (cmd.comp_mask)
 		return -EOPNOTSUPP;
 
-	uobj = idr_write_uobj(&ib_uverbs_rwq_ind_tbl_idr, cmd.ind_tbl_handle,
+	uobj = idr_write_uobj(cmd.ind_tbl_handle,
 			      file->ucontext);
 	if (!uobj)
 		return -EINVAL;
@@ -3691,7 +3687,7 @@ int ib_uverbs_ex_destroy_rwq_ind_table(struct ib_uverbs_file *file,
 	if (ret)
 		return ret;
 
-	idr_remove_uobj(&ib_uverbs_rwq_ind_tbl_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
@@ -3830,7 +3826,7 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
 	flow_id->uobject = uobj;
 	uobj->object = flow_id;
 
-	err = idr_add_uobj(&ib_uverbs_rule_idr, uobj);
+	err = idr_add_uobj(uobj);
 	if (err)
 		goto destroy_flow;
 
@@ -3855,7 +3851,7 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
 		kfree(kern_flow_attr);
 	return 0;
 err_copy:
-	idr_remove_uobj(&ib_uverbs_rule_idr, uobj);
+	idr_remove_uobj(uobj);
 destroy_flow:
 	ib_destroy_flow(flow_id);
 err_free:
@@ -3890,8 +3886,7 @@ int ib_uverbs_ex_destroy_flow(struct ib_uverbs_file *file,
 	if (cmd.comp_mask)
 		return -EINVAL;
 
-	uobj = idr_write_uobj(&ib_uverbs_rule_idr, cmd.flow_handle,
-			      file->ucontext);
+	uobj = idr_write_uobj(cmd.flow_handle, file->ucontext);
 	if (!uobj)
 		return -EINVAL;
 	flow_id = uobj->object;
@@ -3902,7 +3897,7 @@ int ib_uverbs_ex_destroy_flow(struct ib_uverbs_file *file,
 
 	put_uobj_write(uobj);
 
-	idr_remove_uobj(&ib_uverbs_rule_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
@@ -3990,7 +3985,7 @@ static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
 	atomic_set(&srq->usecnt, 0);
 
 	obj->uevent.uobject.object = srq;
-	ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uevent.uobject);
+	ret = idr_add_uobj(&obj->uevent.uobject);
 	if (ret)
 		goto err_destroy;
 
@@ -4024,7 +4019,7 @@ static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
 	return 0;
 
 err_copy:
-	idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uevent.uobject);
+	idr_remove_uobj(&obj->uevent.uobject);
 
 err_destroy:
 	ib_destroy_srq(srq);
@@ -4200,7 +4195,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(&ib_uverbs_srq_idr, cmd.srq_handle, file->ucontext);
+	uobj = idr_write_uobj(cmd.srq_handle, file->ucontext);
 	if (!uobj)
 		return -EINVAL;
 	srq = uobj->object;
@@ -4221,7 +4216,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
 		atomic_dec(&us->uxrcd->refcnt);
 	}
 
-	idr_remove_uobj(&ib_uverbs_srq_idr, uobj);
+	idr_remove_uobj(uobj);
 
 	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index b3f95d4..daee2ba6 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -66,19 +66,6 @@ enum {
 
 static struct class *uverbs_class;
 
-DEFINE_SPINLOCK(ib_uverbs_idr_lock);
-DEFINE_IDR(ib_uverbs_pd_idr);
-DEFINE_IDR(ib_uverbs_mr_idr);
-DEFINE_IDR(ib_uverbs_mw_idr);
-DEFINE_IDR(ib_uverbs_ah_idr);
-DEFINE_IDR(ib_uverbs_cq_idr);
-DEFINE_IDR(ib_uverbs_qp_idr);
-DEFINE_IDR(ib_uverbs_srq_idr);
-DEFINE_IDR(ib_uverbs_xrcd_idr);
-DEFINE_IDR(ib_uverbs_rule_idr);
-DEFINE_IDR(ib_uverbs_wq_idr);
-DEFINE_IDR(ib_uverbs_rwq_ind_tbl_idr);
-
 static DEFINE_SPINLOCK(map_lock);
 static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
 
@@ -235,7 +222,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 	list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) {
 		struct ib_ah *ah = uobj->object;
 
-		idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
+		idr_remove_uobj(uobj);
 		ib_destroy_ah(ah);
 		kfree(uobj);
 	}
@@ -244,7 +231,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 	list_for_each_entry_safe(uobj, tmp, &context->mw_list, list) {
 		struct ib_mw *mw = uobj->object;
 
-		idr_remove_uobj(&ib_uverbs_mw_idr, uobj);
+		idr_remove_uobj(uobj);
 		uverbs_dealloc_mw(mw);
 		kfree(uobj);
 	}
@@ -252,7 +239,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 	list_for_each_entry_safe(uobj, tmp, &context->rule_list, list) {
 		struct ib_flow *flow_id = uobj->object;
 
-		idr_remove_uobj(&ib_uverbs_rule_idr, uobj);
+		idr_remove_uobj(uobj);
 		ib_destroy_flow(flow_id);
 		kfree(uobj);
 	}
@@ -262,7 +249,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 		struct ib_uqp_object *uqp =
 			container_of(uobj, struct ib_uqp_object, uevent.uobject);
 
-		idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
+		idr_remove_uobj(uobj);
 		if (qp == qp->real_qp)
 			ib_uverbs_detach_umcast(qp, uqp);
 		ib_destroy_qp(qp);
@@ -274,7 +261,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 		struct ib_rwq_ind_table *rwq_ind_tbl = uobj->object;
 		struct ib_wq **ind_tbl = rwq_ind_tbl->ind_tbl;
 
-		idr_remove_uobj(&ib_uverbs_rwq_ind_tbl_idr, uobj);
+		idr_remove_uobj(uobj);
 		ib_destroy_rwq_ind_table(rwq_ind_tbl);
 		kfree(ind_tbl);
 		kfree(uobj);
@@ -285,7 +272,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 		struct ib_uwq_object *uwq =
 			container_of(uobj, struct ib_uwq_object, uevent.uobject);
 
-		idr_remove_uobj(&ib_uverbs_wq_idr, uobj);
+		idr_remove_uobj(uobj);
 		ib_destroy_wq(wq);
 		ib_uverbs_release_uevent(file, &uwq->uevent);
 		kfree(uwq);
@@ -296,7 +283,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 		struct ib_uevent_object *uevent =
 			container_of(uobj, struct ib_uevent_object, uobject);
 
-		idr_remove_uobj(&ib_uverbs_srq_idr, uobj);
+		idr_remove_uobj(uobj);
 		ib_destroy_srq(srq);
 		ib_uverbs_release_uevent(file, uevent);
 		kfree(uevent);
@@ -308,7 +295,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 		struct ib_ucq_object *ucq =
 			container_of(uobj, struct ib_ucq_object, uobject);
 
-		idr_remove_uobj(&ib_uverbs_cq_idr, uobj);
+		idr_remove_uobj(uobj);
 		ib_destroy_cq(cq);
 		ib_uverbs_release_ucq(file, ev_file, ucq);
 		kfree(ucq);
@@ -317,7 +304,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 	list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
 		struct ib_mr *mr = uobj->object;
 
-		idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
+		idr_remove_uobj(uobj);
 		ib_dereg_mr(mr);
 		kfree(uobj);
 	}
@@ -328,7 +315,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 		struct ib_uxrcd_object *uxrcd =
 			container_of(uobj, struct ib_uxrcd_object, uobject);
 
-		idr_remove_uobj(&ib_uverbs_xrcd_idr, uobj);
+		idr_remove_uobj(uobj);
 		ib_uverbs_dealloc_xrcd(file->device, xrcd);
 		kfree(uxrcd);
 	}
@@ -337,7 +324,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 	list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
 		struct ib_pd *pd = uobj->object;
 
-		idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
+		idr_remove_uobj(uobj);
 		ib_dealloc_pd(pd);
 		kfree(uobj);
 	}
@@ -1376,13 +1363,6 @@ static void __exit ib_uverbs_cleanup(void)
 	unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
 	if (overflow_maj)
 		unregister_chrdev_region(overflow_maj, IB_UVERBS_MAX_DEVICES);
-	idr_destroy(&ib_uverbs_pd_idr);
-	idr_destroy(&ib_uverbs_mr_idr);
-	idr_destroy(&ib_uverbs_mw_idr);
-	idr_destroy(&ib_uverbs_ah_idr);
-	idr_destroy(&ib_uverbs_cq_idr);
-	idr_destroy(&ib_uverbs_qp_idr);
-	idr_destroy(&ib_uverbs_srq_idr);
 }
 
 module_init(ib_uverbs_init);
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 958a24d..cad2c00 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1863,6 +1863,10 @@ struct ib_device {
 
 	struct iw_cm_verbs	     *iwcm;
 
+	struct idr		idr;
+	/* Global lock in use to safely release device IDR */
+	spinlock_t		idr_lock;
+
 	/**
 	 * alloc_hw_stats - Allocate a struct rdma_hw_stats and fill in the
 	 *   driver initialized data.  The struct is kfree()'ed by the sysfs
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH for-next 2/7] IB/core: Add support for custom types
       [not found] ` <1484132033-3346-1-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  2017-01-11 10:53   ` [PATCH for-next 1/7] IB/core: Refactor IDR to be per-device Matan Barak
@ 2017-01-11 10:53   ` Matan Barak
       [not found]     ` <1484132033-3346-3-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  2017-01-11 10:53   ` [PATCH for-next 3/7] IB/core: Add support for fd objects Matan Barak
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-11 10:53 UTC (permalink / raw)
  To: Doug Ledford
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

The new ioctl infrastructure supports driver specific objects.
Each such object type has a free function, allocation size and an
order of destruction. This information is embedded in the same
table describing the various action allowed on the object, similarly
to object oriented programming.

When a ucontext is created, a new list is created in this ib_ucontext.
This list contains all objects created under this ib_ucontext.
When a ib_ucontext is destroyed, we traverse this list several time
destroying the various objects by the order mentioned in the object
type description. If few object types have the same destruction order,
they are destroyed in an order opposite to their creation order.

Adding an object is done in two parts.
First, an object is allocated and added to IDR/fd table. Then, the
command's handlers (in downstream patches) could work on this object
and fill in its required details.
After a successful command, ib_uverbs_uobject_enable is called and
this user objects becomes ucontext visible.

Removing an uboject is done by calling ib_uverbs_uobject_remove.

We should make sure IDR (per-device) and list (per-ucontext) could
be accessed concurrently without corrupting them.

Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Reviewed-by: Yishai Hadas <yishaih-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Signed-off-by: Haggai Eran <haggaie-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Signed-off-by: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/core/Makefile    |   3 +-
 drivers/infiniband/core/rdma_core.c | 264 ++++++++++++++++++++++++++++++++++++
 drivers/infiniband/core/rdma_core.h |  61 +++++++++
 include/rdma/ib_verbs.h             |   9 ++
 include/rdma/uverbs_ioctl.h         |  60 ++++++++
 5 files changed, 396 insertions(+), 1 deletion(-)
 create mode 100644 drivers/infiniband/core/rdma_core.c
 create mode 100644 drivers/infiniband/core/rdma_core.h
 create mode 100644 include/rdma/uverbs_ioctl.h

diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index edaae9f..1819623 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -28,4 +28,5 @@ ib_umad-y :=			user_mad.o
 
 ib_ucm-y :=			ucm.o
 
-ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_marshall.o
+ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
+				rdma_core.o
diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
new file mode 100644
index 0000000..09b44ec
--- /dev/null
+++ b/drivers/infiniband/core/rdma_core.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/file.h>
+#include <linux/anon_inodes.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/uverbs_ioctl.h>
+#include "uverbs.h"
+#include "rdma_core.h"
+
+static int uverbs_lock_object(struct ib_uobject *uobj,
+			      enum uverbs_idr_access access)
+{
+	if (access == UVERBS_ACCESS_READ)
+		return down_read_trylock(&uobj->usecnt) == 1 ? 0 : -EBUSY;
+
+	/* lock is either WRITE or DESTROY - should be exclusive */
+	return down_write_trylock(&uobj->usecnt) == 1 ? 0 : -EBUSY;
+}
+
+static struct ib_uobject *get_uobj_rcu(int id, struct ib_ucontext *context)
+{
+	struct ib_uobject *uobj;
+
+	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
+			 "uverbs: get_uobj_rcu wasn't called in a rcu_read_lock()!");
+	/* object won't be released as we're protected in rcu */
+	uobj = idr_find(&context->device->idr, id);
+	if (uobj) {
+		if (uobj->context != context)
+			uobj = NULL;
+	}
+
+	return uobj;
+}
+
+struct ib_ucontext_lock {
+	/* locking the uobjects_list */
+	struct mutex lock;
+};
+
+static void init_uobj(struct ib_uobject *uobj, struct ib_ucontext *context)
+{
+	init_rwsem(&uobj->usecnt);
+	uobj->context     = context;
+}
+
+static int uverbs_idr_add_uobj(struct ib_uobject *uobj)
+{
+	int ret;
+
+	idr_preload(GFP_KERNEL);
+	spin_lock(&uobj->context->device->idr_lock);
+
+	/*
+	 * We start with allocating an idr pointing to NULL. This represents an
+	 * object which isn't initialized yet. We'll replace it later on with
+	 * the real object once we commit.
+	 */
+	ret = idr_alloc(&uobj->context->device->idr, NULL, 0, 0, GFP_NOWAIT);
+	if (ret >= 0)
+		uobj->id = ret;
+
+	spin_unlock(&uobj->context->device->idr_lock);
+	idr_preload_end();
+
+	return ret < 0 ? ret : 0;
+}
+
+static void uverbs_idr_remove_uobj(struct ib_uobject *uobj)
+{
+	spin_lock(&uobj->context->device->idr_lock);
+	idr_remove(&uobj->context->device->idr, uobj->id);
+	spin_unlock(&uobj->context->device->idr_lock);
+}
+
+static void put_uobj(struct ib_uobject *uobj)
+{
+	/*
+	 * When we destroy an object, we first just lock it for WRITE and
+	 * actually DESTROY it in the finalize stage. So, the problematic
+	 * scenario is when we just stared the finalize stage of the
+	 * destruction (nothing was executed yet). Now, the other thread
+	 * fetched the object for READ access, but it didn't lock it yet.
+	 * The DESTROY thread continues and starts destroying the object.
+	 * When the other thread continue - without the RCU, it would
+	 * access freed memory. However, the rcu_read_lock delays the free
+	 * until the rcu_read_lock of the READ operation quits. Since the
+	 * write lock of the object is still taken by the DESTROY flow, the
+	 * READ operation will get -EBUSY and it'll just bail out.
+	 */
+	kfree_rcu(uobj, rcu);
+}
+
+/*
+ * Returns the ib_uobject, NULL if the requested object isn't found or an error.
+ * The caller should check for IS_ERR_OR_NULL.
+ */
+static struct ib_uobject *get_uobject_from_context(struct ib_ucontext *ucontext,
+						   const struct uverbs_type_alloc_action *type,
+						   u32 idr,
+						   enum uverbs_idr_access access)
+{
+	struct ib_uobject *uobj;
+	int ret;
+
+	rcu_read_lock();
+	uobj = get_uobj_rcu(idr, ucontext);
+	if (!uobj)
+		goto free;
+
+	if (uobj->type != type) {
+		uobj = NULL;
+		goto free;
+	}
+
+	ret = uverbs_lock_object(uobj, access);
+	if (ret)
+		uobj = ERR_PTR(ret);
+free:
+	rcu_read_unlock();
+	return uobj;
+}
+
+static struct ib_uobject *uverbs_get_uobject_from_idr(const struct uverbs_type_alloc_action *type_alloc,
+						      struct ib_ucontext *ucontext,
+						      enum uverbs_idr_access access,
+						      uint32_t idr)
+{
+	struct ib_uobject *uobj;
+	int ret;
+
+	if (access == UVERBS_ACCESS_NEW) {
+		uobj = kmalloc(type_alloc->obj_size, GFP_KERNEL);
+		if (!uobj)
+			return ERR_PTR(-ENOMEM);
+
+		init_uobj(uobj, ucontext);
+
+		uobj->type = type_alloc;
+		ret = uverbs_idr_add_uobj(uobj);
+		if (ret) {
+			kfree(uobj);
+			return ERR_PTR(ret);
+		}
+
+	} else {
+		uobj = get_uobject_from_context(ucontext, type_alloc, idr,
+						access);
+
+		if (IS_ERR_OR_NULL(uobj))
+			return ERR_PTR(-ENOENT);
+	}
+
+	return uobj;
+}
+
+struct ib_uobject *uverbs_get_uobject_from_context(const struct uverbs_type_alloc_action *type_alloc,
+						   struct ib_ucontext *ucontext,
+						   enum uverbs_idr_access access,
+						   unsigned int id)
+{
+	if (type_alloc->type == UVERBS_ATTR_TYPE_IDR)
+		return uverbs_get_uobject_from_idr(type_alloc, ucontext, access,
+						   id);
+	else
+		return ERR_PTR(-ENOENT);
+}
+
+static void uverbs_uobject_add(struct ib_uobject *uobject)
+{
+	mutex_lock(&uobject->context->uobjects_lock->lock);
+	list_add(&uobject->list, &uobject->context->uobjects);
+	mutex_unlock(&uobject->context->uobjects_lock->lock);
+}
+
+static void uverbs_uobject_remove(struct ib_uobject *uobject)
+{
+	/*
+	 * Calling remove requires exclusive access, so it's not possible
+	 * another thread will use our object since the function is called
+	 * with exclusive access.
+	 */
+	uverbs_idr_remove_uobj(uobject);
+	mutex_lock(&uobject->context->uobjects_lock->lock);
+	list_del(&uobject->list);
+	mutex_unlock(&uobject->context->uobjects_lock->lock);
+	put_uobj(uobject);
+}
+
+static void uverbs_finalize_idr(struct ib_uobject *uobj,
+				enum uverbs_idr_access access,
+				bool commit)
+{
+	switch (access) {
+	case UVERBS_ACCESS_READ:
+		up_read(&uobj->usecnt);
+		break;
+	case UVERBS_ACCESS_NEW:
+		if (commit) {
+			uverbs_uobject_add(uobj);
+			spin_lock(&uobj->context->device->idr_lock);
+			/*
+			 * We already allocated this IDR with a NULL object, so
+			 * this shouldn't fail.
+			 */
+			WARN_ON(idr_replace(&uobj->context->device->idr,
+					    uobj, uobj->id));
+			spin_unlock(&uobj->context->device->idr_lock);
+		} else {
+			uverbs_idr_remove_uobj(uobj);
+			put_uobj(uobj);
+		}
+		break;
+	case UVERBS_ACCESS_WRITE:
+		up_write(&uobj->usecnt);
+		break;
+	case UVERBS_ACCESS_DESTROY:
+		if (commit)
+			uverbs_uobject_remove(uobj);
+		else
+			up_write(&uobj->usecnt);
+		break;
+	}
+}
+
+void uverbs_finalize_object(struct ib_uobject *uobj,
+			    enum uverbs_idr_access access,
+			    bool commit)
+{
+	if (uobj->type->type == UVERBS_ATTR_TYPE_IDR)
+		uverbs_finalize_idr(uobj, access, commit);
+	else
+		WARN_ON(true);
+}
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
new file mode 100644
index 0000000..0142573
--- /dev/null
+++ b/drivers/infiniband/core/rdma_core.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005-2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef RDMA_CORE_H
+#define RDMA_CORE_H
+
+#include <linux/idr.h>
+#include <rdma/uverbs_ioctl.h>
+#include <rdma/ib_verbs.h>
+#include <linux/mutex.h>
+
+/*
+ * Get an ib_uobject that corresponds to the given id from ucontext, assuming
+ * the object is from the given type. Lock it to the required access.
+ * This function could create (access == NEW) or destroy (access == DESTROY)
+ * objects if required. The action will be finalized only when
+ * uverbs_finalize_object is called.
+ */
+struct ib_uobject *uverbs_get_uobject_from_context(const struct uverbs_type_alloc_action *type_alloc,
+						   struct ib_ucontext *ucontext,
+						   enum uverbs_idr_access access,
+						   unsigned int id);
+
+void uverbs_finalize_object(struct ib_uobject *uobj,
+			    enum uverbs_idr_access access,
+			    bool success);
+
+#endif /* RDMA_CORE_H */
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index cad2c00..47f560d 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1331,6 +1331,8 @@ struct ib_fmr_attr {
 
 struct ib_umem;
 
+struct ib_ucontext_lock;
+
 struct ib_ucontext {
 	struct ib_device       *device;
 	struct list_head	pd_list;
@@ -1346,6 +1348,10 @@ struct ib_ucontext {
 	struct list_head	rwq_ind_tbl_list;
 	int			closing;
 
+	/* lock for uobjects list */
+	struct ib_ucontext_lock	*uobjects_lock;
+	struct list_head	uobjects;
+
 	struct pid             *tgid;
 #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
 	struct rb_root      umem_tree;
@@ -1373,8 +1379,11 @@ struct ib_uobject {
 	int			id;		/* index into kernel idr */
 	struct kref		ref;
 	struct rw_semaphore	mutex;		/* protects .live */
+	struct rw_semaphore	usecnt;		/* protects exclusive access */
 	struct rcu_head		rcu;		/* kfree_rcu() overhead */
 	int			live;
+
+	const struct uverbs_type_alloc_action *type;
 };
 
 struct ib_udata {
diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
new file mode 100644
index 0000000..903f6b3
--- /dev/null
+++ b/include/rdma/uverbs_ioctl.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _UVERBS_IOCTL_
+#define _UVERBS_IOCTL_
+
+#include <linux/kernel.h>
+
+enum uverbs_attr_type {
+	UVERBS_ATTR_TYPE_IDR,
+};
+
+enum uverbs_idr_access {
+	UVERBS_ACCESS_READ,
+	UVERBS_ACCESS_WRITE,
+	UVERBS_ACCESS_NEW,
+	UVERBS_ACCESS_DESTROY
+};
+
+struct uverbs_type_alloc_action;
+typedef void (*free_type)(const struct uverbs_type_alloc_action *uobject_type,
+			  struct ib_uobject *uobject);
+
+struct uverbs_type_alloc_action {
+	enum uverbs_attr_type		type;
+	int				order;
+	size_t				obj_size;
+	free_type			free_fn;
+};
+
+#endif
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH for-next 3/7] IB/core: Add support for fd objects
       [not found] ` <1484132033-3346-1-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  2017-01-11 10:53   ` [PATCH for-next 1/7] IB/core: Refactor IDR to be per-device Matan Barak
  2017-01-11 10:53   ` [PATCH for-next 2/7] IB/core: Add support for custom types Matan Barak
@ 2017-01-11 10:53   ` Matan Barak
       [not found]     ` <1484132033-3346-4-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  2017-01-11 10:53   ` [PATCH for-next 4/7] IB/core: Add generic ucontext initialization and teardown Matan Barak
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-11 10:53 UTC (permalink / raw)
  To: Doug Ledford
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

The completion channel we use in verbs infrastructure is FD based.
Previously, we had a separate way to manage this object. Since we
strive for a single way to manage any kind of object in this
infrastructure, we conceptually treat all objects as subclasses
of ib_uobject.

This commit adds the necessary mechanism to support FD based objects
like their IDR counterparts. FD objects release need to be synchronized
with context release. Since FDs could outlives their context, we use
a kref on this lock. We initialize the lock and the kref in downstream
patches. This is acceptable, as we don't use this infrastructure until
a later point in this series.

Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Reviewed-by: Yishai Hadas <yishaih-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/core/rdma_core.c   | 134 +++++++++++++++++++++++++++++++++-
 drivers/infiniband/core/rdma_core.h   |  12 +++
 drivers/infiniband/core/uverbs_main.c |   2 +-
 include/rdma/ib_verbs.h               |   4 +-
 include/rdma/uverbs_ioctl.h           |   8 ++
 5 files changed, 157 insertions(+), 3 deletions(-)

diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index 09b44ec..193591d 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -64,10 +64,20 @@ static struct ib_uobject *get_uobj_rcu(int id, struct ib_ucontext *context)
 }
 
 struct ib_ucontext_lock {
+	struct kref  ref;
 	/* locking the uobjects_list */
 	struct mutex lock;
 };
 
+static void release_uobjects_list_lock(struct kref *ref)
+{
+	struct ib_ucontext_lock *lock = container_of(ref,
+						     struct ib_ucontext_lock,
+						     ref);
+
+	kfree(lock);
+}
+
 static void init_uobj(struct ib_uobject *uobj, struct ib_ucontext *context)
 {
 	init_rwsem(&uobj->usecnt);
@@ -184,6 +194,75 @@ static struct ib_uobject *uverbs_get_uobject_from_idr(const struct uverbs_type_a
 	return uobj;
 }
 
+static struct ib_uobject *uverbs_priv_fd_to_uobject(void *priv)
+{
+	return priv - sizeof(struct ib_uobject);
+}
+
+static struct ib_uobject *uverbs_get_uobject_from_fd(const struct uverbs_type_alloc_action *type_alloc,
+						     struct ib_ucontext *ucontext,
+						     enum uverbs_idr_access access,
+						     unsigned int fd)
+{
+	if (access == UVERBS_ACCESS_NEW) {
+		int _fd;
+		struct ib_uobject *uobj = NULL;
+		struct file *filp;
+
+		_fd = get_unused_fd_flags(O_CLOEXEC);
+		if (_fd < 0)
+			return ERR_PTR(_fd);
+
+		uobj = kmalloc(type_alloc->obj_size, GFP_KERNEL);
+		if (!uobj) {
+			put_unused_fd(_fd);
+			return ERR_PTR(-ENOMEM);
+		}
+
+		init_uobj(uobj, ucontext);
+		filp = anon_inode_getfile(type_alloc->fd.name,
+					  type_alloc->fd.fops,
+					  uverbs_fd_uobj_to_priv(uobj),
+					  type_alloc->fd.flags);
+		if (IS_ERR(filp)) {
+			put_unused_fd(_fd);
+			kfree(uobj);
+			return (void *)filp;
+		}
+
+		/*
+		 * user_handle should be filled by the user,
+		 * the list is filled in the commit operation.
+		 */
+		uobj->type = type_alloc;
+		uobj->id = _fd;
+		uobj->object = filp;
+
+		return uobj;
+	} else if (access == UVERBS_ACCESS_READ) {
+		struct file *f = fget(fd);
+		struct ib_uobject *uobject;
+
+		if (!f)
+			return ERR_PTR(-EBADF);
+
+		uobject = uverbs_priv_fd_to_uobject(f->private_data);
+		if (f->f_op != type_alloc->fd.fops ||
+		    !uobject->context) {
+			fput(f);
+			return ERR_PTR(-EBADF);
+		}
+
+		/*
+		 * No need to protect it with a ref count, as fget increases
+		 * f_count.
+		 */
+		return uobject;
+	} else {
+		return ERR_PTR(-EOPNOTSUPP);
+	}
+}
+
 struct ib_uobject *uverbs_get_uobject_from_context(const struct uverbs_type_alloc_action *type_alloc,
 						   struct ib_ucontext *ucontext,
 						   enum uverbs_idr_access access,
@@ -193,7 +272,8 @@ struct ib_uobject *uverbs_get_uobject_from_context(const struct uverbs_type_allo
 		return uverbs_get_uobject_from_idr(type_alloc, ucontext, access,
 						   id);
 	else
-		return ERR_PTR(-ENOENT);
+		return uverbs_get_uobject_from_fd(type_alloc, ucontext, access,
+						  id);
 }
 
 static void uverbs_uobject_add(struct ib_uobject *uobject)
@@ -253,12 +333,64 @@ static void uverbs_finalize_idr(struct ib_uobject *uobj,
 	}
 }
 
+static void uverbs_finalize_fd(struct ib_uobject *uobj,
+			       enum uverbs_idr_access access,
+			       bool commit)
+{
+	struct file *filp = uobj->object;
+
+	if (access == UVERBS_ACCESS_NEW) {
+		if (commit) {
+			uobj->uobjects_lock = uobj->context->uobjects_lock;
+			kref_get(&uobj->uobjects_lock->ref);
+			uverbs_uobject_add(uobj);
+			fd_install(uobj->id, uobj->object);
+		} else {
+			/* Unsuccessful NEW */
+			fput(filp);
+			put_unused_fd(uobj->id);
+			kfree(uobj);
+		}
+	} else {
+		fput(filp);
+	}
+}
+
 void uverbs_finalize_object(struct ib_uobject *uobj,
 			    enum uverbs_idr_access access,
 			    bool commit)
 {
 	if (uobj->type->type == UVERBS_ATTR_TYPE_IDR)
 		uverbs_finalize_idr(uobj, access, commit);
+	else if (uobj->type->type == UVERBS_ATTR_TYPE_FD)
+		uverbs_finalize_fd(uobj, access, commit);
 	else
 		WARN_ON(true);
 }
+
+static void uverbs_remove_fd(struct ib_uobject *uobject)
+{
+	if (uobject->context) {
+		list_del(&uobject->list);
+		uobject->context = NULL;
+	}
+}
+
+/* user should release the uobject in the release file_operation callback. */
+void uverbs_close_fd(struct file *f)
+{
+	struct ib_uobject *uobject = uverbs_priv_fd_to_uobject(f->private_data);
+
+	mutex_lock(&uobject->uobjects_lock->lock);
+	uverbs_remove_fd(uobject);
+	mutex_unlock(&uobject->uobjects_lock->lock);
+	kref_put(&uobject->uobjects_lock->ref, release_uobjects_list_lock);
+}
+
+void uverbs_cleanup_fd(void *private_data)
+{
+	struct ib_uobject *uobject = uverbs_priv_fd_to_uobject(private_data);
+
+	kfree(uobject);
+}
+
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index 0142573..c71a51c 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -57,5 +57,17 @@ struct ib_uobject *uverbs_get_uobject_from_context(const struct uverbs_type_allo
 void uverbs_finalize_object(struct ib_uobject *uobj,
 			    enum uverbs_idr_access access,
 			    bool success);
+/*
+ * Indicate this fd is no longer used by this consumer, but its memory isn't
+ * released yet. The memory is released only when ib_uverbs_cleanup_fd is
+ * called.
+ */
+void uverbs_close_fd(struct file *f);
+void uverbs_cleanup_fd(void *private_data);
+
+static inline void *uverbs_fd_uobj_to_priv(struct ib_uobject *uobj)
+{
+	return uobj + 1;
+}
 
 #endif /* RDMA_CORE_H */
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index daee2ba6..6e38a7c 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -339,7 +339,7 @@ static void ib_uverbs_comp_dev(struct ib_uverbs_device *dev)
 	complete(&dev->comp);
 }
 
-static void ib_uverbs_release_file(struct kref *ref)
+void ib_uverbs_release_file(struct kref *ref)
 {
 	struct ib_uverbs_file *file =
 		container_of(ref, struct ib_uverbs_file, ref);
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 47f560d..7992fcd 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1335,6 +1335,7 @@ struct ib_fmr_attr {
 
 struct ib_ucontext {
 	struct ib_device       *device;
+	struct ib_uverbs_file  *ufile;
 	struct list_head	pd_list;
 	struct list_head	mr_list;
 	struct list_head	mw_list;
@@ -1376,7 +1377,7 @@ struct ib_uobject {
 	struct ib_ucontext     *context;	/* associated user context */
 	void		       *object;		/* containing object */
 	struct list_head	list;		/* link to context's list */
-	int			id;		/* index into kernel idr */
+	int			id;		/* index into kernel idr/fd */
 	struct kref		ref;
 	struct rw_semaphore	mutex;		/* protects .live */
 	struct rw_semaphore	usecnt;		/* protects exclusive access */
@@ -1384,6 +1385,7 @@ struct ib_uobject {
 	int			live;
 
 	const struct uverbs_type_alloc_action *type;
+	struct ib_ucontext_lock	*uobjects_lock;
 };
 
 struct ib_udata {
diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
index 903f6b3..189e323 100644
--- a/include/rdma/uverbs_ioctl.h
+++ b/include/rdma/uverbs_ioctl.h
@@ -35,8 +35,11 @@
 
 #include <linux/kernel.h>
 
+struct ib_uobject;
+
 enum uverbs_attr_type {
 	UVERBS_ATTR_TYPE_IDR,
+	UVERBS_ATTR_TYPE_FD,
 };
 
 enum uverbs_idr_access {
@@ -55,6 +58,11 @@ struct uverbs_type_alloc_action {
 	int				order;
 	size_t				obj_size;
 	free_type			free_fn;
+	struct {
+		const struct file_operations	*fops;
+		const char			*name;
+		int				flags;
+	} fd;
 };
 
 #endif
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH for-next 4/7] IB/core: Add generic ucontext initialization and teardown
       [not found] ` <1484132033-3346-1-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
                     ` (2 preceding siblings ...)
  2017-01-11 10:53   ` [PATCH for-next 3/7] IB/core: Add support for fd objects Matan Barak
@ 2017-01-11 10:53   ` Matan Barak
       [not found]     ` <1484132033-3346-5-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  2017-01-11 10:53   ` [PATCH for-next 5/7] IB/core: Add macros for declaring types and type groups Matan Barak
                     ` (2 subsequent siblings)
  6 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-11 10:53 UTC (permalink / raw)
  To: Doug Ledford
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

When a ucontext is created, we need to initialize the list of objects.
This list consists of every user object that is associated with
this ucontext. The possible elements in this list are either a file
descriptor or an object which is represented by an IDR.
Every such an object, has a release function (which is called upon
object destruction) and a number associated to its release order.

When a ucontext is destroyed, the list is traversed while holding a
lock. This lock is necessary since a user might try to close a FD
file [s]he created and exists in this list.

Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Reviewed-by: Yishai Hadas <yishaih-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/core/rdma_core.c | 103 ++++++++++++++++++++++++++++++++++--
 drivers/infiniband/core/rdma_core.h |  14 +++++
 include/rdma/uverbs_ioctl.h         |  14 +++++
 3 files changed, 127 insertions(+), 4 deletions(-)

diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index 193591d..4654c74 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -69,6 +69,12 @@ struct ib_ucontext_lock {
 	struct mutex lock;
 };
 
+static void init_uobjects_list_lock(struct ib_ucontext_lock *lock)
+{
+	mutex_init(&lock->lock);
+	kref_init(&lock->ref);
+}
+
 static void release_uobjects_list_lock(struct kref *ref)
 {
 	struct ib_ucontext_lock *lock = container_of(ref,
@@ -283,7 +289,7 @@ static void uverbs_uobject_add(struct ib_uobject *uobject)
 	mutex_unlock(&uobject->context->uobjects_lock->lock);
 }
 
-static void uverbs_uobject_remove(struct ib_uobject *uobject)
+static void uverbs_uobject_remove(struct ib_uobject *uobject, bool lock)
 {
 	/*
 	 * Calling remove requires exclusive access, so it's not possible
@@ -291,9 +297,11 @@ static void uverbs_uobject_remove(struct ib_uobject *uobject)
 	 * with exclusive access.
 	 */
 	uverbs_idr_remove_uobj(uobject);
-	mutex_lock(&uobject->context->uobjects_lock->lock);
+	if (lock)
+		mutex_lock(&uobject->context->uobjects_lock->lock);
 	list_del(&uobject->list);
-	mutex_unlock(&uobject->context->uobjects_lock->lock);
+	if (lock)
+		mutex_unlock(&uobject->context->uobjects_lock->lock);
 	put_uobj(uobject);
 }
 
@@ -326,7 +334,7 @@ static void uverbs_finalize_idr(struct ib_uobject *uobj,
 		break;
 	case UVERBS_ACCESS_DESTROY:
 		if (commit)
-			uverbs_uobject_remove(uobj);
+			uverbs_uobject_remove(uobj, true);
 		else
 			up_write(&uobj->usecnt);
 		break;
@@ -394,3 +402,90 @@ void uverbs_cleanup_fd(void *private_data)
 	kfree(uobject);
 }
 
+static unsigned int get_max_type_orders(const struct uverbs_root *root)
+{
+	unsigned int i;
+	unsigned int max = 0;
+
+	for (i = 0; i < root->num_groups; i++) {
+		unsigned int j;
+		const struct uverbs_type_group *types = root->type_groups[i];
+
+		for (j = 0; j < types->num_types; j++) {
+			/*
+			 * Either this type isn't supported by this ib_device
+			 * (as the group is an array of pointers to types
+			 * indexed by the type) or this type is supported, but
+			 * we can't instantiate objects from this type
+			 * (e.g. you can't instantiate objects of
+			 * UVERBS_DEVICE).
+			 */
+			if (!types->types[j] || !types->types[j]->alloc)
+				continue;
+			if (types->types[j]->alloc->order > max)
+				max = types->types[j]->alloc->order;
+		}
+	}
+
+	return max;
+}
+
+void uverbs_release_ucontext(struct ib_ucontext *ucontext)
+{
+	/*
+	 * Since FD objects could outlive their context, we use a kref'ed
+	 * lock. This lock is referenced when a context and FD objects are
+	 * created. This lock protects concurrent context release from FD
+	 * objects release. Therefore, we need to put this lock object in
+	 * the context and every FD object release.
+	 */
+	kref_put(&ucontext->uobjects_lock->ref, release_uobjects_list_lock);
+}
+
+void uverbs_cleanup_ucontext(struct ib_ucontext *ucontext,
+			     const struct uverbs_root *root)
+{
+	unsigned int num_orders = get_max_type_orders(root);
+	unsigned int i;
+
+	for (i = 0; i <= num_orders; i++) {
+		struct ib_uobject *obj, *next_obj;
+
+		/*
+		 * This souldn't run while executing other commands on this
+		 * context. Thus, the only thing we should take care of is
+		 * releasing a FD while traversing this list. The FD could be
+		 * closed and released from the _release fop of this FD.
+		 * In order to mitigate this, we add a lock.
+		 * We take and release the lock per order traversal in order
+		 * to let other threads (which might still use the FDs) chance
+		 * to run.
+		 */
+		mutex_lock(&ucontext->uobjects_lock->lock);
+		list_for_each_entry_safe(obj, next_obj, &ucontext->uobjects,
+					 list)
+			if (obj->type->order == i) {
+				obj->type->free_fn(obj->type, obj);
+				if (obj->type->type == UVERBS_ATTR_TYPE_IDR)
+					uverbs_uobject_remove(obj, false);
+				else
+					uverbs_remove_fd(obj);
+			}
+		mutex_unlock(&ucontext->uobjects_lock->lock);
+	}
+	uverbs_release_ucontext(ucontext);
+}
+
+int uverbs_initialize_ucontext(struct ib_ucontext *ucontext)
+{
+	ucontext->uobjects_lock = kmalloc(sizeof(*ucontext->uobjects_lock),
+					  GFP_KERNEL);
+	if (!ucontext->uobjects_lock)
+		return -ENOMEM;
+
+	init_uobjects_list_lock(ucontext->uobjects_lock);
+	INIT_LIST_HEAD(&ucontext->uobjects);
+
+	return 0;
+}
+
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index c71a51c..d06bae6 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -58,6 +58,20 @@ void uverbs_finalize_object(struct ib_uobject *uobj,
 			    enum uverbs_idr_access access,
 			    bool success);
 /*
+ * These functions initialize and destroy the context. The context has a
+ * list of objects which is protected by a kref-ed lock, whose purpose is
+ * to protect concurrent FDs (e.g completion channel FDs) release while
+ * traversing the context and releasing its objects. initialize_ucontext
+ * should be called when we create a context. cleanup_ucontext removes all
+ * objects created in the ucontext. release_ucontext drops the reference from
+ * the lock.
+ */
+void uverbs_cleanup_ucontext(struct ib_ucontext *ucontext,
+			     const struct uverbs_root *root);
+int uverbs_initialize_ucontext(struct ib_ucontext *ucontext);
+void uverbs_release_ucontext(struct ib_ucontext *ucontext);
+
+/*
  * Indicate this fd is no longer used by this consumer, but its memory isn't
  * released yet. The memory is released only when ib_uverbs_cleanup_fd is
  * called.
diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
index 189e323..a8b0ff9 100644
--- a/include/rdma/uverbs_ioctl.h
+++ b/include/rdma/uverbs_ioctl.h
@@ -65,4 +65,18 @@ struct uverbs_type_alloc_action {
 	} fd;
 };
 
+struct uverbs_type {
+	const struct uverbs_type_alloc_action   *alloc;
+};
+
+struct uverbs_type_group {
+	size_t					num_types;
+	const struct uverbs_type		**types;
+};
+
+struct uverbs_root {
+	const struct uverbs_type_group		**type_groups;
+	size_t					num_groups;
+};
+
 #endif
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH for-next 5/7] IB/core: Add macros for declaring types and type groups
       [not found] ` <1484132033-3346-1-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
                     ` (3 preceding siblings ...)
  2017-01-11 10:53   ` [PATCH for-next 4/7] IB/core: Add generic ucontext initialization and teardown Matan Barak
@ 2017-01-11 10:53   ` Matan Barak
       [not found]     ` <1484132033-3346-6-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  2017-01-11 10:53   ` [PATCH for-next 6/7] IB/core: Declare all common IB types Matan Barak
  2017-01-11 10:53   ` [PATCH for-next 7/7] IB/core: Use the new IDR and locking infrastructure in uverbs_cmd Matan Barak
  6 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-11 10:53 UTC (permalink / raw)
  To: Doug Ledford
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

In order to initialize and destroy types in a generic way, we need to
provide information about the allocation size, release function and
order. This is done through a macro based DSL (domain specific
language). This patch adds macros to initialize a type and a type
group.

When we transform the write based commands to use this new locking and
allocation schema, we use these types declarations.

Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Reviewed-by: Yishai Hadas <yishaih-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
---
 include/rdma/uverbs_ioctl.h | 50 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 48 insertions(+), 2 deletions(-)

diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
index a8b0ff9..4b569ae 100644
--- a/include/rdma/uverbs_ioctl.h
+++ b/include/rdma/uverbs_ioctl.h
@@ -34,8 +34,7 @@
 #define _UVERBS_IOCTL_
 
 #include <linux/kernel.h>
-
-struct ib_uobject;
+#include <rdma/ib_verbs.h>
 
 enum uverbs_attr_type {
 	UVERBS_ATTR_TYPE_IDR,
@@ -79,4 +78,51 @@ struct uverbs_root {
 	size_t					num_groups;
 };
 
+#define UVERBS_BUILD_BUG_ON(cond) (sizeof(char[1 - 2 * !!(cond)]) -	\
+				   sizeof(char))
+#define UVERBS_TYPE_ALLOC_FD(_order, _obj_size, _free_fn, _fops, _name, _flags)\
+	((const struct uverbs_type_alloc_action)			\
+	 {.type = UVERBS_ATTR_TYPE_FD,					\
+	 .order = _order,						\
+	 .obj_size = (_obj_size) +					\
+		UVERBS_BUILD_BUG_ON((_obj_size) < sizeof(struct ib_uobject)), \
+	 .free_fn = _free_fn,						\
+	 .fd = {.fops = _fops,						\
+		.name = _name,						\
+		.flags = _flags} })
+#define UVERBS_TYPE_ALLOC_IDR_SZ(_size, _order, _free_fn)		\
+	((const struct uverbs_type_alloc_action)			\
+	 {.type = UVERBS_ATTR_TYPE_IDR,					\
+	 .order = _order,						\
+	 .free_fn = _free_fn,						\
+	 .obj_size = (_size) +						\
+		UVERBS_BUILD_BUG_ON((_size) < sizeof(struct ib_uobject)),})
+#define UVERBS_TYPE_ALLOC_IDR(_order, _free_fn)				\
+	 UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uobject), _order, _free_fn)
+#define DECLARE_UVERBS_TYPE(name, _alloc)				\
+	const struct uverbs_type name = {				\
+		.alloc = _alloc,					\
+	}
+#define _UVERBS_TYPE_SZ(...)						\
+	(sizeof((const struct uverbs_type *[]){__VA_ARGS__}) /	\
+	 sizeof(const struct uverbs_type *))
+#define ADD_UVERBS_TYPE(type_idx, type_ptr)				\
+	[type_idx] = ((const struct uverbs_type * const)&(type_ptr))
+#define UVERBS_TYPES(...)  ((const struct uverbs_type_group)		\
+	{.num_types = _UVERBS_TYPE_SZ(__VA_ARGS__),			\
+	 .types = (const struct uverbs_type *[]){__VA_ARGS__} })
+#define DECLARE_UVERBS_TYPES(name, ...)				\
+	const struct uverbs_type_group name = UVERBS_TYPES(__VA_ARGS__)
+
+#define _UVERBS_TYPES_SZ(...)						\
+	(sizeof((const struct uverbs_type_group *[]){__VA_ARGS__}) /	\
+	 sizeof(const struct uverbs_type_group *))
+
+#define UVERBS_TYPES_GROUP(...)						\
+	((const struct uverbs_root){				\
+		.type_groups = (const struct uverbs_type_group *[]){__VA_ARGS__},\
+		.num_groups = _UVERBS_TYPES_SZ(__VA_ARGS__)})
+#define DECLARE_UVERBS_TYPES_GROUP(name, ...)		\
+	const struct uverbs_root name = UVERBS_TYPES_GROUP(__VA_ARGS__)
+
 #endif
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH for-next 6/7] IB/core: Declare all common IB types
       [not found] ` <1484132033-3346-1-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
                     ` (4 preceding siblings ...)
  2017-01-11 10:53   ` [PATCH for-next 5/7] IB/core: Add macros for declaring types and type groups Matan Barak
@ 2017-01-11 10:53   ` Matan Barak
       [not found]     ` <1484132033-3346-7-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  2017-01-11 10:53   ` [PATCH for-next 7/7] IB/core: Use the new IDR and locking infrastructure in uverbs_cmd Matan Barak
  6 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-11 10:53 UTC (permalink / raw)
  To: Doug Ledford
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

This patch declares all the required information for creating and
destroying all common IB types. The refactored infrastructure treats
types in a more object oriented way. Each type encapsulates all the
required information for its creation and destruction.

This patch is required in order to transform all currently uverbs_cmd
verbs to initialize and destroy objects using the refactored
infrastructure. These types are used in downstream patches.

Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Reviewed-by: Yishai Hadas <yishaih-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/core/Makefile           |   2 +-
 drivers/infiniband/core/uverbs.h           |   3 +
 drivers/infiniband/core/uverbs_ioctl_cmd.c | 212 +++++++++++++++++++++++++++++
 drivers/infiniband/core/uverbs_main.c      |   6 +-
 include/rdma/uverbs_ioctl_cmd.h            |  68 +++++++++
 5 files changed, 287 insertions(+), 4 deletions(-)
 create mode 100644 drivers/infiniband/core/uverbs_ioctl_cmd.c
 create mode 100644 include/rdma/uverbs_ioctl_cmd.h

diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index 1819623..7676592 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -29,4 +29,4 @@ ib_umad-y :=			user_mad.o
 ib_ucm-y :=			ucm.o
 
 ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
-				rdma_core.o
+				rdma_core.o uverbs_ioctl_cmd.o
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 6344b80..1940bb9 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -176,6 +176,7 @@ struct ib_ucq_object {
 };
 
 void idr_remove_uobj(struct ib_uobject *uobj);
+extern const struct file_operations uverbs_event_fops;
 
 struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
 					struct ib_device *ib_dev,
@@ -199,6 +200,8 @@ void ib_uverbs_event_handler(struct ib_event_handler *handler,
 void ib_uverbs_dealloc_xrcd(struct ib_uverbs_device *dev, struct ib_xrcd *xrcd);
 
 int uverbs_dealloc_mw(struct ib_mw *mw);
+void ib_uverbs_detach_umcast(struct ib_qp *qp,
+			     struct ib_uqp_object *uobj);
 
 struct ib_uverbs_flow_spec {
 	union {
diff --git a/drivers/infiniband/core/uverbs_ioctl_cmd.c b/drivers/infiniband/core/uverbs_ioctl_cmd.c
new file mode 100644
index 0000000..c49abf6
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_ioctl_cmd.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <rdma/uverbs_ioctl_cmd.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_verbs.h>
+#include <linux/bug.h>
+#include <linux/file.h>
+#include "rdma_core.h"
+#include "uverbs.h"
+
+void uverbs_free_ah(const struct uverbs_type_alloc_action *type_alloc_action,
+		    struct ib_uobject *uobject)
+{
+	ib_destroy_ah((struct ib_ah *)uobject->object);
+}
+
+void uverbs_free_flow(const struct uverbs_type_alloc_action *type_alloc_action,
+		      struct ib_uobject *uobject)
+{
+	ib_destroy_flow((struct ib_flow *)uobject->object);
+}
+
+void uverbs_free_mw(const struct uverbs_type_alloc_action *type_alloc_action,
+		    struct ib_uobject *uobject)
+{
+	uverbs_dealloc_mw((struct ib_mw *)uobject->object);
+}
+
+void uverbs_free_qp(const struct uverbs_type_alloc_action *type_alloc_action,
+		    struct ib_uobject *uobject)
+{
+	struct ib_qp *qp = uobject->object;
+	struct ib_uqp_object *uqp =
+		container_of(uobject, struct ib_uqp_object, uevent.uobject);
+
+	if (qp == qp->real_qp)
+		ib_uverbs_detach_umcast(qp, uqp);
+	ib_destroy_qp(qp);
+	ib_uverbs_release_uevent(uobject->context->ufile, &uqp->uevent);
+}
+
+void uverbs_free_rwq_ind_tbl(const struct uverbs_type_alloc_action *type_alloc_action,
+			     struct ib_uobject *uobject)
+{
+	struct ib_rwq_ind_table *rwq_ind_tbl = uobject->object;
+	struct ib_wq **ind_tbl = rwq_ind_tbl->ind_tbl;
+
+	ib_destroy_rwq_ind_table(rwq_ind_tbl);
+	kfree(ind_tbl);
+}
+
+void uverbs_free_wq(const struct uverbs_type_alloc_action *type_alloc_action,
+		    struct ib_uobject *uobject)
+{
+	struct ib_wq *wq = uobject->object;
+	struct ib_uwq_object *uwq =
+		container_of(uobject, struct ib_uwq_object, uevent.uobject);
+
+	ib_destroy_wq(wq);
+	ib_uverbs_release_uevent(uobject->context->ufile, &uwq->uevent);
+}
+
+void uverbs_free_srq(const struct uverbs_type_alloc_action *type_alloc_action,
+		     struct ib_uobject *uobject)
+{
+	struct ib_srq *srq = uobject->object;
+	struct ib_uevent_object *uevent =
+		container_of(uobject, struct ib_uevent_object, uobject);
+
+	ib_destroy_srq(srq);
+	ib_uverbs_release_uevent(uobject->context->ufile, uevent);
+}
+
+void uverbs_free_cq(const struct uverbs_type_alloc_action *type_alloc_action,
+		    struct ib_uobject *uobject)
+{
+	struct ib_cq *cq = uobject->object;
+	struct ib_uverbs_event_file *ev_file = cq->cq_context;
+	struct ib_ucq_object *ucq =
+		container_of(uobject, struct ib_ucq_object, uobject);
+
+	ib_destroy_cq(cq);
+	ib_uverbs_release_ucq(uobject->context->ufile, ev_file, ucq);
+}
+
+void uverbs_free_mr(const struct uverbs_type_alloc_action *type_alloc_action,
+		    struct ib_uobject *uobject)
+{
+	ib_dereg_mr((struct ib_mr *)uobject->object);
+}
+
+void uverbs_free_xrcd(const struct uverbs_type_alloc_action *type_alloc_action,
+		      struct ib_uobject *uobject)
+{
+	struct ib_xrcd *xrcd = uobject->object;
+
+	mutex_lock(&uobject->context->ufile->device->xrcd_tree_mutex);
+	ib_uverbs_dealloc_xrcd(uobject->context->ufile->device, xrcd);
+	mutex_unlock(&uobject->context->ufile->device->xrcd_tree_mutex);
+}
+
+void uverbs_free_pd(const struct uverbs_type_alloc_action *type_alloc_action,
+		    struct ib_uobject *uobject)
+{
+	ib_dealloc_pd((struct ib_pd *)uobject->object);
+}
+
+void uverbs_free_event_file(const struct uverbs_type_alloc_action *type_alloc_action,
+			    struct ib_uobject *uobject)
+{
+	struct ib_uverbs_event_file *event_file = (void *)(uobject + 1);
+
+	spin_lock_irq(&event_file->lock);
+	event_file->is_closed = 1;
+	spin_unlock_irq(&event_file->lock);
+
+	wake_up_interruptible(&event_file->poll_wait);
+	kill_fasync(&event_file->async_queue, SIGIO, POLL_IN);
+};
+
+DECLARE_UVERBS_TYPE(uverbs_type_comp_channel,
+		    &UVERBS_TYPE_ALLOC_FD(0, sizeof(struct ib_uobject) + sizeof(struct ib_uverbs_event_file),
+					  uverbs_free_event_file,
+					  &uverbs_event_fops,
+					  "[infinibandevent]", O_RDONLY));
+
+DECLARE_UVERBS_TYPE(uverbs_type_cq,
+		    &UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_ucq_object), 0,
+					      uverbs_free_cq));
+
+DECLARE_UVERBS_TYPE(uverbs_type_qp,
+		    &UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uqp_object), 0,
+					      uverbs_free_qp));
+
+DECLARE_UVERBS_TYPE(uverbs_type_mw,
+		    &UVERBS_TYPE_ALLOC_IDR(0, uverbs_free_mw));
+
+DECLARE_UVERBS_TYPE(uverbs_type_mr,
+		    /* 1 is used in order to free the MR after all the MWs */
+		    &UVERBS_TYPE_ALLOC_IDR(1, uverbs_free_mr));
+
+DECLARE_UVERBS_TYPE(uverbs_type_srq,
+		    &UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_usrq_object), 0,
+					      uverbs_free_srq));
+
+DECLARE_UVERBS_TYPE(uverbs_type_ah,
+		    &UVERBS_TYPE_ALLOC_IDR(0, uverbs_free_ah));
+
+DECLARE_UVERBS_TYPE(uverbs_type_flow,
+		    &UVERBS_TYPE_ALLOC_IDR(0, uverbs_free_flow));
+
+DECLARE_UVERBS_TYPE(uverbs_type_wq,
+		    &UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uwq_object), 0,
+					      uverbs_free_wq));
+
+DECLARE_UVERBS_TYPE(uverbs_type_rwq_ind_table,
+		    &UVERBS_TYPE_ALLOC_IDR(0, uverbs_free_rwq_ind_tbl));
+
+DECLARE_UVERBS_TYPE(uverbs_type_xrcd,
+		    &UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uxrcd_object), 0,
+					      uverbs_free_xrcd));
+
+DECLARE_UVERBS_TYPE(uverbs_type_pd,
+		    /* 2 is used in order to free the PD after MRs */
+		    &UVERBS_TYPE_ALLOC_IDR(2, uverbs_free_pd));
+
+DECLARE_UVERBS_TYPES(uverbs_common_types,
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_PD, uverbs_type_pd),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_MR, uverbs_type_mr),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_COMP_CHANNEL, uverbs_type_comp_channel),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_CQ, uverbs_type_cq),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_QP, uverbs_type_qp),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_AH, uverbs_type_ah),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_MW, uverbs_type_mw),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_SRQ, uverbs_type_srq),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_FLOW, uverbs_type_flow),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_WQ, uverbs_type_wq),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_RWQ_IND_TBL,
+				     uverbs_type_rwq_ind_table),
+		     ADD_UVERBS_TYPE(UVERBS_TYPE_XRCD, uverbs_type_xrcd),
+);
+EXPORT_SYMBOL(uverbs_common_types);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 6e38a7c..75c30d9 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -200,8 +200,8 @@ void ib_uverbs_release_uevent(struct ib_uverbs_file *file,
 	spin_unlock_irq(&file->async_file->lock);
 }
 
-static void ib_uverbs_detach_umcast(struct ib_qp *qp,
-				    struct ib_uqp_object *uobj)
+void ib_uverbs_detach_umcast(struct ib_qp *qp,
+			     struct ib_uqp_object *uobj)
 {
 	struct ib_uverbs_mcast_entry *mcast, *tmp;
 
@@ -477,7 +477,7 @@ static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
 	return 0;
 }
 
-static const struct file_operations uverbs_event_fops = {
+const struct file_operations uverbs_event_fops = {
 	.owner	 = THIS_MODULE,
 	.read	 = ib_uverbs_event_read,
 	.poll    = ib_uverbs_event_poll,
diff --git a/include/rdma/uverbs_ioctl_cmd.h b/include/rdma/uverbs_ioctl_cmd.h
new file mode 100644
index 0000000..bab280c
--- /dev/null
+++ b/include/rdma/uverbs_ioctl_cmd.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _UVERBS_IOCTL_CMD_
+#define _UVERBS_IOCTL_CMD_
+
+#include <rdma/uverbs_ioctl.h>
+
+enum uverbs_common_types {
+	UVERBS_TYPE_PD,
+	UVERBS_TYPE_COMP_CHANNEL,
+	UVERBS_TYPE_CQ,
+	UVERBS_TYPE_QP,
+	UVERBS_TYPE_SRQ,
+	UVERBS_TYPE_AH,
+	UVERBS_TYPE_MR,
+	UVERBS_TYPE_MW,
+	UVERBS_TYPE_FLOW,
+	UVERBS_TYPE_XRCD,
+	UVERBS_TYPE_RWQ_IND_TBL,
+	UVERBS_TYPE_WQ,
+	UVERBS_TYPE_LAST,
+};
+
+extern const struct uverbs_type uverbs_type_cq;
+extern const struct uverbs_type uverbs_type_qp;
+extern const struct uverbs_type uverbs_type_rwq_ind_table;
+extern const struct uverbs_type uverbs_type_wq;
+extern const struct uverbs_type uverbs_type_srq;
+extern const struct uverbs_type uverbs_type_ah;
+extern const struct uverbs_type uverbs_type_flow;
+extern const struct uverbs_type uverbs_type_comp_channel;
+extern const struct uverbs_type uverbs_type_mr;
+extern const struct uverbs_type uverbs_type_mw;
+extern const struct uverbs_type uverbs_type_pd;
+extern const struct uverbs_type uverbs_type_xrcd;
+extern const struct uverbs_type_group uverbs_common_types;
+#endif
+
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH for-next 7/7] IB/core: Use the new IDR and locking infrastructure in uverbs_cmd
       [not found] ` <1484132033-3346-1-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
                     ` (5 preceding siblings ...)
  2017-01-11 10:53   ` [PATCH for-next 6/7] IB/core: Declare all common IB types Matan Barak
@ 2017-01-11 10:53   ` Matan Barak
       [not found]     ` <1484132033-3346-8-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  6 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-11 10:53 UTC (permalink / raw)
  To: Doug Ledford
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

The new infrastructure introduced a new locking and objects scheme.
We rewrite the current uverbs_cmd handlers to use them. The new
infrastructure needs a types definition in order to figure out how
to allocate/free resources, which is defined in upstream patches.

This patch refactores the following things:
(*) Instead of having a list per type, we use the ucontext's list
(*) The locking semantics are changed:
      Two commands might try to lock the same object. If this object
      is locked for exclusive object, any concurrent access will get
      -EBUSY. This makes the user serialize access.
(*) The completion channel FD is created by using the infrastructure.
    Its release function and release context are serialized by the
    infrastructure.
(*) The live flag is no longer required as we first allocate an IDR
      and assign a NULL object. When we actually want to enable this
      IDR, we replace the NULL with the actual object.
(*) The handler may need to assign the user_handle field of the
      uobject explicitly.

Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
Reviewed-by: Yishai Hadas <yishaih-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/core/rdma_core.c          |    5 +
 drivers/infiniband/core/rdma_core.h          |    2 +
 drivers/infiniband/core/uverbs.h             |   11 +-
 drivers/infiniband/core/uverbs_cmd.c         | 1112 ++++++++------------------
 drivers/infiniband/core/uverbs_main.c        |  251 ++----
 drivers/infiniband/hw/cxgb3/iwch_provider.c  |    4 +
 drivers/infiniband/hw/cxgb4/provider.c       |    4 +
 drivers/infiniband/hw/hns/hns_roce_main.c    |    4 +
 drivers/infiniband/hw/i40iw/i40iw_verbs.c    |    4 +
 drivers/infiniband/hw/mlx4/main.c            |    4 +
 drivers/infiniband/hw/mlx5/main.c            |    4 +
 drivers/infiniband/hw/mthca/mthca_provider.c |    4 +
 drivers/infiniband/hw/nes/nes_verbs.c        |    4 +
 drivers/infiniband/hw/ocrdma/ocrdma_main.c   |    4 +
 drivers/infiniband/hw/usnic/usnic_ib_main.c  |    4 +
 drivers/infiniband/sw/rdmavt/vt.c            |    4 +
 drivers/infiniband/sw/rxe/rxe_verbs.c        |    4 +
 include/rdma/ib_verbs.h                      |   16 +-
 18 files changed, 486 insertions(+), 959 deletions(-)

diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index 4654c74..5b40120 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -63,6 +63,11 @@ static struct ib_uobject *get_uobj_rcu(int id, struct ib_ucontext *context)
 	return uobj;
 }
 
+bool uverbs_is_live(struct ib_uobject *uobj)
+{
+	return uobj == get_uobj_rcu(uobj->id, uobj->context);
+}
+
 struct ib_ucontext_lock {
 	struct kref  ref;
 	/* locking the uobjects_list */
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index d06bae6..b149471 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -54,6 +54,8 @@ struct ib_uobject *uverbs_get_uobject_from_context(const struct uverbs_type_allo
 						   enum uverbs_idr_access access,
 						   unsigned int id);
 
+/* Check if the object is still alive. This must be called within RCU */
+bool uverbs_is_live(struct ib_uobject *uobj);
 void uverbs_finalize_object(struct ib_uobject *uobj,
 			    enum uverbs_idr_access access,
 			    bool success);
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 1940bb9..70661bd 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -158,6 +158,8 @@ struct ib_usrq_object {
 
 struct ib_uqp_object {
 	struct ib_uevent_object	uevent;
+	/* lock for mcast list */
+	struct mutex		mcast_lock;
 	struct list_head 	mcast_list;
 	struct ib_uxrcd_object *uxrcd;
 };
@@ -175,14 +177,13 @@ struct ib_ucq_object {
 	u32			async_events_reported;
 };
 
-void idr_remove_uobj(struct ib_uobject *uobj);
 extern const struct file_operations uverbs_event_fops;
 
-struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
-					struct ib_device *ib_dev,
-					int is_async);
+void ib_uverbs_init_event_file(struct ib_uverbs_event_file *ev_file,
+			       struct ib_uverbs_file *uverbs_file);
+struct file *ib_uverbs_alloc_async_event_file(struct ib_uverbs_file *uverbs_file,
+					      struct ib_device *ib_dev);
 void ib_uverbs_free_async_event_file(struct ib_uverbs_file *uverbs_file);
-struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
 
 void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
 			   struct ib_uverbs_event_file *ev_file,
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 9e3c7db..339d564 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -40,269 +40,67 @@
 
 #include <linux/uaccess.h>
 
+#include <rdma/uverbs_ioctl.h>
+#include <rdma/uverbs_ioctl_cmd.h>
+#include "rdma_core.h"
+
 #include "uverbs.h"
 #include "core_priv.h"
 
-struct uverbs_lock_class {
-	struct lock_class_key	key;
-	char			name[16];
-};
-
-static struct uverbs_lock_class pd_lock_class	= { .name = "PD-uobj" };
-static struct uverbs_lock_class mr_lock_class	= { .name = "MR-uobj" };
-static struct uverbs_lock_class mw_lock_class	= { .name = "MW-uobj" };
-static struct uverbs_lock_class cq_lock_class	= { .name = "CQ-uobj" };
-static struct uverbs_lock_class qp_lock_class	= { .name = "QP-uobj" };
-static struct uverbs_lock_class ah_lock_class	= { .name = "AH-uobj" };
-static struct uverbs_lock_class srq_lock_class	= { .name = "SRQ-uobj" };
-static struct uverbs_lock_class xrcd_lock_class = { .name = "XRCD-uobj" };
-static struct uverbs_lock_class rule_lock_class = { .name = "RULE-uobj" };
-static struct uverbs_lock_class wq_lock_class = { .name = "WQ-uobj" };
-static struct uverbs_lock_class rwq_ind_table_lock_class = { .name = "IND_TBL-uobj" };
-
-/*
- * The ib_uobject locking scheme is as follows:
- *
- * - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it
- *   needs to be held during all idr write operations.  When an object is
- *   looked up, a reference must be taken on the object's kref before
- *   dropping this lock.  For read operations, the rcu_read_lock()
- *   and rcu_write_lock() but similarly the kref reference is grabbed
- *   before the rcu_read_unlock().
- *
- * - Each object also has an rwsem.  This rwsem must be held for
- *   reading while an operation that uses the object is performed.
- *   For example, while registering an MR, the associated PD's
- *   uobject.mutex must be held for reading.  The rwsem must be held
- *   for writing while initializing or destroying an object.
- *
- * - In addition, each object has a "live" flag.  If this flag is not
- *   set, then lookups of the object will fail even if it is found in
- *   the idr.  This handles a reader that blocks and does not acquire
- *   the rwsem until after the object is destroyed.  The destroy
- *   operation will set the live flag to 0 and then drop the rwsem;
- *   this will allow the reader to acquire the rwsem, see that the
- *   live flag is 0, and then drop the rwsem and its reference to
- *   object.  The underlying storage will not be freed until the last
- *   reference to the object is dropped.
- */
-
-static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
-		      struct ib_ucontext *context, struct uverbs_lock_class *c)
-{
-	uobj->user_handle = user_handle;
-	uobj->context     = context;
-	kref_init(&uobj->ref);
-	init_rwsem(&uobj->mutex);
-	lockdep_set_class_and_name(&uobj->mutex, &c->key, c->name);
-	uobj->live        = 0;
-}
-
-static void release_uobj(struct kref *kref)
-{
-	kfree_rcu(container_of(kref, struct ib_uobject, ref), rcu);
-}
-
-static void put_uobj(struct ib_uobject *uobj)
-{
-	kref_put(&uobj->ref, release_uobj);
-}
-
-static void put_uobj_read(struct ib_uobject *uobj)
-{
-	up_read(&uobj->mutex);
-	put_uobj(uobj);
-}
-
-static void put_uobj_write(struct ib_uobject *uobj)
-{
-	up_write(&uobj->mutex);
-	put_uobj(uobj);
-}
-
-static int idr_add_uobj(struct ib_uobject *uobj)
-{
-	int ret;
-
-	idr_preload(GFP_KERNEL);
-	spin_lock(&uobj->context->device->idr_lock);
-
-	ret = idr_alloc(&uobj->context->device->idr, uobj, 0, 0, GFP_NOWAIT);
-	if (ret >= 0)
-		uobj->id = ret;
-
-	spin_unlock(&uobj->context->device->idr_lock);
-	idr_preload_end();
-
-	return ret < 0 ? ret : 0;
-}
-
-void idr_remove_uobj(struct ib_uobject *uobj)
-{
-	spin_lock(&uobj->context->device->idr_lock);
-	idr_remove(&uobj->context->device->idr, uobj->id);
-	spin_unlock(&uobj->context->device->idr_lock);
-}
-
-static struct ib_uobject *__idr_get_uobj(int id, struct ib_ucontext *context)
-{
-	struct ib_uobject *uobj;
-
-	rcu_read_lock();
-	uobj = idr_find(&context->device->idr, id);
-	if (uobj) {
-		if (uobj->context == context)
-			kref_get(&uobj->ref);
-		else
-			uobj = NULL;
-	}
-	rcu_read_unlock();
-
-	return uobj;
-}
-
-static struct ib_uobject *idr_read_uobj(int id, struct ib_ucontext *context,
-					int nested)
-{
-	struct ib_uobject *uobj;
-
-	uobj = __idr_get_uobj(id, context);
-	if (!uobj)
-		return NULL;
-
-	if (nested)
-		down_read_nested(&uobj->mutex, SINGLE_DEPTH_NESTING);
-	else
-		down_read(&uobj->mutex);
-	if (!uobj->live) {
-		put_uobj_read(uobj);
-		return NULL;
-	}
-
-	return uobj;
-}
-
-static struct ib_uobject *idr_write_uobj(int id, struct ib_ucontext *context)
-{
-	struct ib_uobject *uobj;
-
-	uobj = __idr_get_uobj(id, context);
-	if (!uobj)
-		return NULL;
-
-	down_write(&uobj->mutex);
-	if (!uobj->live) {
-		put_uobj_write(uobj);
-		return NULL;
-	}
-
-	return uobj;
-}
-
-static void *idr_read_obj(int id, struct ib_ucontext *context,
-			  int nested)
-{
-	struct ib_uobject *uobj;
-
-	uobj = idr_read_uobj(id, context, nested);
-	return uobj ? uobj->object : NULL;
-}
+#define idr_get_xxxx(_type, _access, _handle, _context) ({		\
+	const struct uverbs_type * const type = &uverbs_type_## _type;	\
+	struct ib_uobject *uobj = uverbs_get_uobject_from_context(		\
+					type->alloc,			\
+					_context, _access, _handle);	\
+									\
+	IS_ERR(uobj) ? NULL : uobj->object; })
 
 static struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context)
 {
-	return idr_read_obj(pd_handle, context, 0);
+	return idr_get_xxxx(pd, UVERBS_ACCESS_READ, pd_handle, context);
 }
 
-static void put_pd_read(struct ib_pd *pd)
+static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context)
 {
-	put_uobj_read(pd->uobject);
-}
-
-static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context, int nested)
-{
-	return idr_read_obj(cq_handle, context, nested);
-}
-
-static void put_cq_read(struct ib_cq *cq)
-{
-	put_uobj_read(cq->uobject);
-}
-
-static void put_ah_read(struct ib_ah *ah)
-{
-	put_uobj_read(ah->uobject);
+	return idr_get_xxxx(cq, UVERBS_ACCESS_READ, cq_handle, context);
 }
 
 static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
 {
-	return idr_read_obj(ah_handle, context, 0);
+	return idr_get_xxxx(ah, UVERBS_ACCESS_READ, ah_handle, context);
 }
 
 static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context)
 {
-	return idr_read_obj(qp_handle, context, 0);
+	return idr_get_xxxx(qp, UVERBS_ACCESS_READ, qp_handle, context);
 }
 
 static struct ib_wq *idr_read_wq(int wq_handle, struct ib_ucontext *context)
 {
-	return idr_read_obj(wq_handle, context, 0);
-}
-
-static void put_wq_read(struct ib_wq *wq)
-{
-	put_uobj_read(wq->uobject);
+	return idr_get_xxxx(wq, UVERBS_ACCESS_READ, wq_handle, context);
 }
 
 static struct ib_rwq_ind_table *idr_read_rwq_indirection_table(int ind_table_handle,
 							       struct ib_ucontext *context)
 {
-	return idr_read_obj(ind_table_handle, context, 0);
-}
-
-static void put_rwq_indirection_table_read(struct ib_rwq_ind_table *ind_table)
-{
-	put_uobj_read(ind_table->uobject);
-}
-
-static struct ib_qp *idr_write_qp(int qp_handle, struct ib_ucontext *context)
-{
-	struct ib_uobject *uobj;
-
-	uobj = idr_write_uobj(qp_handle, context);
-	return uobj ? uobj->object : NULL;
-}
-
-static void put_qp_read(struct ib_qp *qp)
-{
-	put_uobj_read(qp->uobject);
-}
-
-static void put_qp_write(struct ib_qp *qp)
-{
-	put_uobj_write(qp->uobject);
+	return idr_get_xxxx(rwq_ind_table, UVERBS_ACCESS_READ,
+			    ind_table_handle, context);
 }
 
 static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context)
 {
-	return idr_read_obj(srq_handle, context, 0);
-}
-
-static void put_srq_read(struct ib_srq *srq)
-{
-	put_uobj_read(srq->uobject);
+	return idr_get_xxxx(srq, UVERBS_ACCESS_READ, srq_handle, context);
 }
 
 static struct ib_xrcd *idr_read_xrcd(int xrcd_handle, struct ib_ucontext *context,
 				     struct ib_uobject **uobj)
 {
-	*uobj = idr_read_uobj(xrcd_handle, context, 0);
+	*uobj = uverbs_get_uobject_from_context(uverbs_type_xrcd.alloc,
+						context, UVERBS_ACCESS_READ,
+						xrcd_handle);
 	return *uobj ? (*uobj)->object : NULL;
 }
 
-static void put_xrcd_read(struct ib_uobject *uobj)
-{
-	put_uobj_read(uobj);
-}
 ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
 			      struct ib_device *ib_dev,
 			      const char __user *buf,
@@ -339,17 +137,12 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
 	}
 
 	ucontext->device = ib_dev;
-	INIT_LIST_HEAD(&ucontext->pd_list);
-	INIT_LIST_HEAD(&ucontext->mr_list);
-	INIT_LIST_HEAD(&ucontext->mw_list);
-	INIT_LIST_HEAD(&ucontext->cq_list);
-	INIT_LIST_HEAD(&ucontext->qp_list);
-	INIT_LIST_HEAD(&ucontext->srq_list);
-	INIT_LIST_HEAD(&ucontext->ah_list);
-	INIT_LIST_HEAD(&ucontext->wq_list);
-	INIT_LIST_HEAD(&ucontext->rwq_ind_tbl_list);
-	INIT_LIST_HEAD(&ucontext->xrcd_list);
-	INIT_LIST_HEAD(&ucontext->rule_list);
+	/* ufile is required when some objects are released */
+	ucontext->ufile = file;
+	ret = uverbs_initialize_ucontext(ucontext);
+	if (ret)
+		goto err_ctx;
+
 	rcu_read_lock();
 	ucontext->tgid = get_task_pid(current->group_leader, PIDTYPE_PID);
 	rcu_read_unlock();
@@ -373,7 +166,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
 		goto err_free;
 	resp.async_fd = ret;
 
-	filp = ib_uverbs_alloc_event_file(file, ib_dev, 1);
+	filp = ib_uverbs_alloc_async_event_file(file, ib_dev);
 	if (IS_ERR(filp)) {
 		ret = PTR_ERR(filp);
 		goto err_fd;
@@ -402,6 +195,8 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
 
 err_free:
 	put_pid(ucontext->tgid);
+	uverbs_release_ucontext(ucontext);
+err_ctx:
 	ib_dev->dealloc_ucontext(ucontext);
 
 err:
@@ -553,12 +348,10 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
 		   (unsigned long) cmd.response + sizeof resp,
 		   in_len - sizeof cmd, out_len - sizeof resp);
 
-	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
-	if (!uobj)
-		return -ENOMEM;
-
-	init_uobj(uobj, 0, file->ucontext, &pd_lock_class);
-	down_write(&uobj->mutex);
+	uobj = uverbs_get_uobject_from_context(uverbs_type_pd.alloc, file->ucontext,
+					       UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 
 	pd = ib_dev->alloc_pd(ib_dev, file->ucontext, &udata);
 	if (IS_ERR(pd)) {
@@ -570,12 +363,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
 	pd->uobject = uobj;
 	pd->__internal_mr = NULL;
 	atomic_set(&pd->usecnt, 0);
-
 	uobj->object = pd;
-	ret = idr_add_uobj(uobj);
-	if (ret)
-		goto err_idr;
-
 	memset(&resp, 0, sizeof resp);
 	resp.pd_handle = uobj->id;
 
@@ -585,24 +373,14 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
 		goto err_copy;
 	}
 
-	mutex_lock(&file->mutex);
-	list_add_tail(&uobj->list, &file->ucontext->pd_list);
-	mutex_unlock(&file->mutex);
-
-	uobj->live = 1;
-
-	up_write(&uobj->mutex);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, true);
 
 	return in_len;
 
 err_copy:
-	idr_remove_uobj(uobj);
-
-err_idr:
 	ib_dealloc_pd(pd);
-
 err:
-	put_uobj_write(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, false);
 	return ret;
 }
 
@@ -619,9 +397,11 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(cmd.pd_handle, file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_pd.alloc, file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.pd_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 	pd = uobj->object;
 
 	if (atomic_read(&pd->usecnt)) {
@@ -634,21 +414,12 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
 	if (ret)
 		goto err_put;
 
-	uobj->live = 0;
-	put_uobj_write(uobj);
-
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
-
-	put_uobj(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
 
 	return in_len;
 
 err_put:
-	put_uobj_write(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 	return ret;
 }
 
@@ -786,16 +557,14 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
 		}
 	}
 
-	obj = kmalloc(sizeof *obj, GFP_KERNEL);
-	if (!obj) {
-		ret = -ENOMEM;
+	obj = (struct ib_uxrcd_object *)
+		uverbs_get_uobject_from_context(uverbs_type_xrcd.alloc, file->ucontext,
+						UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(obj)) {
+		ret = PTR_ERR(obj);
 		goto err_tree_mutex_unlock;
 	}
 
-	init_uobj(&obj->uobject, 0, file->ucontext, &xrcd_lock_class);
-
-	down_write(&obj->uobject.mutex);
-
 	if (!xrcd) {
 		xrcd = ib_dev->alloc_xrcd(ib_dev, file->ucontext, &udata);
 		if (IS_ERR(xrcd)) {
@@ -813,10 +582,6 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
 
 	atomic_set(&obj->refcnt, 0);
 	obj->uobject.object = xrcd;
-	ret = idr_add_uobj(&obj->uobject);
-	if (ret)
-		goto err_idr;
-
 	memset(&resp, 0, sizeof resp);
 	resp.xrcd_handle = obj->uobject.id;
 
@@ -825,7 +590,7 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
 			/* create new inode/xrcd table entry */
 			ret = xrcd_table_insert(file->device, inode, xrcd);
 			if (ret)
-				goto err_insert_xrcd;
+				goto err_dealloc_xrcd;
 		}
 		atomic_inc(&xrcd->usecnt);
 	}
@@ -839,12 +604,7 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
 	if (f.file)
 		fdput(f);
 
-	mutex_lock(&file->mutex);
-	list_add_tail(&obj->uobject.list, &file->ucontext->xrcd_list);
-	mutex_unlock(&file->mutex);
-
-	obj->uobject.live = 1;
-	up_write(&obj->uobject.mutex);
+	uverbs_finalize_object(&obj->uobject, UVERBS_ACCESS_NEW, true);
 
 	mutex_unlock(&file->device->xrcd_tree_mutex);
 	return in_len;
@@ -856,14 +616,11 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
 		atomic_dec(&xrcd->usecnt);
 	}
 
-err_insert_xrcd:
-	idr_remove_uobj(&obj->uobject);
-
-err_idr:
+err_dealloc_xrcd:
 	ib_dealloc_xrcd(xrcd);
 
 err:
-	put_uobj_write(&obj->uobject);
+	uverbs_finalize_object(&obj->uobject, UVERBS_ACCESS_NEW, false);
 
 err_tree_mutex_unlock:
 	if (f.file)
@@ -884,24 +641,25 @@ ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file,
 	struct ib_xrcd              *xrcd = NULL;
 	struct inode                *inode = NULL;
 	struct ib_uxrcd_object      *obj;
-	int                         live;
 	int                         ret = 0;
+	bool			    destroyed = false;
 
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
 	mutex_lock(&file->device->xrcd_tree_mutex);
-	uobj = idr_write_uobj(cmd.xrcd_handle, file->ucontext);
-	if (!uobj) {
-		ret = -EINVAL;
-		goto out;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_xrcd.alloc, file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.xrcd_handle);
+	if (IS_ERR(uobj)) {
+		mutex_unlock(&file->device->xrcd_tree_mutex);
+		return PTR_ERR(uobj);
 	}
 
 	xrcd  = uobj->object;
 	inode = xrcd->inode;
 	obj   = container_of(uobj, struct ib_uxrcd_object, uobject);
 	if (atomic_read(&obj->refcnt)) {
-		put_uobj_write(uobj);
 		ret = -EBUSY;
 		goto out;
 	}
@@ -909,30 +667,24 @@ ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file,
 	if (!inode || atomic_dec_and_test(&xrcd->usecnt)) {
 		ret = ib_dealloc_xrcd(uobj->object);
 		if (!ret)
-			uobj->live = 0;
+			uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
+		destroyed = !ret;
 	}
 
-	live = uobj->live;
 	if (inode && ret)
 		atomic_inc(&xrcd->usecnt);
 
-	put_uobj_write(uobj);
-
 	if (ret)
 		goto out;
 
-	if (inode && !live)
+	if (inode && destroyed)
 		xrcd_table_delete(file->device, inode);
 
-	idr_remove_uobj(uobj);
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
-
-	put_uobj(uobj);
 	ret = in_len;
 
 out:
+	if (!destroyed)
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 	mutex_unlock(&file->device->xrcd_tree_mutex);
 	return ret;
 }
@@ -982,12 +734,10 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
 	if (ret)
 		return ret;
 
-	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
-	if (!uobj)
-		return -ENOMEM;
-
-	init_uobj(uobj, 0, file->ucontext, &mr_lock_class);
-	down_write(&uobj->mutex);
+	uobj = uverbs_get_uobject_from_context(uverbs_type_mr.alloc, file->ucontext,
+					       UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 
 	pd = idr_read_pd(cmd.pd_handle, file->ucontext);
 	if (!pd) {
@@ -1017,9 +767,6 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
 	atomic_inc(&pd->usecnt);
 
 	uobj->object = mr;
-	ret = idr_add_uobj(uobj);
-	if (ret)
-		goto err_unreg;
 
 	memset(&resp, 0, sizeof resp);
 	resp.lkey      = mr->lkey;
@@ -1032,29 +779,20 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
 		goto err_copy;
 	}
 
-	put_pd_read(pd);
-
-	mutex_lock(&file->mutex);
-	list_add_tail(&uobj->list, &file->ucontext->mr_list);
-	mutex_unlock(&file->mutex);
-
-	uobj->live = 1;
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, true);
 
-	up_write(&uobj->mutex);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, true);
 
 	return in_len;
 
 err_copy:
-	idr_remove_uobj(uobj);
-
-err_unreg:
 	ib_dereg_mr(mr);
 
 err_put:
-	put_pd_read(pd);
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, false);
 
 err_free:
-	put_uobj_write(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, false);
 	return ret;
 }
 
@@ -1090,10 +828,11 @@ ssize_t ib_uverbs_rereg_mr(struct ib_uverbs_file *file,
 	     (cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK)))
 			return -EINVAL;
 
-	uobj = idr_write_uobj(cmd.mr_handle, file->ucontext);
-
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_mr.alloc, file->ucontext,
+					       UVERBS_ACCESS_WRITE,
+					       cmd.mr_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 
 	mr = uobj->object;
 
@@ -1137,11 +876,11 @@ ssize_t ib_uverbs_rereg_mr(struct ib_uverbs_file *file,
 
 put_uobj_pd:
 	if (cmd.flags & IB_MR_REREG_PD)
-		put_pd_read(pd);
+		uverbs_finalize_object(pd->uobject,
+				       UVERBS_ACCESS_READ, ret == in_len);
 
 put_uobjs:
-
-	put_uobj_write(mr->uobject);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_WRITE, ret == in_len);
 
 	return ret;
 }
@@ -1159,28 +898,22 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(cmd.mr_handle, file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_mr.alloc, file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.mr_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 
 	mr = uobj->object;
 
 	ret = ib_dereg_mr(mr);
-	if (!ret)
-		uobj->live = 0;
-
-	put_uobj_write(uobj);
 
-	if (ret)
+	if (ret) {
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 		return ret;
+	}
 
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
-
-	put_uobj(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
 
 	return in_len;
 }
@@ -1204,12 +937,10 @@ ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof(cmd)))
 		return -EFAULT;
 
-	uobj = kmalloc(sizeof(*uobj), GFP_KERNEL);
-	if (!uobj)
-		return -ENOMEM;
-
-	init_uobj(uobj, 0, file->ucontext, &mw_lock_class);
-	down_write(&uobj->mutex);
+	uobj = uverbs_get_uobject_from_context(uverbs_type_mw.alloc, file->ucontext,
+					       UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 
 	pd = idr_read_pd(cmd.pd_handle, file->ucontext);
 	if (!pd) {
@@ -1234,9 +965,6 @@ ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file,
 	atomic_inc(&pd->usecnt);
 
 	uobj->object = mw;
-	ret = idr_add_uobj(uobj);
-	if (ret)
-		goto err_unalloc;
 
 	memset(&resp, 0, sizeof(resp));
 	resp.rkey      = mw->rkey;
@@ -1248,29 +976,17 @@ ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file,
 		goto err_copy;
 	}
 
-	put_pd_read(pd);
-
-	mutex_lock(&file->mutex);
-	list_add_tail(&uobj->list, &file->ucontext->mw_list);
-	mutex_unlock(&file->mutex);
-
-	uobj->live = 1;
-
-	up_write(&uobj->mutex);
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, true);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, true);
 
 	return in_len;
 
 err_copy:
-	idr_remove_uobj(uobj);
-
-err_unalloc:
 	uverbs_dealloc_mw(mw);
-
 err_put:
-	put_pd_read(pd);
-
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, false);
 err_free:
-	put_uobj_write(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, false);
 	return ret;
 }
 
@@ -1287,28 +1003,21 @@ ssize_t ib_uverbs_dealloc_mw(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof(cmd)))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(cmd.mw_handle, file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_mw.alloc, file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.mw_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 
 	mw = uobj->object;
 
 	ret = uverbs_dealloc_mw(mw);
-	if (!ret)
-		uobj->live = 0;
-
-	put_uobj_write(uobj);
-
-	if (ret)
+	if (ret) {
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 		return ret;
+	}
 
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
-
-	put_uobj(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
 
 	return in_len;
 }
@@ -1320,8 +1029,8 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
 {
 	struct ib_uverbs_create_comp_channel	   cmd;
 	struct ib_uverbs_create_comp_channel_resp  resp;
-	struct file				  *filp;
-	int ret;
+	struct ib_uobject			  *uobj;
+	struct ib_uverbs_event_file		  *ev_file;
 
 	if (out_len < sizeof resp)
 		return -ENOSPC;
@@ -1329,25 +1038,24 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	ret = get_unused_fd_flags(O_CLOEXEC);
-	if (ret < 0)
-		return ret;
-	resp.fd = ret;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_comp_channel.alloc,
+					       file->ucontext,
+					       UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 
-	filp = ib_uverbs_alloc_event_file(file, ib_dev, 0);
-	if (IS_ERR(filp)) {
-		put_unused_fd(resp.fd);
-		return PTR_ERR(filp);
-	}
+	resp.fd = uobj->id;
+
+	ev_file = uverbs_fd_uobj_to_priv(uobj);
+	ib_uverbs_init_event_file(ev_file, file);
 
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
 			 &resp, sizeof resp)) {
-		put_unused_fd(resp.fd);
-		fput(filp);
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, false);
 		return -EFAULT;
 	}
 
-	fd_install(resp.fd, filp);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, true);
 	return in_len;
 }
 
@@ -1365,6 +1073,7 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
 				       void *context)
 {
 	struct ib_ucq_object           *obj;
+	struct ib_uobject	       *ev_uobj = NULL;
 	struct ib_uverbs_event_file    *ev_file = NULL;
 	struct ib_cq                   *cq;
 	int                             ret;
@@ -1374,21 +1083,27 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
 	if (cmd->comp_vector >= file->device->num_comp_vectors)
 		return ERR_PTR(-EINVAL);
 
-	obj = kmalloc(sizeof *obj, GFP_KERNEL);
-	if (!obj)
-		return ERR_PTR(-ENOMEM);
-
-	init_uobj(&obj->uobject, cmd->user_handle, file->ucontext, &cq_lock_class);
-	down_write(&obj->uobject.mutex);
+	obj = (struct ib_ucq_object *)uverbs_get_uobject_from_context(
+						uverbs_type_cq.alloc,
+						file->ucontext,
+						UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(obj))
+		return obj;
 
 	if (cmd->comp_channel >= 0) {
-		ev_file = ib_uverbs_lookup_comp_file(cmd->comp_channel);
-		if (!ev_file) {
-			ret = -EINVAL;
+		ev_uobj = uverbs_get_uobject_from_context(uverbs_type_comp_channel.alloc,
+							  file->ucontext,
+							  UVERBS_ACCESS_READ,
+							  cmd->comp_channel);
+		if (IS_ERR(ev_uobj)) {
+			ret = PTR_ERR(ev_uobj);
 			goto err;
 		}
+		ev_file = uverbs_fd_uobj_to_priv(ev_uobj);
+		kref_get(&ev_file->ref);
 	}
 
+	obj->uobject.user_handle = cmd->user_handle;
 	obj->uverbs_file	   = file;
 	obj->comp_events_reported  = 0;
 	obj->async_events_reported = 0;
@@ -1401,8 +1116,7 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
 	if (cmd_sz > offsetof(typeof(*cmd), flags) + sizeof(cmd->flags))
 		attr.flags = cmd->flags;
 
-	cq = ib_dev->create_cq(ib_dev, &attr,
-					     file->ucontext, uhw);
+	cq = ib_dev->create_cq(ib_dev, &attr, file->ucontext, uhw);
 	if (IS_ERR(cq)) {
 		ret = PTR_ERR(cq);
 		goto err_file;
@@ -1416,10 +1130,6 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
 	atomic_set(&cq->usecnt, 0);
 
 	obj->uobject.object = cq;
-	ret = idr_add_uobj(&obj->uobject);
-	if (ret)
-		goto err_free;
-
 	memset(&resp, 0, sizeof resp);
 	resp.base.cq_handle = obj->uobject.id;
 	resp.base.cqe       = cq->cqe;
@@ -1431,28 +1141,20 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
 	if (ret)
 		goto err_cb;
 
-	mutex_lock(&file->mutex);
-	list_add_tail(&obj->uobject.list, &file->ucontext->cq_list);
-	mutex_unlock(&file->mutex);
-
-	obj->uobject.live = 1;
-
-	up_write(&obj->uobject.mutex);
+	if (ev_uobj)
+		uverbs_finalize_object(ev_uobj, UVERBS_ACCESS_READ, true);
+	uverbs_finalize_object(&obj->uobject, UVERBS_ACCESS_NEW, true);
 
 	return obj;
 
 err_cb:
-	idr_remove_uobj(&obj->uobject);
-
-err_free:
 	ib_destroy_cq(cq);
 
 err_file:
-	if (ev_file)
-		ib_uverbs_release_ucq(file, ev_file, obj);
-
+	if (ev_uobj)
+		uverbs_finalize_object(ev_uobj, UVERBS_ACCESS_READ, false);
 err:
-	put_uobj_write(&obj->uobject);
+	uverbs_finalize_object(&obj->uobject, UVERBS_ACCESS_NEW, false);
 
 	return ERR_PTR(ret);
 }
@@ -1575,7 +1277,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
 		   (unsigned long) cmd.response + sizeof resp,
 		   in_len - sizeof cmd, out_len - sizeof resp);
 
-	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+	cq = idr_read_cq(cmd.cq_handle, file->ucontext);
 	if (!cq)
 		return -EINVAL;
 
@@ -1590,7 +1292,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
 		ret = -EFAULT;
 
 out:
-	put_cq_read(cq);
+	uverbs_finalize_object(cq->uobject, UVERBS_ACCESS_READ, !ret);
 
 	return ret ? ret : in_len;
 }
@@ -1637,7 +1339,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+	cq = idr_read_cq(cmd.cq_handle, file->ucontext);
 	if (!cq)
 		return -EINVAL;
 
@@ -1669,7 +1371,8 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
 	ret = in_len;
 
 out_put:
-	put_cq_read(cq);
+	uverbs_finalize_object(cq->uobject, UVERBS_ACCESS_READ,
+			       ret == in_len);
 	return ret;
 }
 
@@ -1684,14 +1387,14 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+	cq = idr_read_cq(cmd.cq_handle, file->ucontext);
 	if (!cq)
 		return -EINVAL;
 
 	ib_req_notify_cq(cq, cmd.solicited_only ?
 			 IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
 
-	put_cq_read(cq);
+	uverbs_finalize_object(cq->uobject, UVERBS_ACCESS_READ, true);
 
 	return in_len;
 }
@@ -1712,36 +1415,30 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(cmd.cq_handle, file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_cq.alloc,
+					       file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.cq_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
+
 	cq      = uobj->object;
 	ev_file = cq->cq_context;
 	obj     = container_of(cq->uobject, struct ib_ucq_object, uobject);
 
 	ret = ib_destroy_cq(cq);
-	if (!ret)
-		uobj->live = 0;
-
-	put_uobj_write(uobj);
-
-	if (ret)
+	if (ret) {
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 		return ret;
-
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
+	}
 
 	ib_uverbs_release_ucq(file, ev_file, obj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
 
 	memset(&resp, 0, sizeof resp);
 	resp.comp_events_reported  = obj->comp_events_reported;
 	resp.async_events_reported = obj->async_events_reported;
 
-	put_uobj(uobj);
-
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
 			 &resp, sizeof resp))
 		return -EFAULT;
@@ -1777,13 +1474,16 @@ static int create_qp(struct ib_uverbs_file *file,
 	if (cmd->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
 		return -EPERM;
 
-	obj = kzalloc(sizeof *obj, GFP_KERNEL);
-	if (!obj)
-		return -ENOMEM;
+	obj = (struct ib_uqp_object *)uverbs_get_uobject_from_context(
+						uverbs_type_qp.alloc,
+						file->ucontext,
+						UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+	obj->uxrcd = NULL;
+	obj->uevent.uobject.user_handle = cmd->user_handle;
+	mutex_init(&obj->mcast_lock);
 
-	init_uobj(&obj->uevent.uobject, cmd->user_handle, file->ucontext,
-		  &qp_lock_class);
-	down_write(&obj->uevent.uobject.mutex);
 	if (cmd_sz >= offsetof(typeof(*cmd), rwq_ind_tbl_handle) +
 		      sizeof(cmd->rwq_ind_tbl_handle) &&
 		      (cmd->comp_mask & IB_UVERBS_CREATE_QP_MASK_IND_TABLE)) {
@@ -1836,7 +1536,7 @@ static int create_qp(struct ib_uverbs_file *file,
 			if (!ind_tbl) {
 				if (cmd->recv_cq_handle != cmd->send_cq_handle) {
 					rcq = idr_read_cq(cmd->recv_cq_handle,
-							  file->ucontext, 0);
+							  file->ucontext);
 					if (!rcq) {
 						ret = -EINVAL;
 						goto err_put;
@@ -1846,7 +1546,7 @@ static int create_qp(struct ib_uverbs_file *file,
 		}
 
 		if (has_sq)
-			scq = idr_read_cq(cmd->send_cq_handle, file->ucontext, !!rcq);
+			scq = idr_read_cq(cmd->send_cq_handle, file->ucontext);
 		if (!ind_tbl)
 			rcq = rcq ?: scq;
 		pd  = idr_read_pd(cmd->pd_handle, file->ucontext);
@@ -1935,9 +1635,6 @@ static int create_qp(struct ib_uverbs_file *file,
 	qp->uobject = &obj->uevent.uobject;
 
 	obj->uevent.uobject.object = qp;
-	ret = idr_add_uobj(&obj->uevent.uobject);
-	if (ret)
-		goto err_destroy;
 
 	memset(&resp, 0, sizeof resp);
 	resp.base.qpn             = qp->qp_num;
@@ -1959,50 +1656,42 @@ static int create_qp(struct ib_uverbs_file *file,
 		obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
 					  uobject);
 		atomic_inc(&obj->uxrcd->refcnt);
-		put_xrcd_read(xrcd_uobj);
+		uverbs_finalize_object(xrcd_uobj, UVERBS_ACCESS_READ, true);
 	}
 
 	if (pd)
-		put_pd_read(pd);
+		uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, true);
 	if (scq)
-		put_cq_read(scq);
+		uverbs_finalize_object(scq->uobject, UVERBS_ACCESS_READ, true);
 	if (rcq && rcq != scq)
-		put_cq_read(rcq);
+		uverbs_finalize_object(rcq->uobject, UVERBS_ACCESS_READ, true);
 	if (srq)
-		put_srq_read(srq);
+		uverbs_finalize_object(srq->uobject, UVERBS_ACCESS_READ, true);
 	if (ind_tbl)
-		put_rwq_indirection_table_read(ind_tbl);
+		uverbs_finalize_object(ind_tbl->uobject, UVERBS_ACCESS_READ, true);
 
-	mutex_lock(&file->mutex);
-	list_add_tail(&obj->uevent.uobject.list, &file->ucontext->qp_list);
-	mutex_unlock(&file->mutex);
-
-	obj->uevent.uobject.live = 1;
-
-	up_write(&obj->uevent.uobject.mutex);
+	uverbs_finalize_object(&obj->uevent.uobject, UVERBS_ACCESS_NEW, true);
 
 	return 0;
-err_cb:
-	idr_remove_uobj(&obj->uevent.uobject);
 
-err_destroy:
+err_cb:
 	ib_destroy_qp(qp);
 
 err_put:
 	if (xrcd)
-		put_xrcd_read(xrcd_uobj);
+		uverbs_finalize_object(xrcd_uobj, UVERBS_ACCESS_READ, false);
 	if (pd)
-		put_pd_read(pd);
+		uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, false);
 	if (scq)
-		put_cq_read(scq);
+		uverbs_finalize_object(scq->uobject, UVERBS_ACCESS_READ, false);
 	if (rcq && rcq != scq)
-		put_cq_read(rcq);
+		uverbs_finalize_object(rcq->uobject, UVERBS_ACCESS_READ, false);
 	if (srq)
-		put_srq_read(srq);
+		uverbs_finalize_object(srq->uobject, UVERBS_ACCESS_READ, false);
 	if (ind_tbl)
-		put_rwq_indirection_table_read(ind_tbl);
+		uverbs_finalize_object(ind_tbl->uobject, UVERBS_ACCESS_READ, false);
 
-	put_uobj_write(&obj->uevent.uobject);
+	uverbs_finalize_object(&obj->uevent.uobject, UVERBS_ACCESS_NEW, false);
 	return ret;
 }
 
@@ -2138,12 +1827,12 @@ ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
 		   (unsigned long) cmd.response + sizeof resp,
 		   in_len - sizeof cmd, out_len - sizeof resp);
 
-	obj = kmalloc(sizeof *obj, GFP_KERNEL);
-	if (!obj)
-		return -ENOMEM;
-
-	init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_class);
-	down_write(&obj->uevent.uobject.mutex);
+	obj = (struct ib_uqp_object *)uverbs_get_uobject_from_context(
+						uverbs_type_qp.alloc,
+						file->ucontext,
+						UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
 
 	xrcd = idr_read_xrcd(cmd.pd_handle, file->ucontext, &xrcd_uobj);
 	if (!xrcd) {
@@ -2163,15 +1852,13 @@ ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
 	qp = ib_open_qp(xrcd, &attr);
 	if (IS_ERR(qp)) {
 		ret = PTR_ERR(qp);
-		goto err_put;
+		goto err_xrcd;
 	}
 
 	qp->uobject = &obj->uevent.uobject;
 
 	obj->uevent.uobject.object = qp;
-	ret = idr_add_uobj(&obj->uevent.uobject);
-	if (ret)
-		goto err_destroy;
+	obj->uevent.uobject.user_handle = cmd.user_handle;
 
 	memset(&resp, 0, sizeof resp);
 	resp.qpn       = qp->qp_num;
@@ -2180,32 +1867,23 @@ ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
 			 &resp, sizeof resp)) {
 		ret = -EFAULT;
-		goto err_remove;
+		goto err_destroy;
 	}
 
 	obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object, uobject);
 	atomic_inc(&obj->uxrcd->refcnt);
-	put_xrcd_read(xrcd_uobj);
-
-	mutex_lock(&file->mutex);
-	list_add_tail(&obj->uevent.uobject.list, &file->ucontext->qp_list);
-	mutex_unlock(&file->mutex);
-
-	obj->uevent.uobject.live = 1;
+	uverbs_finalize_object(xrcd_uobj, UVERBS_ACCESS_READ, true);
 
-	up_write(&obj->uevent.uobject.mutex);
+	uverbs_finalize_object(&obj->uevent.uobject, UVERBS_ACCESS_NEW, true);
 
 	return in_len;
 
-err_remove:
-	idr_remove_uobj(&obj->uevent.uobject);
-
 err_destroy:
 	ib_destroy_qp(qp);
-
+err_xrcd:
+	uverbs_finalize_object(xrcd_uobj, UVERBS_ACCESS_READ, false);
 err_put:
-	put_xrcd_read(xrcd_uobj);
-	put_uobj_write(&obj->uevent.uobject);
+	uverbs_finalize_object(&obj->uevent.uobject, UVERBS_ACCESS_NEW, false);
 	return ret;
 }
 
@@ -2238,9 +1916,7 @@ ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
 	}
 
 	ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
-
-	put_qp_read(qp);
-
+	uverbs_finalize_object(qp->uobject, UVERBS_ACCESS_READ, !ret);
 	if (ret)
 		goto out;
 
@@ -2407,7 +2083,7 @@ static int modify_qp(struct ib_uverbs_file *file,
 	}
 
 release_qp:
-	put_qp_read(qp);
+	uverbs_finalize_object(qp->uobject, UVERBS_ACCESS_READ, !ret);
 
 out:
 	kfree(attr);
@@ -2494,40 +2170,34 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
 
 	memset(&resp, 0, sizeof resp);
 
-	uobj = idr_write_uobj(cmd.qp_handle, file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_qp.alloc, file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.qp_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
+
 	qp  = uobj->object;
 	obj = container_of(uobj, struct ib_uqp_object, uevent.uobject);
 
 	if (!list_empty(&obj->mcast_list)) {
-		put_uobj_write(uobj);
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 		return -EBUSY;
 	}
 
 	ret = ib_destroy_qp(qp);
-	if (!ret)
-		uobj->live = 0;
-
-	put_uobj_write(uobj);
-
-	if (ret)
+	if (ret) {
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 		return ret;
+	}
 
 	if (obj->uxrcd)
 		atomic_dec(&obj->uxrcd->refcnt);
 
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
-
 	ib_uverbs_release_uevent(file, &obj->uevent);
 
 	resp.events_reported = obj->uevent.events_reported;
 
-	put_uobj(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
 
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
 			 &resp, sizeof resp))
@@ -2714,11 +2384,13 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
 		ret = -EFAULT;
 
 out_put:
-	put_qp_read(qp);
+	uverbs_finalize_object(qp->uobject, UVERBS_ACCESS_READ, !ret);
 
 	while (wr) {
 		if (is_ud && ud_wr(wr)->ah)
-			put_ah_read(ud_wr(wr)->ah);
+			uverbs_finalize_object(ud_wr(wr)->ah->uobject,
+					       UVERBS_ACCESS_READ, !ret);
+
 		next = wr->next;
 		kfree(wr);
 		wr = next;
@@ -2842,14 +2514,14 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
 	resp.bad_wr = 0;
 	ret = qp->device->post_recv(qp->real_qp, wr, &bad_wr);
 
-	put_qp_read(qp);
-
-	if (ret)
+	uverbs_finalize_object(qp->uobject, UVERBS_ACCESS_READ, !ret);
+	if (ret) {
 		for (next = wr; next; next = next->next) {
 			++resp.bad_wr;
 			if (next == bad_wr)
 				break;
 		}
+	}
 
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
 			 &resp, sizeof resp))
@@ -2892,7 +2564,7 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
 	resp.bad_wr = 0;
 	ret = srq->device->post_srq_recv(srq, wr, &bad_wr);
 
-	put_srq_read(srq);
+	uverbs_finalize_object(srq->uobject, UVERBS_ACCESS_READ, !ret);
 
 	if (ret)
 		for (next = wr; next; next = next->next) {
@@ -2939,12 +2611,11 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
 		   (unsigned long)cmd.response + sizeof(resp),
 		   in_len - sizeof(cmd), out_len - sizeof(resp));
 
-	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
-	if (!uobj)
-		return -ENOMEM;
-
-	init_uobj(uobj, cmd.user_handle, file->ucontext, &ah_lock_class);
-	down_write(&uobj->mutex);
+	uobj = uverbs_get_uobject_from_context(uverbs_type_ah.alloc,
+					       file->ucontext,
+					       UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 
 	pd = idr_read_pd(cmd.pd_handle, file->ucontext);
 	if (!pd) {
@@ -2976,12 +2647,9 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
 	ah->pd      = pd;
 	atomic_inc(&pd->usecnt);
 	ah->uobject  = uobj;
+	uobj->user_handle = cmd.user_handle;
 	uobj->object = ah;
 
-	ret = idr_add_uobj(uobj);
-	if (ret)
-		goto err_destroy;
-
 	resp.ah_handle = uobj->id;
 
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
@@ -2990,29 +2658,19 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
 		goto err_copy;
 	}
 
-	put_pd_read(pd);
-
-	mutex_lock(&file->mutex);
-	list_add_tail(&uobj->list, &file->ucontext->ah_list);
-	mutex_unlock(&file->mutex);
-
-	uobj->live = 1;
-
-	up_write(&uobj->mutex);
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, true);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, true);
 
 	return in_len;
 
 err_copy:
-	idr_remove_uobj(uobj);
-
-err_destroy:
 	ib_destroy_ah(ah);
 
 err_put:
-	put_pd_read(pd);
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, false);
 
 err:
-	put_uobj_write(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, false);
 	return ret;
 }
 
@@ -3028,29 +2686,22 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(cmd.ah_handle, file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_ah.alloc, file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.ah_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
+
 	ah = uobj->object;
 
 	ret = ib_destroy_ah(ah);
-	if (!ret)
-		uobj->live = 0;
-
-	put_uobj_write(uobj);
-
-	if (ret)
+	if (ret) {
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 		return ret;
-
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
-
-	put_uobj(uobj);
-
-	return in_len;
+	} else {
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
+		return in_len;
+	}
 }
 
 ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
@@ -3067,12 +2718,13 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	qp = idr_write_qp(cmd.qp_handle, file->ucontext);
+	qp = idr_read_qp(cmd.qp_handle, file->ucontext);
 	if (!qp)
 		return -EINVAL;
 
 	obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
 
+	mutex_lock(&obj->mcast_lock);
 	list_for_each_entry(mcast, &obj->mcast_list, list)
 		if (cmd.mlid == mcast->lid &&
 		    !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
@@ -3096,8 +2748,8 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
 		kfree(mcast);
 
 out_put:
-	put_qp_write(qp);
-
+	mutex_unlock(&obj->mcast_lock);
+	uverbs_finalize_object(qp->uobject, UVERBS_ACCESS_READ, !ret);
 	return ret ? ret : in_len;
 }
 
@@ -3115,16 +2767,17 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	qp = idr_write_qp(cmd.qp_handle, file->ucontext);
+	qp = idr_read_qp(cmd.qp_handle, file->ucontext);
 	if (!qp)
 		return -EINVAL;
 
+	obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
+	mutex_lock(&obj->mcast_lock);
+
 	ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
 	if (ret)
 		goto out_put;
 
-	obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
-
 	list_for_each_entry(mcast, &obj->mcast_list, list)
 		if (cmd.mlid == mcast->lid &&
 		    !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
@@ -3134,8 +2787,8 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
 		}
 
 out_put:
-	put_qp_write(qp);
-
+	mutex_unlock(&obj->mcast_lock);
+	uverbs_finalize_object(qp->uobject, UVERBS_ACCESS_READ, !ret);
 	return ret ? ret : in_len;
 }
 
@@ -3296,20 +2949,20 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
 	if (cmd.comp_mask)
 		return -EOPNOTSUPP;
 
-	obj = kmalloc(sizeof(*obj), GFP_KERNEL);
-	if (!obj)
-		return -ENOMEM;
+	obj = (struct ib_uwq_object *)uverbs_get_uobject_from_context(
+						uverbs_type_wq.alloc,
+						file->ucontext,
+						UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
 
-	init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext,
-		  &wq_lock_class);
-	down_write(&obj->uevent.uobject.mutex);
 	pd  = idr_read_pd(cmd.pd_handle, file->ucontext);
 	if (!pd) {
 		err = -EINVAL;
 		goto err_uobj;
 	}
 
-	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+	cq = idr_read_cq(cmd.cq_handle, file->ucontext);
 	if (!cq) {
 		err = -EINVAL;
 		goto err_put_pd;
@@ -3341,9 +2994,6 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
 	atomic_inc(&cq->usecnt);
 	wq->uobject = &obj->uevent.uobject;
 	obj->uevent.uobject.object = wq;
-	err = idr_add_uobj(&obj->uevent.uobject);
-	if (err)
-		goto destroy_wq;
 
 	memset(&resp, 0, sizeof(resp));
 	resp.wq_handle = obj->uevent.uobject.id;
@@ -3356,27 +3006,19 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
 	if (err)
 		goto err_copy;
 
-	put_pd_read(pd);
-	put_cq_read(cq);
-
-	mutex_lock(&file->mutex);
-	list_add_tail(&obj->uevent.uobject.list, &file->ucontext->wq_list);
-	mutex_unlock(&file->mutex);
-
-	obj->uevent.uobject.live = 1;
-	up_write(&obj->uevent.uobject.mutex);
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, true);
+	uverbs_finalize_object(cq->uobject, UVERBS_ACCESS_READ, true);
+	uverbs_finalize_object(&obj->uevent.uobject, UVERBS_ACCESS_NEW, true);
 	return 0;
 
 err_copy:
-	idr_remove_uobj(&obj->uevent.uobject);
-destroy_wq:
 	ib_destroy_wq(wq);
 err_put_cq:
-	put_cq_read(cq);
+	uverbs_finalize_object(cq->uobject, UVERBS_ACCESS_READ, false);
 err_put_pd:
-	put_pd_read(pd);
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, false);
 err_uobj:
-	put_uobj_write(&obj->uevent.uobject);
+	uverbs_finalize_object(&obj->uevent.uobject, UVERBS_ACCESS_NEW, false);
 
 	return err;
 }
@@ -3417,30 +3059,23 @@ int ib_uverbs_ex_destroy_wq(struct ib_uverbs_file *file,
 		return -EOPNOTSUPP;
 
 	resp.response_length = required_resp_len;
-	uobj = idr_write_uobj(cmd.wq_handle,
-			      file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_ah.alloc, file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.wq_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
 
 	wq = uobj->object;
 	obj = container_of(uobj, struct ib_uwq_object, uevent.uobject);
 	ret = ib_destroy_wq(wq);
-	if (!ret)
-		uobj->live = 0;
-
-	put_uobj_write(uobj);
-	if (ret)
+	if (ret) {
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 		return ret;
-
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
+	}
 
 	ib_uverbs_release_uevent(file, &obj->uevent);
 	resp.events_reported = obj->uevent.events_reported;
-	put_uobj(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
 
 	ret = ib_copy_to_udata(ucore, &resp, resp.response_length);
 	if (ret)
@@ -3486,7 +3121,7 @@ int ib_uverbs_ex_modify_wq(struct ib_uverbs_file *file,
 	wq_attr.curr_wq_state = cmd.curr_wq_state;
 	wq_attr.wq_state = cmd.wq_state;
 	ret = wq->device->modify_wq(wq, &wq_attr, cmd.attr_mask, uhw);
-	put_wq_read(wq);
+	uverbs_finalize_object(wq->uobject, UVERBS_ACCESS_READ, !ret);
 	return ret;
 }
 
@@ -3573,14 +3208,15 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
 		wqs[num_read_wqs] = wq;
 	}
 
-	uobj = kmalloc(sizeof(*uobj), GFP_KERNEL);
-	if (!uobj) {
-		err = -ENOMEM;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_rwq_ind_table.alloc,
+					       file->ucontext,
+					       UVERBS_ACCESS_NEW,
+					       0);
+	if (IS_ERR(uobj)) {
+		err = PTR_ERR(uobj);
 		goto put_wqs;
 	}
 
-	init_uobj(uobj, 0, file->ucontext, &rwq_ind_table_lock_class);
-	down_write(&uobj->mutex);
 	init_attr.log_ind_tbl_size = cmd.log_ind_tbl_size;
 	init_attr.ind_tbl = wqs;
 	rwq_ind_tbl = ib_dev->create_rwq_ind_table(ib_dev, &init_attr, uhw);
@@ -3600,10 +3236,6 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
 	for (i = 0; i < num_wq_handles; i++)
 		atomic_inc(&wqs[i]->usecnt);
 
-	err = idr_add_uobj(uobj);
-	if (err)
-		goto destroy_ind_tbl;
-
 	resp.ind_tbl_handle = uobj->id;
 	resp.ind_tbl_num = rwq_ind_tbl->ind_tbl_num;
 	resp.response_length = required_resp_len;
@@ -3616,26 +3248,18 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
 	kfree(wqs_handles);
 
 	for (j = 0; j < num_read_wqs; j++)
-		put_wq_read(wqs[j]);
-
-	mutex_lock(&file->mutex);
-	list_add_tail(&uobj->list, &file->ucontext->rwq_ind_tbl_list);
-	mutex_unlock(&file->mutex);
-
-	uobj->live = 1;
+		uverbs_finalize_object(wqs[j]->uobject, UVERBS_ACCESS_READ, true);
 
-	up_write(&uobj->mutex);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, true);
 	return 0;
 
 err_copy:
-	idr_remove_uobj(uobj);
-destroy_ind_tbl:
 	ib_destroy_rwq_ind_table(rwq_ind_tbl);
 err_uobj:
-	put_uobj_write(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, false);
 put_wqs:
 	for (j = 0; j < num_read_wqs; j++)
-		put_wq_read(wqs[j]);
+		uverbs_finalize_object(wqs[j]->uobject, UVERBS_ACCESS_READ, false);
 err_free:
 	kfree(wqs_handles);
 	kfree(wqs);
@@ -3671,29 +3295,23 @@ int ib_uverbs_ex_destroy_rwq_ind_table(struct ib_uverbs_file *file,
 	if (cmd.comp_mask)
 		return -EOPNOTSUPP;
 
-	uobj = idr_write_uobj(cmd.ind_tbl_handle,
-			      file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_rwq_ind_table.alloc,
+					       file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.ind_tbl_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
+
 	rwq_ind_tbl = uobj->object;
 	ind_tbl = rwq_ind_tbl->ind_tbl;
 
 	ret = ib_destroy_rwq_ind_table(rwq_ind_tbl);
-	if (!ret)
-		uobj->live = 0;
-
-	put_uobj_write(uobj);
-
-	if (ret)
+	if (ret) {
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 		return ret;
+	}
 
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
-
-	put_uobj(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
 	kfree(ind_tbl);
 	return ret;
 }
@@ -3769,13 +3387,12 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
 		kern_flow_attr = &cmd.flow_attr;
 	}
 
-	uobj = kmalloc(sizeof(*uobj), GFP_KERNEL);
-	if (!uobj) {
-		err = -ENOMEM;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_flow.alloc, file->ucontext,
+					       UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(uobj)) {
+		err = PTR_ERR(uobj);
 		goto err_free_attr;
 	}
-	init_uobj(uobj, 0, file->ucontext, &rule_lock_class);
-	down_write(&uobj->mutex);
 
 	qp = idr_read_qp(cmd.qp_handle, file->ucontext);
 	if (!qp) {
@@ -3826,10 +3443,6 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
 	flow_id->uobject = uobj;
 	uobj->object = flow_id;
 
-	err = idr_add_uobj(uobj);
-	if (err)
-		goto destroy_flow;
-
 	memset(&resp, 0, sizeof(resp));
 	resp.flow_handle = uobj->id;
 
@@ -3838,28 +3451,20 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
 	if (err)
 		goto err_copy;
 
-	put_qp_read(qp);
-	mutex_lock(&file->mutex);
-	list_add_tail(&uobj->list, &file->ucontext->rule_list);
-	mutex_unlock(&file->mutex);
-
-	uobj->live = 1;
-
-	up_write(&uobj->mutex);
+	uverbs_finalize_object(qp->uobject, UVERBS_ACCESS_READ, true);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, true);
 	kfree(flow_attr);
 	if (cmd.flow_attr.num_of_specs)
 		kfree(kern_flow_attr);
 	return 0;
 err_copy:
-	idr_remove_uobj(uobj);
-destroy_flow:
 	ib_destroy_flow(flow_id);
 err_free:
 	kfree(flow_attr);
 err_put:
-	put_qp_read(qp);
+	uverbs_finalize_object(qp->uobject, UVERBS_ACCESS_READ, false);
 err_uobj:
-	put_uobj_write(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_NEW, false);
 err_free_attr:
 	if (cmd.flow_attr.num_of_specs)
 		kfree(kern_flow_attr);
@@ -3886,25 +3491,17 @@ int ib_uverbs_ex_destroy_flow(struct ib_uverbs_file *file,
 	if (cmd.comp_mask)
 		return -EINVAL;
 
-	uobj = idr_write_uobj(cmd.flow_handle, file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_flow.alloc,
+					       file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.flow_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
+
 	flow_id = uobj->object;
 
 	ret = ib_destroy_flow(flow_id);
-	if (!ret)
-		uobj->live = 0;
-
-	put_uobj_write(uobj);
-
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
-
-	put_uobj(uobj);
-
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, !ret);
 	return ret;
 }
 
@@ -3921,12 +3518,12 @@ static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
 	struct ib_srq_init_attr          attr;
 	int ret;
 
-	obj = kmalloc(sizeof *obj, GFP_KERNEL);
-	if (!obj)
-		return -ENOMEM;
-
-	init_uobj(&obj->uevent.uobject, cmd->user_handle, file->ucontext, &srq_lock_class);
-	down_write(&obj->uevent.uobject.mutex);
+	obj = (struct ib_usrq_object *)uverbs_get_uobject_from_context(
+						uverbs_type_srq.alloc,
+						file->ucontext,
+						UVERBS_ACCESS_NEW, 0);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
 
 	if (cmd->srq_type == IB_SRQT_XRC) {
 		attr.ext.xrc.xrcd  = idr_read_xrcd(cmd->xrcd_handle, file->ucontext, &xrcd_uobj);
@@ -3938,7 +3535,7 @@ static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
 		obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object, uobject);
 		atomic_inc(&obj->uxrcd->refcnt);
 
-		attr.ext.xrc.cq  = idr_read_cq(cmd->cq_handle, file->ucontext, 0);
+		attr.ext.xrc.cq  = idr_read_cq(cmd->cq_handle, file->ucontext);
 		if (!attr.ext.xrc.cq) {
 			ret = -EINVAL;
 			goto err_put_xrcd;
@@ -3985,9 +3582,7 @@ static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
 	atomic_set(&srq->usecnt, 0);
 
 	obj->uevent.uobject.object = srq;
-	ret = idr_add_uobj(&obj->uevent.uobject);
-	if (ret)
-		goto err_destroy;
+	obj->uevent.uobject.user_handle = cmd->user_handle;
 
 	memset(&resp, 0, sizeof resp);
 	resp.srq_handle = obj->uevent.uobject.id;
@@ -4003,42 +3598,34 @@ static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
 	}
 
 	if (cmd->srq_type == IB_SRQT_XRC) {
-		put_uobj_read(xrcd_uobj);
-		put_cq_read(attr.ext.xrc.cq);
+		uverbs_finalize_object(xrcd_uobj, UVERBS_ACCESS_READ, true);
+		uverbs_finalize_object(attr.ext.xrc.cq->uobject,
+				       UVERBS_ACCESS_READ, true);
 	}
-	put_pd_read(pd);
-
-	mutex_lock(&file->mutex);
-	list_add_tail(&obj->uevent.uobject.list, &file->ucontext->srq_list);
-	mutex_unlock(&file->mutex);
-
-	obj->uevent.uobject.live = 1;
-
-	up_write(&obj->uevent.uobject.mutex);
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, true);
+	uverbs_finalize_object(&obj->uevent.uobject, UVERBS_ACCESS_NEW, true);
 
 	return 0;
 
 err_copy:
-	idr_remove_uobj(&obj->uevent.uobject);
-
-err_destroy:
 	ib_destroy_srq(srq);
 
 err_put:
-	put_pd_read(pd);
+	uverbs_finalize_object(pd->uobject, UVERBS_ACCESS_READ, false);
 
 err_put_cq:
 	if (cmd->srq_type == IB_SRQT_XRC)
-		put_cq_read(attr.ext.xrc.cq);
+		uverbs_finalize_object(attr.ext.xrc.cq->uobject,
+				       UVERBS_ACCESS_READ, false);
 
 err_put_xrcd:
 	if (cmd->srq_type == IB_SRQT_XRC) {
 		atomic_dec(&obj->uxrcd->refcnt);
-		put_uobj_read(xrcd_uobj);
+		uverbs_finalize_object(xrcd_uobj, UVERBS_ACCESS_READ, false);
 	}
 
 err:
-	put_uobj_write(&obj->uevent.uobject);
+	uverbs_finalize_object(&obj->uevent.uobject, UVERBS_ACCESS_NEW, false);
 	return ret;
 }
 
@@ -4132,8 +3719,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
 
 	ret = srq->device->modify_srq(srq, &attr, cmd.attr_mask, &udata);
 
-	put_srq_read(srq);
-
+	uverbs_finalize_object(srq->uobject, UVERBS_ACCESS_READ, !ret);
 	return ret ? ret : in_len;
 }
 
@@ -4160,8 +3746,7 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
 
 	ret = ib_query_srq(srq, &attr);
 
-	put_srq_read(srq);
-
+	uverbs_finalize_object(srq->uobject, UVERBS_ACCESS_READ, !ret);
 	if (ret)
 		return ret;
 
@@ -4195,39 +3780,34 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	uobj = idr_write_uobj(cmd.srq_handle, file->ucontext);
-	if (!uobj)
-		return -EINVAL;
+	uobj = uverbs_get_uobject_from_context(uverbs_type_srq.alloc,
+					       file->ucontext,
+					       UVERBS_ACCESS_DESTROY,
+					       cmd.srq_handle);
+	if (IS_ERR(uobj))
+		return PTR_ERR(uobj);
+
 	srq = uobj->object;
 	obj = container_of(uobj, struct ib_uevent_object, uobject);
 	srq_type = srq->srq_type;
 
 	ret = ib_destroy_srq(srq);
-	if (!ret)
-		uobj->live = 0;
-
-	put_uobj_write(uobj);
-
-	if (ret)
+	if (ret) {
+		uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, false);
 		return ret;
+	}
 
 	if (srq_type == IB_SRQT_XRC) {
 		us = container_of(obj, struct ib_usrq_object, uevent);
 		atomic_dec(&us->uxrcd->refcnt);
 	}
 
-	idr_remove_uobj(uobj);
-
-	mutex_lock(&file->mutex);
-	list_del(&uobj->list);
-	mutex_unlock(&file->mutex);
-
 	ib_uverbs_release_uevent(file, obj);
 
 	memset(&resp, 0, sizeof resp);
 	resp.events_reported = obj->events_reported;
 
-	put_uobj(uobj);
+	uverbs_finalize_object(uobj, UVERBS_ACCESS_DESTROY, true);
 
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
 			 &resp, sizeof resp))
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 75c30d9..d7c189f 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -51,6 +51,7 @@
 #include <rdma/ib.h>
 
 #include "uverbs.h"
+#include "rdma_core.h"
 
 MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("InfiniBand userspace verbs access");
@@ -154,7 +155,7 @@ static void ib_uverbs_release_dev(struct kobject *kobj)
 	.release = ib_uverbs_release_dev,
 };
 
-static void ib_uverbs_release_event_file(struct kref *ref)
+static void ib_uverbs_release_async_event_file(struct kref *ref)
 {
 	struct ib_uverbs_event_file *file =
 		container_of(ref, struct ib_uverbs_event_file, ref);
@@ -162,6 +163,14 @@ static void ib_uverbs_release_event_file(struct kref *ref)
 	kfree(file);
 }
 
+static void ib_uverbs_release_event_file(struct kref *ref)
+{
+	struct ib_uverbs_event_file *file =
+		container_of(ref, struct ib_uverbs_event_file, ref);
+
+	uverbs_cleanup_fd(file);
+}
+
 void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
 			  struct ib_uverbs_event_file *ev_file,
 			  struct ib_ucq_object *uobj)
@@ -215,120 +224,8 @@ void ib_uverbs_detach_umcast(struct ib_qp *qp,
 static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 				      struct ib_ucontext *context)
 {
-	struct ib_uobject *uobj, *tmp;
-
 	context->closing = 1;
-
-	list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) {
-		struct ib_ah *ah = uobj->object;
-
-		idr_remove_uobj(uobj);
-		ib_destroy_ah(ah);
-		kfree(uobj);
-	}
-
-	/* Remove MWs before QPs, in order to support type 2A MWs. */
-	list_for_each_entry_safe(uobj, tmp, &context->mw_list, list) {
-		struct ib_mw *mw = uobj->object;
-
-		idr_remove_uobj(uobj);
-		uverbs_dealloc_mw(mw);
-		kfree(uobj);
-	}
-
-	list_for_each_entry_safe(uobj, tmp, &context->rule_list, list) {
-		struct ib_flow *flow_id = uobj->object;
-
-		idr_remove_uobj(uobj);
-		ib_destroy_flow(flow_id);
-		kfree(uobj);
-	}
-
-	list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) {
-		struct ib_qp *qp = uobj->object;
-		struct ib_uqp_object *uqp =
-			container_of(uobj, struct ib_uqp_object, uevent.uobject);
-
-		idr_remove_uobj(uobj);
-		if (qp == qp->real_qp)
-			ib_uverbs_detach_umcast(qp, uqp);
-		ib_destroy_qp(qp);
-		ib_uverbs_release_uevent(file, &uqp->uevent);
-		kfree(uqp);
-	}
-
-	list_for_each_entry_safe(uobj, tmp, &context->rwq_ind_tbl_list, list) {
-		struct ib_rwq_ind_table *rwq_ind_tbl = uobj->object;
-		struct ib_wq **ind_tbl = rwq_ind_tbl->ind_tbl;
-
-		idr_remove_uobj(uobj);
-		ib_destroy_rwq_ind_table(rwq_ind_tbl);
-		kfree(ind_tbl);
-		kfree(uobj);
-	}
-
-	list_for_each_entry_safe(uobj, tmp, &context->wq_list, list) {
-		struct ib_wq *wq = uobj->object;
-		struct ib_uwq_object *uwq =
-			container_of(uobj, struct ib_uwq_object, uevent.uobject);
-
-		idr_remove_uobj(uobj);
-		ib_destroy_wq(wq);
-		ib_uverbs_release_uevent(file, &uwq->uevent);
-		kfree(uwq);
-	}
-
-	list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) {
-		struct ib_srq *srq = uobj->object;
-		struct ib_uevent_object *uevent =
-			container_of(uobj, struct ib_uevent_object, uobject);
-
-		idr_remove_uobj(uobj);
-		ib_destroy_srq(srq);
-		ib_uverbs_release_uevent(file, uevent);
-		kfree(uevent);
-	}
-
-	list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {
-		struct ib_cq *cq = uobj->object;
-		struct ib_uverbs_event_file *ev_file = cq->cq_context;
-		struct ib_ucq_object *ucq =
-			container_of(uobj, struct ib_ucq_object, uobject);
-
-		idr_remove_uobj(uobj);
-		ib_destroy_cq(cq);
-		ib_uverbs_release_ucq(file, ev_file, ucq);
-		kfree(ucq);
-	}
-
-	list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
-		struct ib_mr *mr = uobj->object;
-
-		idr_remove_uobj(uobj);
-		ib_dereg_mr(mr);
-		kfree(uobj);
-	}
-
-	mutex_lock(&file->device->xrcd_tree_mutex);
-	list_for_each_entry_safe(uobj, tmp, &context->xrcd_list, list) {
-		struct ib_xrcd *xrcd = uobj->object;
-		struct ib_uxrcd_object *uxrcd =
-			container_of(uobj, struct ib_uxrcd_object, uobject);
-
-		idr_remove_uobj(uobj);
-		ib_uverbs_dealloc_xrcd(file->device, xrcd);
-		kfree(uxrcd);
-	}
-	mutex_unlock(&file->device->xrcd_tree_mutex);
-
-	list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
-		struct ib_pd *pd = uobj->object;
-
-		idr_remove_uobj(uobj);
-		ib_dealloc_pd(pd);
-		kfree(uobj);
-	}
-
+	uverbs_cleanup_ucontext(context, context->device->specs_root);
 	put_pid(context->tgid);
 
 	return context->device->dealloc_ucontext(context);
@@ -447,7 +344,7 @@ static int ib_uverbs_event_fasync(int fd, struct file *filp, int on)
 	return fasync_helper(fd, filp, on, &file->async_queue);
 }
 
-static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
+static int ib_uverbs_async_event_close(struct inode *inode, struct file *filp)
 {
 	struct ib_uverbs_event_file *file = filp->private_data;
 	struct ib_uverbs_event *entry, *tmp;
@@ -472,6 +369,26 @@ static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
 	mutex_unlock(&file->uverbs_file->device->lists_mutex);
 
 	kref_put(&file->uverbs_file->ref, ib_uverbs_release_file);
+	kref_put(&file->ref, ib_uverbs_release_async_event_file);
+
+	return 0;
+}
+
+static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
+{
+	struct ib_uverbs_event_file *file = filp->private_data;
+	struct ib_uverbs_event *entry, *tmp;
+
+	spin_lock_irq(&file->lock);
+	list_for_each_entry_safe(entry, tmp, &file->event_list, list) {
+		if (entry->counter)
+			list_del(&entry->obj_list);
+		kfree(entry);
+	}
+	spin_unlock_irq(&file->lock);
+
+	uverbs_close_fd(filp);
+	kref_put(&file->uverbs_file->ref, ib_uverbs_release_file);
 	kref_put(&file->ref, ib_uverbs_release_event_file);
 
 	return 0;
@@ -486,6 +403,15 @@ static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
 	.llseek	 = no_llseek,
 };
 
+static const struct file_operations uverbs_async_event_fops = {
+	.owner	 = THIS_MODULE,
+	.read	 = ib_uverbs_event_read,
+	.poll    = ib_uverbs_event_poll,
+	.release = ib_uverbs_async_event_close,
+	.fasync  = ib_uverbs_event_fasync,
+	.llseek	 = no_llseek,
+};
+
 void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context)
 {
 	struct ib_uverbs_event_file    *file = cq_context;
@@ -570,7 +496,8 @@ void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
 	struct ib_uevent_object *uobj;
 
 	/* for XRC target qp's, check that qp is live */
-	if (!event->element.qp->uobject || !event->element.qp->uobject->live)
+	if (!event->element.qp->uobject ||
+	    !uverbs_is_live(event->element.qp->uobject))
 		return;
 
 	uobj = container_of(event->element.qp->uobject,
@@ -615,22 +542,13 @@ void ib_uverbs_event_handler(struct ib_event_handler *handler,
 
 void ib_uverbs_free_async_event_file(struct ib_uverbs_file *file)
 {
-	kref_put(&file->async_file->ref, ib_uverbs_release_event_file);
+	kref_put(&file->async_file->ref, ib_uverbs_release_async_event_file);
 	file->async_file = NULL;
 }
 
-struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
-					struct ib_device	*ib_dev,
-					int is_async)
+void ib_uverbs_init_event_file(struct ib_uverbs_event_file *ev_file,
+			       struct ib_uverbs_file *uverbs_file)
 {
-	struct ib_uverbs_event_file *ev_file;
-	struct file *filp;
-	int ret;
-
-	ev_file = kzalloc(sizeof(*ev_file), GFP_KERNEL);
-	if (!ev_file)
-		return ERR_PTR(-ENOMEM);
-
 	kref_init(&ev_file->ref);
 	spin_lock_init(&ev_file->lock);
 	INIT_LIST_HEAD(&ev_file->event_list);
@@ -639,8 +557,22 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
 	kref_get(&ev_file->uverbs_file->ref);
 	ev_file->async_queue = NULL;
 	ev_file->is_closed   = 0;
+	ev_file->is_async   = 0;
+}
 
-	filp = anon_inode_getfile("[infinibandevent]", &uverbs_event_fops,
+struct file *ib_uverbs_alloc_async_event_file(struct ib_uverbs_file *uverbs_file,
+					      struct ib_device	*ib_dev)
+{
+	struct ib_uverbs_event_file *ev_file;
+	struct file *filp;
+	int ret;
+
+	ev_file = kzalloc(sizeof(*ev_file), GFP_KERNEL);
+	if (!ev_file)
+		return ERR_PTR(-ENOMEM);
+
+	ib_uverbs_init_event_file(ev_file, uverbs_file);
+	filp = anon_inode_getfile("[infinibandevent]", &uverbs_async_event_fops,
 				  ev_file, O_RDONLY);
 	if (IS_ERR(filp))
 		goto err_put_refs;
@@ -650,26 +582,25 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
 		      &uverbs_file->device->uverbs_events_file_list);
 	mutex_unlock(&uverbs_file->device->lists_mutex);
 
-	if (is_async) {
-		WARN_ON(uverbs_file->async_file);
-		uverbs_file->async_file = ev_file;
-		kref_get(&uverbs_file->async_file->ref);
-		INIT_IB_EVENT_HANDLER(&uverbs_file->event_handler,
-				      ib_dev,
-				      ib_uverbs_event_handler);
-		ret = ib_register_event_handler(&uverbs_file->event_handler);
-		if (ret)
-			goto err_put_file;
-
-		/* At that point async file stuff was fully set */
-		ev_file->is_async = 1;
-	}
+	WARN_ON(uverbs_file->async_file);
+	uverbs_file->async_file = ev_file;
+	kref_get(&uverbs_file->async_file->ref);
+	INIT_IB_EVENT_HANDLER(&uverbs_file->event_handler,
+			      ib_dev,
+			      ib_uverbs_event_handler);
+	ret = ib_register_event_handler(&uverbs_file->event_handler);
+	if (ret)
+		goto err_put_file;
+
+	/* At that point async file stuff was fully set */
+	ev_file->is_async = 1;
 
 	return filp;
 
 err_put_file:
 	fput(filp);
-	kref_put(&uverbs_file->async_file->ref, ib_uverbs_release_event_file);
+	kref_put(&uverbs_file->async_file->ref,
+		 ib_uverbs_release_async_event_file);
 	uverbs_file->async_file = NULL;
 	return ERR_PTR(ret);
 
@@ -679,35 +610,6 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
 	return filp;
 }
 
-/*
- * Look up a completion event file by FD.  If lookup is successful,
- * takes a ref to the event file struct that it returns; if
- * unsuccessful, returns NULL.
- */
-struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd)
-{
-	struct ib_uverbs_event_file *ev_file = NULL;
-	struct fd f = fdget(fd);
-
-	if (!f.file)
-		return NULL;
-
-	if (f.file->f_op != &uverbs_event_fops)
-		goto out;
-
-	ev_file = f.file->private_data;
-	if (ev_file->is_async) {
-		ev_file = NULL;
-		goto out;
-	}
-
-	kref_get(&ev_file->ref);
-
-out:
-	fdput(f);
-	return ev_file;
-}
-
 static int verify_command_mask(struct ib_device *ib_dev, __u32 command)
 {
 	u64 mask;
@@ -999,7 +901,8 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp)
 	mutex_unlock(&file->device->lists_mutex);
 
 	if (file->async_file)
-		kref_put(&file->async_file->ref, ib_uverbs_release_event_file);
+		kref_put(&file->async_file->ref,
+			 ib_uverbs_release_async_event_file);
 
 	kref_put(&file->ref, ib_uverbs_release_file);
 	kobject_put(&dev->kobj);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 9d5fe18..a3274f7 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -53,6 +53,7 @@
 #include <rdma/ib_smi.h>
 #include <rdma/ib_umem.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 
 #include "cxio_hal.h"
 #include "iwch.h"
@@ -1361,6 +1362,8 @@ static void get_dev_fw_ver_str(struct ib_device *ibdev, char *str,
 	snprintf(str, str_len, "%s", info.fw_version);
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 int iwch_register_device(struct iwch_dev *dev)
 {
 	int ret;
@@ -1454,6 +1457,7 @@ int iwch_register_device(struct iwch_dev *dev)
 	memcpy(dev->ibdev.iwcm->ifname, dev->rdev.t3cdev_p->lldev->name,
 	       sizeof(dev->ibdev.iwcm->ifname));
 
+	dev->ibdev.specs_root = (struct uverbs_root *)&root;
 	ret = ib_register_device(&dev->ibdev, NULL);
 	if (ret)
 		goto bail1;
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index 49b51b7..693c13f 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -51,6 +51,7 @@
 #include <rdma/ib_smi.h>
 #include <rdma/ib_umem.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 
 #include "iw_cxgb4.h"
 
@@ -530,6 +531,8 @@ static void get_dev_fw_str(struct ib_device *dev, char *str,
 		 FW_HDR_FW_VER_BUILD_G(c4iw_dev->rdev.lldi.fw_vers));
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 int c4iw_register_device(struct c4iw_dev *dev)
 {
 	int ret;
@@ -625,6 +628,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
 	memcpy(dev->ibdev.iwcm->ifname, dev->rdev.lldi.ports[0]->name,
 	       sizeof(dev->ibdev.iwcm->ifname));
 
+	dev->ibdev.specs_root = (struct uverbs_root *)&root;
 	ret = ib_register_device(&dev->ibdev, NULL);
 	if (ret)
 		goto bail1;
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index 4953d9c..72870a2 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -36,6 +36,7 @@
 #include <rdma/ib_smi.h>
 #include <rdma/ib_user_verbs.h>
 #include <rdma/ib_cache.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 #include "hns_roce_common.h"
 #include "hns_roce_device.h"
 #include <rdma/hns-abi.h>
@@ -422,6 +423,8 @@ static void hns_roce_unregister_device(struct hns_roce_dev *hr_dev)
 	ib_unregister_device(&hr_dev->ib_dev);
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 static int hns_roce_register_device(struct hns_roce_dev *hr_dev)
 {
 	int ret;
@@ -505,6 +508,7 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev)
 	/* OTHERS */
 	ib_dev->get_port_immutable	= hns_roce_port_immutable;
 
+	dev->ib_dev.specs_root = (struct uverbs_root *)&root;
 	ret = ib_register_device(ib_dev, NULL);
 	if (ret) {
 		dev_err(dev, "ib_register_device failed!\n");
diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
index 29e97df..deeb47a 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
@@ -43,6 +43,7 @@
 #include <rdma/ib_verbs.h>
 #include <rdma/iw_cm.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 #include <rdma/ib_umem.h>
 #include "i40iw.h"
 
@@ -2869,6 +2870,8 @@ void i40iw_destroy_rdma_device(struct i40iw_ib_device *iwibdev)
 	ib_dealloc_device(&iwibdev->ibdev);
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 /**
  * i40iw_register_rdma_device - register iwarp device to IB
  * @iwdev: iwarp device
@@ -2883,6 +2886,7 @@ int i40iw_register_rdma_device(struct i40iw_device *iwdev)
 		return -ENOMEM;
 	iwibdev = iwdev->iwibdev;
 
+	iwibdev->ibdev.specs_root = (struct uverbs_root *)&root;
 	ret = ib_register_device(&iwibdev->ibdev, NULL);
 	if (ret)
 		goto error;
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 7031a8dd..9d6b13b 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -45,6 +45,7 @@
 
 #include <rdma/ib_smi.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 #include <rdma/ib_addr.h>
 #include <rdma/ib_cache.h>
 
@@ -2570,6 +2571,8 @@ static void get_fw_ver_str(struct ib_device *device, char *str,
 		 (int) dev->dev->caps.fw_ver & 0xffff);
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 static void *mlx4_ib_add(struct mlx4_dev *dev)
 {
 	struct mlx4_ib_dev *ibdev;
@@ -2852,6 +2855,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
 	if (mlx4_ib_alloc_diag_counters(ibdev))
 		goto err_steer_free_bitmap;
 
+	ibdev->ib_dev.specs_root = (struct uverbs_root *)&root;
 	if (ib_register_device(&ibdev->ib_dev, NULL))
 		goto err_diag_counters;
 
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index d566f67..b0d307d 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -54,6 +54,7 @@
 #include <linux/etherdevice.h>
 #include <linux/mlx5/fs.h>
 #include "mlx5_ib.h"
+#include <rdma/uverbs_ioctl_cmd.h>
 
 #define DRIVER_NAME "mlx5_ib"
 #define DRIVER_VERSION "2.2-1"
@@ -3027,6 +3028,8 @@ static int mlx5_ib_get_hw_stats(struct ib_device *ibdev,
 	return ARRAY_SIZE(names);
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
 {
 	struct mlx5_ib_dev *dev;
@@ -3237,6 +3240,7 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
 	if (err)
 		goto err_odp;
 
+	dev->ib_dev.specs_root = (struct uverbs_root *)&root;
 	err = ib_register_device(&dev->ib_dev, NULL);
 	if (err)
 		goto err_q_cnt;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index d317087..304c47c 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -37,6 +37,7 @@
 #include <rdma/ib_smi.h>
 #include <rdma/ib_umem.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -1189,6 +1190,8 @@ static void get_dev_fw_str(struct ib_device *device, char *str,
 		 (int) dev->fw_ver & 0xffff);
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 int mthca_register_device(struct mthca_dev *dev)
 {
 	int ret;
@@ -1296,6 +1299,7 @@ int mthca_register_device(struct mthca_dev *dev)
 
 	mutex_init(&dev->cap_mask_mutex);
 
+	dev->ib_dev.specs_root = (struct uverbs_root *)&root;
 	ret = ib_register_device(&dev->ib_dev, NULL);
 	if (ret)
 		return ret;
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index aff9fb1..c6829cd 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -41,6 +41,7 @@
 #include <rdma/ib_verbs.h>
 #include <rdma/iw_cm.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 
 #include "nes.h"
 
@@ -3862,6 +3863,8 @@ void nes_destroy_ofa_device(struct nes_ib_device *nesibdev)
 }
 
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 /**
  * nes_register_ofa_device
  */
@@ -3872,6 +3875,7 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev)
 	struct nes_adapter *nesadapter = nesdev->nesadapter;
 	int i, ret;
 
+	nesvnic->nesibdev->ibdev.specs_root = (struct uverbs_root *)&root;
 	ret = ib_register_device(&nesvnic->nesibdev->ibdev, NULL);
 	if (ret) {
 		return ret;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 8960715..539f512 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -44,6 +44,7 @@
 #include <linux/idr.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 #include <rdma/ib_addr.h>
 #include <rdma/ib_mad.h>
 
@@ -115,6 +116,8 @@ static void get_dev_fw_str(struct ib_device *device, char *str,
 	snprintf(str, str_len, "%s", &dev->attr.fw_ver[0]);
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 static int ocrdma_register_device(struct ocrdma_dev *dev)
 {
 	strlcpy(dev->ibdev.name, "ocrdma%d", IB_DEVICE_NAME_MAX);
@@ -218,6 +221,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
 		dev->ibdev.destroy_srq = ocrdma_destroy_srq;
 		dev->ibdev.post_srq_recv = ocrdma_post_srq_recv;
 	}
+	dev->ibdev.specs_root = (struct uverbs_root *)&root;
 	return ib_register_device(&dev->ibdev, NULL);
 }
 
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c
index 0a89a95..19ff7f7 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_main.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c
@@ -48,6 +48,7 @@
 #include <linux/netdevice.h>
 
 #include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 #include <rdma/ib_addr.h>
 
 #include "usnic_abi.h"
@@ -346,6 +347,8 @@ static void usnic_get_dev_fw_str(struct ib_device *device,
 	snprintf(str, str_len, "%s", info.fw_version);
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 /* Start of PF discovery section */
 static void *usnic_ib_device_add(struct pci_dev *dev)
 {
@@ -432,6 +435,7 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
 	us_ibdev->ib_dev.get_dev_fw_str     = usnic_get_dev_fw_str;
 
 
+	us_ibdev->ib_dev.specs_root = (struct uverbs_root *)&root;
 	if (ib_register_device(&us_ibdev->ib_dev, NULL))
 		goto err_fwd_dealloc;
 
diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c
index d430c2f..c8b4a05 100644
--- a/drivers/infiniband/sw/rdmavt/vt.c
+++ b/drivers/infiniband/sw/rdmavt/vt.c
@@ -47,6 +47,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <rdma/uverbs_ioctl_cmd.h>
 #include "vt.h"
 #include "trace.h"
 
@@ -714,6 +715,8 @@ static noinline int check_support(struct rvt_dev_info *rdi, int verb)
 	return 0;
 }
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 /**
  * rvt_register_device - register a driver
  * @rdi: main dev structure for all of rdmavt operations
@@ -826,6 +829,7 @@ int rvt_register_device(struct rvt_dev_info *rdi)
 	rdi->ibdev.num_comp_vectors = 1;
 
 	/* We are now good to announce we exist */
+	rdi->ibdev.specs_root = (struct uverbs_root *)&root;
 	ret =  ib_register_device(&rdi->ibdev, rdi->driver_f.port_callback);
 	if (ret) {
 		rvt_pr_err(rdi, "Failed to register driver with ib core.\n");
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index beb7021..df1c975 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -34,6 +34,7 @@
 #include "rxe.h"
 #include "rxe_loc.h"
 #include "rxe_queue.h"
+#include <rdma/uverbs_ioctl_cmd.h>
 
 static int rxe_query_device(struct ib_device *dev,
 			    struct ib_device_attr *attr,
@@ -1221,6 +1222,8 @@ static ssize_t rxe_show_parent(struct device *device,
 	&dev_attr_parent,
 };
 
+DECLARE_UVERBS_TYPES_GROUP(root, &uverbs_common_types);
+
 int rxe_register_device(struct rxe_dev *rxe)
 {
 	int err;
@@ -1318,6 +1321,7 @@ int rxe_register_device(struct rxe_dev *rxe)
 	dev->attach_mcast = rxe_attach_mcast;
 	dev->detach_mcast = rxe_detach_mcast;
 
+	dev->specs_root = (struct uverbs_root *)&root;
 	err = ib_register_device(dev, NULL);
 	if (err) {
 		pr_warn("rxe_register_device failed, err = %d\n", err);
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 7992fcd..9025090 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1336,17 +1336,6 @@ struct ib_fmr_attr {
 struct ib_ucontext {
 	struct ib_device       *device;
 	struct ib_uverbs_file  *ufile;
-	struct list_head	pd_list;
-	struct list_head	mr_list;
-	struct list_head	mw_list;
-	struct list_head	cq_list;
-	struct list_head	qp_list;
-	struct list_head	srq_list;
-	struct list_head	ah_list;
-	struct list_head	xrcd_list;
-	struct list_head	rule_list;
-	struct list_head	wq_list;
-	struct list_head	rwq_ind_tbl_list;
 	int			closing;
 
 	/* lock for uobjects list */
@@ -1378,11 +1367,8 @@ struct ib_uobject {
 	void		       *object;		/* containing object */
 	struct list_head	list;		/* link to context's list */
 	int			id;		/* index into kernel idr/fd */
-	struct kref		ref;
-	struct rw_semaphore	mutex;		/* protects .live */
 	struct rw_semaphore	usecnt;		/* protects exclusive access */
 	struct rcu_head		rcu;		/* kfree_rcu() overhead */
-	int			live;
 
 	const struct uverbs_type_alloc_action *type;
 	struct ib_ucontext_lock	*uobjects_lock;
@@ -2141,6 +2127,8 @@ struct ib_device {
 	 */
 	int (*get_port_immutable)(struct ib_device *, u8, struct ib_port_immutable *);
 	void (*get_dev_fw_str)(struct ib_device *, char *str, size_t str_len);
+
+	struct uverbs_root                      *specs_root;
 };
 
 struct ib_client {
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 1/7] IB/core: Refactor IDR to be per-device
       [not found]     ` <1484132033-3346-2-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
@ 2017-01-11 22:39       ` Jason Gunthorpe
       [not found]         ` <20170111223917.GA31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-11 22:39 UTC (permalink / raw)
  To: Matan Barak
  Cc: Doug Ledford, linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Wed, Jan 11, 2017 at 12:53:47PM +0200, Matan Barak wrote:
> From: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
> 
> The current code creates an IDR per type. Since types are currently
> common for all vendors and known in advance, this was good enough.
> However, the proposed ioctl based infrastructure allows each vendor
> to declare only some of the common types and declare its own specific
> types.
> 
> Thus, we decided to implement IDR to be per device and refactor it to
> use a new file.

I'm still unclear why we want the idr to be global and not per
/dev/uverbs0 open fd.

__idr_get_uobj forces a strong association:

                if (uobj->context == context)

Why on earth should we have a shared IDR when the objects cannot
actually be shared?

Surely that just wastes memory and harms performance.

I know we have talked about this before, but I think there should be a
strong reason why we don't move this into struct ib_ucontext in this
patch.

> +static void ib_device_allocate_idrs(struct ib_device *device)
> +{
> +	spin_lock_init(&device->idr_lock);
> +	idr_init(&device->idr);
> +}
> +
> +static void ib_device_destroy_idrs(struct ib_device *device)
> +{
> +	idr_destroy(&device->idr);
> +}

Not sure why we need these wrappers..

> @@ -230,24 +228,24 @@ static void put_cq_read(struct ib_cq *cq)
>  	put_uobj_read(cq->uobject);
>  }
>  
> -static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
> +static void put_ah_read(struct ib_ah *ah)
>  {
> -	return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context, 0);
> +	put_uobj_read(ah->uobject);
>  }
>  
> -static void put_ah_read(struct ib_ah *ah)
> +static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
>  {
> -	put_uobj_read(ah->uobject);
> +	return idr_read_obj(ah_handle, context, 0);
>  }

These two functions got reordered, makes the diff ugly.

> +	struct idr		idr;
> +	/* Global lock in use to safely release device IDR */
> +	spinlock_t		idr_lock;

That comment doesn't make sense, has nothing to do with
release... 'spinlock protects idr'

Otherwise this patch looks fine to me.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 7/7] IB/core: Use the new IDR and locking infrastructure in uverbs_cmd
       [not found]     ` <1484132033-3346-8-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
@ 2017-01-11 22:49       ` kbuild test robot
  2017-01-11 23:43       ` kbuild test robot
  1 sibling, 0 replies; 27+ messages in thread
From: kbuild test robot @ 2017-01-11 22:49 UTC (permalink / raw)
  Cc: kbuild-all-JC7UmRfGjtg, Doug Ledford,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

[-- Attachment #1: Type: text/plain, Size: 1474 bytes --]

Hi Matan,

[auto build test ERROR on rdma/master]
[also build test ERROR on v4.10-rc3]
[cannot apply to next-20170111]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Matan-Barak/Change-IDR-usage-and-locking-in-uverbs/20170112-043750
base:   https://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma.git master
config: x86_64-allyesdebian (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

>> drivers/infiniband/hw/cxgb3/built-in.o:(.rodata+0xc50): multiple definition of `root'
   drivers/infiniband/hw/mthca/built-in.o:(.rodata+0x640): first defined here
   drivers/infiniband/hw/cxgb4/built-in.o:(.rodata+0x1880): multiple definition of `root'
   drivers/infiniband/hw/mthca/built-in.o:(.rodata+0x640): first defined here
   drivers/infiniband/hw/mlx4/built-in.o:(.rodata+0x4b0): multiple definition of `root'
   drivers/infiniband/hw/mthca/built-in.o:(.rodata+0x640): first defined here
   drivers/infiniband/hw/nes/built-in.o:(.rodata+0xe80): multiple definition of `root'
   drivers/infiniband/hw/mthca/built-in.o:(.rodata+0x640): first defined here

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 38065 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 2/7] IB/core: Add support for custom types
       [not found]     ` <1484132033-3346-3-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
@ 2017-01-11 23:28       ` Jason Gunthorpe
       [not found]         ` <20170111232811.GB31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-11 23:28 UTC (permalink / raw)
  To: Matan Barak
  Cc: Doug Ledford, linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Wed, Jan 11, 2017 at 12:53:48PM +0200, Matan Barak wrote:

> +static struct ib_uobject *get_uobj_rcu(int id, struct ib_ucontext *context)
> +{
> +	struct ib_uobject *uobj;
> +
> +	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
> +			 "uverbs: get_uobj_rcu wasn't called in a rcu_read_lock()!");
> +	/* object won't be released as we're protected in rcu */
> +	uobj = idr_find(&context->device->idr, id);

So.. I think you need another patch in your series to rework the idr
globally to use rcu. Waiting till patch 7 seems too late

I'd particularly like to see this series without patch 5..

Reworking this to RCU seems like a good idea. Even better would be to
have per-fd locking domains ;)

> +	/*
> +	 * We start with allocating an idr pointing to NULL. This represents an
> +	 * object which isn't initialized yet. We'll replace it later on with
> +	 * the real object once we commit.
> +	 */
> +	ret = idr_alloc(&uobj->context->device->idr, NULL, 0, 0, GFP_NOWAIT);
> +	if (ret >= 0)
> +		uobj->id = ret;

And probably another patch to replace live with NULL.

These are both big changes, it would be better to see them with their
full context, not as stubs like this. Patch 7 has the code for this
but it is all intermingled with so much other stuff..

> +	/*
> +	 * When we destroy an object, we first just lock it for WRITE and
> +	 * actually DESTROY it in the finalize stage. So, the problematic
> +	 * scenario is when we just stared the finalize stage of the
> +	 * destruction (nothing was executed yet). Now, the other thread
> +	 * fetched the object for READ access, but it didn't lock it yet.
> +	 * The DESTROY thread continues and starts destroying the object.
> +	 * When the other thread continue - without the RCU, it would
> +	 * access freed memory. However, the rcu_read_lock delays the free
> +	 * until the rcu_read_lock of the READ operation quits. Since the
> +	 * write lock of the object is still taken by the DESTROY flow, the
> +	 * READ operation will get -EBUSY and it'll just bail out.
> +	 */
> +	kfree_rcu(uobj, rcu);

Zoiks. But yes, ok, it makes sense. Good comment.

> +/*
> + * Returns the ib_uobject, NULL if the requested object isn't found or an error.
> + * The caller should check for IS_ERR_OR_NULL.

Some people really hate IS_ERR_OR_NULL.. Why would the caller handle
NULL differently? Why not return -ENOENT?

> + */
> +static struct ib_uobject *get_uobject_from_context(struct ib_ucontext *ucontext,
> +						   const struct uverbs_type_alloc_action *type,
> +						   u32 idr,
> +						   enum uverbs_idr_access access)
> +{
> +	struct ib_uobject *uobj;
> +	int ret;
> +
> +	rcu_read_lock();
> +	uobj = get_uobj_rcu(idr, ucontext);

Is there a reason we have get_uobj_rcu() at all ? Just inline it.

> +	if (!uobj)
> +		goto free;
> +
> +	if (uobj->type != type) {
> +		uobj = NULL;

But this is an error, not no found.

> +static struct ib_uobject *uverbs_get_uobject_from_idr(const struct uverbs_type_alloc_action *type_alloc,
> +						      struct ib_ucontext *ucontext,
> +						      enum uverbs_idr_access access,
> +						      uint32_t idr)

u32 for the kernel please, check all patches

Why do we need to have three confusingly named functions to implement
one thing? Does it even make sense that add/get/destroy are all one
function?

I'm not sure it makes any sense to overload
uverbs_get_uobject_from_context for these two very different cases..
They don't even have the same type in the uapi (int vs u32)

I think you should just stick with uverbs_get_uobject_from_idr/_fd and
skip the common getter one..

> +{
> +	struct ib_uobject *uobj;
> +	int ret;
> +
> +	if (access == UVERBS_ACCESS_NEW) {
> +		uobj = kmalloc(type_alloc->obj_size, GFP_KERNEL);
> +		if (!uobj)
> +			return ERR_PTR(-ENOMEM);

Does this really make sense as an access enum and not just a different
function? This one one function is doing far too much I suspect.

Use function pointers:

 struct ub_uobject *obj = type_alloc->ops->allocate(type_alloc, ucontext);

> +static void uverbs_uobject_add(struct ib_uobject *uobject)
> +{
> +	mutex_lock(&uobject->context->uobjects_lock->lock);
> +	list_add(&uobject->list, &uobject->context->uobjects);
> +	mutex_unlock(&uobject->context->uobjects_lock->lock);
> +}
> +
> +static void uverbs_uobject_remove(struct ib_uobject *uobject)
> +{
> +	/*
> +	 * Calling remove requires exclusive access, so it's not possible
> +	 * another thread will use our object since the function is called
> +	 * with exclusive access.
> +	 */
> +	uverbs_idr_remove_uobj(uobject);
> +	mutex_lock(&uobject->context->uobjects_lock->lock);
> +	list_del(&uobject->list);
> +	mutex_unlock(&uobject->context->uobjects_lock->lock);
> +	put_uobj(uobject);

What does this put pair with? Usually a put like this would pair with
a get inside the _add function. So this deserves a comment at least.
If it is pairing with a get the caller performed then it should not be
here.

> +static void uverbs_finalize_idr(struct ib_uobject *uobj,
> +				enum uverbs_idr_access access,
> +				bool commit)
> +{
> +	switch (access) {
> +	case UVERBS_ACCESS_READ:
> +		up_read(&uobj->usecnt);
> +		break;
> +	case UVERBS_ACCESS_NEW:
> +		if (commit) {
> +			uverbs_uobject_add(uobj);
> +			spin_lock(&uobj->context->device->idr_lock);
> +			/*
> +			 * We already allocated this IDR with a NULL object, so
> +			 * this shouldn't fail.
> +			 */
> +			WARN_ON(idr_replace(&uobj->context->device->idr,
> +					    uobj, uobj->id));
> +			spin_unlock(&uobj->context->device->idr_lock);
> +		} else {
> +			uverbs_idr_remove_uobj(uobj);
> +			put_uobj(uobj);
> +		}
> +		break;
> +	case UVERBS_ACCESS_WRITE:
> +		up_write(&uobj->usecnt);
> +		break;
> +	case UVERBS_ACCESS_DESTROY:
> +		if (commit)
> +			uverbs_uobject_remove(uobj);
> +		else
> +			up_write(&uobj->usecnt);

Again wondering if ACCESS_DESTROY makes any sense..

> +		break;
> +	}
> +}
> +
> +void uverbs_finalize_object(struct ib_uobject *uobj,
> +			    enum uverbs_idr_access access,
> +			    bool commit)
> +{
> +	if (uobj->type->type == UVERBS_ATTR_TYPE_IDR)
> +		uverbs_finalize_idr(uobj, access, commit);
> +	else
> +		WARN_ON(true);

I think you should use ops like the rest of the kernel.

  uobj->ops->finalize(uobj,access,commit);

Get rid of these switch version.

> +
>  struct ib_ucontext {
>  	struct ib_device       *device;
>  	struct list_head	pd_list;
> @@ -1346,6 +1348,10 @@ struct ib_ucontext {
>  	struct list_head	rwq_ind_tbl_list;
>  	int			closing;
>  
> +	/* lock for uobjects list */
> +	struct ib_ucontext_lock	*uobjects_lock;

This is so weird. Why do we have a pointer to a struct mutex? This
serves absolutely no function at this point in the series, just inline
the mutex.

> +	struct list_head	uobjects;
> +
>  	struct pid             *tgid;
>  #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
>  	struct rb_root      umem_tree;
> @@ -1373,8 +1379,11 @@ struct ib_uobject {
>  	int			id;		/* index into kernel idr */

Shouldn't this be u32?

>  	struct kref		ref;
>  	struct rw_semaphore	mutex;		/* protects .live */
> +	struct rw_semaphore	usecnt;		/* protects exclusive access */

usecnt isn't really a cnt, better name?

> +	const struct uverbs_type_alloc_action *type;

[..]

> +struct uverbs_type_alloc_action;
> +typedef void (*free_type)(const struct uverbs_type_alloc_action *uobject_type,
> +			  struct ib_uobject *uobject);
> +
> +struct uverbs_type_alloc_action {
> +	enum uverbs_attr_type		type;
> +	int				order;
> +	size_t				obj_size;
> +	free_type			free_fn;
> +};

Just make a sensible meta-class struct like other parts of the kernel:

struct uverbs_obj_type {
   unsigned int destroy_order;
   size_t allocation_size;

   struct ib_uobject (*alloc)(..);
   void (*free)(..);
   void (*lookup)(..);
};

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 7/7] IB/core: Use the new IDR and locking infrastructure in uverbs_cmd
       [not found]     ` <1484132033-3346-8-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
  2017-01-11 22:49       ` kbuild test robot
@ 2017-01-11 23:43       ` kbuild test robot
  1 sibling, 0 replies; 27+ messages in thread
From: kbuild test robot @ 2017-01-11 23:43 UTC (permalink / raw)
  Cc: kbuild-all-JC7UmRfGjtg, Doug Ledford,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas, Jason Gunthorpe,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran, Matan Barak

[-- Attachment #1: Type: text/plain, Size: 1033 bytes --]

Hi Matan,

[auto build test ERROR on rdma/master]
[also build test ERROR on v4.10-rc3]
[cannot apply to next-20170111]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Matan-Barak/Change-IDR-usage-and-locking-in-uverbs/20170112-043750
base:   https://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma.git master
config: ia64-defconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=ia64 

All errors (new ones prefixed by >>):

>> ERROR: "uverbs_common_types" [drivers/infiniband/hw/mthca/ib_mthca.ko] undefined!

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 18112 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 3/7] IB/core: Add support for fd objects
       [not found]     ` <1484132033-3346-4-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
@ 2017-01-11 23:58       ` Jason Gunthorpe
       [not found]         ` <20170111235801.GC31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-11 23:58 UTC (permalink / raw)
  To: Matan Barak
  Cc: Doug Ledford, linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Wed, Jan 11, 2017 at 12:53:49PM +0200, Matan Barak wrote:

> This commit adds the necessary mechanism to support FD based objects
> like their IDR counterparts. FD objects release need to be synchronized
> with context release. Since FDs could outlives their context, we use
> a kref on this lock. We initialize the lock and the kref in downstream
> patches. This is acceptable, as we don't use this infrastructure until
> a later point in this series.

This seems unnecessarily complicated. Just hold the kref on the
ucontext in the fd. There isn't a problem with a dummy version of that
struct hanging around..

> +static struct ib_uobject *uverbs_get_uobject_from_fd(const struct uverbs_type_alloc_action *type_alloc,
> +						     struct ib_ucontext *ucontext,
> +						     enum uverbs_idr_access access,
> +						     unsigned int fd)
> +{
> +	if (access == UVERBS_ACCESS_NEW) {
> +		int _fd;

Something has gone terribly wrong if you need _ to disambiguate with a
function argument...
> +	} else if (access == UVERBS_ACCESS_READ) {
> +		struct file *f = fget(fd);
> +		struct ib_uobject *uobject;
> +
> +		if (!f)
> +			return ERR_PTR(-EBADF);
> +
> +		uobject = uverbs_priv_fd_to_uobject(f->private_data);
> +		if (f->f_op != type_alloc->fd.fops ||
> +		    !uobject->context) {

I think the if should be split, if fops isn't correct then do not even
call uverbs_priv_fd_to_uobject.

> +void uverbs_cleanup_fd(void *private_data)
> +{
> +	struct ib_uobject *uobject = uverbs_priv_fd_to_uobject(private_data);
> +
> +	kfree(uobject);
> +}

Woah, this is not OK at this point in the series. There is really too
much stuff bundled into patch 7 to make proper sense of this.

I don't like this design. Do not implicitly prepend ib_uobject to
structures. Require the users to include the struct as is common in
linux.

Do not drop the kref out of ib_uobject, that should be the master
kref, drop the kref out of ib_uverbs_event_file instead.

> +static inline void *uverbs_fd_uobj_to_priv(struct ib_uobject *uobj)
> +{
> +	return uobj + 1;
> +}

Which means stuff like this can go away..

> -	int			id;		/* index into kernel idr */
> +	int			id;		/* index into kernel idr/fd */

Why do we need to store the fd number at all? We can *never* use it in
the kernel except as the argument to fdinstall. For that reason we
should never store it.

Can you move the fdallocate into finalize? At the very least 0 the
value after fdinstall so people don't get the wrong idea down the
road.

>  	int				order;
>  	size_t				obj_size;
>  	free_type			free_fn;
> +	struct {
> +		const struct file_operations	*fops;
> +		const char			*name;

Maybe name should be common

This idea also seems reasonable to me in general, but again, I'd
rather see it more completely implemented in this patch instead of
deferring so much stuff in to the giant #7 patch.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 4/7] IB/core: Add generic ucontext initialization and teardown
       [not found]     ` <1484132033-3346-5-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
@ 2017-01-12  0:09       ` Jason Gunthorpe
  0 siblings, 0 replies; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-12  0:09 UTC (permalink / raw)
  To: Matan Barak
  Cc: Doug Ledford, linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Wed, Jan 11, 2017 at 12:53:50PM +0200, Matan Barak wrote:
> When a ucontext is created, we need to initialize the list of objects.
> This list consists of every user object that is associated with
> this ucontext. The possible elements in this list are either a file
> descriptor or an object which is represented by an IDR.
> Every such an object, has a release function (which is called upon
> object destruction) and a number associated to its release order.

Please use standard names. As discussed my last message, every
uobject should have a kref, and the 'release' function is *only* the
function that gets called on last-put.

The purpose of this destruction and ordering is to destroy *device*
resources *only*. It has nothing to do with ordering kref puts.

> +static unsigned int get_max_type_orders(const struct uverbs_root *root)
> +{
> +	unsigned int i;
> +	unsigned int max = 0;
> +
> +	for (i = 0; i < root->num_groups; i++) {
> +		unsigned int j;
> +		const struct uverbs_type_group *types = root->type_groups[i];
> +
> +		for (j = 0; j < types->num_types; j++) {
> +			/*
> +			 * Either this type isn't supported by this ib_device
> +			 * (as the group is an array of pointers to types
> +			 * indexed by the type) or this type is supported, but
> +			 * we can't instantiate objects from this type
> +			 * (e.g. you can't instantiate objects of
> +			 * UVERBS_DEVICE).
> +			 */
> +			if (!types->types[j] || !types->types[j]->alloc)
> +				continue;
> +			if (types->types[j]->alloc->order > max)
> +				max = types->types[j]->alloc->order;
> +		}
> +	}

This seems like an inefficient algorithm, just use something like this
for destroy:

cur_order = 0
    while (!list_empty(&ucontext->uobjects)) {
        next_order = MAX;
	list_for_each_entry_safe(obj, next_obj, &ucontext->uobjects,
				 list) {
             if (object->type->order == cur_order) {
	       ..
	     } else
                   next_order = min(object->type->order, next_order);
        }
	cur_order = next_order;
    }

> +void uverbs_release_ucontext(struct ib_ucontext *ucontext)
> +{
> +	/*
> +	 * Since FD objects could outlive their context, we use a kref'ed
> +	 * lock. This lock is referenced when a context and FD objects are
> +	 * created. This lock protects concurrent context release from FD
> +	 * objects release. Therefore, we need to put this lock object in
> +	 * the context and every FD object release.
> +	 */
> +	kref_put(&ucontext->uobjects_lock->ref, release_uobjects_list_lock);
> +}

A function called release that doesn't do release?

> +struct uverbs_type {
> +	const struct uverbs_type_alloc_action   *alloc;
> +};
> +
> +struct uverbs_type_group {
> +	size_t					num_types;
> +	const struct uverbs_type		**types;
> +};
> +
> +struct uverbs_root {
> +	const struct uverbs_type_group		**type_groups;
> +	size_t					num_groups;
> +};

None of this is necessary at this point in the series, as I said in an
earlier patch just create a single sensible meta-class type and store
the order in there.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 5/7] IB/core: Add macros for declaring types and type groups
       [not found]     ` <1484132033-3346-6-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
@ 2017-01-12  0:10       ` Jason Gunthorpe
       [not found]         ` <20170112001029.GE31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-12  0:10 UTC (permalink / raw)
  To: Matan Barak
  Cc: Doug Ledford, linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Wed, Jan 11, 2017 at 12:53:51PM +0200, Matan Barak wrote:
> In order to initialize and destroy types in a generic way, we need to
> provide information about the allocation size, release function and
> order. This is done through a macro based DSL (domain specific
> language). This patch adds macros to initialize a type and a type
> group.
> 
> When we transform the write based commands to use this new locking and
> allocation schema, we use these types declarations.
> 
> Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
> Reviewed-by: Yishai Hadas <yishaih-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
>  include/rdma/uverbs_ioctl.h | 50 +++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 48 insertions(+), 2 deletions(-)

None of this makes any sense to me at this point in the series.

Just use a sane meta-class type and the 'usual' linux static const
initializer scheme.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 6/7] IB/core: Declare all common IB types
       [not found]     ` <1484132033-3346-7-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
@ 2017-01-12  0:19       ` Jason Gunthorpe
       [not found]         ` <20170112001955.GF31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-12  0:19 UTC (permalink / raw)
  To: Matan Barak
  Cc: Doug Ledford, linux-rdma-u79uwXL29TY76Z2rM5mHXA, Yishai Hadas,
	Sean Hefty, Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Wed, Jan 11, 2017 at 12:53:52PM +0200, Matan Barak wrote:

> diff --git a/drivers/infiniband/core/uverbs_ioctl_cmd.c b/drivers/infiniband/core/uverbs_ioctl_cmd.c
> new file mode 100644

This is not really an appropriate file name for this point in the
series...

> +DECLARE_UVERBS_TYPE(uverbs_type_comp_channel,
> +		    &UVERBS_TYPE_ALLOC_FD(0, sizeof(struct ib_uobject) + sizeof(struct ib_uverbs_event_file),
> +					  uverbs_free_event_file,
> +					  &uverbs_event_fops,
> +					  "[infinibandevent]",
> O_RDONLY));

Really hate these macros.

const struct ib_uobject_type uverbs_type_comp_channel = {
       .size = sizeof(struct ib_uverbs_event_file,
       .destroy = uverbs_destroy_event_file, // destroy = release device resources!!
       .fd = {
          .fops = &uverbs_event_fops,
	  .name = "[infinibandevent]"
       },
};

If you can't do it without macros something else is wrong.

> +DECLARE_UVERBS_TYPES(uverbs_common_types,
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_PD, uverbs_type_pd),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_MR, uverbs_type_mr),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_COMP_CHANNEL, uverbs_type_comp_channel),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_CQ, uverbs_type_cq),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_QP, uverbs_type_qp),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_AH, uverbs_type_ah),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_MW, uverbs_type_mw),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_SRQ, uverbs_type_srq),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_FLOW, uverbs_type_flow),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_WQ, uverbs_type_wq),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_RWQ_IND_TBL,
> +				     uverbs_type_rwq_ind_table),
> +		     ADD_UVERBS_TYPE(UVERBS_TYPE_XRCD, uverbs_type_xrcd),
> +);
> +EXPORT_SYMBOL(uverbs_common_types);

No purpose at this point in the series.

I didn't look carefully at patch 7 due to to convoluted it is, split
it please..

Everything else looks broadly reasonable to me and is a good overall
improvement I think.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 6/7] IB/core: Declare all common IB types
       [not found]         ` <20170112001955.GF31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
@ 2017-01-12  6:48           ` Matan Barak
  2017-01-17 17:37           ` Matan Barak
  1 sibling, 0 replies; 27+ messages in thread
From: Matan Barak @ 2017-01-12  6:48 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Thu, Jan 12, 2017 at 2:19 AM, Jason Gunthorpe
<jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> wrote:
> On Wed, Jan 11, 2017 at 12:53:52PM +0200, Matan Barak wrote:
>
>> diff --git a/drivers/infiniband/core/uverbs_ioctl_cmd.c b/drivers/infiniband/core/uverbs_ioctl_cmd.c
>> new file mode 100644
>
> This is not really an appropriate file name for this point in the
> series...
>
>> +DECLARE_UVERBS_TYPE(uverbs_type_comp_channel,
>> +                 &UVERBS_TYPE_ALLOC_FD(0, sizeof(struct ib_uobject) + sizeof(struct ib_uverbs_event_file),
>> +                                       uverbs_free_event_file,
>> +                                       &uverbs_event_fops,
>> +                                       "[infinibandevent]",
>> O_RDONLY));
>
> Really hate these macros.
>
> const struct ib_uobject_type uverbs_type_comp_channel = {
>        .size = sizeof(struct ib_uverbs_event_file,
>        .destroy = uverbs_destroy_event_file, // destroy = release device resources!!
>        .fd = {
>           .fops = &uverbs_event_fops,
>           .name = "[infinibandevent]"
>        },
> };
>
> If you can't do it without macros something else is wrong.
>
>> +DECLARE_UVERBS_TYPES(uverbs_common_types,
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_PD, uverbs_type_pd),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_MR, uverbs_type_mr),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_COMP_CHANNEL, uverbs_type_comp_channel),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_CQ, uverbs_type_cq),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_QP, uverbs_type_qp),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_AH, uverbs_type_ah),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_MW, uverbs_type_mw),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_SRQ, uverbs_type_srq),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_FLOW, uverbs_type_flow),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_WQ, uverbs_type_wq),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_RWQ_IND_TBL,
>> +                                  uverbs_type_rwq_ind_table),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_XRCD, uverbs_type_xrcd),
>> +);
>> +EXPORT_SYMBOL(uverbs_common_types);
>
> No purpose at this point in the series.
>
> I didn't look carefully at patch 7 due to to convoluted it is, split
> it please..
>
> Everything else looks broadly reasonable to me and is a good overall
> improvement I think.

Thanks for the review Jason :)
I'll read it thoroughly and answer/ask for clarifications early next week.

>
> Jason

Matan

> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 1/7] IB/core: Refactor IDR to be per-device
       [not found]         ` <20170111223917.GA31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
@ 2017-01-17 17:08           ` Matan Barak
       [not found]             ` <CAAKD3BDMDyahSu1uFPE_bA=QXAy9Q+qdMPoVw-hJTrFN3um9rg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-17 17:08 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Thu, Jan 12, 2017 at 12:39 AM, Jason Gunthorpe
<jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> wrote:
> On Wed, Jan 11, 2017 at 12:53:47PM +0200, Matan Barak wrote:
>> From: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
>>
>> The current code creates an IDR per type. Since types are currently
>> common for all vendors and known in advance, this was good enough.
>> However, the proposed ioctl based infrastructure allows each vendor
>> to declare only some of the common types and declare its own specific
>> types.
>>
>> Thus, we decided to implement IDR to be per device and refactor it to
>> use a new file.
>
> I'm still unclear why we want the idr to be global and not per
> /dev/uverbs0 open fd.
>

Assuming we keep the current separate fds model (i.e, per-device fd
and another rdma-cm fd),
what is the actual benefit here?
Memory wise - we'll probably consume a lot more (every idr layer is >
2K on a 64bit architecture),
so sharing here might have some memory usage benefits.

> __idr_get_uobj forces a strong association:
>
>                 if (uobj->context == context)
>
> Why on earth should we have a shared IDR when the objects cannot
> actually be shared?
>

It's closer to the current approach (which could be refined later on)
and it's probably more optimized memory wise.

> Surely that just wastes memory and harms performance.
>
> I know we have talked about this before, but I think there should be a
> strong reason why we don't move this into struct ib_ucontext in this
> patch.
>

We can, but except for dropping the (uobj->context == context)
condition and *maybe* getting some
negligible performance benefits (if the per-context idr tree is indeed
lower in height), what will we gain?

>> +static void ib_device_allocate_idrs(struct ib_device *device)
>> +{
>> +     spin_lock_init(&device->idr_lock);
>> +     idr_init(&device->idr);
>> +}
>> +
>> +static void ib_device_destroy_idrs(struct ib_device *device)
>> +{
>> +     idr_destroy(&device->idr);
>> +}
>
> Not sure why we need these wrappers..
>

Agreed, they can be inlined.

>> @@ -230,24 +228,24 @@ static void put_cq_read(struct ib_cq *cq)
>>       put_uobj_read(cq->uobject);
>>  }
>>
>> -static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
>> +static void put_ah_read(struct ib_ah *ah)
>>  {
>> -     return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context, 0);
>> +     put_uobj_read(ah->uobject);
>>  }
>>
>> -static void put_ah_read(struct ib_ah *ah)
>> +static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
>>  {
>> -     put_uobj_read(ah->uobject);
>> +     return idr_read_obj(ah_handle, context, 0);
>>  }
>
> These two functions got reordered, makes the diff ugly.
>

Yep, thanks.

>> +     struct idr              idr;
>> +     /* Global lock in use to safely release device IDR */
>> +     spinlock_t              idr_lock;
>
> That comment doesn't make sense, has nothing to do with
> release... 'spinlock protects idr'
>

Yeah, it's only protecting the idr. I'll fix that.

> Otherwise this patch looks fine to me.
>
> Jason

Thanks for reviewing.

Matan

> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 2/7] IB/core: Add support for custom types
       [not found]         ` <20170111232811.GB31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
@ 2017-01-17 17:23           ` Matan Barak
       [not found]             ` <CAAKD3BBkzoLuY3TF=bDK3U=rnLzK0uWmDL2tgsUwmBoGTXAqrw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-17 17:23 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Thu, Jan 12, 2017 at 1:28 AM, Jason Gunthorpe
<jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> wrote:
> On Wed, Jan 11, 2017 at 12:53:48PM +0200, Matan Barak wrote:
>
>> +static struct ib_uobject *get_uobj_rcu(int id, struct ib_ucontext *context)
>> +{
>> +     struct ib_uobject *uobj;
>> +
>> +     RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
>> +                      "uverbs: get_uobj_rcu wasn't called in a rcu_read_lock()!");
>> +     /* object won't be released as we're protected in rcu */
>> +     uobj = idr_find(&context->device->idr, id);
>
> So.. I think you need another patch in your series to rework the idr
> globally to use rcu. Waiting till patch 7 seems too late
>

I'm not sure I followed here.
The idr mechanism uses RCU as of the current code for fetching ids.

> I'd particularly like to see this series without patch 5..
>

The major purpose of this series is to be a parliamentary step to the
ABI, which as you recall,
uses a macro based language to declare types. I can simplify it in
this series to directly initialize the
types, but that means the next series will modify these lines to the
macros language.

> Reworking this to RCU seems like a good idea. Even better would be to
> have per-fd locking domains ;)
>

What do you mean by "per-fd locking domains"?

>> +     /*
>> +      * We start with allocating an idr pointing to NULL. This represents an
>> +      * object which isn't initialized yet. We'll replace it later on with
>> +      * the real object once we commit.
>> +      */
>> +     ret = idr_alloc(&uobj->context->device->idr, NULL, 0, 0, GFP_NOWAIT);
>> +     if (ret >= 0)
>> +             uobj->id = ret;
>
> And probably another patch to replace live with NULL.
>

The whole implementation here is replaced, so if we have a patch that replaces
live with NULL in the current implementation and then later on in the
series we re-work
the API, we actually delete lines we've added at the same series.
Since we replace here the whole
idr/fd objects management, I think it's better to review the
locking/lifetime as an infrastructure
rather than bunch of changes in the usage of the current infrastructure.

> These are both big changes, it would be better to see them with their
> full context, not as stubs like this. Patch 7 has the code for this
> but it is all intermingled with so much other stuff..
>

Although putting an infrastructure and then using it in later patches
is common practice in
the kernel, I can look into embedding the required changes in the
infrastructure changes.
Saying that, testing that it's really bi-sectable could be a
nightmare, so I'm not really sure it's worth here.

>> +     /*
>> +      * When we destroy an object, we first just lock it for WRITE and
>> +      * actually DESTROY it in the finalize stage. So, the problematic
>> +      * scenario is when we just stared the finalize stage of the
>> +      * destruction (nothing was executed yet). Now, the other thread
>> +      * fetched the object for READ access, but it didn't lock it yet.
>> +      * The DESTROY thread continues and starts destroying the object.
>> +      * When the other thread continue - without the RCU, it would
>> +      * access freed memory. However, the rcu_read_lock delays the free
>> +      * until the rcu_read_lock of the READ operation quits. Since the
>> +      * write lock of the object is still taken by the DESTROY flow, the
>> +      * READ operation will get -EBUSY and it'll just bail out.
>> +      */
>> +     kfree_rcu(uobj, rcu);
>
> Zoiks. But yes, ok, it makes sense. Good comment.
>
>> +/*
>> + * Returns the ib_uobject, NULL if the requested object isn't found or an error.
>> + * The caller should check for IS_ERR_OR_NULL.
>
> Some people really hate IS_ERR_OR_NULL.. Why would the caller handle
> NULL differently? Why not return -ENOENT?
>

Ok

>> + */
>> +static struct ib_uobject *get_uobject_from_context(struct ib_ucontext *ucontext,
>> +                                                const struct uverbs_type_alloc_action *type,
>> +                                                u32 idr,
>> +                                                enum uverbs_idr_access access)
>> +{
>> +     struct ib_uobject *uobj;
>> +     int ret;
>> +
>> +     rcu_read_lock();
>> +     uobj = get_uobj_rcu(idr, ucontext);
>
> Is there a reason we have get_uobj_rcu() at all ? Just inline it.
>

It's later used for uverbs_is_live.

>> +     if (!uobj)
>> +             goto free;
>> +
>> +     if (uobj->type != type) {
>> +             uobj = NULL;
>
> But this is an error, not no found.
>

Ok, I'll fix.

>> +static struct ib_uobject *uverbs_get_uobject_from_idr(const struct uverbs_type_alloc_action *type_alloc,
>> +                                                   struct ib_ucontext *ucontext,
>> +                                                   enum uverbs_idr_access access,
>> +                                                   uint32_t idr)
>
> u32 for the kernel please, check all patches
>

Right, actually idr should be an int :)

> Why do we need to have three confusingly named functions to implement
> one thing? Does it even make sense that add/get/destroy are all one
> function?
>

It's a preliminary step for the next series which actually introduces the ABI.
If you recall, the metadata for each attribute contains how to access it.
I'll take a look into changing the enums and switch-cases to function
pointers and examine if it also fits the new model well enough.
Saying that, we only have two types (idr and fds) and we don't expect
to add much later

> I'm not sure it makes any sense to overload
> uverbs_get_uobject_from_context for these two very different cases..
> They don't even have the same type in the uapi (int vs u32)
>

I could split them to two different functions here. There are some
benefits of the current way.
You could of rdma_core as managing a big repository of objects of all
types and you could get
any object using the tuple (type,id). If we go to the function
pointers model, you'll probably just go to
type->lookup function.

> I think you should just stick with uverbs_get_uobject_from_idr/_fd and
> skip the common getter one..
>

Ok

>> +{
>> +     struct ib_uobject *uobj;
>> +     int ret;
>> +
>> +     if (access == UVERBS_ACCESS_NEW) {
>> +             uobj = kmalloc(type_alloc->obj_size, GFP_KERNEL);
>> +             if (!uobj)
>> +                     return ERR_PTR(-ENOMEM);
>
> Does this really make sense as an access enum and not just a different
> function? This one one function is doing far too much I suspect.
>
> Use function pointers:
>
>  struct ub_uobject *obj = type_alloc->ops->allocate(type_alloc, ucontext);
>

For the same reason as seen above - the goal here is to use ACCESS_ identifiers
in the DSL to specify how to use the object. Therefore, I think enum
makes sense.
If we transform this into function pointers, the new ABI (next series)
will probably use a wrapper
function to execute the correct function pointer.

>> +static void uverbs_uobject_add(struct ib_uobject *uobject)
>> +{
>> +     mutex_lock(&uobject->context->uobjects_lock->lock);
>> +     list_add(&uobject->list, &uobject->context->uobjects);
>> +     mutex_unlock(&uobject->context->uobjects_lock->lock);
>> +}
>> +
>> +static void uverbs_uobject_remove(struct ib_uobject *uobject)
>> +{
>> +     /*
>> +      * Calling remove requires exclusive access, so it's not possible
>> +      * another thread will use our object since the function is called
>> +      * with exclusive access.
>> +      */
>> +     uverbs_idr_remove_uobj(uobject);
>> +     mutex_lock(&uobject->context->uobjects_lock->lock);
>> +     list_del(&uobject->list);
>> +     mutex_unlock(&uobject->context->uobjects_lock->lock);
>> +     put_uobj(uobject);
>
> What does this put pair with? Usually a put like this would pair with
> a get inside the _add function. So this deserves a comment at least.
> If it is pairing with a get the caller performed then it should not be
> here.
>

They're a pair in a sense they're both used in the finalize stage of the IDR
object creation. Both object creation and object destruction are split
into two parts.
Object creation is mainly done in the "get" stage while object
destruction is mostly
done in the "finalize" stage.

>> +static void uverbs_finalize_idr(struct ib_uobject *uobj,
>> +                             enum uverbs_idr_access access,
>> +                             bool commit)
>> +{
>> +     switch (access) {
>> +     case UVERBS_ACCESS_READ:
>> +             up_read(&uobj->usecnt);
>> +             break;
>> +     case UVERBS_ACCESS_NEW:
>> +             if (commit) {
>> +                     uverbs_uobject_add(uobj);
>> +                     spin_lock(&uobj->context->device->idr_lock);
>> +                     /*
>> +                      * We already allocated this IDR with a NULL object, so
>> +                      * this shouldn't fail.
>> +                      */
>> +                     WARN_ON(idr_replace(&uobj->context->device->idr,
>> +                                         uobj, uobj->id));
>> +                     spin_unlock(&uobj->context->device->idr_lock);
>> +             } else {
>> +                     uverbs_idr_remove_uobj(uobj);
>> +                     put_uobj(uobj);
>> +             }
>> +             break;
>> +     case UVERBS_ACCESS_WRITE:
>> +             up_write(&uobj->usecnt);
>> +             break;
>> +     case UVERBS_ACCESS_DESTROY:
>> +             if (commit)
>> +                     uverbs_uobject_remove(uobj);
>> +             else
>> +                     up_write(&uobj->usecnt);
>
> Again wondering if ACCESS_DESTROY makes any sense..
>

Why? If you write a destroy_qp handler, it makes sense that the QP_HANDLE
will have ACCESS_DESTROY behavior.

>> +             break;
>> +     }
>> +}
>> +
>> +void uverbs_finalize_object(struct ib_uobject *uobj,
>> +                         enum uverbs_idr_access access,
>> +                         bool commit)
>> +{
>> +     if (uobj->type->type == UVERBS_ATTR_TYPE_IDR)
>> +             uverbs_finalize_idr(uobj, access, commit);
>> +     else
>> +             WARN_ON(true);
>
> I think you should use ops like the rest of the kernel.
>
>   uobj->ops->finalize(uobj,access,commit);
>
> Get rid of these switch version.
>

Maybe we could a type->finalize pointer and populate that
automatically in type creation.
I first want to see how the function pointers model ends up.

>> +
>>  struct ib_ucontext {
>>       struct ib_device       *device;
>>       struct list_head        pd_list;
>> @@ -1346,6 +1348,10 @@ struct ib_ucontext {
>>       struct list_head        rwq_ind_tbl_list;
>>       int                     closing;
>>
>> +     /* lock for uobjects list */
>> +     struct ib_ucontext_lock *uobjects_lock;
>
> This is so weird. Why do we have a pointer to a struct mutex? This
> serves absolutely no function at this point in the series, just inline
> the mutex.
>

It's used in the next patch as a kref-ed lock. The purpose here is
that a FD object could outlive its context.
However, since you suggest to allow keeping a dummy ucontext alive,
I'll just add a kref and inline the lock.

>> +     struct list_head        uobjects;
>> +
>>       struct pid             *tgid;
>>  #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
>>       struct rb_root      umem_tree;
>> @@ -1373,8 +1379,11 @@ struct ib_uobject {
>>       int                     id;             /* index into kernel idr */
>
> Shouldn't this be u32?
>

idr_alloc actually returns an int. Actually, we need to change all ids
to be int and allocate
an idr with S32_MAX as end.

>>       struct kref             ref;
>>       struct rw_semaphore     mutex;          /* protects .live */
>> +     struct rw_semaphore     usecnt;         /* protects exclusive access */
>
> usecnt isn't really a cnt, better name?
>

I could rename it to currently_used. What do you think?

>> +     const struct uverbs_type_alloc_action *type;
>
> [..]
>
>> +struct uverbs_type_alloc_action;
>> +typedef void (*free_type)(const struct uverbs_type_alloc_action *uobject_type,
>> +                       struct ib_uobject *uobject);
>> +
>> +struct uverbs_type_alloc_action {
>> +     enum uverbs_attr_type           type;
>> +     int                             order;
>> +     size_t                          obj_size;
>> +     free_type                       free_fn;
>> +};
>
> Just make a sensible meta-class struct like other parts of the kernel:
>
> struct uverbs_obj_type {
>    unsigned int destroy_order;
>    size_t allocation_size;
>
>    struct ib_uobject (*alloc)(..);
>    void (*free)(..);
>    void (*lookup)(..);
> };
>

We could use function pointers instead of enum. I'll start refactor
the code to use this approach.
If it turns out to make more sense, I'll use this in V2:

struct uverbs_obj_type_ops {
        /*
         * Get an ib_uobject that corresponds to the given id from ucontext,
         * These functions could create or destroy objects if required.
         * The action will be finalized only when commit or abort fops are
         * called.
         */
        struct ib_uobject *(*alloc_begin)(const struct uverbs_obj_type *type,
                                          struct ib_ucontext *ucontext);
        struct ib_uobject *(*lookup_get)(const struct uverbs_obj_type *type,
                                         struct ib_ucontext *ucontext, int id,
                                         bool write);
        void (*alloc_commit)(struct ib_uobject *uobj);
        void (*alloc_abort)(struct ib_uobject *uobj);
        void (*lookup_put)(struct ib_uobject *uobj, bool write);
        void (*destroy_commit)(struct ib_uobject *uobj);
        void (*hot_unplug)(struct ib_uobject *uobj);
};

struct uverbs_obj_type {
        const struct uverbs_obj_type_ops * const ops;
        unsigned int destroy_order;
};

struct uverbs_obj_idr_type {
        struct uverbs_obj_type  type;
        size_t                  obj_size;
        void (*hot_unplug)(struct ib_uobject *uobj);
};

struct uverbs_obj_fd_type {
        struct uverbs_obj_type  type;
        size_t                  obj_size;
        void (*hot_unplug)(struct ib_uobject *uobj);
        const struct file_operations    *fops;
        const char                      *name;
        int                             flags;
};

Probably ops will be the same for all IDR/FD types (use the same
pointer) and the custom behavior
should be embedded in uverbs_obj_idr_type/uverbs_obj_fd_type.

> Jason

Thanks for reviewing.

Matan

> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 3/7] IB/core: Add support for fd objects
       [not found]         ` <20170111235801.GC31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
@ 2017-01-17 17:24           ` Matan Barak
       [not found]             ` <CAAKD3BBQLxnh-keng+LjZEyWBYKbXN_Sszk1BcGnyVeZU_45nw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-17 17:24 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Thu, Jan 12, 2017 at 1:58 AM, Jason Gunthorpe
<jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> wrote:
> On Wed, Jan 11, 2017 at 12:53:49PM +0200, Matan Barak wrote:
>
>> This commit adds the necessary mechanism to support FD based objects
>> like their IDR counterparts. FD objects release need to be synchronized
>> with context release. Since FDs could outlives their context, we use
>> a kref on this lock. We initialize the lock and the kref in downstream
>> patches. This is acceptable, as we don't use this infrastructure until
>> a later point in this series.
>
> This seems unnecessarily complicated. Just hold the kref on the
> ucontext in the fd. There isn't a problem with a dummy version of that
> struct hanging around..
>

Ok, I'll split the current event file structure to a completion event
file which begins with  and ib_uobject
and an asynchronous event_file.

>> +static struct ib_uobject *uverbs_get_uobject_from_fd(const struct uverbs_type_alloc_action *type_alloc,
>> +                                                  struct ib_ucontext *ucontext,
>> +                                                  enum uverbs_idr_access access,
>> +                                                  unsigned int fd)
>> +{
>> +     if (access == UVERBS_ACCESS_NEW) {
>> +             int _fd;
>
> Something has gone terribly wrong if you need _ to disambiguate with a
> function argument...

I'll rename it to new_fd.

>> +     } else if (access == UVERBS_ACCESS_READ) {
>> +             struct file *f = fget(fd);
>> +             struct ib_uobject *uobject;
>> +
>> +             if (!f)
>> +                     return ERR_PTR(-EBADF);
>> +
>> +             uobject = uverbs_priv_fd_to_uobject(f->private_data);
>> +             if (f->f_op != type_alloc->fd.fops ||
>> +                 !uobject->context) {
>
> I think the if should be split, if fops isn't correct then do not even
> call uverbs_priv_fd_to_uobject.
>

If we start file objects with ib_uobject, we no longer need this
conversion function.

>> +void uverbs_cleanup_fd(void *private_data)
>> +{
>> +     struct ib_uobject *uobject = uverbs_priv_fd_to_uobject(private_data);
>> +
>> +     kfree(uobject);
>> +}
>
> Woah, this is not OK at this point in the series. There is really too
> much stuff bundled into patch 7 to make proper sense of this.
>

This is a standard structure of a series - you first build up the
infrastructure and then use it
to change everything. I'm a bit worried that embedding the actual
changes with the infrastructural
changes will require massive amounts of testing to verify it's bisect-able.

> I don't like this design. Do not implicitly prepend ib_uobject to
> structures. Require the users to include the struct as is common in
> linux.
>

I'll change that. It means we'll have different structures for the
completion event and the
asynchronous event (there will be a shared part of course).

> Do not drop the kref out of ib_uobject, that should be the master
> kref, drop the kref out of ib_uverbs_event_file instead.
>

I didn't really follow, could you please clarify?

>> +static inline void *uverbs_fd_uobj_to_priv(struct ib_uobject *uobj)
>> +{
>> +     return uobj + 1;
>> +}
>
> Which means stuff like this can go away..
>

Right

>> -     int                     id;             /* index into kernel idr */
>> +     int                     id;             /* index into kernel idr/fd */
>
> Why do we need to store the fd number at all? We can *never* use it in
> the kernel except as the argument to fdinstall. For that reason we
> should never store it.
>

It's only used for fdinstall.

> Can you move the fdallocate into finalize? At the very least 0 the
> value after fdinstall so people don't get the wrong idea down the
> road.
>

It can't be moved to finalize, as fdallocate could fail and we assume nothing
in the finalize stage could fail. However, I'll zero this value.

>>       int                             order;
>>       size_t                          obj_size;
>>       free_type                       free_fn;
>> +     struct {
>> +             const struct file_operations    *fops;
>> +             const char                      *name;
>
> Maybe name should be common
>

This could be a nice enhancement when we add an ability to print the
parsing tree.
I prefer to postpone this till we actually have code that uses this name.

> This idea also seems reasonable to me in general, but again, I'd
> rather see it more completely implemented in this patch instead of
> deferring so much stuff in to the giant #7 patch.
>

I agree it could make the review easier, but the effort to make sure the code
is really bisectable will be pretty big.

> Jason

Matan

> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 5/7] IB/core: Add macros for declaring types and type groups
       [not found]         ` <20170112001029.GE31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
@ 2017-01-17 17:25           ` Matan Barak
       [not found]             ` <CAAKD3BCvEP4MdvSy6dD0DDjfyd+PO8Y=7O+qFwPO5rjGDW_nfA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-17 17:25 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Thu, Jan 12, 2017 at 2:10 AM, Jason Gunthorpe
<jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> wrote:
> On Wed, Jan 11, 2017 at 12:53:51PM +0200, Matan Barak wrote:
>> In order to initialize and destroy types in a generic way, we need to
>> provide information about the allocation size, release function and
>> order. This is done through a macro based DSL (domain specific
>> language). This patch adds macros to initialize a type and a type
>> group.
>>
>> When we transform the write based commands to use this new locking and
>> allocation schema, we use these types declarations.
>>
>> Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
>> Reviewed-by: Yishai Hadas <yishaih-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
>>  include/rdma/uverbs_ioctl.h | 50 +++++++++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 48 insertions(+), 2 deletions(-)
>
> None of this makes any sense to me at this point in the series.
>
> Just use a sane meta-class type and the 'usual' linux static const
> initializer scheme.
>

I could of course drop this patch and use static initializes. However,
this mean we'll re-write
the next patch using macro language in the next patch (as we introduce
actions there).
I also think the declarations themselves look pretty tidy this way.

> Jason

Matan

> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 6/7] IB/core: Declare all common IB types
       [not found]         ` <20170112001955.GF31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
  2017-01-12  6:48           ` Matan Barak
@ 2017-01-17 17:37           ` Matan Barak
       [not found]             ` <CAAKD3BBKnJRNF+iqRSkjmGVcff=Hd68wVvXW7y+=pnnc4=yDfA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 27+ messages in thread
From: Matan Barak @ 2017-01-17 17:37 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Thu, Jan 12, 2017 at 2:19 AM, Jason Gunthorpe
<jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> wrote:
> On Wed, Jan 11, 2017 at 12:53:52PM +0200, Matan Barak wrote:
>
>> diff --git a/drivers/infiniband/core/uverbs_ioctl_cmd.c b/drivers/infiniband/core/uverbs_ioctl_cmd.c
>> new file mode 100644
>
> This is not really an appropriate file name for this point in the
> series...
>

Yeah, maybe we could call that uverbs_std_types.c

>> +DECLARE_UVERBS_TYPE(uverbs_type_comp_channel,
>> +                 &UVERBS_TYPE_ALLOC_FD(0, sizeof(struct ib_uobject) + sizeof(struct ib_uverbs_event_file),
>> +                                       uverbs_free_event_file,
>> +                                       &uverbs_event_fops,
>> +                                       "[infinibandevent]",
>> O_RDONLY));
>
> Really hate these macros.
>
> const struct ib_uobject_type uverbs_type_comp_channel = {
>        .size = sizeof(struct ib_uverbs_event_file,
>        .destroy = uverbs_destroy_event_file, // destroy = release device resources!!
>        .fd = {
>           .fops = &uverbs_event_fops,
>           .name = "[infinibandevent]"
>        },
> };
>
> If you can't do it without macros something else is wrong.
>

We could initialize directly of course, but the code will be more
complex than what you proposed (there are some structure
nestings and pointers there).
Anyway, what's wrong with this macro? It's pretty straight forward,
it's a common schema in this code and it even checks
that the object_size makes sense.

>> +DECLARE_UVERBS_TYPES(uverbs_common_types,
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_PD, uverbs_type_pd),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_MR, uverbs_type_mr),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_COMP_CHANNEL, uverbs_type_comp_channel),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_CQ, uverbs_type_cq),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_QP, uverbs_type_qp),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_AH, uverbs_type_ah),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_MW, uverbs_type_mw),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_SRQ, uverbs_type_srq),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_FLOW, uverbs_type_flow),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_WQ, uverbs_type_wq),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_RWQ_IND_TBL,
>> +                                  uverbs_type_rwq_ind_table),
>> +                  ADD_UVERBS_TYPE(UVERBS_TYPE_XRCD, uverbs_type_xrcd),
>> +);
>> +EXPORT_SYMBOL(uverbs_common_types);
>
> No purpose at this point in the series.
>

It was used for finding the max order, but it's no longer needed.

> I didn't look carefully at patch 7 due to to convoluted it is, split
> it please..
>

It can be split, but checking that it's actually bi-sectable would
require a lot of efforts.

> Everything else looks broadly reasonable to me and is a good overall
> improvement I think.
>

Thanks for the review.
I'll fix and post v2.

> Jason

Matan

> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 1/7] IB/core: Refactor IDR to be per-device
       [not found]             ` <CAAKD3BDMDyahSu1uFPE_bA=QXAy9Q+qdMPoVw-hJTrFN3um9rg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2017-01-17 18:09               ` Jason Gunthorpe
  0 siblings, 0 replies; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-17 18:09 UTC (permalink / raw)
  To: Matan Barak
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran


On Tue, Jan 17, 2017 at 07:08:02PM +0200, Matan Barak wrote:

> > I'm still unclear why we want the idr to be global and not per
> > /dev/uverbs0 open fd.
> 
> Assuming we keep the current separate fds model (i.e, per-device fd
> and another rdma-cm fd), what is the actual benefit here?  Memory
> wise - we'll probably consume a lot more (every idr layer is > 2K on
> a 64bit architecture), so sharing here might have some memory usage
> benefits.

Well, it makes things simpler and clearer.

- Locking is per ucontext, not per-device global, so it is potentially
  more parallel.
- Obvious that the lifetime of these objects is tied to the lifetime
  of the ucontext
- max idr value is per-context, not per system, so the tree will be
  intrinsiclly smaller. (eg consider a MPI that allocates 1 million
  objects is permanently degrading the global IDR)
- idr exhaustion is per-context not global, thus it plays nicer with
  a memory cgroup controller.
- It is very clear you have to have a ucontext fd to make any use
  of the object numbers - this is an essential property from a
  security perspective.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 2/7] IB/core: Add support for custom types
       [not found]             ` <CAAKD3BBkzoLuY3TF=bDK3U=rnLzK0uWmDL2tgsUwmBoGTXAqrw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2017-01-17 19:01               ` Jason Gunthorpe
  0 siblings, 0 replies; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-17 19:01 UTC (permalink / raw)
  To: Matan Barak
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Tue, Jan 17, 2017 at 07:23:47PM +0200, Matan Barak wrote:
> On Thu, Jan 12, 2017 at 1:28 AM, Jason Gunthorpe
> <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> wrote:
> > On Wed, Jan 11, 2017 at 12:53:48PM +0200, Matan Barak wrote:
> >
> >> +static struct ib_uobject *get_uobj_rcu(int id, struct ib_ucontext *context)
> >> +{
> >> +     struct ib_uobject *uobj;
> >> +
> >> +     RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
> >> +                      "uverbs: get_uobj_rcu wasn't called in a rcu_read_lock()!");
> >> +     /* object won't be released as we're protected in rcu */
> >> +     uobj = idr_find(&context->device->idr, id);
> >
> > So.. I think you need another patch in your series to rework the idr
> > globally to use rcu. Waiting till patch 7 seems too late
> 
> I'm not sure I followed here.
> The idr mechanism uses RCU as of the current code for fetching ids.

Hmm, Not sure what I was thinking, but yes.. this is the same as
__idr_get_uobj, so why does it exist?

> The major purpose of this series is to be a parliamentary step to
> the ABI, which as you recall, uses a macro based language to declare
> types.

Yes, but that seem controversial, let us get this part done without
that.
 
> What do you mean by "per-fd locking domains"?

Put the IDR into the ucontext and a per-ucontext rcu + spinlock for it..

> > And probably another patch to replace live with NULL.
> 
> The whole implementation here is replaced, so if we have a patch
> that replaces live with NULL in the current implementation and then
> later on in the series we re-work the API, we actually delete lines
> we've added at the same series.

The kernel philsophy is to try an avoid these 'flag day' kinds of
approaches. You are adding new code that does not work with the old
code which makes it incredibly hard to review, and then just swithing
everything over.

At the same time many fundamental designs are being altered.

You might have a point if the two approaches could exist
concurrently, but that is not the case in these patches.

> Saying that, testing that it's really bi-sectable could be a
> nightmare, so I'm not really sure it's worth here.


> >> +     /*
> >> +      * When we destroy an object, we first just lock it for WRITE and
> >> +      * actually DESTROY it in the finalize stage. So, the problematic
> >> +      * scenario is when we just stared the finalize stage of the
> >> +      * destruction (nothing was executed yet). Now, the other thread
> >> +      * fetched the object for READ access, but it didn't lock it yet.
> >> +      * The DESTROY thread continues and starts destroying the object.
> >> +      * When the other thread continue - without the RCU, it would
> >> +      * access freed memory. However, the rcu_read_lock delays the free
> >> +      * until the rcu_read_lock of the READ operation quits. Since the
> >> +      * write lock of the object is still taken by the DESTROY flow, the
> >> +      * READ operation will get -EBUSY and it'll just bail out.
> >> +      */
> >> +     kfree_rcu(uobj, rcu);
> >
> > Zoiks. But yes, ok, it makes sense. Good comment.

Actually, why is this replacing release_uobj? Why is it now
called put_uobj? Why is something that doesn't use a kref called put?
Why is a kfree being called outside a kref release function?

Seems wrong...

> > Is there a reason we have get_uobj_rcu() at all ? Just inline it.
> 
> It's later used for uverbs_is_live.

Huh. That bit of code in ib_uverbs_qp_event_handler seems super
sketchy. Looks like the qp there comes from the open_list? Seems to me
that the open_list needs to be cleaned up before the object is removed
from the idr, eliminating the need for the uverbs_is_live at all.

> >> +                                                   struct ib_ucontext *ucontext,
> >> +                                                   enum uverbs_idr_access access,
> >> +                                                   uint32_t idr)
> >
> > u32 for the kernel please, check all patches
> 
> Right, actually idr should be an int :)

Our UAPI is u32 for sane 64/32 bit compat, the IDR has to be limited
to min(U32_MAX-1,INT_MAX). (may as well reserve U32_MAX for error)

> It's a preliminary step for the next series which actually introduces the ABI.
> If you recall, the metadata for each attribute contains how to access it.
> I'll take a look into changing the enums and switch-cases to function
> pointers and examine if it also fits the new model well enough.
> Saying that, we only have two types (idr and fds) and we don't expect
> to add much later

But this makes no sense here, handle the switch from the enum in the
code that works with those future macro structures.

> I could split them to two different functions here. There are some
> benefits of the current way.  You could of rdma_core as managing a
> big repository of objects of all types and you could get any object
> using the tuple (type,id). If we go to the function pointers model,
> you'll probably just go to type->lookup function.

The different types seem to have significant differences (eg with
locking) so I'm not sure that single model even makes sense.

> in the DSL to specify how to use the object. Therefore, I think enum
> makes sense.  If we transform this into function pointers, the new
> ABI (next series) will probably use a wrapper function to execute
> the correct function pointer.

Seems OK to me

> >> +static void uverbs_uobject_add(struct ib_uobject *uobject)
> >> +{
> >> +     mutex_lock(&uobject->context->uobjects_lock->lock);
> >> +     list_add(&uobject->list, &uobject->context->uobjects);
> >> +     mutex_unlock(&uobject->context->uobjects_lock->lock);
> >> +}
> >> +
> >> +static void uverbs_uobject_remove(struct ib_uobject *uobject)
> >> +{
> >> +     /*
> >> +      * Calling remove requires exclusive access, so it's not possible
> >> +      * another thread will use our object since the function is called
> >> +      * with exclusive access.
> >> +      */
> >> +     uverbs_idr_remove_uobj(uobject);
> >> +     mutex_lock(&uobject->context->uobjects_lock->lock);
> >> +     list_del(&uobject->list);
> >> +     mutex_unlock(&uobject->context->uobjects_lock->lock);
> >> +     put_uobj(uobject);
> >
> > What does this put pair with? Usually a put like this would pair with
> > a get inside the _add function. So this deserves a comment at least.
> > If it is pairing with a get the caller performed then it should not be
> > here.
> 
> They're a pair in a sense they're both used in the finalize stage of
> the IDR object creation. Both object creation and object destruction
> are split into two parts.  Object creation is mainly done in the
> "get" stage while object destruction is mostly done in the
> "finalize" stage.

I think this goes back to my earlier comment about put_uobj not making
much sense - for something named put there needs to be a paired get
and that get isn't clear.

> Why? If you write a destroy_qp handler, it makes sense that the QP_HANDLE
> will have ACCESS_DESTROY behavior.

Sure but it really isn't much of an ACCESS ..

> >>  #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
> >>       struct rb_root      umem_tree;
> >> @@ -1373,8 +1379,11 @@ struct ib_uobject {
> >>       int                     id;             /* index into kernel idr */
> >
> > Shouldn't this be u32?
> 
> idr_alloc actually returns an int. Actually, we need to change all ids
> to be int and allocate
> an idr with S32_MAX as end.

The uapi is u32, see above...

> >>       struct kref             ref;
> >>       struct rw_semaphore     mutex;          /* protects .live */
> >> +     struct rw_semaphore     usecnt;         /* protects exclusive access */
> >
> > usecnt isn't really a cnt, better name?
> 
> I could rename it to currently_used. What do you think?

Maybe call it destroy_lock? reading_lock?

> We could use function pointers instead of enum. I'll start refactor
> the code to use this approach.
> If it turns out to make more sense, I'll use this in V2:
> 
> struct uverbs_obj_type_ops {
>         /*
>          * Get an ib_uobject that corresponds to the given id from ucontext,
>          * These functions could create or destroy objects if required.
>          * The action will be finalized only when commit or abort fops are
>          * called.
>          */
>         struct ib_uobject *(*alloc_begin)(const struct uverbs_obj_type *type,
>                                           struct ib_ucontext *ucontext);
>         struct ib_uobject *(*lookup_get)(const struct uverbs_obj_type *type,
>                                          struct ib_ucontext *ucontext, int id,
>                                          bool write);
>         void (*alloc_commit)(struct ib_uobject *uobj);
>         void (*alloc_abort)(struct ib_uobject *uobj);
>         void (*lookup_put)(struct ib_uobject *uobj, bool write);
>         void (*destroy_commit)(struct ib_uobject *uobj);
>         void (*hot_unplug)(struct ib_uobject *uobj);
> };
> 
> struct uverbs_obj_type {
>         const struct uverbs_obj_type_ops * const ops;
>         unsigned int destroy_order;
> };
> 
> struct uverbs_obj_idr_type {
>         struct uverbs_obj_type  type;
>         size_t                  obj_size;
>         void (*hot_unplug)(struct ib_uobject *uobj);
> };
>
> struct uverbs_obj_fd_type {
>         struct uverbs_obj_type  type;
>         size_t                  obj_size;
>         void (*hot_unplug)(struct ib_uobject *uobj);
>         const struct file_operations    *fops;
>         const char                      *name;
>         int                             flags;
> };

I'd probably just use a union or unused struct members, so much
simpler than all these structs. Like you say we probably only have two
kinds, no reason to be fancy.

> Probably ops will be the same for all IDR/FD types (use the same
> pointer)

Then why have it?

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 3/7] IB/core: Add support for fd objects
       [not found]             ` <CAAKD3BBQLxnh-keng+LjZEyWBYKbXN_Sszk1BcGnyVeZU_45nw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2017-01-17 19:11               ` Jason Gunthorpe
  0 siblings, 0 replies; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-17 19:11 UTC (permalink / raw)
  To: Matan Barak
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Tue, Jan 17, 2017 at 07:24:59PM +0200, Matan Barak wrote:
> >> +void uverbs_cleanup_fd(void *private_data)
> >> +{
> >> +     struct ib_uobject *uobject = uverbs_priv_fd_to_uobject(private_data);
> >> +
> >> +     kfree(uobject);
> >> +}
> >
> > Woah, this is not OK at this point in the series. There is really too
> > much stuff bundled into patch 7 to make proper sense of this.
> >
> 
> This is a standard structure of a series - you first build up the
> infrastructure and then use it to change everything.

Well, again, no, this is not normal. At this point in the series the
lifetime model for uboject is totally screwed up between the new/old
code. That is not OK

Do not get confused with how you write *new code* vs how you
*transform* old code. This is the latter and I expect each patch in
the series to globally follow or change the overal invarients. Do not
introduce two incompatible schemes.

> worried that embedding the actual changes with the infrastructural
> changes will require massive amounts of testing to verify it's
> bisect-able.

If each patch makes internal self consisent sense and compiles I'm
happy enough... Not asking that every patch be exhaustively tested.

As it stands this series is pretty useless for bisection because
everything hinges on the final patch, so having at least the ideas
properly broken up is a win from that standpoint.

> > Do not drop the kref out of ib_uobject, that should be the master
> > kref, drop the kref out of ib_uverbs_event_file instead.
> 
> I didn't really follow, could you please clarify?

In patch 7 you delete the kref from ib_uobject, but keep a kref in
ib_uverbs_event_file.

Instead you should keep the kref in ib_uobject, make it work properly,
and discard the kref in ib_uverbs_event_file when you add in
ib_uobject as a member.

The uobject kref semantics around the IDR should be pretty simple: The
IDR holds a kref on all the members of the IDR. get on add, put on
remove.

The per-uobject rwlock prevents removing the object from the IDR so
anything operating within the read side of the rwlock does not need to
kref get. Only when the uobject is transfered outside that rwlock is a
get required (eg for fops private_data)

Not mangling the kref model of uobject should make the two APIs more
compatible.

> It can't be moved to finalize, as fdallocate could fail and we assume nothing
> in the finalize stage could fail. However, I'll zero this value.

Okay, sure, -1 or something.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 5/7] IB/core: Add macros for declaring types and type groups
       [not found]             ` <CAAKD3BCvEP4MdvSy6dD0DDjfyd+PO8Y=7O+qFwPO5rjGDW_nfA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2017-01-17 19:13               ` Jason Gunthorpe
  0 siblings, 0 replies; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-17 19:13 UTC (permalink / raw)
  To: Matan Barak
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Tue, Jan 17, 2017 at 07:25:22PM +0200, Matan Barak wrote:
> On Thu, Jan 12, 2017 at 2:10 AM, Jason Gunthorpe
> <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org> wrote:
> > On Wed, Jan 11, 2017 at 12:53:51PM +0200, Matan Barak wrote:
> >> In order to initialize and destroy types in a generic way, we need to
> >> provide information about the allocation size, release function and
> >> order. This is done through a macro based DSL (domain specific
> >> language). This patch adds macros to initialize a type and a type
> >> group.
> >>
> >> When we transform the write based commands to use this new locking and
> >> allocation schema, we use these types declarations.
> >>
> >> Signed-off-by: Matan Barak <matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
> >> Reviewed-by: Yishai Hadas <yishaih-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
> >>  include/rdma/uverbs_ioctl.h | 50 +++++++++++++++++++++++++++++++++++++++++++--
> >>  1 file changed, 48 insertions(+), 2 deletions(-)
> >
> > None of this makes any sense to me at this point in the series.
> >
> > Just use a sane meta-class type and the 'usual' linux static const
> > initializer scheme.
> 
> I could of course drop this patch and use static
> initializes. However, this mean we'll re-write the next patch using
> macro language in the next patch (as we introduce actions there).  I
> also think the declarations themselves look pretty tidy this way.

Why would it be rewritten? The per-object static initializer should be
basically good indefinately? The next series will introduce macros to
add per-type functions but that shouldn't disturb the initializer.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH for-next 6/7] IB/core: Declare all common IB types
       [not found]             ` <CAAKD3BBKnJRNF+iqRSkjmGVcff=Hd68wVvXW7y+=pnnc4=yDfA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2017-01-17 19:15               ` Jason Gunthorpe
  0 siblings, 0 replies; 27+ messages in thread
From: Jason Gunthorpe @ 2017-01-17 19:15 UTC (permalink / raw)
  To: Matan Barak
  Cc: Matan Barak, Doug Ledford, linux-rdma, Yishai Hadas, Sean Hefty,
	Ira Weiny, Christoph Lameter, Majd Dibbiny, Tal Alon,
	Leon Romanovsky, Liran Liss, Haggai Eran

On Tue, Jan 17, 2017 at 07:37:30PM +0200, Matan Barak wrote:
> >> +DECLARE_UVERBS_TYPE(uverbs_type_comp_channel,
> >> +                 &UVERBS_TYPE_ALLOC_FD(0, sizeof(struct ib_uobject) + sizeof(struct ib_uverbs_event_file),
> >> +                                       uverbs_free_event_file,
> >> +                                       &uverbs_event_fops,
> >> +                                       "[infinibandevent]",
> >> O_RDONLY));
> >
> > Really hate these macros.
> >
> > const struct ib_uobject_type uverbs_type_comp_channel = {
> >        .size = sizeof(struct ib_uverbs_event_file,
> >        .destroy = uverbs_destroy_event_file, // destroy = release device resources!!
> >        .fd = {
> >           .fops = &uverbs_event_fops,
> >           .name = "[infinibandevent]"
> >        },
> > };
> >
> > If you can't do it without macros something else is wrong.
> >
> 
> We could initialize directly of course, but the code will be more
> complex than what you proposed (there are some structure
> nestings and pointers there).

Why would it be more complex? That does what the macro does. Don't
make it more complex ;)

> Anyway, what's wrong with this macro? It's pretty straight forward,
> it's a common schema in this code and it even checks
> that the object_size makes sense.

There are too many parameters, it is too hard to casually follow, and
it doesn't fit the typical kernel model for this kind of thing.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2017-01-17 19:15 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-11 10:53 [PATCH for-next 0/7] Change IDR usage and locking in uverbs Matan Barak
     [not found] ` <1484132033-3346-1-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2017-01-11 10:53   ` [PATCH for-next 1/7] IB/core: Refactor IDR to be per-device Matan Barak
     [not found]     ` <1484132033-3346-2-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2017-01-11 22:39       ` Jason Gunthorpe
     [not found]         ` <20170111223917.GA31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
2017-01-17 17:08           ` Matan Barak
     [not found]             ` <CAAKD3BDMDyahSu1uFPE_bA=QXAy9Q+qdMPoVw-hJTrFN3um9rg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-01-17 18:09               ` Jason Gunthorpe
2017-01-11 10:53   ` [PATCH for-next 2/7] IB/core: Add support for custom types Matan Barak
     [not found]     ` <1484132033-3346-3-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2017-01-11 23:28       ` Jason Gunthorpe
     [not found]         ` <20170111232811.GB31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
2017-01-17 17:23           ` Matan Barak
     [not found]             ` <CAAKD3BBkzoLuY3TF=bDK3U=rnLzK0uWmDL2tgsUwmBoGTXAqrw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-01-17 19:01               ` Jason Gunthorpe
2017-01-11 10:53   ` [PATCH for-next 3/7] IB/core: Add support for fd objects Matan Barak
     [not found]     ` <1484132033-3346-4-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2017-01-11 23:58       ` Jason Gunthorpe
     [not found]         ` <20170111235801.GC31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
2017-01-17 17:24           ` Matan Barak
     [not found]             ` <CAAKD3BBQLxnh-keng+LjZEyWBYKbXN_Sszk1BcGnyVeZU_45nw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-01-17 19:11               ` Jason Gunthorpe
2017-01-11 10:53   ` [PATCH for-next 4/7] IB/core: Add generic ucontext initialization and teardown Matan Barak
     [not found]     ` <1484132033-3346-5-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2017-01-12  0:09       ` Jason Gunthorpe
2017-01-11 10:53   ` [PATCH for-next 5/7] IB/core: Add macros for declaring types and type groups Matan Barak
     [not found]     ` <1484132033-3346-6-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2017-01-12  0:10       ` Jason Gunthorpe
     [not found]         ` <20170112001029.GE31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
2017-01-17 17:25           ` Matan Barak
     [not found]             ` <CAAKD3BCvEP4MdvSy6dD0DDjfyd+PO8Y=7O+qFwPO5rjGDW_nfA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-01-17 19:13               ` Jason Gunthorpe
2017-01-11 10:53   ` [PATCH for-next 6/7] IB/core: Declare all common IB types Matan Barak
     [not found]     ` <1484132033-3346-7-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2017-01-12  0:19       ` Jason Gunthorpe
     [not found]         ` <20170112001955.GF31682-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
2017-01-12  6:48           ` Matan Barak
2017-01-17 17:37           ` Matan Barak
     [not found]             ` <CAAKD3BBKnJRNF+iqRSkjmGVcff=Hd68wVvXW7y+=pnnc4=yDfA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-01-17 19:15               ` Jason Gunthorpe
2017-01-11 10:53   ` [PATCH for-next 7/7] IB/core: Use the new IDR and locking infrastructure in uverbs_cmd Matan Barak
     [not found]     ` <1484132033-3346-8-git-send-email-matanb-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2017-01-11 22:49       ` kbuild test robot
2017-01-11 23:43       ` kbuild test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.