diff options
author | Jason Gunthorpe <jgg@mellanox.com> | 2018-07-10 13:43:06 -0600 |
---|---|---|
committer | Jason Gunthorpe <jgg@mellanox.com> | 2018-07-25 14:21:46 -0600 |
commit | 22fa27fbc64d01cbbe1e4da751e64cc22d24a6e4 (patch) | |
tree | 98ba4f304011ac9a6e05d9bbdd12045b7a6b4598 /drivers/infiniband/core/rdma_core.c | |
parent | c36ee46dafaea1bb525c4e34d3e35dd9a6768a47 (diff) | |
download | linux-22fa27fbc64d01cbbe1e4da751e64cc22d24a6e4.tar.bz2 |
IB/uverbs: Fix locking around struct ib_uverbs_file ucontext
We have a parallel unlocked reader and writer with ib_uverbs_get_context()
vs everything else, and nothing guarantees this works properly.
Audit and fix all of the places that access ucontext to use one of the
following locking schemes:
- Call ib_uverbs_get_ucontext() under SRCU and check for failure
- Access the ucontext through an struct ib_uobject context member
while holding a READ or WRITE lock on the uobject.
This value cannot be NULL and has no race.
- Hold the ucontext_lock and check for ufile->ucontext !NULL
This also re-implements ib_uverbs_get_ucontext() in a way that is safe
against concurrent ib_uverbs_get_context() and disassociation.
As a side effect, every access to ucontext in the commands is via
ib_uverbs_get_context() with an error check, or via the uobject, so there
is no longer any need for the core code to check ucontext on every command
call. These checks are also removed.
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Diffstat (limited to 'drivers/infiniband/core/rdma_core.c')
-rw-r--r-- | drivers/infiniband/core/rdma_core.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 8a6ce66d4726..a63844ba8414 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -154,8 +154,14 @@ int __uobj_perform_destroy(const struct uverbs_obj_type *type, u32 id, static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile, const struct uverbs_obj_type *type) { - struct ib_uobject *uobj = kzalloc(type->obj_size, GFP_KERNEL); + struct ib_uobject *uobj; + struct ib_ucontext *ucontext; + + ucontext = ib_uverbs_get_ucontext(ufile); + if (IS_ERR(ucontext)) + return ERR_CAST(ucontext); + uobj = kzalloc(type->obj_size, GFP_KERNEL); if (!uobj) return ERR_PTR(-ENOMEM); /* @@ -163,7 +169,7 @@ static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile, * The object is added to the list in the commit stage. */ uobj->ufile = ufile; - uobj->context = ufile->ucontext; + uobj->context = ucontext; INIT_LIST_HEAD(&uobj->list); uobj->type = type; /* @@ -309,7 +315,7 @@ static struct ib_uobject *alloc_begin_idr_uobject(const struct uverbs_obj_type * if (ret) goto uobj_put; - ret = ib_rdmacg_try_charge(&uobj->cg_obj, ufile->ucontext->device, + ret = ib_rdmacg_try_charge(&uobj->cg_obj, uobj->context->device, RDMACG_RESOURCE_HCA_OBJECT); if (ret) goto idr_remove; @@ -761,7 +767,7 @@ static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile, * FIXME: Drivers are not permitted to fail dealloc_ucontext, remove * the error return. */ - ret = ucontext->device->dealloc_ucontext(ufile->ucontext); + ret = ucontext->device->dealloc_ucontext(ucontext); WARN_ON(ret); ufile->ucontext = NULL; |