Commit 6b0d08f4 authored by Jason Gunthorpe's avatar Jason Gunthorpe

IB/uverbs: Use uverbs_api to manage the object type inside the uobject

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