diff mbox series

[v1,03/10] IB/uverbs: Use uverbs_api to manage the object type inside the uobject

Message ID 20180810021444.14014-4-jgg@ziepe.ca (mailing list archive)
State Accepted
Delegated to: Jason Gunthorpe
Headers show
Series Allow dissociation after destroy for the ioctl methods | expand

Commit Message

Jason Gunthorpe Aug. 10, 2018, 2:14 a.m. UTC
From: Jason Gunthorpe <jgg@mellanox.com>

Currently the struct uverbs_obj_type stored in the ib_uobject is part of
the .rodata segment of the module that defines the object. This is a
problem if drivers define new uapi objects as we will be left with a
dangling pointer after device disassociation.

Switch the uverbs_obj_type for struct uverbs_api_object, which is
allocated memory that is part of the uverbs_api and is guaranteed to
always exist. Further this moves the 'type_class' into this memory which
means access to the IDR/FD function pointers is also guaranteed. Drivers
cannot define new types.

This makes it safe to continue to use all uobjects, including driver
defined ones, after disassociation.

Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
---
 drivers/infiniband/core/rdma_core.c    | 100 ++++++++++++++-----------
 drivers/infiniband/core/rdma_core.h    |   2 +-
 drivers/infiniband/core/uverbs_ioctl.c |   6 +-
 include/rdma/ib_verbs.h                |   2 +-
 include/rdma/uverbs_std_types.h        |  30 ++++----
 include/rdma/uverbs_types.h            |   9 ++-
 6 files changed, 79 insertions(+), 70 deletions(-)

Comments

Shamir Rabinovitch Aug. 13, 2018, 12:18 p.m. UTC | #1
On Thu, Aug 09, 2018 at 08:14:37PM -0600, Jason Gunthorpe wrote:
> From: Jason Gunthorpe <jgg@mellanox.com>
> 
> Currently the struct uverbs_obj_type stored in the ib_uobject is part of
> the .rodata segment of the module that defines the object. This is a
> problem if drivers define new uapi objects as we will be left with a
> dangling pointer after device disassociation.

Just to clarify - 'after disassociation' == module unload - right? 

> 
> Switch the uverbs_obj_type for struct uverbs_api_object, which is
> allocated memory that is part of the uverbs_api and is guaranteed to
> always exist. Further this moves the 'type_class' into this memory which

If issue is ro data access after module unload then the 'type_class' is
now on kmalloc memory so it's ok to access it's data even after module
unload. But it's data include 'uverbs_obj_type_class' which has function
pointers that are no longer valid after module unload. Can this be an
issue? 

> means access to the IDR/FD function pointers is also guaranteed. Drivers
> cannot define new types.
> 
> This makes it safe to continue to use all uobjects, including driver
> defined ones, after disassociation.
> 
> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Shamir Rabinovitch Aug. 13, 2018, 1:22 p.m. UTC | #2
On Mon, Aug 13, 2018 at 03:18:08PM +0300, Shamir Rabinovitch wrote:
> On Thu, Aug 09, 2018 at 08:14:37PM -0600, Jason Gunthorpe wrote:
> > From: Jason Gunthorpe <jgg@mellanox.com>
> > 
> > Currently the struct uverbs_obj_type stored in the ib_uobject is part of
> > the .rodata segment of the module that defines the object. This is a
> > problem if drivers define new uapi objects as we will be left with a
> > dangling pointer after device disassociation.
> 
> Just to clarify - 'after disassociation' == module unload - right? 
> 
> > 
> > Switch the uverbs_obj_type for struct uverbs_api_object, which is
> > allocated memory that is part of the uverbs_api and is guaranteed to
> > always exist. Further this moves the 'type_class' into this memory which
> 
> If issue is ro data access after module unload then the 'type_class' is
> now on kmalloc memory so it's ok to access it's data even after module
> unload. But it's data include 'uverbs_obj_type_class' which has function
> pointers that are no longer valid after module unload. Can this be an
> issue? 
> 

Ah, I see this is taken care in 'uverbs_disassociate_api' in this line
"object_elm->type_attrs = NULL;" 

So just wonder if there is need to do the same for 'object_elm->type_class'
pointer.

> > means access to the IDR/FD function pointers is also guaranteed. Drivers
> > cannot define new types.
> > 
> > This makes it safe to continue to use all uobjects, including driver
> > defined ones, after disassociation.
> > 
> > Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Jason Gunthorpe Aug. 13, 2018, 3:10 p.m. UTC | #3
On Mon, Aug 13, 2018 at 03:18:08PM +0300, Shamir Rabinovitch wrote:
> On Thu, Aug 09, 2018 at 08:14:37PM -0600, Jason Gunthorpe wrote:
> > From: Jason Gunthorpe <jgg@mellanox.com>
> > 
> > Currently the struct uverbs_obj_type stored in the ib_uobject is part of
> > the .rodata segment of the module that defines the object. This is a
> > problem if drivers define new uapi objects as we will be left with a
> > dangling pointer after device disassociation.
> 
> Just to clarify - 'after disassociation' == module unload - right? 

Yes, in the cases we have today, module unload is required.

But as a general rule, after the ib_unregister_device the core code
should never touch any memory or call any functions provided by the
driver, this is just bad practice.

> > Switch the uverbs_obj_type for struct uverbs_api_object, which is
> > allocated memory that is part of the uverbs_api and is guaranteed to
> > always exist. Further this moves the 'type_class' into this memory which
> 
> If issue is ro data access after module unload then the 'type_class' is
> now on kmalloc memory so it's ok to access it's data even after module
> unload.

'type_class' points to either uverbs_idr_class or uverbs_fd_class -
both of these are located in the uverbs module so are safe to use.

Further, the code has this:

                                /*
                                 * Today drivers are only permitted to use
                                 * idr_class types. They cannot use FD types
                                 * because we currently have no way to revoke
                                 * the fops pointer after device
                                 * disassociation.
                                 */
                                if (WARN_ON(is_driver &&
                                            obj->type_attrs->type_class !=
                                                    &uverbs_idr_class))
                                        return -EINVAL;


Which prevents drivers from creating their own type_class in their own
module. This is not permitted today due to need to access the
type_class after disassoctiation.

Jason
Jason Gunthorpe Aug. 13, 2018, 3:11 p.m. UTC | #4
On Mon, Aug 13, 2018 at 04:22:47PM +0300, Shamir Rabinovitch wrote:

> > > Switch the uverbs_obj_type for struct uverbs_api_object, which is
> > > allocated memory that is part of the uverbs_api and is guaranteed to
> > > always exist. Further this moves the 'type_class' into this memory which
> > 
> > If issue is ro data access after module unload then the 'type_class' is
> > now on kmalloc memory so it's ok to access it's data even after module
> > unload. But it's data include 'uverbs_obj_type_class' which has function
> > pointers that are no longer valid after module unload. Can this be an
> > issue? 
> 
> Ah, I see this is taken care in 'uverbs_disassociate_api' in this line
> "object_elm->type_attrs = NULL;" 

Yes, type_attrs is defined in the rodata of the module, it is created
as the result of something like UVERBS_TYPE_ALLOC_IDR_SZ()

Jason
diff mbox series

Patch

diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index 4235b9ddc2adaf..2814228ead39f0 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -97,7 +97,7 @@  static void uverbs_uobject_free(struct kref *ref)
 	struct ib_uobject *uobj =
 		container_of(ref, struct ib_uobject, ref);
 
-	if (uobj->type->type_class->needs_kfree_rcu)
+	if (uobj->uapi_object->type_class->needs_kfree_rcu)
 		kfree_rcu(uobj, rcu);
 	else
 		kfree(uobj);
@@ -180,7 +180,7 @@  static int uverbs_destroy_uobject(struct ib_uobject *uobj,
 	assert_uverbs_usecnt(uobj, UVERBS_LOOKUP_WRITE);
 
 	if (uobj->object) {
-		ret = uobj->type->type_class->destroy_hw(uobj, reason);
+		ret = uobj->uapi_object->type_class->destroy_hw(uobj, reason);
 		if (ret) {
 			if (ib_is_destroy_retryable(ret, reason, uobj))
 				return ret;
@@ -197,7 +197,7 @@  static int uverbs_destroy_uobject(struct ib_uobject *uobj,
 	if (reason == RDMA_REMOVE_ABORT) {
 		WARN_ON(!list_empty(&uobj->list));
 		WARN_ON(!uobj->context);
-		uobj->type->type_class->alloc_abort(uobj);
+		uobj->uapi_object->type_class->alloc_abort(uobj);
 	}
 
 	uobj->context = NULL;
@@ -210,7 +210,7 @@  static int uverbs_destroy_uobject(struct ib_uobject *uobj,
 	if (reason != RDMA_REMOVE_DESTROY)
 		atomic_set(&uobj->usecnt, 0);
 	else
-		uobj->type->type_class->remove_handle(uobj);
+		uobj->uapi_object->type_class->remove_handle(uobj);
 
 	if (!list_empty(&uobj->list)) {
 		spin_lock_irqsave(&ufile->uobjects_lock, flags);
@@ -268,13 +268,13 @@  int uobj_destroy(struct ib_uobject *uobj)
  * with a NULL object pointer. The caller must pair this with
  * uverbs_put_destroy.
  */
-struct ib_uobject *__uobj_get_destroy(const struct uverbs_obj_type *type,
+struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj,
 				      u32 id, struct ib_uverbs_file *ufile)
 {
 	struct ib_uobject *uobj;
 	int ret;
 
-	uobj = rdma_lookup_get_uobject(type, ufile, id, UVERBS_LOOKUP_DESTROY);
+	uobj = rdma_lookup_get_uobject(obj, ufile, id, UVERBS_LOOKUP_DESTROY);
 	if (IS_ERR(uobj))
 		return uobj;
 
@@ -292,27 +292,22 @@  struct ib_uobject *__uobj_get_destroy(const struct uverbs_obj_type *type,
  * on success (negative errno on failure). For use by callers that do not need
  * the uobj.
  */
-int __uobj_perform_destroy(const struct uverbs_obj_type *type, u32 id,
+int __uobj_perform_destroy(const struct uverbs_api_object *obj, u32 id,
 			   struct ib_uverbs_file *ufile, int success_res)
 {
 	struct ib_uobject *uobj;
 
-	uobj = __uobj_get_destroy(type, id, ufile);
+	uobj = __uobj_get_destroy(obj, id, ufile);
 	if (IS_ERR(uobj))
 		return PTR_ERR(uobj);
 
-	/*
-	 * FIXME: After destroy this is not safe. We no longer hold the rwsem
-	 * so disassociation could have completed and unloaded the module that
-	 * backs the uobj->type pointer.
-	 */
 	rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_WRITE);
 	return success_res;
 }
 
 /* alloc_uobj must be undone by uverbs_destroy_uobject() */
 static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile,
-				     const struct uverbs_obj_type *type)
+				     const struct uverbs_api_object *obj)
 {
 	struct ib_uobject *uobj;
 	struct ib_ucontext *ucontext;
@@ -321,7 +316,7 @@  static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile,
 	if (IS_ERR(ucontext))
 		return ERR_CAST(ucontext);
 
-	uobj = kzalloc(type->obj_size, GFP_KERNEL);
+	uobj = kzalloc(obj->type_attrs->obj_size, GFP_KERNEL);
 	if (!uobj)
 		return ERR_PTR(-ENOMEM);
 	/*
@@ -331,7 +326,7 @@  static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile,
 	uobj->ufile = ufile;
 	uobj->context = ucontext;
 	INIT_LIST_HEAD(&uobj->list);
-	uobj->type = type;
+	uobj->uapi_object = obj;
 	/*
 	 * Allocated objects start out as write locked to deny any other
 	 * syscalls from accessing them until they are committed. See
@@ -368,7 +363,7 @@  static int idr_add_uobj(struct ib_uobject *uobj)
 
 /* Returns the ib_uobject or an error. The caller should check for IS_ERR. */
 static struct ib_uobject *
-lookup_get_idr_uobject(const struct uverbs_obj_type *type,
+lookup_get_idr_uobject(const struct uverbs_api_object *obj,
 		       struct ib_uverbs_file *ufile, s64 id,
 		       enum rdma_lookup_mode mode)
 {
@@ -401,15 +396,14 @@  lookup_get_idr_uobject(const struct uverbs_obj_type *type,
 }
 
 static struct ib_uobject *
-lookup_get_fd_uobject(const struct uverbs_obj_type *type,
+lookup_get_fd_uobject(const struct uverbs_api_object *obj,
 		      struct ib_uverbs_file *ufile, s64 id,
 		      enum rdma_lookup_mode mode)
 {
+	const struct uverbs_obj_fd_type *fd_type;
 	struct file *f;
 	struct ib_uobject *uobject;
 	int fdno = id;
-	const struct uverbs_obj_fd_type *fd_type =
-		container_of(type, struct uverbs_obj_fd_type, type);
 
 	if (fdno != id)
 		return ERR_PTR(-EINVAL);
@@ -417,6 +411,11 @@  lookup_get_fd_uobject(const struct uverbs_obj_type *type,
 	if (mode != UVERBS_LOOKUP_READ)
 		return ERR_PTR(-EOPNOTSUPP);
 
+	if (!obj->type_attrs)
+		return ERR_PTR(-EIO);
+	fd_type =
+		container_of(obj->type_attrs, struct uverbs_obj_fd_type, type);
+
 	f = fget(fdno);
 	if (!f)
 		return ERR_PTR(-EBADF);
@@ -436,18 +435,21 @@  lookup_get_fd_uobject(const struct uverbs_obj_type *type,
 	return uobject;
 }
 
-struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_obj_type *type,
+struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_api_object *obj,
 					   struct ib_uverbs_file *ufile, s64 id,
 					   enum rdma_lookup_mode mode)
 {
 	struct ib_uobject *uobj;
 	int ret;
 
-	uobj = type->type_class->lookup_get(type, ufile, id, mode);
+	if (!obj)
+		return ERR_PTR(-EINVAL);
+
+	uobj = obj->type_class->lookup_get(obj, ufile, id, mode);
 	if (IS_ERR(uobj))
 		return uobj;
 
-	if (uobj->type != type) {
+	if (uobj->uapi_object != obj) {
 		ret = -EINVAL;
 		goto free;
 	}
@@ -469,18 +471,19 @@  struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_obj_type *type,
 
 	return uobj;
 free:
-	uobj->type->type_class->lookup_put(uobj, mode);
+	obj->type_class->lookup_put(uobj, mode);
 	uverbs_uobject_put(uobj);
 	return ERR_PTR(ret);
 }
 
-static struct ib_uobject *alloc_begin_idr_uobject(const struct uverbs_obj_type *type,
-						  struct ib_uverbs_file *ufile)
+static struct ib_uobject *
+alloc_begin_idr_uobject(const struct uverbs_api_object *obj,
+			struct ib_uverbs_file *ufile)
 {
 	int ret;
 	struct ib_uobject *uobj;
 
-	uobj = alloc_uobj(ufile, type);
+	uobj = alloc_uobj(ufile, obj);
 	if (IS_ERR(uobj))
 		return uobj;
 
@@ -504,8 +507,9 @@  static struct ib_uobject *alloc_begin_idr_uobject(const struct uverbs_obj_type *
 	return ERR_PTR(ret);
 }
 
-static struct ib_uobject *alloc_begin_fd_uobject(const struct uverbs_obj_type *type,
-						 struct ib_uverbs_file *ufile)
+static struct ib_uobject *
+alloc_begin_fd_uobject(const struct uverbs_api_object *obj,
+		       struct ib_uverbs_file *ufile)
 {
 	int new_fd;
 	struct ib_uobject *uobj;
@@ -514,7 +518,7 @@  static struct ib_uobject *alloc_begin_fd_uobject(const struct uverbs_obj_type *t
 	if (new_fd < 0)
 		return ERR_PTR(new_fd);
 
-	uobj = alloc_uobj(ufile, type);
+	uobj = alloc_uobj(ufile, obj);
 	if (IS_ERR(uobj)) {
 		put_unused_fd(new_fd);
 		return uobj;
@@ -526,11 +530,14 @@  static struct ib_uobject *alloc_begin_fd_uobject(const struct uverbs_obj_type *t
 	return uobj;
 }
 
-struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_obj_type *type,
+struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj,
 					    struct ib_uverbs_file *ufile)
 {
 	struct ib_uobject *ret;
 
+	if (!obj)
+		return ERR_PTR(-EINVAL);
+
 	/*
 	 * The hw_destroy_rwsem is held across the entire object creation and
 	 * released during rdma_alloc_commit_uobject or
@@ -539,7 +546,7 @@  struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_obj_type *type,
 	if (!down_read_trylock(&ufile->hw_destroy_rwsem))
 		return ERR_PTR(-EIO);
 
-	ret = type->type_class->alloc_begin(type, ufile);
+	ret = obj->type_class->alloc_begin(obj, ufile);
 	if (IS_ERR(ret)) {
 		up_read(&ufile->hw_destroy_rwsem);
 		return ret;
@@ -561,8 +568,8 @@  static int __must_check destroy_hw_idr_uobject(struct ib_uobject *uobj,
 					       enum rdma_remove_reason why)
 {
 	const struct uverbs_obj_idr_type *idr_type =
-		container_of(uobj->type, struct uverbs_obj_idr_type,
-			     type);
+		container_of(uobj->uapi_object->type_attrs,
+			     struct uverbs_obj_idr_type, type);
 	int ret = idr_type->destroy_object(uobj, why);
 
 	/*
@@ -599,8 +606,8 @@  static void alloc_abort_fd_uobject(struct ib_uobject *uobj)
 static int __must_check destroy_hw_fd_uobject(struct ib_uobject *uobj,
 					      enum rdma_remove_reason why)
 {
-	const struct uverbs_obj_fd_type *fd_type =
-		container_of(uobj->type, struct uverbs_obj_fd_type, type);
+	const struct uverbs_obj_fd_type *fd_type = container_of(
+		uobj->uapi_object->type_attrs, struct uverbs_obj_fd_type, type);
 	int ret = fd_type->context_closed(uobj, why);
 
 	if (ib_is_destroy_retryable(ret, why, uobj))
@@ -633,8 +640,8 @@  static int alloc_commit_idr_uobject(struct ib_uobject *uobj)
 
 static int alloc_commit_fd_uobject(struct ib_uobject *uobj)
 {
-	const struct uverbs_obj_fd_type *fd_type =
-		container_of(uobj->type, struct uverbs_obj_fd_type, type);
+	const struct uverbs_obj_fd_type *fd_type = container_of(
+		uobj->uapi_object->type_attrs, struct uverbs_obj_fd_type, type);
 	int fd = uobj->id;
 	struct file *filp;
 
@@ -679,7 +686,7 @@  int __must_check rdma_alloc_commit_uobject(struct ib_uobject *uobj)
 	int ret;
 
 	/* alloc_commit consumes the uobj kref */
-	ret = uobj->type->type_class->alloc_commit(uobj);
+	ret = uobj->uapi_object->type_class->alloc_commit(uobj);
 	if (ret) {
 		uverbs_destroy_uobject(uobj, RDMA_REMOVE_ABORT);
 		up_read(&ufile->hw_destroy_rwsem);
@@ -735,7 +742,7 @@  void rdma_lookup_put_uobject(struct ib_uobject *uobj,
 			     enum rdma_lookup_mode mode)
 {
 	assert_uverbs_usecnt(uobj, mode);
-	uobj->type->type_class->lookup_put(uobj, mode);
+	uobj->uapi_object->type_class->lookup_put(uobj, mode);
 	/*
 	 * In order to unlock an object, either decrease its usecnt for
 	 * read access or zero it in case of exclusive access. See
@@ -995,23 +1002,26 @@  const struct uverbs_obj_type_class uverbs_fd_class = {
 EXPORT_SYMBOL(uverbs_fd_class);
 
 struct ib_uobject *
-uverbs_get_uobject_from_file(const struct uverbs_obj_type *type_attrs,
+uverbs_get_uobject_from_file(u16 object_id,
 			     struct ib_uverbs_file *ufile,
 			     enum uverbs_obj_access access, s64 id)
 {
+	const struct uverbs_api_object *obj =
+		uapi_get_object(ufile->device->uapi, object_id);
+
 	switch (access) {
 	case UVERBS_ACCESS_READ:
-		return rdma_lookup_get_uobject(type_attrs, ufile, id,
+		return rdma_lookup_get_uobject(obj, ufile, id,
 					       UVERBS_LOOKUP_READ);
 	case UVERBS_ACCESS_DESTROY:
 		/* Actual destruction is done inside uverbs_handle_method */
-		return rdma_lookup_get_uobject(type_attrs, ufile, id,
+		return rdma_lookup_get_uobject(obj, ufile, id,
 					       UVERBS_LOOKUP_DESTROY);
 	case UVERBS_ACCESS_WRITE:
-		return rdma_lookup_get_uobject(type_attrs, ufile, id,
+		return rdma_lookup_get_uobject(obj, ufile, id,
 					       UVERBS_LOOKUP_WRITE);
 	case UVERBS_ACCESS_NEW:
-		return rdma_alloc_begin_uobject(type_attrs, ufile);
+		return rdma_alloc_begin_uobject(obj, ufile);
 	default:
 		WARN_ON(true);
 		return ERR_PTR(-EOPNOTSUPP);
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index 55a687285b1daa..d89569d87b1cff 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -89,7 +89,7 @@  void uverbs_close_fd(struct file *f);
  * uverbs_finalize_objects are called.
  */
 struct ib_uobject *
-uverbs_get_uobject_from_file(const struct uverbs_obj_type *type_attrs,
+uverbs_get_uobject_from_file(u16 object_id,
 			     struct ib_uverbs_file *ufile,
 			     enum uverbs_obj_access access, s64 id);
 
diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index f0655a84f9d9c9..8fd64f2b147a56 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -57,7 +57,6 @@  static int uverbs_process_attr(struct ib_uverbs_file *ufile,
 	const struct uverbs_attr_spec *spec;
 	const struct uverbs_attr_spec *val_spec;
 	struct uverbs_attr *e;
-	const struct uverbs_object_spec *object;
 	struct uverbs_obj_attr *o_attr;
 	struct uverbs_attr *elements = attr_bundle_h->attrs;
 
@@ -145,9 +144,6 @@  static int uverbs_process_attr(struct ib_uverbs_file *ufile,
 			return -EINVAL;
 
 		o_attr = &e->obj_attr;
-		object = uverbs_get_object(ufile, spec->u.obj.obj_type);
-		if (!object)
-			return -EINVAL;
 
 		/* specs are allowed to have only one destroy attribute */
 		WARN_ON(spec->u.obj.access == UVERBS_ACCESS_DESTROY &&
@@ -162,7 +158,7 @@  static int uverbs_process_attr(struct ib_uverbs_file *ufile,
 		 * IDR implementation today rejects negative IDs
 		 */
 		o_attr->uobject = uverbs_get_uobject_from_file(
-					object->type_attrs,
+					spec->u.obj.obj_type,
 					ufile,
 					spec->u.obj.access,
 					uattr->data_s64);
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 3b07201b9a804e..5d404c20b49f27 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1524,7 +1524,7 @@  struct ib_uobject {
 	atomic_t		usecnt;		/* protects exclusive access */
 	struct rcu_head		rcu;		/* kfree_rcu() overhead */
 
-	const struct uverbs_obj_type *type;
+	const struct uverbs_api_object *uapi_object;
 };
 
 struct ib_udata {
diff --git a/include/rdma/uverbs_std_types.h b/include/rdma/uverbs_std_types.h
index 64ee2545dd3db3..3b00231cc084d7 100644
--- a/include/rdma/uverbs_std_types.h
+++ b/include/rdma/uverbs_std_types.h
@@ -54,14 +54,15 @@  static inline const struct uverbs_object_tree_def *uverbs_default_get_objects(vo
  */
 #define _uobj_check_id(_id) ((_id) * typecheck(u32, _id))
 
-#define uobj_get_type(_object) UVERBS_OBJECT(_object).type_attrs
+#define uobj_get_type(_ufile, _object)                                         \
+	uapi_get_object((_ufile)->device->uapi, _object)
 
 #define uobj_get_read(_type, _id, _ufile)                                      \
-	rdma_lookup_get_uobject(uobj_get_type(_type), _ufile,                  \
+	rdma_lookup_get_uobject(uobj_get_type(_ufile, _type), _ufile,          \
 				_uobj_check_id(_id), UVERBS_LOOKUP_READ)
 
 #define ufd_get_read(_type, _fdnum, _ufile)                                    \
-	rdma_lookup_get_uobject(uobj_get_type(_type), _ufile,                  \
+	rdma_lookup_get_uobject(uobj_get_type(_ufile, _type), _ufile,          \
 				(_fdnum)*typecheck(s32, _fdnum),               \
 				UVERBS_LOOKUP_READ)
 
@@ -76,20 +77,21 @@  static inline void *_uobj_get_obj_read(struct ib_uobject *uobj)
 		uobj_get_read(_type, _id, _ufile)))
 
 #define uobj_get_write(_type, _id, _ufile)                                     \
-	rdma_lookup_get_uobject(uobj_get_type(_type), _ufile,                  \
+	rdma_lookup_get_uobject(uobj_get_type(_ufile, _type), _ufile,          \
 				_uobj_check_id(_id), UVERBS_LOOKUP_WRITE)
 
-int __uobj_perform_destroy(const struct uverbs_obj_type *type, u32 id,
+int __uobj_perform_destroy(const struct uverbs_api_object *obj, u32 id,
 			   struct ib_uverbs_file *ufile, int success_res);
 #define uobj_perform_destroy(_type, _id, _ufile, _success_res)                 \
-	__uobj_perform_destroy(uobj_get_type(_type), _uobj_check_id(_id),      \
-			       _ufile, _success_res)
+	__uobj_perform_destroy(uobj_get_type(_ufile, _type),                   \
+			       _uobj_check_id(_id), _ufile, _success_res)
 
-struct ib_uobject *__uobj_get_destroy(const struct uverbs_obj_type *type,
+struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj,
 				      u32 id, struct ib_uverbs_file *ufile);
 
 #define uobj_get_destroy(_type, _id, _ufile)                                   \
-	__uobj_get_destroy(uobj_get_type(_type), _uobj_check_id(_id), _ufile)
+	__uobj_get_destroy(uobj_get_type(_ufile, _type), _uobj_check_id(_id),  \
+			   _ufile)
 
 static inline void uobj_put_destroy(struct ib_uobject *uobj)
 {
@@ -124,11 +126,11 @@  static inline void uobj_alloc_abort(struct ib_uobject *uobj)
 	rdma_alloc_abort_uobject(uobj);
 }
 
-static inline struct ib_uobject *__uobj_alloc(const struct uverbs_obj_type *type,
-					      struct ib_uverbs_file *ufile,
-					      struct ib_device **ib_dev)
+static inline struct ib_uobject *
+__uobj_alloc(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile,
+	     struct ib_device **ib_dev)
 {
-	struct ib_uobject *uobj = rdma_alloc_begin_uobject(type, ufile);
+	struct ib_uobject *uobj = rdma_alloc_begin_uobject(obj, ufile);
 
 	if (!IS_ERR(uobj))
 		*ib_dev = uobj->context->device;
@@ -136,7 +138,7 @@  static inline struct ib_uobject *__uobj_alloc(const struct uverbs_obj_type *type
 }
 
 #define uobj_alloc(_type, _ufile, _ib_dev)                                     \
-	__uobj_alloc(uobj_get_type(_type), _ufile, _ib_dev)
+	__uobj_alloc(uobj_get_type(_ufile, _type), _ufile, _ib_dev)
 
 #endif
 
diff --git a/include/rdma/uverbs_types.h b/include/rdma/uverbs_types.h
index 1ab9a85eebd9f2..acb1bfa3cc99a5 100644
--- a/include/rdma/uverbs_types.h
+++ b/include/rdma/uverbs_types.h
@@ -37,6 +37,7 @@ 
 #include <rdma/ib_verbs.h>
 
 struct uverbs_obj_type;
+struct uverbs_api_object;
 
 enum rdma_lookup_mode {
 	UVERBS_LOOKUP_READ,
@@ -81,14 +82,14 @@  enum rdma_lookup_mode {
  * alloc_abort returns.
  */
 struct uverbs_obj_type_class {
-	struct ib_uobject *(*alloc_begin)(const struct uverbs_obj_type *type,
+	struct ib_uobject *(*alloc_begin)(const struct uverbs_api_object *obj,
 					  struct ib_uverbs_file *ufile);
 	/* This consumes the kref on uobj */
 	int (*alloc_commit)(struct ib_uobject *uobj);
 	/* This does not consume the kref on uobj */
 	void (*alloc_abort)(struct ib_uobject *uobj);
 
-	struct ib_uobject *(*lookup_get)(const struct uverbs_obj_type *type,
+	struct ib_uobject *(*lookup_get)(const struct uverbs_api_object *obj,
 					 struct ib_uverbs_file *ufile, s64 id,
 					 enum rdma_lookup_mode mode);
 	void (*lookup_put)(struct ib_uobject *uobj, enum rdma_lookup_mode mode);
@@ -128,12 +129,12 @@  struct uverbs_obj_idr_type {
 					   enum rdma_remove_reason why);
 };
 
-struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_obj_type *type,
+struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_api_object *obj,
 					   struct ib_uverbs_file *ufile, s64 id,
 					   enum rdma_lookup_mode mode);
 void rdma_lookup_put_uobject(struct ib_uobject *uobj,
 			     enum rdma_lookup_mode mode);
-struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_obj_type *type,
+struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj,
 					    struct ib_uverbs_file *ufile);
 void rdma_alloc_abort_uobject(struct ib_uobject *uobj);
 int __must_check rdma_alloc_commit_uobject(struct ib_uobject *uobj);