2005-07-08 08:57:13 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2005 Topspin Communications. All rights reserved.
|
2007-03-05 08:15:11 +08:00
|
|
|
* Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved.
|
2005-09-28 06:07:25 +08:00
|
|
|
* Copyright (c) 2005 PathScale, Inc. All rights reserved.
|
2006-02-14 08:31:57 +08:00
|
|
|
* Copyright (c) 2006 Mellanox Technologies. All rights reserved.
|
2005-07-08 08:57:13 +08:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2005-09-27 04:53:25 +08:00
|
|
|
#include <linux/file.h>
|
2005-10-29 06:38:26 +08:00
|
|
|
#include <linux/fs.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2014-12-11 23:04:17 +08:00
|
|
|
#include <linux/sched.h>
|
2005-09-27 04:53:25 +08:00
|
|
|
|
2016-12-25 03:46:01 +08:00
|
|
|
#include <linux/uaccess.h>
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2017-04-04 18:31:44 +08:00
|
|
|
#include <rdma/uverbs_types.h>
|
|
|
|
#include <rdma/uverbs_std_types.h>
|
|
|
|
#include "rdma_core.h"
|
|
|
|
|
2005-07-08 08:57:13 +08:00
|
|
|
#include "uverbs.h"
|
2013-12-13 00:03:17 +08:00
|
|
|
#include "core_priv.h"
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:36 +08:00
|
|
|
/*
|
|
|
|
* Copy a response to userspace. If the provided 'resp' is larger than the
|
|
|
|
* user buffer it is silently truncated. If the user provided a larger buffer
|
|
|
|
* then the trailing portion is zero filled.
|
|
|
|
*
|
|
|
|
* These semantics are intended to support future extension of the output
|
|
|
|
* structures.
|
|
|
|
*/
|
|
|
|
static int uverbs_response(struct uverbs_attr_bundle *attrs, const void *resp,
|
|
|
|
size_t resp_len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2019-01-11 14:21:44 +08:00
|
|
|
if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
|
|
|
|
return uverbs_copy_to_struct_or_zero(
|
|
|
|
attrs, UVERBS_ATTR_CORE_OUT, resp, resp_len);
|
|
|
|
|
2018-11-26 02:58:36 +08:00
|
|
|
if (copy_to_user(attrs->ucore.outbuf, resp,
|
|
|
|
min(attrs->ucore.outlen, resp_len)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2018-12-11 17:41:05 +08:00
|
|
|
if (resp_len < attrs->ucore.outlen) {
|
|
|
|
/*
|
|
|
|
* Zero fill any extra memory that user
|
|
|
|
* space might have provided.
|
|
|
|
*/
|
|
|
|
ret = clear_user(attrs->ucore.outbuf + resp_len,
|
|
|
|
attrs->ucore.outlen - resp_len);
|
2018-11-26 02:58:36 +08:00
|
|
|
if (ret)
|
2018-12-11 17:41:05 +08:00
|
|
|
return -EFAULT;
|
2018-11-26 02:58:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
/*
|
|
|
|
* Copy a request from userspace. If the provided 'req' is larger than the
|
|
|
|
* user buffer then the user buffer is zero extended into the 'req'. If 'req'
|
|
|
|
* is smaller than the user buffer then the uncopied bytes in the user buffer
|
|
|
|
* must be zero.
|
|
|
|
*/
|
|
|
|
static int uverbs_request(struct uverbs_attr_bundle *attrs, void *req,
|
|
|
|
size_t req_len)
|
|
|
|
{
|
|
|
|
if (copy_from_user(req, attrs->ucore.inbuf,
|
|
|
|
min(attrs->ucore.inlen, req_len)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (attrs->ucore.inlen < req_len) {
|
|
|
|
memset(req + attrs->ucore.inlen, 0,
|
|
|
|
req_len - attrs->ucore.inlen);
|
|
|
|
} else if (attrs->ucore.inlen > req_len) {
|
|
|
|
if (!ib_is_buffer_cleared(attrs->ucore.inbuf + req_len,
|
|
|
|
attrs->ucore.inlen - req_len))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
/*
|
|
|
|
* Generate the value for the 'response_length' protocol used by write_ex.
|
|
|
|
* This is the number of bytes the kernel actually wrote. Userspace can use
|
|
|
|
* this to detect what structure members in the response the kernel
|
|
|
|
* understood.
|
|
|
|
*/
|
|
|
|
static u32 uverbs_response_length(struct uverbs_attr_bundle *attrs,
|
|
|
|
size_t resp_len)
|
|
|
|
{
|
|
|
|
return min_t(size_t, attrs->ucore.outlen, resp_len);
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:42 +08:00
|
|
|
/*
|
|
|
|
* The iterator version of the request interface is for handlers that need to
|
|
|
|
* step over a flex array at the end of a command header.
|
|
|
|
*/
|
|
|
|
struct uverbs_req_iter {
|
|
|
|
const void __user *cur;
|
|
|
|
const void __user *end;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int uverbs_request_start(struct uverbs_attr_bundle *attrs,
|
|
|
|
struct uverbs_req_iter *iter,
|
|
|
|
void *req,
|
|
|
|
size_t req_len)
|
|
|
|
{
|
|
|
|
if (attrs->ucore.inlen < req_len)
|
|
|
|
return -ENOSPC;
|
|
|
|
|
|
|
|
if (copy_from_user(req, attrs->ucore.inbuf, req_len))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
iter->cur = attrs->ucore.inbuf + req_len;
|
|
|
|
iter->end = attrs->ucore.inbuf + attrs->ucore.inlen;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int uverbs_request_next(struct uverbs_req_iter *iter, void *val,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
if (iter->cur + len > iter->end)
|
|
|
|
return -ENOSPC;
|
|
|
|
|
|
|
|
if (copy_from_user(val, iter->cur, len))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
iter->cur += len;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:43 +08:00
|
|
|
static const void __user *uverbs_request_next_ptr(struct uverbs_req_iter *iter,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
const void __user *res = iter->cur;
|
|
|
|
|
|
|
|
if (iter->cur + len > iter->end)
|
2019-03-28 07:50:46 +08:00
|
|
|
return (void __force __user *)ERR_PTR(-ENOSPC);
|
2018-11-26 02:58:43 +08:00
|
|
|
iter->cur += len;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:42 +08:00
|
|
|
static int uverbs_request_finish(struct uverbs_req_iter *iter)
|
|
|
|
{
|
|
|
|
if (!ib_is_buffer_cleared(iter->cur, iter->end - iter->cur))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-22 01:55:22 +08:00
|
|
|
/*
|
|
|
|
* When calling a destroy function during an error unwind we need to pass in
|
|
|
|
* the udata that is sanitized of all user arguments. Ie from the driver
|
|
|
|
* perspective it looks like no udata was passed.
|
|
|
|
*/
|
|
|
|
struct ib_udata *uverbs_get_cleared_udata(struct uverbs_attr_bundle *attrs)
|
|
|
|
{
|
|
|
|
attrs->driver_udata = (struct ib_udata){};
|
|
|
|
return &attrs->driver_udata;
|
|
|
|
}
|
|
|
|
|
2017-04-04 18:31:47 +08:00
|
|
|
static struct ib_uverbs_completion_event_file *
|
2019-04-01 00:10:03 +08:00
|
|
|
_ib_uverbs_lookup_comp_file(s32 fd, struct uverbs_attr_bundle *attrs)
|
2017-04-04 18:31:47 +08:00
|
|
|
{
|
2018-07-11 10:55:14 +08:00
|
|
|
struct ib_uobject *uobj = ufd_get_read(UVERBS_OBJECT_COMP_CHANNEL,
|
2018-11-26 02:51:13 +08:00
|
|
|
fd, attrs);
|
2017-04-04 18:31:47 +08:00
|
|
|
|
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return (void *)uobj;
|
|
|
|
|
|
|
|
uverbs_uobject_get(uobj);
|
|
|
|
uobj_put_read(uobj);
|
|
|
|
|
2018-07-04 16:32:11 +08:00
|
|
|
return container_of(uobj, struct ib_uverbs_completion_event_file,
|
|
|
|
uobj);
|
2017-04-04 18:31:47 +08:00
|
|
|
}
|
2018-07-11 10:55:14 +08:00
|
|
|
#define ib_uverbs_lookup_comp_file(_fd, _ufile) \
|
|
|
|
_ib_uverbs_lookup_comp_file((_fd)*typecheck(s32, _fd), _ufile)
|
2017-04-04 18:31:47 +08:00
|
|
|
|
2020-01-09 02:05:34 +08:00
|
|
|
int ib_alloc_ucontext(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
2020-01-09 02:05:34 +08:00
|
|
|
struct ib_uverbs_file *ufile = attrs->ufile;
|
|
|
|
struct ib_ucontext *ucontext;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-01-09 02:05:34 +08:00
|
|
|
ib_dev = srcu_dereference(ufile->device->ib_dev,
|
|
|
|
&ufile->device->disassociate_srcu);
|
|
|
|
if (!ib_dev)
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
ucontext = rdma_zalloc_drv_obj(ib_dev, ib_ucontext);
|
|
|
|
if (!ucontext)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
ucontext->device = ib_dev;
|
|
|
|
ucontext->ufile = ufile;
|
|
|
|
xa_init_flags(&ucontext->mmap_xa, XA_FLAGS_ALLOC);
|
2020-09-22 17:11:04 +08:00
|
|
|
|
|
|
|
rdma_restrack_new(&ucontext->res, RDMA_RESTRACK_CTX);
|
2020-09-22 17:11:06 +08:00
|
|
|
rdma_restrack_set_name(&ucontext->res, NULL);
|
2020-01-09 02:05:34 +08:00
|
|
|
attrs->context = ucontext;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ib_init_ucontext(struct uverbs_attr_bundle *attrs)
|
|
|
|
{
|
|
|
|
struct ib_ucontext *ucontext = attrs->context;
|
|
|
|
struct ib_uverbs_file *file = attrs->ufile;
|
|
|
|
int ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-01-09 02:05:33 +08:00
|
|
|
if (!down_read_trylock(&file->hw_destroy_rwsem))
|
|
|
|
return -EIO;
|
2018-07-11 10:55:19 +08:00
|
|
|
mutex_lock(&file->ucontext_lock);
|
2005-09-27 04:01:03 +08:00
|
|
|
if (file->ucontext) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2020-01-09 02:05:34 +08:00
|
|
|
ret = ib_rdmacg_try_charge(&ucontext->cg_obj, ucontext->device,
|
|
|
|
RDMACG_RESOURCE_HCA_HANDLE);
|
2017-01-10 08:02:14 +08:00
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
2020-01-09 02:05:34 +08:00
|
|
|
ret = ucontext->device->ops.alloc_ucontext(ucontext,
|
|
|
|
&attrs->driver_udata);
|
|
|
|
if (ret)
|
|
|
|
goto err_uncharge;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-09-22 17:11:06 +08:00
|
|
|
rdma_restrack_add(&ucontext->res);
|
2019-04-30 22:23:21 +08:00
|
|
|
|
2020-01-09 02:05:34 +08:00
|
|
|
/*
|
|
|
|
* Make sure that ib_uverbs_get_ucontext() sees the pointer update
|
|
|
|
* only after all writes to setup the ucontext have completed
|
|
|
|
*/
|
|
|
|
smp_store_release(&file->ucontext, ucontext);
|
|
|
|
|
|
|
|
mutex_unlock(&file->ucontext_lock);
|
|
|
|
up_read(&file->hw_destroy_rwsem);
|
|
|
|
return 0;
|
2017-04-04 18:31:44 +08:00
|
|
|
|
2020-01-09 02:05:34 +08:00
|
|
|
err_uncharge:
|
|
|
|
ib_rdmacg_uncharge(&ucontext->cg_obj, ucontext->device,
|
|
|
|
RDMACG_RESOURCE_HCA_HANDLE);
|
|
|
|
err:
|
|
|
|
mutex_unlock(&file->ucontext_lock);
|
|
|
|
up_read(&file->hw_destroy_rwsem);
|
|
|
|
return ret;
|
|
|
|
}
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-01-09 02:05:34 +08:00
|
|
|
static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs)
|
|
|
|
{
|
|
|
|
struct ib_uverbs_get_context_resp resp;
|
|
|
|
struct ib_uverbs_get_context cmd;
|
|
|
|
struct ib_device *ib_dev;
|
|
|
|
struct ib_uobject *uobj;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = ib_alloc_ucontext(attrs);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2019-10-30 17:44:11 +08:00
|
|
|
|
2020-01-09 01:22:05 +08:00
|
|
|
uobj = uobj_alloc(UVERBS_OBJECT_ASYNC_EVENT, attrs, &ib_dev);
|
|
|
|
if (IS_ERR(uobj)) {
|
|
|
|
ret = PTR_ERR(uobj);
|
2020-01-09 02:05:34 +08:00
|
|
|
goto err_ucontext;
|
2005-09-27 04:53:25 +08:00
|
|
|
}
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-01-09 02:05:34 +08:00
|
|
|
resp = (struct ib_uverbs_get_context_resp){
|
|
|
|
.num_comp_vectors = attrs->ufile->device->num_comp_vectors,
|
|
|
|
.async_fd = uobj->id,
|
|
|
|
};
|
2018-11-26 02:58:37 +08:00
|
|
|
ret = uverbs_response(attrs, &resp, sizeof(resp));
|
|
|
|
if (ret)
|
2020-01-09 01:22:05 +08:00
|
|
|
goto err_uobj;
|
2005-09-27 04:01:03 +08:00
|
|
|
|
2020-01-09 02:05:34 +08:00
|
|
|
ret = ib_init_ucontext(attrs);
|
2019-02-13 02:39:16 +08:00
|
|
|
if (ret)
|
2020-01-09 01:22:05 +08:00
|
|
|
goto err_uobj;
|
2005-09-27 04:53:25 +08:00
|
|
|
|
2020-01-09 01:22:05 +08:00
|
|
|
ib_uverbs_init_async_event_file(
|
|
|
|
container_of(uobj, struct ib_uverbs_async_event_file, uobj));
|
|
|
|
rdma_alloc_commit_uobject(uobj, attrs);
|
2018-11-26 02:51:14 +08:00
|
|
|
return 0;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-01-09 01:22:05 +08:00
|
|
|
err_uobj:
|
2020-05-19 15:27:05 +08:00
|
|
|
rdma_alloc_abort_uobject(uobj, attrs, false);
|
2020-01-09 02:05:34 +08:00
|
|
|
err_ucontext:
|
2020-09-22 17:11:04 +08:00
|
|
|
rdma_restrack_put(&attrs->context->res);
|
2020-01-09 02:05:34 +08:00
|
|
|
kfree(attrs->context);
|
|
|
|
attrs->context = NULL;
|
2005-09-27 04:01:03 +08:00
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
2018-07-26 11:40:17 +08:00
|
|
|
static void copy_query_dev_fields(struct ib_ucontext *ucontext,
|
2015-02-08 19:28:50 +08:00
|
|
|
struct ib_uverbs_query_device_resp *resp,
|
|
|
|
struct ib_device_attr *attr)
|
|
|
|
{
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev = ucontext->device;
|
|
|
|
|
2015-02-08 19:28:50 +08:00
|
|
|
resp->fw_ver = attr->fw_ver;
|
2015-08-13 23:32:04 +08:00
|
|
|
resp->node_guid = ib_dev->node_guid;
|
2015-02-08 19:28:50 +08:00
|
|
|
resp->sys_image_guid = attr->sys_image_guid;
|
|
|
|
resp->max_mr_size = attr->max_mr_size;
|
|
|
|
resp->page_size_cap = attr->page_size_cap;
|
|
|
|
resp->vendor_id = attr->vendor_id;
|
|
|
|
resp->vendor_part_id = attr->vendor_part_id;
|
|
|
|
resp->hw_ver = attr->hw_ver;
|
|
|
|
resp->max_qp = attr->max_qp;
|
|
|
|
resp->max_qp_wr = attr->max_qp_wr;
|
2022-04-04 23:26:42 +08:00
|
|
|
resp->device_cap_flags = lower_32_bits(attr->device_cap_flags);
|
2018-06-18 23:05:26 +08:00
|
|
|
resp->max_sge = min(attr->max_send_sge, attr->max_recv_sge);
|
2015-02-08 19:28:50 +08:00
|
|
|
resp->max_sge_rd = attr->max_sge_rd;
|
|
|
|
resp->max_cq = attr->max_cq;
|
|
|
|
resp->max_cqe = attr->max_cqe;
|
|
|
|
resp->max_mr = attr->max_mr;
|
|
|
|
resp->max_pd = attr->max_pd;
|
|
|
|
resp->max_qp_rd_atom = attr->max_qp_rd_atom;
|
|
|
|
resp->max_ee_rd_atom = attr->max_ee_rd_atom;
|
|
|
|
resp->max_res_rd_atom = attr->max_res_rd_atom;
|
|
|
|
resp->max_qp_init_rd_atom = attr->max_qp_init_rd_atom;
|
|
|
|
resp->max_ee_init_rd_atom = attr->max_ee_init_rd_atom;
|
|
|
|
resp->atomic_cap = attr->atomic_cap;
|
|
|
|
resp->max_ee = attr->max_ee;
|
|
|
|
resp->max_rdd = attr->max_rdd;
|
|
|
|
resp->max_mw = attr->max_mw;
|
|
|
|
resp->max_raw_ipv6_qp = attr->max_raw_ipv6_qp;
|
|
|
|
resp->max_raw_ethy_qp = attr->max_raw_ethy_qp;
|
|
|
|
resp->max_mcast_grp = attr->max_mcast_grp;
|
|
|
|
resp->max_mcast_qp_attach = attr->max_mcast_qp_attach;
|
|
|
|
resp->max_total_mcast_qp_attach = attr->max_total_mcast_qp_attach;
|
|
|
|
resp->max_ah = attr->max_ah;
|
|
|
|
resp->max_srq = attr->max_srq;
|
|
|
|
resp->max_srq_wr = attr->max_srq_wr;
|
|
|
|
resp->max_srq_sge = attr->max_srq_sge;
|
|
|
|
resp->max_pkeys = attr->max_pkeys;
|
|
|
|
resp->local_ca_ack_delay = attr->local_ca_ack_delay;
|
2021-03-01 15:04:20 +08:00
|
|
|
resp->phys_port_cnt = min_t(u32, ib_dev->phys_port_cnt, U8_MAX);
|
2015-02-08 19:28:50 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_query_device(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_query_device cmd;
|
|
|
|
struct ib_uverbs_query_device_resp resp;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_ucontext *ucontext;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2018-07-26 11:40:17 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
ucontext = ib_uverbs_get_ucontext(attrs);
|
2018-07-26 11:40:17 +08:00
|
|
|
if (IS_ERR(ucontext))
|
|
|
|
return PTR_ERR(ucontext);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
|
|
|
memset(&resp, 0, sizeof resp);
|
2018-07-26 11:40:17 +08:00
|
|
|
copy_query_dev_fields(ucontext, &resp, &ucontext->device->attrs);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_query_port(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_query_port cmd;
|
|
|
|
struct ib_uverbs_query_port_resp resp;
|
|
|
|
struct ib_port_attr attr;
|
|
|
|
int ret;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_ucontext *ucontext;
|
|
|
|
struct ib_device *ib_dev;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
ucontext = ib_uverbs_get_ucontext(attrs);
|
2018-07-26 11:40:17 +08:00
|
|
|
if (IS_ERR(ucontext))
|
|
|
|
return PTR_ERR(ucontext);
|
|
|
|
ib_dev = ucontext->device;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2015-08-13 23:32:04 +08:00
|
|
|
ret = ib_query_port(ib_dev, cmd.port_num, &attr);
|
2005-07-08 08:57:13 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
memset(&resp, 0, sizeof resp);
|
2018-12-09 17:58:06 +08:00
|
|
|
copy_port_attr_to_resp(&attr, &resp, ib_dev, cmd.port_num);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_alloc_pd(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
2020-07-19 13:22:23 +08:00
|
|
|
struct ib_uverbs_alloc_pd_resp resp = {};
|
2005-07-08 08:57:13 +08:00
|
|
|
struct ib_uverbs_alloc_pd cmd;
|
|
|
|
struct ib_uobject *uobj;
|
|
|
|
struct ib_pd *pd;
|
|
|
|
int ret;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_alloc(UVERBS_OBJECT_PD, attrs, &ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2019-02-03 20:55:51 +08:00
|
|
|
pd = rdma_zalloc_drv_obj(ib_dev, ib_pd);
|
|
|
|
if (!pd) {
|
|
|
|
ret = -ENOMEM;
|
2005-07-08 08:57:13 +08:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2015-08-13 23:32:04 +08:00
|
|
|
pd->device = ib_dev;
|
2005-07-08 08:57:13 +08:00
|
|
|
pd->uobject = uobj;
|
|
|
|
atomic_set(&pd->usecnt, 0);
|
2019-02-03 20:55:51 +08:00
|
|
|
|
2020-09-22 17:11:04 +08:00
|
|
|
rdma_restrack_new(&pd->res, RDMA_RESTRACK_PD);
|
2020-09-22 17:11:06 +08:00
|
|
|
rdma_restrack_set_name(&pd->res, NULL);
|
|
|
|
|
2019-04-01 00:10:07 +08:00
|
|
|
ret = ib_dev->ops.alloc_pd(pd, &attrs->driver_udata);
|
2019-02-03 20:55:51 +08:00
|
|
|
if (ret)
|
|
|
|
goto err_alloc;
|
2020-09-22 17:11:06 +08:00
|
|
|
rdma_restrack_add(&pd->res);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj->object = pd;
|
|
|
|
uobj_finalize_uobj_create(uobj, attrs);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
resp.pd_handle = uobj->id;
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-09-28 06:07:25 +08:00
|
|
|
|
2019-02-03 20:55:51 +08:00
|
|
|
err_alloc:
|
2020-09-22 17:11:04 +08:00
|
|
|
rdma_restrack_put(&pd->res);
|
2019-02-03 20:55:51 +08:00
|
|
|
kfree(pd);
|
2005-07-08 08:57:13 +08:00
|
|
|
err:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(uobj, attrs);
|
2005-07-08 08:57:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_dealloc_pd(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_dealloc_pd cmd;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return uobj_perform_destroy(UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
2011-05-24 23:33:46 +08:00
|
|
|
struct xrcd_table_entry {
|
|
|
|
struct rb_node node;
|
|
|
|
struct ib_xrcd *xrcd;
|
|
|
|
struct inode *inode;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int xrcd_table_insert(struct ib_uverbs_device *dev,
|
|
|
|
struct inode *inode,
|
|
|
|
struct ib_xrcd *xrcd)
|
|
|
|
{
|
|
|
|
struct xrcd_table_entry *entry, *scan;
|
|
|
|
struct rb_node **p = &dev->xrcd_tree.rb_node;
|
|
|
|
struct rb_node *parent = NULL;
|
|
|
|
|
|
|
|
entry = kmalloc(sizeof *entry, GFP_KERNEL);
|
|
|
|
if (!entry)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
entry->xrcd = xrcd;
|
|
|
|
entry->inode = inode;
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
parent = *p;
|
|
|
|
scan = rb_entry(parent, struct xrcd_table_entry, node);
|
|
|
|
|
|
|
|
if (inode < scan->inode) {
|
|
|
|
p = &(*p)->rb_left;
|
|
|
|
} else if (inode > scan->inode) {
|
|
|
|
p = &(*p)->rb_right;
|
|
|
|
} else {
|
|
|
|
kfree(entry);
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_link_node(&entry->node, parent, p);
|
|
|
|
rb_insert_color(&entry->node, &dev->xrcd_tree);
|
|
|
|
igrab(inode);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct xrcd_table_entry *xrcd_table_search(struct ib_uverbs_device *dev,
|
|
|
|
struct inode *inode)
|
|
|
|
{
|
|
|
|
struct xrcd_table_entry *entry;
|
|
|
|
struct rb_node *p = dev->xrcd_tree.rb_node;
|
|
|
|
|
|
|
|
while (p) {
|
|
|
|
entry = rb_entry(p, struct xrcd_table_entry, node);
|
|
|
|
|
|
|
|
if (inode < entry->inode)
|
|
|
|
p = p->rb_left;
|
|
|
|
else if (inode > entry->inode)
|
|
|
|
p = p->rb_right;
|
|
|
|
else
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ib_xrcd *find_xrcd(struct ib_uverbs_device *dev, struct inode *inode)
|
|
|
|
{
|
|
|
|
struct xrcd_table_entry *entry;
|
|
|
|
|
|
|
|
entry = xrcd_table_search(dev, inode);
|
|
|
|
if (!entry)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return entry->xrcd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xrcd_table_delete(struct ib_uverbs_device *dev,
|
|
|
|
struct inode *inode)
|
|
|
|
{
|
|
|
|
struct xrcd_table_entry *entry;
|
|
|
|
|
|
|
|
entry = xrcd_table_search(dev, inode);
|
|
|
|
if (entry) {
|
|
|
|
iput(inode);
|
|
|
|
rb_erase(&entry->node, &dev->xrcd_tree);
|
|
|
|
kfree(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_open_xrcd(struct uverbs_attr_bundle *attrs)
|
2011-05-24 23:33:46 +08:00
|
|
|
{
|
2018-11-26 02:51:13 +08:00
|
|
|
struct ib_uverbs_device *ibudev = attrs->ufile->device;
|
2020-07-19 13:22:23 +08:00
|
|
|
struct ib_uverbs_open_xrcd_resp resp = {};
|
2011-05-24 23:33:46 +08:00
|
|
|
struct ib_uverbs_open_xrcd cmd;
|
|
|
|
struct ib_uxrcd_object *obj;
|
|
|
|
struct ib_xrcd *xrcd = NULL;
|
|
|
|
struct inode *inode = NULL;
|
|
|
|
int new_xrcd = 0;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2020-07-21 01:56:26 +08:00
|
|
|
struct fd f = {};
|
|
|
|
int ret;
|
2011-05-24 23:33:46 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2011-05-24 23:33:46 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
mutex_lock(&ibudev->xrcd_tree_mutex);
|
2011-05-24 23:33:46 +08:00
|
|
|
|
|
|
|
if (cmd.fd != -1) {
|
|
|
|
/* search for file descriptor */
|
2012-08-29 00:52:22 +08:00
|
|
|
f = fdget(cmd.fd);
|
|
|
|
if (!f.file) {
|
2011-05-24 23:33:46 +08:00
|
|
|
ret = -EBADF;
|
|
|
|
goto err_tree_mutex_unlock;
|
|
|
|
}
|
|
|
|
|
2013-01-24 06:07:38 +08:00
|
|
|
inode = file_inode(f.file);
|
2018-11-26 02:51:13 +08:00
|
|
|
xrcd = find_xrcd(ibudev, inode);
|
2011-05-24 23:33:46 +08:00
|
|
|
if (!xrcd && !(cmd.oflags & O_CREAT)) {
|
|
|
|
/* no file descriptor. Need CREATE flag */
|
|
|
|
ret = -EAGAIN;
|
|
|
|
goto err_tree_mutex_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xrcd && cmd.oflags & O_EXCL) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_tree_mutex_unlock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
obj = (struct ib_uxrcd_object *)uobj_alloc(UVERBS_OBJECT_XRCD, attrs,
|
2018-07-26 11:40:17 +08:00
|
|
|
&ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(obj)) {
|
|
|
|
ret = PTR_ERR(obj);
|
2011-05-24 23:33:46 +08:00
|
|
|
goto err_tree_mutex_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!xrcd) {
|
2020-07-06 20:27:15 +08:00
|
|
|
xrcd = ib_alloc_xrcd_user(ib_dev, inode, &attrs->driver_udata);
|
2011-05-24 23:33:46 +08:00
|
|
|
if (IS_ERR(xrcd)) {
|
|
|
|
ret = PTR_ERR(xrcd);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
new_xrcd = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set(&obj->refcnt, 0);
|
|
|
|
obj->uobject.object = xrcd;
|
|
|
|
|
|
|
|
if (inode) {
|
|
|
|
if (new_xrcd) {
|
|
|
|
/* create new inode/xrcd table entry */
|
2018-11-26 02:51:13 +08:00
|
|
|
ret = xrcd_table_insert(ibudev, inode, xrcd);
|
2011-05-24 23:33:46 +08:00
|
|
|
if (ret)
|
2017-04-04 18:31:44 +08:00
|
|
|
goto err_dealloc_xrcd;
|
2011-05-24 23:33:46 +08:00
|
|
|
}
|
|
|
|
atomic_inc(&xrcd->usecnt);
|
|
|
|
}
|
|
|
|
|
2012-08-29 00:52:22 +08:00
|
|
|
if (f.file)
|
|
|
|
fdput(f);
|
2011-05-24 23:33:46 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
mutex_unlock(&ibudev->xrcd_tree_mutex);
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_finalize_uobj_create(&obj->uobject, attrs);
|
2018-02-14 18:35:39 +08:00
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
resp.xrcd_handle = obj->uobject.id;
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2011-05-24 23:33:46 +08:00
|
|
|
|
2017-04-04 18:31:44 +08:00
|
|
|
err_dealloc_xrcd:
|
2020-07-06 20:27:15 +08:00
|
|
|
ib_dealloc_xrcd_user(xrcd, uverbs_get_cleared_udata(attrs));
|
2011-05-24 23:33:46 +08:00
|
|
|
|
|
|
|
err:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(&obj->uobject, attrs);
|
2011-05-24 23:33:46 +08:00
|
|
|
|
|
|
|
err_tree_mutex_unlock:
|
2012-08-29 00:52:22 +08:00
|
|
|
if (f.file)
|
|
|
|
fdput(f);
|
2011-05-24 23:33:46 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
mutex_unlock(&ibudev->xrcd_tree_mutex);
|
2011-05-24 23:33:46 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_close_xrcd(struct uverbs_attr_bundle *attrs)
|
2011-05-24 23:33:46 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_close_xrcd cmd;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2011-05-24 23:33:46 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2011-05-24 23:33:46 +08:00
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return uobj_perform_destroy(UVERBS_OBJECT_XRCD, cmd.xrcd_handle, attrs);
|
2011-05-24 23:33:46 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 00:10:05 +08:00
|
|
|
int ib_uverbs_dealloc_xrcd(struct ib_uobject *uobject, struct ib_xrcd *xrcd,
|
2019-04-01 00:10:06 +08:00
|
|
|
enum rdma_remove_reason why,
|
|
|
|
struct uverbs_attr_bundle *attrs)
|
2011-05-24 23:33:46 +08:00
|
|
|
{
|
|
|
|
struct inode *inode;
|
2017-04-04 18:31:43 +08:00
|
|
|
int ret;
|
2019-04-01 00:10:06 +08:00
|
|
|
struct ib_uverbs_device *dev = attrs->ufile->device;
|
2011-05-24 23:33:46 +08:00
|
|
|
|
|
|
|
inode = xrcd->inode;
|
|
|
|
if (inode && !atomic_dec_and_test(&xrcd->usecnt))
|
2017-04-04 18:31:43 +08:00
|
|
|
return 0;
|
2011-05-24 23:33:46 +08:00
|
|
|
|
2020-07-06 20:27:15 +08:00
|
|
|
ret = ib_dealloc_xrcd_user(xrcd, &attrs->driver_udata);
|
2020-11-04 22:45:55 +08:00
|
|
|
if (ret) {
|
2017-04-04 18:31:43 +08:00
|
|
|
atomic_inc(&xrcd->usecnt);
|
2018-06-20 22:11:39 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inode)
|
2011-05-24 23:33:46 +08:00
|
|
|
xrcd_table_delete(dev, inode);
|
2017-04-04 18:31:43 +08:00
|
|
|
|
2020-11-04 22:45:55 +08:00
|
|
|
return 0;
|
2011-05-24 23:33:46 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_reg_mr(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
2020-07-19 13:22:23 +08:00
|
|
|
struct ib_uverbs_reg_mr_resp resp = {};
|
2005-07-08 08:57:13 +08:00
|
|
|
struct ib_uverbs_reg_mr cmd;
|
2007-03-05 08:15:11 +08:00
|
|
|
struct ib_uobject *uobj;
|
2005-07-08 08:57:13 +08:00
|
|
|
struct ib_pd *pd;
|
|
|
|
struct ib_mr *mr;
|
|
|
|
int ret;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
|
|
|
if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_alloc(UVERBS_OBJECT_MR, attrs, &ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-11-30 15:58:36 +08:00
|
|
|
ret = ib_check_mr_access(ib_dev, cmd.access_flags);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
|
2007-02-23 05:16:51 +08:00
|
|
|
if (!pd) {
|
|
|
|
ret = -EINVAL;
|
2007-03-05 08:15:11 +08:00
|
|
|
goto err_free;
|
2007-02-23 05:16:51 +08:00
|
|
|
}
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-12-11 03:09:48 +08:00
|
|
|
mr = pd->device->ops.reg_user_mr(pd, cmd.start, cmd.length, cmd.hca_va,
|
|
|
|
cmd.access_flags,
|
|
|
|
&attrs->driver_udata);
|
2005-07-08 08:57:13 +08:00
|
|
|
if (IS_ERR(mr)) {
|
|
|
|
ret = PTR_ERR(mr);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto err_put;
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mr->device = pd->device;
|
|
|
|
mr->pd = pd;
|
2019-06-11 23:52:38 +08:00
|
|
|
mr->type = IB_MR_TYPE_USER;
|
2018-04-26 20:42:55 +08:00
|
|
|
mr->dm = NULL;
|
2019-06-11 23:52:41 +08:00
|
|
|
mr->sig_attrs = NULL;
|
2007-03-05 08:15:11 +08:00
|
|
|
mr->uobject = uobj;
|
2005-07-08 08:57:13 +08:00
|
|
|
atomic_inc(&pd->usecnt);
|
2020-06-30 17:39:11 +08:00
|
|
|
mr->iova = cmd.hca_va;
|
2022-09-21 16:08:43 +08:00
|
|
|
mr->length = cmd.length;
|
2020-09-22 17:11:04 +08:00
|
|
|
|
|
|
|
rdma_restrack_new(&mr->res, RDMA_RESTRACK_MR);
|
2020-09-22 17:11:06 +08:00
|
|
|
rdma_restrack_set_name(&mr->res, NULL);
|
|
|
|
rdma_restrack_add(&mr->res);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2007-03-05 08:15:11 +08:00
|
|
|
uobj->object = mr;
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(pd);
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_finalize_uobj_create(uobj, attrs);
|
2005-09-28 06:07:25 +08:00
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
resp.lkey = mr->lkey;
|
|
|
|
resp.rkey = mr->rkey;
|
|
|
|
resp.mr_handle = uobj->id;
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-07-08 08:57:13 +08:00
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
err_put:
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(pd);
|
2005-07-08 08:57:13 +08:00
|
|
|
err_free:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(uobj, attrs);
|
2005-07-08 08:57:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_rereg_mr(struct uverbs_attr_bundle *attrs)
|
2014-07-31 16:01:28 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_rereg_mr cmd;
|
|
|
|
struct ib_uverbs_rereg_mr_resp resp;
|
|
|
|
struct ib_mr *mr;
|
|
|
|
int ret;
|
|
|
|
struct ib_uobject *uobj;
|
2020-11-30 15:58:37 +08:00
|
|
|
struct ib_uobject *new_uobj;
|
|
|
|
struct ib_device *ib_dev;
|
|
|
|
struct ib_pd *orig_pd;
|
|
|
|
struct ib_pd *new_pd;
|
|
|
|
struct ib_mr *new_mr;
|
2014-07-31 16:01:28 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2014-07-31 16:01:28 +08:00
|
|
|
|
2020-11-30 15:58:35 +08:00
|
|
|
if (!cmd.flags)
|
2014-07-31 16:01:28 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2020-11-30 15:58:35 +08:00
|
|
|
if (cmd.flags & ~IB_MR_REREG_SUPPORTED)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2014-07-31 16:01:28 +08:00
|
|
|
if ((cmd.flags & IB_MR_REREG_TRANS) &&
|
2020-11-30 15:58:35 +08:00
|
|
|
(cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
|
|
|
|
return -EINVAL;
|
2014-07-31 16:01:28 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_get_write(UVERBS_OBJECT_MR, cmd.mr_handle, attrs);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
2014-07-31 16:01:28 +08:00
|
|
|
|
|
|
|
mr = uobj->object;
|
|
|
|
|
2018-04-26 20:42:54 +08:00
|
|
|
if (mr->dm) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto put_uobjs;
|
|
|
|
}
|
|
|
|
|
2014-07-31 16:01:28 +08:00
|
|
|
if (cmd.flags & IB_MR_REREG_ACCESS) {
|
2020-11-30 15:58:36 +08:00
|
|
|
ret = ib_check_mr_access(mr->device, cmd.access_flags);
|
2014-07-31 16:01:28 +08:00
|
|
|
if (ret)
|
|
|
|
goto put_uobjs;
|
|
|
|
}
|
|
|
|
|
2020-11-30 15:58:37 +08:00
|
|
|
orig_pd = mr->pd;
|
2014-07-31 16:01:28 +08:00
|
|
|
if (cmd.flags & IB_MR_REREG_PD) {
|
2020-11-30 15:58:37 +08:00
|
|
|
new_pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle,
|
|
|
|
attrs);
|
|
|
|
if (!new_pd) {
|
2014-07-31 16:01:28 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto put_uobjs;
|
|
|
|
}
|
2020-11-30 15:58:37 +08:00
|
|
|
} else {
|
|
|
|
new_pd = mr->pd;
|
2014-07-31 16:01:28 +08:00
|
|
|
}
|
|
|
|
|
2020-11-30 15:58:37 +08:00
|
|
|
/*
|
|
|
|
* The driver might create a new HW object as part of the rereg, we need
|
|
|
|
* to have a uobject ready to hold it.
|
|
|
|
*/
|
|
|
|
new_uobj = uobj_alloc(UVERBS_OBJECT_MR, attrs, &ib_dev);
|
|
|
|
if (IS_ERR(new_uobj)) {
|
|
|
|
ret = PTR_ERR(new_uobj);
|
2014-07-31 16:01:28 +08:00
|
|
|
goto put_uobj_pd;
|
2020-11-30 15:58:37 +08:00
|
|
|
}
|
2019-02-18 22:23:22 +08:00
|
|
|
|
2020-11-30 15:58:37 +08:00
|
|
|
new_mr = ib_dev->ops.rereg_user_mr(mr, cmd.flags, cmd.start, cmd.length,
|
|
|
|
cmd.hca_va, cmd.access_flags, new_pd,
|
|
|
|
&attrs->driver_udata);
|
|
|
|
if (IS_ERR(new_mr)) {
|
|
|
|
ret = PTR_ERR(new_mr);
|
|
|
|
goto put_new_uobj;
|
2014-07-31 16:01:28 +08:00
|
|
|
}
|
2020-11-30 15:58:37 +08:00
|
|
|
if (new_mr) {
|
|
|
|
new_mr->device = new_pd->device;
|
|
|
|
new_mr->pd = new_pd;
|
|
|
|
new_mr->type = IB_MR_TYPE_USER;
|
|
|
|
new_mr->uobject = uobj;
|
|
|
|
atomic_inc(&new_pd->usecnt);
|
|
|
|
new_uobj->object = new_mr;
|
|
|
|
|
|
|
|
rdma_restrack_new(&new_mr->res, RDMA_RESTRACK_MR);
|
|
|
|
rdma_restrack_set_name(&new_mr->res, NULL);
|
|
|
|
rdma_restrack_add(&new_mr->res);
|
2014-07-31 16:01:28 +08:00
|
|
|
|
2020-11-30 15:58:37 +08:00
|
|
|
/*
|
|
|
|
* The new uobj for the new HW object is put into the same spot
|
|
|
|
* in the IDR and the old uobj & HW object is deleted.
|
|
|
|
*/
|
|
|
|
rdma_assign_uobject(uobj, new_uobj, attrs);
|
|
|
|
rdma_alloc_commit_uobject(new_uobj, attrs);
|
|
|
|
uobj_put_destroy(uobj);
|
|
|
|
new_uobj = NULL;
|
|
|
|
uobj = NULL;
|
|
|
|
mr = new_mr;
|
|
|
|
} else {
|
|
|
|
if (cmd.flags & IB_MR_REREG_PD) {
|
|
|
|
atomic_dec(&orig_pd->usecnt);
|
|
|
|
mr->pd = new_pd;
|
|
|
|
atomic_inc(&new_pd->usecnt);
|
|
|
|
}
|
2022-09-21 16:08:43 +08:00
|
|
|
if (cmd.flags & IB_MR_REREG_TRANS) {
|
2020-11-30 15:58:37 +08:00
|
|
|
mr->iova = cmd.hca_va;
|
2022-09-21 16:08:43 +08:00
|
|
|
mr->length = cmd.length;
|
|
|
|
}
|
2020-11-30 15:58:37 +08:00
|
|
|
}
|
2020-06-30 17:39:11 +08:00
|
|
|
|
2014-07-31 16:01:28 +08:00
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
|
|
resp.lkey = mr->lkey;
|
|
|
|
resp.rkey = mr->rkey;
|
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
ret = uverbs_response(attrs, &resp, sizeof(resp));
|
2014-07-31 16:01:28 +08:00
|
|
|
|
2020-11-30 15:58:37 +08:00
|
|
|
put_new_uobj:
|
|
|
|
if (new_uobj)
|
|
|
|
uobj_alloc_abort(new_uobj, attrs);
|
2014-07-31 16:01:28 +08:00
|
|
|
put_uobj_pd:
|
|
|
|
if (cmd.flags & IB_MR_REREG_PD)
|
2020-11-30 15:58:37 +08:00
|
|
|
uobj_put_obj_read(new_pd);
|
2014-07-31 16:01:28 +08:00
|
|
|
|
|
|
|
put_uobjs:
|
2020-11-30 15:58:37 +08:00
|
|
|
if (uobj)
|
|
|
|
uobj_put_write(uobj);
|
2014-07-31 16:01:28 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_dereg_mr(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_dereg_mr cmd;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return uobj_perform_destroy(UVERBS_OBJECT_MR, cmd.mr_handle, attrs);
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_alloc_mw(struct uverbs_attr_bundle *attrs)
|
2013-02-07 00:19:13 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_alloc_mw cmd;
|
2020-09-02 16:16:22 +08:00
|
|
|
struct ib_uverbs_alloc_mw_resp resp = {};
|
2013-02-07 00:19:13 +08:00
|
|
|
struct ib_uobject *uobj;
|
|
|
|
struct ib_pd *pd;
|
|
|
|
struct ib_mw *mw;
|
|
|
|
int ret;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2013-02-07 00:19:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2013-02-07 00:19:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_alloc(UVERBS_OBJECT_MW, attrs, &ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
2013-02-07 00:19:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
|
2013-02-07 00:19:13 +08:00
|
|
|
if (!pd) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
|
2019-02-19 21:07:34 +08:00
|
|
|
if (cmd.mw_type != IB_MW_TYPE_1 && cmd.mw_type != IB_MW_TYPE_2) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
2020-09-02 16:16:22 +08:00
|
|
|
mw = rdma_zalloc_drv_obj(ib_dev, ib_mw);
|
|
|
|
if (!mw) {
|
|
|
|
ret = -ENOMEM;
|
2013-02-07 00:19:13 +08:00
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
2020-09-02 16:16:22 +08:00
|
|
|
mw->device = ib_dev;
|
|
|
|
mw->pd = pd;
|
2013-02-07 00:19:13 +08:00
|
|
|
mw->uobject = uobj;
|
2020-09-02 16:16:22 +08:00
|
|
|
mw->type = cmd.mw_type;
|
|
|
|
|
|
|
|
ret = pd->device->ops.alloc_mw(mw, &attrs->driver_udata);
|
|
|
|
if (ret)
|
|
|
|
goto err_alloc;
|
|
|
|
|
2013-02-07 00:19:13 +08:00
|
|
|
atomic_inc(&pd->usecnt);
|
|
|
|
|
|
|
|
uobj->object = mw;
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_put_obj_read(pd);
|
|
|
|
uobj_finalize_uobj_create(uobj, attrs);
|
2013-02-07 00:19:13 +08:00
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
resp.rkey = mw->rkey;
|
2013-02-07 00:19:13 +08:00
|
|
|
resp.mw_handle = uobj->id;
|
2020-07-19 13:22:23 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2013-02-07 00:19:13 +08:00
|
|
|
|
2020-09-02 16:16:22 +08:00
|
|
|
err_alloc:
|
|
|
|
kfree(mw);
|
2013-02-07 00:19:13 +08:00
|
|
|
err_put:
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(pd);
|
2013-02-07 00:19:13 +08:00
|
|
|
err_free:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(uobj, attrs);
|
2013-02-07 00:19:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_dealloc_mw(struct uverbs_attr_bundle *attrs)
|
2013-02-07 00:19:13 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_dealloc_mw cmd;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2013-02-07 00:19:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2013-02-07 00:19:13 +08:00
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return uobj_perform_destroy(UVERBS_OBJECT_MW, cmd.mw_handle, attrs);
|
2013-02-07 00:19:13 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_create_comp_channel(struct uverbs_attr_bundle *attrs)
|
2005-09-27 04:53:25 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_create_comp_channel cmd;
|
|
|
|
struct ib_uverbs_create_comp_channel_resp resp;
|
2017-04-04 18:31:47 +08:00
|
|
|
struct ib_uobject *uobj;
|
|
|
|
struct ib_uverbs_completion_event_file *ev_file;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2018-11-26 02:58:37 +08:00
|
|
|
int ret;
|
2005-09-27 04:53:25 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-09-27 04:53:25 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_alloc(UVERBS_OBJECT_COMP_CHANNEL, attrs, &ib_dev);
|
2017-04-04 18:31:47 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
2010-01-18 14:38:00 +08:00
|
|
|
|
2017-04-04 18:31:47 +08:00
|
|
|
ev_file = container_of(uobj, struct ib_uverbs_completion_event_file,
|
2018-07-04 16:32:11 +08:00
|
|
|
uobj);
|
2017-04-18 17:03:42 +08:00
|
|
|
ib_uverbs_init_event_queue(&ev_file->ev_queue);
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_finalize_uobj_create(uobj, attrs);
|
2005-09-27 04:53:25 +08:00
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
resp.fd = uobj->id;
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-09-27 04:53:25 +08:00
|
|
|
}
|
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
static int create_cq(struct uverbs_attr_bundle *attrs,
|
|
|
|
struct ib_uverbs_ex_create_cq *cmd)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
struct ib_ucq_object *obj;
|
2017-04-04 18:31:47 +08:00
|
|
|
struct ib_uverbs_completion_event_file *ev_file = NULL;
|
2005-07-08 08:57:13 +08:00
|
|
|
struct ib_cq *cq;
|
|
|
|
int ret;
|
2020-07-19 13:22:23 +08:00
|
|
|
struct ib_uverbs_ex_create_cq_resp resp = {};
|
2015-06-11 21:35:20 +08:00
|
|
|
struct ib_cq_init_attr attr = {};
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2018-02-14 20:38:43 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
if (cmd->comp_vector >= attrs->ufile->device->num_comp_vectors)
|
2020-07-19 13:22:23 +08:00
|
|
|
return -EINVAL;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
obj = (struct ib_ucq_object *)uobj_alloc(UVERBS_OBJECT_CQ, attrs,
|
2018-07-26 11:40:17 +08:00
|
|
|
&ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(obj))
|
2020-07-19 13:22:23 +08:00
|
|
|
return PTR_ERR(obj);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
|
2015-06-11 21:35:23 +08:00
|
|
|
if (cmd->comp_channel >= 0) {
|
2018-11-26 02:51:13 +08:00
|
|
|
ev_file = ib_uverbs_lookup_comp_file(cmd->comp_channel, attrs);
|
2017-04-04 18:31:47 +08:00
|
|
|
if (IS_ERR(ev_file)) {
|
|
|
|
ret = PTR_ERR(ev_file);
|
2006-01-07 08:43:14 +08:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-09 01:21:57 +08:00
|
|
|
obj->uevent.uobject.user_handle = cmd->user_handle;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
INIT_LIST_HEAD(&obj->comp_list);
|
2020-01-09 01:21:57 +08:00
|
|
|
INIT_LIST_HEAD(&obj->uevent.event_list);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2015-06-11 21:35:23 +08:00
|
|
|
attr.cqe = cmd->cqe;
|
|
|
|
attr.comp_vector = cmd->comp_vector;
|
2018-11-26 02:58:44 +08:00
|
|
|
attr.flags = cmd->flags;
|
2015-06-11 21:35:23 +08:00
|
|
|
|
2019-05-28 19:37:29 +08:00
|
|
|
cq = rdma_zalloc_drv_obj(ib_dev, ib_cq);
|
|
|
|
if (!cq) {
|
|
|
|
ret = -ENOMEM;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto err_file;
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
2015-08-13 23:32:04 +08:00
|
|
|
cq->device = ib_dev;
|
2020-01-09 01:21:58 +08:00
|
|
|
cq->uobject = obj;
|
2005-07-08 08:57:13 +08:00
|
|
|
cq->comp_handler = ib_uverbs_comp_handler;
|
|
|
|
cq->event_handler = ib_uverbs_cq_event_handler;
|
2017-08-01 13:28:35 +08:00
|
|
|
cq->cq_context = ev_file ? &ev_file->ev_queue : NULL;
|
2005-07-08 08:57:13 +08:00
|
|
|
atomic_set(&cq->usecnt, 0);
|
|
|
|
|
2020-09-22 17:11:04 +08:00
|
|
|
rdma_restrack_new(&cq->res, RDMA_RESTRACK_CQ);
|
2020-09-22 17:11:06 +08:00
|
|
|
rdma_restrack_set_name(&cq->res, NULL);
|
|
|
|
|
2019-05-28 19:37:29 +08:00
|
|
|
ret = ib_dev->ops.create_cq(cq, &attr, &attrs->driver_udata);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
2020-09-22 17:11:06 +08:00
|
|
|
rdma_restrack_add(&cq->res);
|
2019-05-28 19:37:29 +08:00
|
|
|
|
2020-01-09 01:21:57 +08:00
|
|
|
obj->uevent.uobject.object = cq;
|
2020-05-19 15:27:06 +08:00
|
|
|
obj->uevent.event_file = READ_ONCE(attrs->ufile->default_async_file);
|
|
|
|
if (obj->uevent.event_file)
|
|
|
|
uverbs_uobject_get(&obj->uevent.event_file->uobj);
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
|
2020-05-19 15:27:06 +08:00
|
|
|
|
2020-01-09 01:21:57 +08:00
|
|
|
resp.base.cq_handle = obj->uevent.uobject.id;
|
2020-07-19 13:22:23 +08:00
|
|
|
resp.base.cqe = cq->cqe;
|
2018-11-26 02:58:39 +08:00
|
|
|
resp.response_length = uverbs_response_length(attrs, sizeof(resp));
|
2020-07-19 13:22:23 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2015-06-11 21:35:23 +08:00
|
|
|
|
2019-05-28 19:37:29 +08:00
|
|
|
err_free:
|
2020-09-22 17:11:04 +08:00
|
|
|
rdma_restrack_put(&cq->res);
|
2019-05-28 19:37:29 +08:00
|
|
|
kfree(cq);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
err_file:
|
2006-01-07 08:43:14 +08:00
|
|
|
if (ev_file)
|
2020-01-09 01:22:06 +08:00
|
|
|
ib_uverbs_release_ucq(ev_file, obj);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
err:
|
2020-01-09 01:21:57 +08:00
|
|
|
uobj_alloc_abort(&obj->uevent.uobject, attrs);
|
2020-07-19 13:22:23 +08:00
|
|
|
return ret;
|
2015-06-11 21:35:23 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_create_cq(struct uverbs_attr_bundle *attrs)
|
2015-06-11 21:35:23 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_create_cq cmd;
|
|
|
|
struct ib_uverbs_ex_create_cq cmd_ex;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2015-06-11 21:35:23 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-06-11 21:35:23 +08:00
|
|
|
|
|
|
|
memset(&cmd_ex, 0, sizeof(cmd_ex));
|
|
|
|
cmd_ex.user_handle = cmd.user_handle;
|
|
|
|
cmd_ex.cqe = cmd.cqe;
|
|
|
|
cmd_ex.comp_vector = cmd.comp_vector;
|
|
|
|
cmd_ex.comp_channel = cmd.comp_channel;
|
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
return create_cq(attrs, &cmd_ex);
|
2015-06-11 21:35:23 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_create_cq(struct uverbs_attr_bundle *attrs)
|
2015-06-11 21:35:23 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_ex_create_cq cmd;
|
2018-11-26 02:58:39 +08:00
|
|
|
int ret;
|
2015-06-11 21:35:23 +08:00
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-06-11 21:35:23 +08:00
|
|
|
|
|
|
|
if (cmd.comp_mask)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (cmd.reserved)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
return create_cq(attrs, &cmd);
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_resize_cq(struct uverbs_attr_bundle *attrs)
|
2006-01-31 06:29:21 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_resize_cq cmd;
|
2017-08-01 14:41:35 +08:00
|
|
|
struct ib_uverbs_resize_cq_resp resp = {};
|
2006-01-31 06:29:21 +08:00
|
|
|
struct ib_cq *cq;
|
2020-07-21 01:56:26 +08:00
|
|
|
int ret;
|
2006-01-31 06:29:21 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2006-01-31 06:29:21 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (!cq)
|
|
|
|
return -EINVAL;
|
2006-01-31 06:29:21 +08:00
|
|
|
|
2018-12-11 03:09:48 +08:00
|
|
|
ret = cq->device->ops.resize_cq(cq, cmd.cqe, &attrs->driver_udata);
|
2006-01-31 06:29:21 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
resp.cqe = cq->cqe;
|
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
ret = uverbs_response(attrs, &resp, sizeof(resp));
|
2006-01-31 06:29:21 +08:00
|
|
|
out:
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2006-01-31 06:29:21 +08:00
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return ret;
|
2006-01-31 06:29:21 +08:00
|
|
|
}
|
|
|
|
|
2017-06-09 01:37:49 +08:00
|
|
|
static int copy_wc_to_user(struct ib_device *ib_dev, void __user *dest,
|
|
|
|
struct ib_wc *wc)
|
2010-10-13 17:13:12 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_wc tmp;
|
|
|
|
|
|
|
|
tmp.wr_id = wc->wr_id;
|
|
|
|
tmp.status = wc->status;
|
|
|
|
tmp.opcode = wc->opcode;
|
|
|
|
tmp.vendor_err = wc->vendor_err;
|
|
|
|
tmp.byte_len = wc->byte_len;
|
2018-01-12 05:43:05 +08:00
|
|
|
tmp.ex.imm_data = wc->ex.imm_data;
|
2010-10-13 17:13:12 +08:00
|
|
|
tmp.qp_num = wc->qp->qp_num;
|
|
|
|
tmp.src_qp = wc->src_qp;
|
|
|
|
tmp.wc_flags = wc->wc_flags;
|
|
|
|
tmp.pkey_index = wc->pkey_index;
|
2017-06-09 01:37:49 +08:00
|
|
|
if (rdma_cap_opa_ah(ib_dev, wc->port_num))
|
2017-08-15 02:17:43 +08:00
|
|
|
tmp.slid = OPA_TO_IB_UCAST_LID(wc->slid);
|
2017-06-09 01:37:49 +08:00
|
|
|
else
|
2017-08-15 02:17:43 +08:00
|
|
|
tmp.slid = ib_lid_cpu16(wc->slid);
|
2010-10-13 17:13:12 +08:00
|
|
|
tmp.sl = wc->sl;
|
|
|
|
tmp.dlid_path_bits = wc->dlid_path_bits;
|
|
|
|
tmp.port_num = wc->port_num;
|
|
|
|
tmp.reserved = 0;
|
|
|
|
|
|
|
|
if (copy_to_user(dest, &tmp, sizeof tmp))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs)
|
2005-10-15 06:26:04 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_poll_cq cmd;
|
2010-10-13 17:13:12 +08:00
|
|
|
struct ib_uverbs_poll_cq_resp resp;
|
|
|
|
u8 __user *header_ptr;
|
|
|
|
u8 __user *data_ptr;
|
2005-10-15 06:26:04 +08:00
|
|
|
struct ib_cq *cq;
|
2010-10-13 17:13:12 +08:00
|
|
|
struct ib_wc wc;
|
|
|
|
int ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
|
2010-10-13 17:13:12 +08:00
|
|
|
if (!cq)
|
|
|
|
return -EINVAL;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2010-10-13 17:13:12 +08:00
|
|
|
/* we copy a struct ib_uverbs_poll_cq_resp to user space */
|
2018-11-26 02:58:35 +08:00
|
|
|
header_ptr = attrs->ucore.outbuf;
|
2010-10-13 17:13:12 +08:00
|
|
|
data_ptr = header_ptr + sizeof resp;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
|
2010-10-13 17:13:12 +08:00
|
|
|
memset(&resp, 0, sizeof resp);
|
|
|
|
while (resp.count < cmd.ne) {
|
|
|
|
ret = ib_poll_cq(cq, 1, &wc);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out_put;
|
|
|
|
if (!ret)
|
|
|
|
break;
|
|
|
|
|
2018-07-26 11:40:17 +08:00
|
|
|
ret = copy_wc_to_user(cq->device, data_ptr, &wc);
|
2010-10-13 17:13:12 +08:00
|
|
|
if (ret)
|
|
|
|
goto out_put;
|
|
|
|
|
|
|
|
data_ptr += sizeof(struct ib_uverbs_wc);
|
|
|
|
++resp.count;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2010-10-13 17:13:12 +08:00
|
|
|
if (copy_to_user(header_ptr, &resp, sizeof resp)) {
|
2005-10-15 06:26:04 +08:00
|
|
|
ret = -EFAULT;
|
2010-10-13 17:13:12 +08:00
|
|
|
goto out_put;
|
|
|
|
}
|
2019-02-15 04:13:31 +08:00
|
|
|
ret = 0;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2019-01-11 14:21:44 +08:00
|
|
|
if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
|
|
|
|
ret = uverbs_output_written(attrs, UVERBS_ATTR_CORE_OUT);
|
|
|
|
|
2010-10-13 17:13:12 +08:00
|
|
|
out_put:
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2010-10-13 17:13:12 +08:00
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_req_notify_cq(struct uverbs_attr_bundle *attrs)
|
2005-10-15 06:26:04 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_req_notify_cq cmd;
|
|
|
|
struct ib_cq *cq;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
|
2006-09-23 06:17:19 +08:00
|
|
|
if (!cq)
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
return -EINVAL;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
ib_req_notify_cq(cq, cmd.solicited_only ?
|
|
|
|
IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
|
|
|
|
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2018-11-26 02:51:14 +08:00
|
|
|
return 0;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_destroy_cq(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
2005-09-10 06:55:08 +08:00
|
|
|
struct ib_uverbs_destroy_cq cmd;
|
|
|
|
struct ib_uverbs_destroy_cq_resp resp;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
struct ib_uobject *uobj;
|
|
|
|
struct ib_ucq_object *obj;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_get_destroy(UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
|
|
|
|
2020-01-09 01:21:57 +08:00
|
|
|
obj = container_of(uobj, struct ib_ucq_object, uevent.uobject);
|
2017-04-04 18:31:44 +08:00
|
|
|
memset(&resp, 0, sizeof(resp));
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
resp.comp_events_reported = obj->comp_events_reported;
|
2020-01-09 01:21:57 +08:00
|
|
|
resp.async_events_reported = obj->uevent.events_reported;
|
2005-09-10 06:55:08 +08:00
|
|
|
|
2018-07-26 11:40:11 +08:00
|
|
|
uobj_put_destroy(uobj);
|
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
static int create_qp(struct uverbs_attr_bundle *attrs,
|
2018-11-26 02:58:44 +08:00
|
|
|
struct ib_uverbs_ex_create_qp *cmd)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
2015-10-21 22:00:42 +08:00
|
|
|
struct ib_uqp_object *obj;
|
|
|
|
struct ib_device *device;
|
|
|
|
struct ib_pd *pd = NULL;
|
|
|
|
struct ib_xrcd *xrcd = NULL;
|
2017-04-04 18:31:44 +08:00
|
|
|
struct ib_uobject *xrcd_uobj = ERR_PTR(-ENOENT);
|
2015-10-21 22:00:42 +08:00
|
|
|
struct ib_cq *scq = NULL, *rcq = NULL;
|
|
|
|
struct ib_srq *srq = NULL;
|
|
|
|
struct ib_qp *qp;
|
2016-05-23 20:20:55 +08:00
|
|
|
struct ib_qp_init_attr attr = {};
|
2020-07-19 13:22:23 +08:00
|
|
|
struct ib_uverbs_ex_create_qp_resp resp = {};
|
2015-10-21 22:00:42 +08:00
|
|
|
int ret;
|
2016-05-23 20:20:55 +08:00
|
|
|
struct ib_rwq_ind_table *ind_tbl = NULL;
|
|
|
|
bool has_sq = true;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2015-10-21 22:00:42 +08:00
|
|
|
|
2020-09-26 18:24:47 +08:00
|
|
|
switch (cmd->qp_type) {
|
|
|
|
case IB_QPT_RAW_PACKET:
|
|
|
|
if (!capable(CAP_NET_RAW))
|
|
|
|
return -EPERM;
|
|
|
|
break;
|
|
|
|
case IB_QPT_RC:
|
|
|
|
case IB_QPT_UC:
|
|
|
|
case IB_QPT_UD:
|
|
|
|
case IB_QPT_XRC_INI:
|
|
|
|
case IB_QPT_XRC_TGT:
|
|
|
|
case IB_QPT_DRIVER:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2012-03-01 18:17:51 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
obj = (struct ib_uqp_object *)uobj_alloc(UVERBS_OBJECT_QP, attrs,
|
2018-07-26 11:40:17 +08:00
|
|
|
&ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(obj))
|
|
|
|
return PTR_ERR(obj);
|
|
|
|
obj->uxrcd = NULL;
|
|
|
|
obj->uevent.uobject.user_handle = cmd->user_handle;
|
2017-04-04 18:31:45 +08:00
|
|
|
mutex_init(&obj->mcast_lock);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:44 +08:00
|
|
|
if (cmd->comp_mask & IB_UVERBS_CREATE_QP_MASK_IND_TABLE) {
|
2018-07-04 16:32:09 +08:00
|
|
|
ind_tbl = uobj_get_obj_read(rwq_ind_table,
|
|
|
|
UVERBS_OBJECT_RWQ_IND_TBL,
|
2018-11-26 02:51:13 +08:00
|
|
|
cmd->rwq_ind_tbl_handle, attrs);
|
2016-05-23 20:20:55 +08:00
|
|
|
if (!ind_tbl) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
attr.rwq_ind_tbl = ind_tbl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ind_tbl && (cmd->max_recv_wr || cmd->max_recv_sge || cmd->is_srq)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ind_tbl && !cmd->max_send_wr)
|
|
|
|
has_sq = false;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2015-10-21 22:00:42 +08:00
|
|
|
if (cmd->qp_type == IB_QPT_XRC_TGT) {
|
2018-03-19 21:02:33 +08:00
|
|
|
xrcd_uobj = uobj_get_read(UVERBS_OBJECT_XRCD, cmd->pd_handle,
|
2018-11-26 02:51:13 +08:00
|
|
|
attrs);
|
2017-04-04 18:31:44 +08:00
|
|
|
|
|
|
|
if (IS_ERR(xrcd_uobj)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
xrcd = (struct ib_xrcd *)xrcd_uobj->object;
|
2011-05-27 15:00:12 +08:00
|
|
|
if (!xrcd) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
device = xrcd->device;
|
2011-05-26 23:17:04 +08:00
|
|
|
} else {
|
2015-10-21 22:00:42 +08:00
|
|
|
if (cmd->qp_type == IB_QPT_XRC_INI) {
|
|
|
|
cmd->max_recv_wr = 0;
|
|
|
|
cmd->max_recv_sge = 0;
|
2011-05-27 15:00:12 +08:00
|
|
|
} else {
|
2015-10-21 22:00:42 +08:00
|
|
|
if (cmd->is_srq) {
|
2018-07-04 16:32:09 +08:00
|
|
|
srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ,
|
2018-11-26 02:51:13 +08:00
|
|
|
cmd->srq_handle, attrs);
|
2017-08-17 20:52:07 +08:00
|
|
|
if (!srq || srq->srq_type == IB_SRQT_XRC) {
|
2011-05-27 15:00:12 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
}
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
|
2016-05-23 20:20:55 +08:00
|
|
|
if (!ind_tbl) {
|
|
|
|
if (cmd->recv_cq_handle != cmd->send_cq_handle) {
|
2018-07-04 16:32:09 +08:00
|
|
|
rcq = uobj_get_obj_read(
|
|
|
|
cq, UVERBS_OBJECT_CQ,
|
2018-11-26 02:51:13 +08:00
|
|
|
cmd->recv_cq_handle, attrs);
|
2016-05-23 20:20:55 +08:00
|
|
|
if (!rcq) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
}
|
2011-05-26 23:17:04 +08:00
|
|
|
}
|
|
|
|
}
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
|
2016-05-23 20:20:55 +08:00
|
|
|
if (has_sq)
|
2018-07-04 16:32:09 +08:00
|
|
|
scq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
|
2018-11-26 02:51:13 +08:00
|
|
|
cmd->send_cq_handle, attrs);
|
2020-12-16 15:17:54 +08:00
|
|
|
if (!ind_tbl && cmd->qp_type != IB_QPT_XRC_INI)
|
2016-05-23 20:20:55 +08:00
|
|
|
rcq = rcq ?: scq;
|
2018-07-04 16:32:09 +08:00
|
|
|
pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle,
|
2018-11-26 02:51:13 +08:00
|
|
|
attrs);
|
2016-05-23 20:20:55 +08:00
|
|
|
if (!pd || (!scq && has_sq)) {
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
2011-05-27 15:00:12 +08:00
|
|
|
device = pd->device;
|
2011-05-26 23:17:04 +08:00
|
|
|
}
|
|
|
|
|
2005-07-08 08:57:13 +08:00
|
|
|
attr.event_handler = ib_uverbs_qp_event_handler;
|
|
|
|
attr.send_cq = scq;
|
|
|
|
attr.recv_cq = rcq;
|
2005-08-19 03:24:13 +08:00
|
|
|
attr.srq = srq;
|
2011-05-27 15:00:12 +08:00
|
|
|
attr.xrcd = xrcd;
|
2015-10-21 22:00:42 +08:00
|
|
|
attr.sq_sig_type = cmd->sq_sig_all ? IB_SIGNAL_ALL_WR :
|
|
|
|
IB_SIGNAL_REQ_WR;
|
|
|
|
attr.qp_type = cmd->qp_type;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2015-10-21 22:00:42 +08:00
|
|
|
attr.cap.max_send_wr = cmd->max_send_wr;
|
|
|
|
attr.cap.max_recv_wr = cmd->max_recv_wr;
|
|
|
|
attr.cap.max_send_sge = cmd->max_send_sge;
|
|
|
|
attr.cap.max_recv_sge = cmd->max_recv_sge;
|
|
|
|
attr.cap.max_inline_data = cmd->max_inline_data;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
INIT_LIST_HEAD(&obj->uevent.event_list);
|
|
|
|
INIT_LIST_HEAD(&obj->mcast_list);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:44 +08:00
|
|
|
attr.create_flags = cmd->create_flags;
|
2015-12-20 18:16:10 +08:00
|
|
|
if (attr.create_flags & ~(IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK |
|
|
|
|
IB_QP_CREATE_CROSS_CHANNEL |
|
|
|
|
IB_QP_CREATE_MANAGED_SEND |
|
2016-04-17 22:19:36 +08:00
|
|
|
IB_QP_CREATE_MANAGED_RECV |
|
2017-01-18 21:40:00 +08:00
|
|
|
IB_QP_CREATE_SCATTER_FCS |
|
2017-06-08 21:15:07 +08:00
|
|
|
IB_QP_CREATE_CVLAN_STRIPPING |
|
2017-10-29 19:59:44 +08:00
|
|
|
IB_QP_CREATE_SOURCE_QPN |
|
|
|
|
IB_QP_CREATE_PCI_WRITE_END_PADDING)) {
|
2015-10-21 22:00:42 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
2017-06-08 21:15:07 +08:00
|
|
|
if (attr.create_flags & IB_QP_CREATE_SOURCE_QPN) {
|
|
|
|
if (!capable(CAP_NET_RAW)) {
|
|
|
|
ret = -EPERM;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
attr.source_qpn = cmd->source_qpn;
|
|
|
|
}
|
|
|
|
|
2021-08-04 02:20:38 +08:00
|
|
|
qp = ib_create_qp_user(device, pd, &attr, &attrs->driver_udata, obj,
|
|
|
|
KBUILD_MODNAME);
|
2005-07-08 08:57:13 +08:00
|
|
|
if (IS_ERR(qp)) {
|
|
|
|
ret = PTR_ERR(qp);
|
2017-04-04 18:31:44 +08:00
|
|
|
goto err_put;
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
2021-08-04 02:20:37 +08:00
|
|
|
ib_qp_usecnt_inc(qp);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
obj->uevent.uobject.object = qp;
|
2020-05-19 15:27:06 +08:00
|
|
|
obj->uevent.event_file = READ_ONCE(attrs->ufile->default_async_file);
|
|
|
|
if (obj->uevent.event_file)
|
|
|
|
uverbs_uobject_get(&obj->uevent.event_file->uobj);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2013-08-01 23:49:54 +08:00
|
|
|
if (xrcd) {
|
|
|
|
obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
|
|
|
|
uobject);
|
|
|
|
atomic_inc(&obj->uxrcd->refcnt);
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_read(xrcd_uobj);
|
2013-08-01 23:49:54 +08:00
|
|
|
}
|
|
|
|
|
2011-05-27 15:00:12 +08:00
|
|
|
if (pd)
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(pd);
|
2011-05-27 15:00:12 +08:00
|
|
|
if (scq)
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&scq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2011-05-26 23:17:04 +08:00
|
|
|
if (rcq && rcq != scq)
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&rcq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (srq)
|
2020-01-09 01:22:00 +08:00
|
|
|
rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2016-05-23 20:20:55 +08:00
|
|
|
if (ind_tbl)
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(ind_tbl);
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
|
|
|
|
|
|
|
|
resp.base.qpn = qp->qp_num;
|
|
|
|
resp.base.qp_handle = obj->uevent.uobject.id;
|
|
|
|
resp.base.max_recv_sge = attr.cap.max_recv_sge;
|
|
|
|
resp.base.max_send_sge = attr.cap.max_send_sge;
|
|
|
|
resp.base.max_recv_wr = attr.cap.max_recv_wr;
|
|
|
|
resp.base.max_send_wr = attr.cap.max_send_wr;
|
|
|
|
resp.base.max_inline_data = attr.cap.max_inline_data;
|
|
|
|
resp.response_length = uverbs_response_length(attrs, sizeof(resp));
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
|
|
|
|
err_put:
|
2017-04-04 18:31:44 +08:00
|
|
|
if (!IS_ERR(xrcd_uobj))
|
|
|
|
uobj_put_read(xrcd_uobj);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (pd)
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(pd);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (scq)
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&scq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2006-07-24 06:16:04 +08:00
|
|
|
if (rcq && rcq != scq)
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&rcq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (srq)
|
2020-01-09 01:22:00 +08:00
|
|
|
rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2016-05-23 20:20:55 +08:00
|
|
|
if (ind_tbl)
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(ind_tbl);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(&obj->uevent.uobject, attrs);
|
2005-07-08 08:57:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_create_qp(struct uverbs_attr_bundle *attrs)
|
2015-10-21 22:00:42 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_create_qp cmd;
|
|
|
|
struct ib_uverbs_ex_create_qp cmd_ex;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2015-10-21 22:00:42 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-10-21 22:00:42 +08:00
|
|
|
|
|
|
|
memset(&cmd_ex, 0, sizeof(cmd_ex));
|
|
|
|
cmd_ex.user_handle = cmd.user_handle;
|
|
|
|
cmd_ex.pd_handle = cmd.pd_handle;
|
|
|
|
cmd_ex.send_cq_handle = cmd.send_cq_handle;
|
|
|
|
cmd_ex.recv_cq_handle = cmd.recv_cq_handle;
|
|
|
|
cmd_ex.srq_handle = cmd.srq_handle;
|
|
|
|
cmd_ex.max_send_wr = cmd.max_send_wr;
|
|
|
|
cmd_ex.max_recv_wr = cmd.max_recv_wr;
|
|
|
|
cmd_ex.max_send_sge = cmd.max_send_sge;
|
|
|
|
cmd_ex.max_recv_sge = cmd.max_recv_sge;
|
|
|
|
cmd_ex.max_inline_data = cmd.max_inline_data;
|
|
|
|
cmd_ex.sq_sig_all = cmd.sq_sig_all;
|
|
|
|
cmd_ex.qp_type = cmd.qp_type;
|
|
|
|
cmd_ex.is_srq = cmd.is_srq;
|
|
|
|
|
2018-11-26 02:58:44 +08:00
|
|
|
return create_qp(attrs, &cmd_ex);
|
2015-10-21 22:00:42 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_create_qp(struct uverbs_attr_bundle *attrs)
|
2015-10-21 22:00:42 +08:00
|
|
|
{
|
2018-11-26 02:58:39 +08:00
|
|
|
struct ib_uverbs_ex_create_qp cmd;
|
|
|
|
int ret;
|
2015-10-21 22:00:42 +08:00
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-10-21 22:00:42 +08:00
|
|
|
|
2016-05-23 20:20:55 +08:00
|
|
|
if (cmd.comp_mask & ~IB_UVERBS_CREATE_QP_SUP_COMP_MASK)
|
2015-10-21 22:00:42 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (cmd.reserved)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-11-26 02:58:44 +08:00
|
|
|
return create_qp(attrs, &cmd);
|
2015-10-21 22:00:42 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_open_qp(struct uverbs_attr_bundle *attrs)
|
2011-08-12 04:57:43 +08:00
|
|
|
{
|
2020-07-19 13:22:23 +08:00
|
|
|
struct ib_uverbs_create_qp_resp resp = {};
|
2011-08-12 04:57:43 +08:00
|
|
|
struct ib_uverbs_open_qp cmd;
|
|
|
|
struct ib_uqp_object *obj;
|
|
|
|
struct ib_xrcd *xrcd;
|
|
|
|
struct ib_qp *qp;
|
2020-01-09 01:22:02 +08:00
|
|
|
struct ib_qp_open_attr attr = {};
|
2011-08-12 04:57:43 +08:00
|
|
|
int ret;
|
2020-07-21 01:56:26 +08:00
|
|
|
struct ib_uobject *xrcd_uobj;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2011-08-12 04:57:43 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2011-08-12 04:57:43 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
obj = (struct ib_uqp_object *)uobj_alloc(UVERBS_OBJECT_QP, attrs,
|
2018-07-26 11:40:17 +08:00
|
|
|
&ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(obj))
|
|
|
|
return PTR_ERR(obj);
|
2011-08-12 04:57:43 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
xrcd_uobj = uobj_get_read(UVERBS_OBJECT_XRCD, cmd.pd_handle, attrs);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(xrcd_uobj)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
2011-08-12 04:57:43 +08:00
|
|
|
|
2017-04-04 18:31:44 +08:00
|
|
|
xrcd = (struct ib_xrcd *)xrcd_uobj->object;
|
2011-08-12 04:57:43 +08:00
|
|
|
if (!xrcd) {
|
|
|
|
ret = -EINVAL;
|
2017-04-04 18:31:44 +08:00
|
|
|
goto err_xrcd;
|
2011-08-12 04:57:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
attr.event_handler = ib_uverbs_qp_event_handler;
|
|
|
|
attr.qp_num = cmd.qpn;
|
|
|
|
attr.qp_type = cmd.qp_type;
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&obj->uevent.event_list);
|
|
|
|
INIT_LIST_HEAD(&obj->mcast_list);
|
|
|
|
|
|
|
|
qp = ib_open_qp(xrcd, &attr);
|
|
|
|
if (IS_ERR(qp)) {
|
|
|
|
ret = PTR_ERR(qp);
|
2017-04-04 18:31:44 +08:00
|
|
|
goto err_xrcd;
|
2011-08-12 04:57:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
obj->uevent.uobject.object = qp;
|
2017-04-04 18:31:44 +08:00
|
|
|
obj->uevent.uobject.user_handle = cmd.user_handle;
|
2011-08-12 04:57:43 +08:00
|
|
|
|
2013-08-01 23:49:54 +08:00
|
|
|
obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object, uobject);
|
|
|
|
atomic_inc(&obj->uxrcd->refcnt);
|
2020-01-09 01:21:59 +08:00
|
|
|
qp->uobject = obj;
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_read(xrcd_uobj);
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
|
2011-08-12 04:57:43 +08:00
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
resp.qpn = qp->qp_num;
|
|
|
|
resp.qp_handle = obj->uevent.uobject.id;
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2011-08-12 04:57:43 +08:00
|
|
|
|
2017-04-04 18:31:44 +08:00
|
|
|
err_xrcd:
|
|
|
|
uobj_put_read(xrcd_uobj);
|
2011-08-12 04:57:43 +08:00
|
|
|
err_put:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(&obj->uevent.uobject, attrs);
|
2011-08-12 04:57:43 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-17 20:50:33 +08:00
|
|
|
static void copy_ah_attr_to_uverbs(struct ib_uverbs_qp_dest *uverb_attr,
|
|
|
|
struct rdma_ah_attr *rdma_attr)
|
|
|
|
{
|
|
|
|
const struct ib_global_route *grh;
|
|
|
|
|
|
|
|
uverb_attr->dlid = rdma_ah_get_dlid(rdma_attr);
|
|
|
|
uverb_attr->sl = rdma_ah_get_sl(rdma_attr);
|
|
|
|
uverb_attr->src_path_bits = rdma_ah_get_path_bits(rdma_attr);
|
|
|
|
uverb_attr->static_rate = rdma_ah_get_static_rate(rdma_attr);
|
|
|
|
uverb_attr->is_global = !!(rdma_ah_get_ah_flags(rdma_attr) &
|
|
|
|
IB_AH_GRH);
|
|
|
|
if (uverb_attr->is_global) {
|
|
|
|
grh = rdma_ah_read_grh(rdma_attr);
|
|
|
|
memcpy(uverb_attr->dgid, grh->dgid.raw, 16);
|
|
|
|
uverb_attr->flow_label = grh->flow_label;
|
|
|
|
uverb_attr->sgid_index = grh->sgid_index;
|
|
|
|
uverb_attr->hop_limit = grh->hop_limit;
|
|
|
|
uverb_attr->traffic_class = grh->traffic_class;
|
|
|
|
}
|
|
|
|
uverb_attr->port_num = rdma_ah_get_port_num(rdma_attr);
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_query_qp(struct uverbs_attr_bundle *attrs)
|
2006-02-14 08:31:25 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_query_qp cmd;
|
|
|
|
struct ib_uverbs_query_qp_resp resp;
|
|
|
|
struct ib_qp *qp;
|
|
|
|
struct ib_qp_attr *attr;
|
|
|
|
struct ib_qp_init_attr *init_attr;
|
|
|
|
int ret;
|
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2006-02-14 08:31:25 +08:00
|
|
|
|
|
|
|
attr = kmalloc(sizeof *attr, GFP_KERNEL);
|
|
|
|
init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL);
|
|
|
|
if (!attr || !init_attr) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (!qp) {
|
2006-02-14 08:31:25 +08:00
|
|
|
ret = -EINVAL;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
|
2006-02-14 08:31:25 +08:00
|
|
|
|
2020-01-09 01:21:59 +08:00
|
|
|
rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2006-02-14 08:31:25 +08:00
|
|
|
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
memset(&resp, 0, sizeof resp);
|
|
|
|
|
|
|
|
resp.qp_state = attr->qp_state;
|
|
|
|
resp.cur_qp_state = attr->cur_qp_state;
|
|
|
|
resp.path_mtu = attr->path_mtu;
|
|
|
|
resp.path_mig_state = attr->path_mig_state;
|
|
|
|
resp.qkey = attr->qkey;
|
|
|
|
resp.rq_psn = attr->rq_psn;
|
|
|
|
resp.sq_psn = attr->sq_psn;
|
|
|
|
resp.dest_qp_num = attr->dest_qp_num;
|
|
|
|
resp.qp_access_flags = attr->qp_access_flags;
|
|
|
|
resp.pkey_index = attr->pkey_index;
|
|
|
|
resp.alt_pkey_index = attr->alt_pkey_index;
|
2006-10-25 18:54:20 +08:00
|
|
|
resp.sq_draining = attr->sq_draining;
|
2006-02-14 08:31:25 +08:00
|
|
|
resp.max_rd_atomic = attr->max_rd_atomic;
|
|
|
|
resp.max_dest_rd_atomic = attr->max_dest_rd_atomic;
|
|
|
|
resp.min_rnr_timer = attr->min_rnr_timer;
|
|
|
|
resp.port_num = attr->port_num;
|
|
|
|
resp.timeout = attr->timeout;
|
|
|
|
resp.retry_cnt = attr->retry_cnt;
|
|
|
|
resp.rnr_retry = attr->rnr_retry;
|
|
|
|
resp.alt_port_num = attr->alt_port_num;
|
|
|
|
resp.alt_timeout = attr->alt_timeout;
|
|
|
|
|
2017-08-17 20:50:33 +08:00
|
|
|
copy_ah_attr_to_uverbs(&resp.dest, &attr->ah_attr);
|
|
|
|
copy_ah_attr_to_uverbs(&resp.alt_dest, &attr->alt_ah_attr);
|
2006-02-14 08:31:25 +08:00
|
|
|
|
|
|
|
resp.max_send_wr = init_attr->cap.max_send_wr;
|
|
|
|
resp.max_recv_wr = init_attr->cap.max_recv_wr;
|
|
|
|
resp.max_send_sge = init_attr->cap.max_send_sge;
|
|
|
|
resp.max_recv_sge = init_attr->cap.max_recv_sge;
|
|
|
|
resp.max_inline_data = init_attr->cap.max_inline_data;
|
2006-03-03 03:25:27 +08:00
|
|
|
resp.sq_sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
|
2006-02-14 08:31:25 +08:00
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
ret = uverbs_response(attrs, &resp, sizeof(resp));
|
2006-02-14 08:31:25 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
kfree(attr);
|
|
|
|
kfree(init_attr);
|
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return ret;
|
2006-02-14 08:31:25 +08:00
|
|
|
}
|
|
|
|
|
2011-05-26 23:17:04 +08:00
|
|
|
/* Remove ignored fields set in the attribute mask */
|
|
|
|
static int modify_qp_mask(enum ib_qp_type qp_type, int mask)
|
|
|
|
{
|
|
|
|
switch (qp_type) {
|
|
|
|
case IB_QPT_XRC_INI:
|
|
|
|
return mask & ~(IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_MIN_RNR_TIMER);
|
2011-05-27 15:00:12 +08:00
|
|
|
case IB_QPT_XRC_TGT:
|
|
|
|
return mask & ~(IB_QP_MAX_QP_RD_ATOMIC | IB_QP_RETRY_CNT |
|
|
|
|
IB_QP_RNR_RETRY);
|
2011-05-26 23:17:04 +08:00
|
|
|
default:
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-17 20:50:33 +08:00
|
|
|
static void copy_ah_attr_from_uverbs(struct ib_device *dev,
|
|
|
|
struct rdma_ah_attr *rdma_attr,
|
|
|
|
struct ib_uverbs_qp_dest *uverb_attr)
|
|
|
|
{
|
|
|
|
rdma_attr->type = rdma_ah_find_type(dev, uverb_attr->port_num);
|
|
|
|
if (uverb_attr->is_global) {
|
|
|
|
rdma_ah_set_grh(rdma_attr, NULL,
|
|
|
|
uverb_attr->flow_label,
|
|
|
|
uverb_attr->sgid_index,
|
|
|
|
uverb_attr->hop_limit,
|
|
|
|
uverb_attr->traffic_class);
|
|
|
|
rdma_ah_set_dgid_raw(rdma_attr, uverb_attr->dgid);
|
|
|
|
} else {
|
|
|
|
rdma_ah_set_ah_flags(rdma_attr, 0);
|
|
|
|
}
|
|
|
|
rdma_ah_set_dlid(rdma_attr, uverb_attr->dlid);
|
|
|
|
rdma_ah_set_sl(rdma_attr, uverb_attr->sl);
|
|
|
|
rdma_ah_set_path_bits(rdma_attr, uverb_attr->src_path_bits);
|
|
|
|
rdma_ah_set_static_rate(rdma_attr, uverb_attr->static_rate);
|
|
|
|
rdma_ah_set_port_num(rdma_attr, uverb_attr->port_num);
|
|
|
|
rdma_ah_set_make_grd(rdma_attr, false);
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
static int modify_qp(struct uverbs_attr_bundle *attrs,
|
2018-11-26 02:51:18 +08:00
|
|
|
struct ib_uverbs_ex_modify_qp *cmd)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
2016-12-01 19:43:15 +08:00
|
|
|
struct ib_qp_attr *attr;
|
|
|
|
struct ib_qp *qp;
|
|
|
|
int ret;
|
2006-08-12 05:58:09 +08:00
|
|
|
|
2018-06-13 15:22:02 +08:00
|
|
|
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
|
2005-07-08 08:57:13 +08:00
|
|
|
if (!attr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd->base.qp_handle,
|
|
|
|
attrs);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (!qp) {
|
2005-07-08 08:57:13 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-07-14 22:41:30 +08:00
|
|
|
if ((cmd->base.attr_mask & IB_QP_PORT) &&
|
|
|
|
!rdma_is_port_valid(qp->device, cmd->base.port_num)) {
|
2017-06-27 20:09:13 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto release_qp;
|
|
|
|
}
|
|
|
|
|
2018-07-11 16:23:52 +08:00
|
|
|
if ((cmd->base.attr_mask & IB_QP_AV)) {
|
|
|
|
if (!rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto release_qp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd->base.attr_mask & IB_QP_STATE &&
|
|
|
|
cmd->base.qp_state == IB_QPS_RTR) {
|
|
|
|
/* We are in INIT->RTR TRANSITION (if we are not,
|
|
|
|
* this transition will be rejected in subsequent checks).
|
|
|
|
* In the INIT->RTR transition, we cannot have IB_QP_PORT set,
|
|
|
|
* but the IB_QP_STATE flag is required.
|
|
|
|
*
|
|
|
|
* Since kernel 3.14 (commit dbf727de7440), the uverbs driver,
|
|
|
|
* when IB_QP_AV is set, has required inclusion of a valid
|
|
|
|
* port number in the primary AV. (AVs are created and handled
|
|
|
|
* differently for infiniband and ethernet (RoCE) ports).
|
|
|
|
*
|
|
|
|
* Check the port number included in the primary AV against
|
|
|
|
* the port number in the qp struct, which was set (and saved)
|
|
|
|
* in the RST->INIT transition.
|
|
|
|
*/
|
|
|
|
if (cmd->base.dest.port_num != qp->real_qp->port) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto release_qp;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* We are in SQD->SQD. (If we are not, this transition will
|
|
|
|
* be rejected later in the verbs layer checks).
|
|
|
|
* Check for both IB_QP_PORT and IB_QP_AV, these can be set
|
|
|
|
* together in the SQD->SQD transition.
|
|
|
|
*
|
|
|
|
* If only IP_QP_AV was set, add in IB_QP_PORT as well (the
|
|
|
|
* verbs layer driver does not track primary port changes
|
|
|
|
* resulting from path migration. Thus, in SQD, if the primary
|
|
|
|
* AV is modified, the primary port should also be modified).
|
|
|
|
*
|
|
|
|
* Note that in this transition, the IB_QP_STATE flag
|
|
|
|
* is not allowed.
|
|
|
|
*/
|
|
|
|
if (((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT))
|
|
|
|
== (IB_QP_AV | IB_QP_PORT)) &&
|
|
|
|
cmd->base.port_num != cmd->base.dest.port_num) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto release_qp;
|
|
|
|
}
|
|
|
|
if ((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT))
|
|
|
|
== IB_QP_AV) {
|
|
|
|
cmd->base.attr_mask |= IB_QP_PORT;
|
|
|
|
cmd->base.port_num = cmd->base.dest.port_num;
|
|
|
|
}
|
|
|
|
}
|
2018-02-14 18:35:40 +08:00
|
|
|
}
|
|
|
|
|
2017-12-06 04:30:01 +08:00
|
|
|
if ((cmd->base.attr_mask & IB_QP_ALT_PATH) &&
|
2018-02-14 18:35:40 +08:00
|
|
|
(!rdma_is_port_valid(qp->device, cmd->base.alt_port_num) ||
|
2018-07-11 16:23:52 +08:00
|
|
|
!rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num) ||
|
|
|
|
cmd->base.alt_port_num != cmd->base.alt_dest.port_num)) {
|
2017-12-06 04:30:01 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto release_qp;
|
|
|
|
}
|
|
|
|
|
2018-03-11 19:51:33 +08:00
|
|
|
if ((cmd->base.attr_mask & IB_QP_CUR_STATE &&
|
|
|
|
cmd->base.cur_qp_state > IB_QPS_ERR) ||
|
2018-09-18 15:51:37 +08:00
|
|
|
(cmd->base.attr_mask & IB_QP_STATE &&
|
|
|
|
cmd->base.qp_state > IB_QPS_ERR)) {
|
2018-03-11 19:51:33 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto release_qp;
|
|
|
|
}
|
|
|
|
|
2018-09-18 15:51:37 +08:00
|
|
|
if (cmd->base.attr_mask & IB_QP_STATE)
|
|
|
|
attr->qp_state = cmd->base.qp_state;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_CUR_STATE)
|
|
|
|
attr->cur_qp_state = cmd->base.cur_qp_state;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_PATH_MTU)
|
|
|
|
attr->path_mtu = cmd->base.path_mtu;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_PATH_MIG_STATE)
|
|
|
|
attr->path_mig_state = cmd->base.path_mig_state;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_QKEY)
|
|
|
|
attr->qkey = cmd->base.qkey;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_RQ_PSN)
|
|
|
|
attr->rq_psn = cmd->base.rq_psn;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_SQ_PSN)
|
|
|
|
attr->sq_psn = cmd->base.sq_psn;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_DEST_QPN)
|
|
|
|
attr->dest_qp_num = cmd->base.dest_qp_num;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_ACCESS_FLAGS)
|
|
|
|
attr->qp_access_flags = cmd->base.qp_access_flags;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_PKEY_INDEX)
|
|
|
|
attr->pkey_index = cmd->base.pkey_index;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY)
|
|
|
|
attr->en_sqd_async_notify = cmd->base.en_sqd_async_notify;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
|
|
|
|
attr->max_rd_atomic = cmd->base.max_rd_atomic;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
|
|
|
|
attr->max_dest_rd_atomic = cmd->base.max_dest_rd_atomic;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_MIN_RNR_TIMER)
|
|
|
|
attr->min_rnr_timer = cmd->base.min_rnr_timer;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_PORT)
|
|
|
|
attr->port_num = cmd->base.port_num;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_TIMEOUT)
|
|
|
|
attr->timeout = cmd->base.timeout;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_RETRY_CNT)
|
|
|
|
attr->retry_cnt = cmd->base.retry_cnt;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_RNR_RETRY)
|
|
|
|
attr->rnr_retry = cmd->base.rnr_retry;
|
|
|
|
if (cmd->base.attr_mask & IB_QP_ALT_PATH) {
|
|
|
|
attr->alt_port_num = cmd->base.alt_port_num;
|
|
|
|
attr->alt_timeout = cmd->base.alt_timeout;
|
|
|
|
attr->alt_pkey_index = cmd->base.alt_pkey_index;
|
|
|
|
}
|
|
|
|
if (cmd->base.attr_mask & IB_QP_RATE_LIMIT)
|
|
|
|
attr->rate_limit = cmd->rate_limit;
|
2016-12-01 19:43:15 +08:00
|
|
|
|
2017-08-23 13:35:40 +08:00
|
|
|
if (cmd->base.attr_mask & IB_QP_AV)
|
2017-08-17 20:50:33 +08:00
|
|
|
copy_ah_attr_from_uverbs(qp->device, &attr->ah_attr,
|
|
|
|
&cmd->base.dest);
|
2016-12-01 19:43:15 +08:00
|
|
|
|
2017-08-23 13:35:40 +08:00
|
|
|
if (cmd->base.attr_mask & IB_QP_ALT_PATH)
|
2017-08-17 20:50:33 +08:00
|
|
|
copy_ah_attr_from_uverbs(qp->device, &attr->alt_ah_attr,
|
|
|
|
&cmd->base.alt_dest);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2017-05-23 16:26:09 +08:00
|
|
|
ret = ib_modify_qp_with_udata(qp, attr,
|
|
|
|
modify_qp_mask(qp->qp_type,
|
|
|
|
cmd->base.attr_mask),
|
2018-11-26 02:51:18 +08:00
|
|
|
&attrs->driver_udata);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
|
2015-02-05 19:53:52 +08:00
|
|
|
release_qp:
|
2020-01-09 01:21:59 +08:00
|
|
|
rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2005-07-08 08:57:13 +08:00
|
|
|
out:
|
|
|
|
kfree(attr);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_modify_qp(struct uverbs_attr_bundle *attrs)
|
2016-12-01 19:43:15 +08:00
|
|
|
{
|
2018-11-26 02:58:39 +08:00
|
|
|
struct ib_uverbs_ex_modify_qp cmd;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2016-12-01 19:43:15 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd.base, sizeof(cmd.base));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2016-12-01 19:43:15 +08:00
|
|
|
|
2020-10-04 07:20:06 +08:00
|
|
|
if (cmd.base.attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
|
2016-12-01 19:43:15 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2018-11-26 02:51:18 +08:00
|
|
|
return modify_qp(attrs, &cmd);
|
2016-12-01 19:43:15 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_modify_qp(struct uverbs_attr_bundle *attrs)
|
2016-12-01 19:43:15 +08:00
|
|
|
{
|
2018-11-26 02:58:39 +08:00
|
|
|
struct ib_uverbs_ex_modify_qp cmd;
|
2018-11-26 02:58:40 +08:00
|
|
|
struct ib_uverbs_ex_modify_qp_resp resp = {
|
|
|
|
.response_length = uverbs_response_length(attrs, sizeof(resp))
|
|
|
|
};
|
2016-12-01 19:43:15 +08:00
|
|
|
int ret;
|
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2016-12-01 19:43:15 +08:00
|
|
|
/*
|
|
|
|
* Last bit is reserved for extending the attr_mask by
|
|
|
|
* using another field.
|
|
|
|
*/
|
2020-10-04 07:20:06 +08:00
|
|
|
if (cmd.base.attr_mask & ~(IB_QP_ATTR_STANDARD_BITS | IB_QP_RATE_LIMIT))
|
2016-12-01 19:43:15 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2018-11-26 02:58:40 +08:00
|
|
|
ret = modify_qp(attrs, &cmd);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2016-12-01 19:43:15 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_destroy_qp(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
2005-09-10 06:55:08 +08:00
|
|
|
struct ib_uverbs_destroy_qp cmd;
|
|
|
|
struct ib_uverbs_destroy_qp_resp resp;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
struct ib_uobject *uobj;
|
|
|
|
struct ib_uqp_object *obj;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_get_destroy(UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
obj = container_of(uobj, struct ib_uqp_object, uevent.uobject);
|
2018-07-26 11:40:11 +08:00
|
|
|
memset(&resp, 0, sizeof(resp));
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
resp.events_reported = obj->uevent.events_reported;
|
2018-07-26 11:40:11 +08:00
|
|
|
|
|
|
|
uobj_put_destroy(uobj);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
2015-10-08 16:16:33 +08:00
|
|
|
static void *alloc_wr(size_t wr_size, __u32 num_sge)
|
|
|
|
{
|
2021-04-07 16:15:50 +08:00
|
|
|
if (num_sge >= (U32_MAX - ALIGN(wr_size, sizeof(struct ib_sge))) /
|
|
|
|
sizeof(struct ib_sge))
|
2017-03-25 03:55:17 +08:00
|
|
|
return NULL;
|
|
|
|
|
2021-04-07 16:15:50 +08:00
|
|
|
return kmalloc(ALIGN(wr_size, sizeof(struct ib_sge)) +
|
|
|
|
num_sge * sizeof(struct ib_sge),
|
|
|
|
GFP_KERNEL);
|
2017-03-25 03:55:17 +08:00
|
|
|
}
|
2015-10-08 16:16:33 +08:00
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs)
|
2005-10-15 06:26:04 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_post_send cmd;
|
|
|
|
struct ib_uverbs_post_send_resp resp;
|
|
|
|
struct ib_uverbs_send_wr *user_wr;
|
2018-07-19 00:25:32 +08:00
|
|
|
struct ib_send_wr *wr = NULL, *last, *next;
|
|
|
|
const struct ib_send_wr *bad_wr;
|
2005-10-15 06:26:04 +08:00
|
|
|
struct ib_qp *qp;
|
|
|
|
int i, sg_ind;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
int is_ud;
|
2018-11-26 02:58:37 +08:00
|
|
|
int ret, ret2;
|
2015-12-01 23:13:51 +08:00
|
|
|
size_t next_size;
|
2018-11-26 02:58:43 +08:00
|
|
|
const struct ib_sge __user *sgls;
|
|
|
|
const void __user *wqes;
|
|
|
|
struct uverbs_req_iter iter;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:43 +08:00
|
|
|
ret = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
wqes = uverbs_request_next_ptr(&iter, cmd.wqe_size * cmd.wr_count);
|
|
|
|
if (IS_ERR(wqes))
|
|
|
|
return PTR_ERR(wqes);
|
|
|
|
sgls = uverbs_request_next_ptr(
|
|
|
|
&iter, cmd.sge_count * sizeof(struct ib_uverbs_sge));
|
|
|
|
if (IS_ERR(sgls))
|
|
|
|
return PTR_ERR(sgls);
|
|
|
|
ret = uverbs_request_finish(&iter);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
|
|
|
user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL);
|
|
|
|
if (!user_wr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
|
2019-01-07 19:36:56 +08:00
|
|
|
if (!qp) {
|
|
|
|
ret = -EINVAL;
|
2005-10-15 06:26:04 +08:00
|
|
|
goto out;
|
2019-01-07 19:36:56 +08:00
|
|
|
}
|
2005-10-15 06:26:04 +08:00
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
is_ud = qp->qp_type == IB_QPT_UD;
|
2005-10-15 06:26:04 +08:00
|
|
|
sg_ind = 0;
|
|
|
|
last = NULL;
|
|
|
|
for (i = 0; i < cmd.wr_count; ++i) {
|
2018-11-26 02:58:43 +08:00
|
|
|
if (copy_from_user(user_wr, wqes + i * cmd.wqe_size,
|
2005-10-15 06:26:04 +08:00
|
|
|
cmd.wqe_size)) {
|
|
|
|
ret = -EFAULT;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto out_put;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (user_wr->num_sge + sg_ind > cmd.sge_count) {
|
|
|
|
ret = -EINVAL;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto out_put;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2015-10-08 16:16:33 +08:00
|
|
|
if (is_ud) {
|
|
|
|
struct ib_ud_wr *ud;
|
|
|
|
|
|
|
|
if (user_wr->opcode != IB_WR_SEND &&
|
|
|
|
user_wr->opcode != IB_WR_SEND_WITH_IMM) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
|
2015-12-01 23:13:51 +08:00
|
|
|
next_size = sizeof(*ud);
|
|
|
|
ud = alloc_wr(next_size, user_wr->num_sge);
|
2015-10-08 16:16:33 +08:00
|
|
|
if (!ud) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
|
2018-07-04 16:32:09 +08:00
|
|
|
ud->ah = uobj_get_obj_read(ah, UVERBS_OBJECT_AH,
|
2018-11-26 02:51:13 +08:00
|
|
|
user_wr->wr.ud.ah, attrs);
|
2015-10-08 16:16:33 +08:00
|
|
|
if (!ud->ah) {
|
|
|
|
kfree(ud);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
ud->remote_qpn = user_wr->wr.ud.remote_qpn;
|
|
|
|
ud->remote_qkey = user_wr->wr.ud.remote_qkey;
|
|
|
|
|
|
|
|
next = &ud->wr;
|
|
|
|
} else if (user_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
|
|
|
|
user_wr->opcode == IB_WR_RDMA_WRITE ||
|
|
|
|
user_wr->opcode == IB_WR_RDMA_READ) {
|
|
|
|
struct ib_rdma_wr *rdma;
|
|
|
|
|
2015-12-01 23:13:51 +08:00
|
|
|
next_size = sizeof(*rdma);
|
|
|
|
rdma = alloc_wr(next_size, user_wr->num_sge);
|
2015-10-08 16:16:33 +08:00
|
|
|
if (!rdma) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
rdma->remote_addr = user_wr->wr.rdma.remote_addr;
|
|
|
|
rdma->rkey = user_wr->wr.rdma.rkey;
|
|
|
|
|
|
|
|
next = &rdma->wr;
|
|
|
|
} else if (user_wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
|
|
|
|
user_wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
|
|
|
|
struct ib_atomic_wr *atomic;
|
|
|
|
|
2015-12-01 23:13:51 +08:00
|
|
|
next_size = sizeof(*atomic);
|
|
|
|
atomic = alloc_wr(next_size, user_wr->num_sge);
|
2015-10-08 16:16:33 +08:00
|
|
|
if (!atomic) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic->remote_addr = user_wr->wr.atomic.remote_addr;
|
|
|
|
atomic->compare_add = user_wr->wr.atomic.compare_add;
|
|
|
|
atomic->swap = user_wr->wr.atomic.swap;
|
|
|
|
atomic->rkey = user_wr->wr.atomic.rkey;
|
|
|
|
|
|
|
|
next = &atomic->wr;
|
|
|
|
} else if (user_wr->opcode == IB_WR_SEND ||
|
|
|
|
user_wr->opcode == IB_WR_SEND_WITH_IMM ||
|
|
|
|
user_wr->opcode == IB_WR_SEND_WITH_INV) {
|
2015-12-01 23:13:51 +08:00
|
|
|
next_size = sizeof(*next);
|
|
|
|
next = alloc_wr(next_size, user_wr->num_sge);
|
2015-10-08 16:16:33 +08:00
|
|
|
if (!next) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = -EINVAL;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto out_put;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2015-10-08 16:16:33 +08:00
|
|
|
if (user_wr->opcode == IB_WR_SEND_WITH_IMM ||
|
|
|
|
user_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
|
|
|
|
next->ex.imm_data =
|
|
|
|
(__be32 __force) user_wr->ex.imm_data;
|
|
|
|
} else if (user_wr->opcode == IB_WR_SEND_WITH_INV) {
|
|
|
|
next->ex.invalidate_rkey = user_wr->ex.invalidate_rkey;
|
|
|
|
}
|
|
|
|
|
2005-10-15 06:26:04 +08:00
|
|
|
if (!last)
|
|
|
|
wr = next;
|
|
|
|
else
|
|
|
|
last->next = next;
|
|
|
|
last = next;
|
|
|
|
|
|
|
|
next->next = NULL;
|
|
|
|
next->wr_id = user_wr->wr_id;
|
|
|
|
next->num_sge = user_wr->num_sge;
|
|
|
|
next->opcode = user_wr->opcode;
|
|
|
|
next->send_flags = user_wr->send_flags;
|
|
|
|
|
|
|
|
if (next->num_sge) {
|
|
|
|
next->sg_list = (void *) next +
|
2015-12-01 23:13:51 +08:00
|
|
|
ALIGN(next_size, sizeof(struct ib_sge));
|
2018-11-26 02:58:43 +08:00
|
|
|
if (copy_from_user(next->sg_list, sgls + sg_ind,
|
|
|
|
next->num_sge *
|
|
|
|
sizeof(struct ib_sge))) {
|
2005-10-15 06:26:04 +08:00
|
|
|
ret = -EFAULT;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto out_put;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
sg_ind += next->num_sge;
|
|
|
|
} else
|
|
|
|
next->sg_list = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp.bad_wr = 0;
|
2018-12-11 03:09:48 +08:00
|
|
|
ret = qp->device->ops.post_send(qp->real_qp, wr, &bad_wr);
|
2005-10-15 06:26:04 +08:00
|
|
|
if (ret)
|
|
|
|
for (next = wr; next; next = next->next) {
|
|
|
|
++resp.bad_wr;
|
|
|
|
if (next == bad_wr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
ret2 = uverbs_response(attrs, &resp, sizeof(resp));
|
|
|
|
if (ret2)
|
|
|
|
ret = ret2;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
out_put:
|
2020-01-09 01:21:59 +08:00
|
|
|
rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2005-10-15 06:26:04 +08:00
|
|
|
|
|
|
|
while (wr) {
|
2015-10-08 16:16:33 +08:00
|
|
|
if (is_ud && ud_wr(wr)->ah)
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(ud_wr(wr)->ah);
|
2005-10-15 06:26:04 +08:00
|
|
|
next = wr->next;
|
|
|
|
kfree(wr);
|
|
|
|
wr = next;
|
|
|
|
}
|
|
|
|
|
2006-06-22 22:47:27 +08:00
|
|
|
out:
|
2005-10-15 06:26:04 +08:00
|
|
|
kfree(user_wr);
|
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:43 +08:00
|
|
|
static struct ib_recv_wr *
|
|
|
|
ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count,
|
|
|
|
u32 wqe_size, u32 sge_count)
|
2005-10-15 06:26:04 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_recv_wr *user_wr;
|
|
|
|
struct ib_recv_wr *wr = NULL, *last, *next;
|
|
|
|
int sg_ind;
|
|
|
|
int i;
|
|
|
|
int ret;
|
2018-11-26 02:58:43 +08:00
|
|
|
const struct ib_sge __user *sgls;
|
|
|
|
const void __user *wqes;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2021-04-07 16:15:50 +08:00
|
|
|
if (wqe_size < sizeof(struct ib_uverbs_recv_wr))
|
2005-10-15 06:26:04 +08:00
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
2018-11-26 02:58:43 +08:00
|
|
|
wqes = uverbs_request_next_ptr(iter, wqe_size * wr_count);
|
|
|
|
if (IS_ERR(wqes))
|
|
|
|
return ERR_CAST(wqes);
|
|
|
|
sgls = uverbs_request_next_ptr(
|
|
|
|
iter, sge_count * sizeof(struct ib_uverbs_sge));
|
|
|
|
if (IS_ERR(sgls))
|
|
|
|
return ERR_CAST(sgls);
|
|
|
|
ret = uverbs_request_finish(iter);
|
|
|
|
if (ret)
|
|
|
|
return ERR_PTR(ret);
|
|
|
|
|
2005-10-15 06:26:04 +08:00
|
|
|
user_wr = kmalloc(wqe_size, GFP_KERNEL);
|
|
|
|
if (!user_wr)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
sg_ind = 0;
|
|
|
|
last = NULL;
|
|
|
|
for (i = 0; i < wr_count; ++i) {
|
2018-11-26 02:58:43 +08:00
|
|
|
if (copy_from_user(user_wr, wqes + i * wqe_size,
|
2005-10-15 06:26:04 +08:00
|
|
|
wqe_size)) {
|
|
|
|
ret = -EFAULT;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user_wr->num_sge + sg_ind > sge_count) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2017-03-25 03:55:17 +08:00
|
|
|
if (user_wr->num_sge >=
|
2021-04-07 16:15:50 +08:00
|
|
|
(U32_MAX - ALIGN(sizeof(*next), sizeof(struct ib_sge))) /
|
|
|
|
sizeof(struct ib_sge)) {
|
2017-03-25 03:55:17 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2021-04-07 16:15:50 +08:00
|
|
|
next = kmalloc(ALIGN(sizeof(*next), sizeof(struct ib_sge)) +
|
|
|
|
user_wr->num_sge * sizeof(struct ib_sge),
|
2005-10-15 06:26:04 +08:00
|
|
|
GFP_KERNEL);
|
|
|
|
if (!next) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!last)
|
|
|
|
wr = next;
|
|
|
|
else
|
|
|
|
last->next = next;
|
|
|
|
last = next;
|
|
|
|
|
|
|
|
next->next = NULL;
|
|
|
|
next->wr_id = user_wr->wr_id;
|
|
|
|
next->num_sge = user_wr->num_sge;
|
|
|
|
|
|
|
|
if (next->num_sge) {
|
2021-04-07 16:15:50 +08:00
|
|
|
next->sg_list = (void *)next +
|
|
|
|
ALIGN(sizeof(*next), sizeof(struct ib_sge));
|
2018-11-26 02:58:43 +08:00
|
|
|
if (copy_from_user(next->sg_list, sgls + sg_ind,
|
|
|
|
next->num_sge *
|
|
|
|
sizeof(struct ib_sge))) {
|
2005-10-15 06:26:04 +08:00
|
|
|
ret = -EFAULT;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
sg_ind += next->num_sge;
|
|
|
|
} else
|
|
|
|
next->sg_list = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(user_wr);
|
|
|
|
return wr;
|
|
|
|
|
|
|
|
err:
|
|
|
|
kfree(user_wr);
|
|
|
|
|
|
|
|
while (wr) {
|
|
|
|
next = wr->next;
|
|
|
|
kfree(wr);
|
|
|
|
wr = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERR_PTR(ret);
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_post_recv(struct uverbs_attr_bundle *attrs)
|
2005-10-15 06:26:04 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_post_recv cmd;
|
|
|
|
struct ib_uverbs_post_recv_resp resp;
|
2018-07-19 00:25:32 +08:00
|
|
|
struct ib_recv_wr *wr, *next;
|
|
|
|
const struct ib_recv_wr *bad_wr;
|
2005-10-15 06:26:04 +08:00
|
|
|
struct ib_qp *qp;
|
2018-11-26 02:58:37 +08:00
|
|
|
int ret, ret2;
|
2018-11-26 02:58:43 +08:00
|
|
|
struct uverbs_req_iter iter;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:43 +08:00
|
|
|
ret = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:43 +08:00
|
|
|
wr = ib_uverbs_unmarshall_recv(&iter, cmd.wr_count, cmd.wqe_size,
|
|
|
|
cmd.sge_count);
|
2005-10-15 06:26:04 +08:00
|
|
|
if (IS_ERR(wr))
|
|
|
|
return PTR_ERR(wr);
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
|
2018-11-26 02:58:37 +08:00
|
|
|
if (!qp) {
|
|
|
|
ret = -EINVAL;
|
2005-10-15 06:26:04 +08:00
|
|
|
goto out;
|
2018-11-26 02:58:37 +08:00
|
|
|
}
|
2005-10-15 06:26:04 +08:00
|
|
|
|
|
|
|
resp.bad_wr = 0;
|
2018-12-11 03:09:48 +08:00
|
|
|
ret = qp->device->ops.post_recv(qp->real_qp, wr, &bad_wr);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
|
2020-01-09 01:21:59 +08:00
|
|
|
rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (ret) {
|
2005-10-15 06:26:04 +08:00
|
|
|
for (next = wr; next; next = next->next) {
|
|
|
|
++resp.bad_wr;
|
|
|
|
if (next == bad_wr)
|
|
|
|
break;
|
|
|
|
}
|
2017-04-04 18:31:44 +08:00
|
|
|
}
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
ret2 = uverbs_response(attrs, &resp, sizeof(resp));
|
|
|
|
if (ret2)
|
|
|
|
ret = ret2;
|
2005-10-15 06:26:04 +08:00
|
|
|
out:
|
|
|
|
while (wr) {
|
|
|
|
next = wr->next;
|
|
|
|
kfree(wr);
|
|
|
|
wr = next;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_post_srq_recv(struct uverbs_attr_bundle *attrs)
|
2005-10-15 06:26:04 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_post_srq_recv cmd;
|
|
|
|
struct ib_uverbs_post_srq_recv_resp resp;
|
2018-07-19 00:25:32 +08:00
|
|
|
struct ib_recv_wr *wr, *next;
|
|
|
|
const struct ib_recv_wr *bad_wr;
|
2005-10-15 06:26:04 +08:00
|
|
|
struct ib_srq *srq;
|
2018-11-26 02:58:37 +08:00
|
|
|
int ret, ret2;
|
2018-11-26 02:58:43 +08:00
|
|
|
struct uverbs_req_iter iter;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:43 +08:00
|
|
|
ret = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:43 +08:00
|
|
|
wr = ib_uverbs_unmarshall_recv(&iter, cmd.wr_count, cmd.wqe_size,
|
|
|
|
cmd.sge_count);
|
2005-10-15 06:26:04 +08:00
|
|
|
if (IS_ERR(wr))
|
|
|
|
return PTR_ERR(wr);
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
|
2018-11-26 02:58:37 +08:00
|
|
|
if (!srq) {
|
|
|
|
ret = -EINVAL;
|
2005-10-15 06:26:04 +08:00
|
|
|
goto out;
|
2018-11-26 02:58:37 +08:00
|
|
|
}
|
2005-10-15 06:26:04 +08:00
|
|
|
|
|
|
|
resp.bad_wr = 0;
|
2018-12-11 03:09:48 +08:00
|
|
|
ret = srq->device->ops.post_srq_recv(srq, wr, &bad_wr);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
|
2020-01-09 01:22:00 +08:00
|
|
|
rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
|
2005-10-15 06:26:04 +08:00
|
|
|
if (ret)
|
|
|
|
for (next = wr; next; next = next->next) {
|
|
|
|
++resp.bad_wr;
|
|
|
|
if (next == bad_wr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
ret2 = uverbs_response(attrs, &resp, sizeof(resp));
|
|
|
|
if (ret2)
|
|
|
|
ret = ret2;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
while (wr) {
|
|
|
|
next = wr->next;
|
|
|
|
kfree(wr);
|
|
|
|
wr = next;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_create_ah(struct uverbs_attr_bundle *attrs)
|
2005-10-15 06:26:04 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_create_ah cmd;
|
|
|
|
struct ib_uverbs_create_ah_resp resp;
|
|
|
|
struct ib_uobject *uobj;
|
|
|
|
struct ib_pd *pd;
|
|
|
|
struct ib_ah *ah;
|
2018-06-13 15:22:02 +08:00
|
|
|
struct rdma_ah_attr attr = {};
|
2005-10-15 06:26:04 +08:00
|
|
|
int ret;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_alloc(UVERBS_OBJECT_AH, attrs, &ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-07-26 11:40:17 +08:00
|
|
|
if (!rdma_is_port_valid(ib_dev, cmd.attr.port_num)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (!pd) {
|
2005-10-15 06:26:04 +08:00
|
|
|
ret = -EINVAL;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto err;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2017-04-30 02:41:29 +08:00
|
|
|
attr.type = rdma_ah_find_type(ib_dev, cmd.attr.port_num);
|
2017-08-05 04:54:16 +08:00
|
|
|
rdma_ah_set_make_grd(&attr, false);
|
2017-04-30 02:41:28 +08:00
|
|
|
rdma_ah_set_dlid(&attr, cmd.attr.dlid);
|
|
|
|
rdma_ah_set_sl(&attr, cmd.attr.sl);
|
|
|
|
rdma_ah_set_path_bits(&attr, cmd.attr.src_path_bits);
|
|
|
|
rdma_ah_set_static_rate(&attr, cmd.attr.static_rate);
|
|
|
|
rdma_ah_set_port_num(&attr, cmd.attr.port_num);
|
|
|
|
|
2017-04-30 02:41:16 +08:00
|
|
|
if (cmd.attr.is_global) {
|
2017-04-30 02:41:28 +08:00
|
|
|
rdma_ah_set_grh(&attr, NULL, cmd.attr.grh.flow_label,
|
|
|
|
cmd.attr.grh.sgid_index,
|
|
|
|
cmd.attr.grh.hop_limit,
|
|
|
|
cmd.attr.grh.traffic_class);
|
|
|
|
rdma_ah_set_dgid_raw(&attr, cmd.attr.grh.dgid);
|
2017-04-30 02:41:16 +08:00
|
|
|
} else {
|
2017-04-30 02:41:28 +08:00
|
|
|
rdma_ah_set_ah_flags(&attr, 0);
|
2017-04-30 02:41:16 +08:00
|
|
|
}
|
2016-11-23 14:23:24 +08:00
|
|
|
|
2018-11-26 02:51:18 +08:00
|
|
|
ah = rdma_create_user_ah(pd, &attr, &attrs->driver_udata);
|
2005-10-15 06:26:04 +08:00
|
|
|
if (IS_ERR(ah)) {
|
|
|
|
ret = PTR_ERR(ah);
|
2017-04-04 18:31:44 +08:00
|
|
|
goto err_put;
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
ah->uobject = uobj;
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj->user_handle = cmd.user_handle;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
uobj->object = ah;
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(pd);
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_finalize_uobj_create(uobj, attrs);
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
resp.ah_handle = uobj->id;
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2017-04-04 18:31:44 +08:00
|
|
|
err_put:
|
|
|
|
uobj_put_obj_read(pd);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
err:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(uobj, attrs);
|
2005-10-15 06:26:04 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_destroy_ah(struct uverbs_attr_bundle *attrs)
|
2005-10-15 06:26:04 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_destroy_ah cmd;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-10-15 06:26:04 +08:00
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return uobj_perform_destroy(UVERBS_OBJECT_AH, cmd.ah_handle, attrs);
|
2005-10-15 06:26:04 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_attach_mcast(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_attach_mcast cmd;
|
|
|
|
struct ib_qp *qp;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
struct ib_uqp_object *obj;
|
2005-11-30 08:57:01 +08:00
|
|
|
struct ib_uverbs_mcast_entry *mcast;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
int ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (!qp)
|
|
|
|
return -EINVAL;
|
2005-11-30 08:57:01 +08:00
|
|
|
|
2020-01-09 01:21:59 +08:00
|
|
|
obj = qp->uobject;
|
2005-11-30 08:57:01 +08:00
|
|
|
|
2017-04-04 18:31:45 +08:00
|
|
|
mutex_lock(&obj->mcast_lock);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
list_for_each_entry(mcast, &obj->mcast_list, list)
|
2005-11-30 08:57:01 +08:00
|
|
|
if (cmd.mlid == mcast->lid &&
|
|
|
|
!memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
|
|
|
|
ret = 0;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto out_put;
|
2005-11-30 08:57:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
|
|
|
|
if (!mcast) {
|
|
|
|
ret = -ENOMEM;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
goto out_put;
|
2005-11-30 08:57:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mcast->lid = cmd.mlid;
|
|
|
|
memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2005-11-30 08:57:01 +08:00
|
|
|
ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (!ret)
|
|
|
|
list_add_tail(&mcast->list, &obj->mcast_list);
|
|
|
|
else
|
2005-11-30 08:57:01 +08:00
|
|
|
kfree(mcast);
|
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
out_put:
|
2017-04-04 18:31:45 +08:00
|
|
|
mutex_unlock(&obj->mcast_lock);
|
2020-01-09 01:21:59 +08:00
|
|
|
rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_detach_mcast(struct uverbs_attr_bundle *attrs)
|
2005-07-08 08:57:13 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_detach_mcast cmd;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
struct ib_uqp_object *obj;
|
2005-07-08 08:57:13 +08:00
|
|
|
struct ib_qp *qp;
|
2005-11-30 08:57:01 +08:00
|
|
|
struct ib_uverbs_mcast_entry *mcast;
|
2019-07-04 20:50:27 +08:00
|
|
|
int ret;
|
2017-04-10 01:15:32 +08:00
|
|
|
bool found = false;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (!qp)
|
|
|
|
return -EINVAL;
|
2005-07-08 08:57:13 +08:00
|
|
|
|
2020-01-09 01:21:59 +08:00
|
|
|
obj = qp->uobject;
|
2017-04-04 18:31:45 +08:00
|
|
|
mutex_lock(&obj->mcast_lock);
|
2017-04-04 18:31:44 +08:00
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
list_for_each_entry(mcast, &obj->mcast_list, list)
|
2005-11-30 08:57:01 +08:00
|
|
|
if (cmd.mlid == mcast->lid &&
|
|
|
|
!memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
|
|
|
|
list_del(&mcast->list);
|
|
|
|
kfree(mcast);
|
2017-04-10 01:15:32 +08:00
|
|
|
found = true;
|
2005-11-30 08:57:01 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-04-10 01:15:32 +08:00
|
|
|
if (!found) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ib_detach_mcast(qp, (union ib_gid *)cmd.gid, cmd.mlid);
|
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
out_put:
|
2017-04-04 18:31:45 +08:00
|
|
|
mutex_unlock(&obj->mcast_lock);
|
2020-01-09 01:21:59 +08:00
|
|
|
rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2018-11-26 02:51:14 +08:00
|
|
|
return ret;
|
2005-07-08 08:57:13 +08:00
|
|
|
}
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2018-09-06 22:27:06 +08:00
|
|
|
struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
|
2018-03-28 14:27:46 +08:00
|
|
|
{
|
|
|
|
struct ib_uflow_resources *resources;
|
|
|
|
|
2018-05-31 21:43:37 +08:00
|
|
|
resources = kzalloc(sizeof(*resources), GFP_KERNEL);
|
2018-03-28 14:27:46 +08:00
|
|
|
|
|
|
|
if (!resources)
|
2018-06-05 12:55:02 +08:00
|
|
|
return NULL;
|
2018-05-31 21:43:37 +08:00
|
|
|
|
2018-06-24 16:23:47 +08:00
|
|
|
if (!num_specs)
|
|
|
|
goto out;
|
|
|
|
|
2018-05-31 21:43:37 +08:00
|
|
|
resources->counters =
|
|
|
|
kcalloc(num_specs, sizeof(*resources->counters), GFP_KERNEL);
|
|
|
|
resources->collection =
|
|
|
|
kcalloc(num_specs, sizeof(*resources->collection), GFP_KERNEL);
|
|
|
|
|
2018-06-05 12:55:02 +08:00
|
|
|
if (!resources->counters || !resources->collection)
|
|
|
|
goto err;
|
2018-03-28 14:27:46 +08:00
|
|
|
|
2018-06-24 16:23:47 +08:00
|
|
|
out:
|
2018-03-28 14:27:46 +08:00
|
|
|
resources->max = num_specs;
|
|
|
|
return resources;
|
2018-05-31 21:43:37 +08:00
|
|
|
|
2018-06-05 12:55:02 +08:00
|
|
|
err:
|
2018-05-31 21:43:37 +08:00
|
|
|
kfree(resources->counters);
|
|
|
|
kfree(resources);
|
2018-06-05 12:55:02 +08:00
|
|
|
|
2018-05-31 21:43:37 +08:00
|
|
|
return NULL;
|
2018-03-28 14:27:46 +08:00
|
|
|
}
|
2018-09-06 22:27:06 +08:00
|
|
|
EXPORT_SYMBOL(flow_resources_alloc);
|
2018-03-28 14:27:46 +08:00
|
|
|
|
|
|
|
void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2018-07-23 20:25:08 +08:00
|
|
|
if (!uflow_res)
|
|
|
|
return;
|
|
|
|
|
2018-05-31 21:43:37 +08:00
|
|
|
for (i = 0; i < uflow_res->collection_num; i++)
|
2018-03-28 14:27:46 +08:00
|
|
|
atomic_dec(&uflow_res->collection[i]->usecnt);
|
|
|
|
|
2018-05-31 21:43:37 +08:00
|
|
|
for (i = 0; i < uflow_res->counters_num; i++)
|
|
|
|
atomic_dec(&uflow_res->counters[i]->usecnt);
|
|
|
|
|
|
|
|
kfree(uflow_res->collection);
|
|
|
|
kfree(uflow_res->counters);
|
2018-03-28 14:27:46 +08:00
|
|
|
kfree(uflow_res);
|
|
|
|
}
|
2018-09-06 22:27:06 +08:00
|
|
|
EXPORT_SYMBOL(ib_uverbs_flow_resources_free);
|
2018-03-28 14:27:46 +08:00
|
|
|
|
2018-09-06 22:27:06 +08:00
|
|
|
void flow_resources_add(struct ib_uflow_resources *uflow_res,
|
|
|
|
enum ib_flow_spec_type type,
|
|
|
|
void *ibobj)
|
2018-03-28 14:27:46 +08:00
|
|
|
{
|
|
|
|
WARN_ON(uflow_res->num >= uflow_res->max);
|
|
|
|
|
2018-05-31 21:43:37 +08:00
|
|
|
switch (type) {
|
|
|
|
case IB_FLOW_SPEC_ACTION_HANDLE:
|
|
|
|
atomic_inc(&((struct ib_flow_action *)ibobj)->usecnt);
|
|
|
|
uflow_res->collection[uflow_res->collection_num++] =
|
|
|
|
(struct ib_flow_action *)ibobj;
|
|
|
|
break;
|
|
|
|
case IB_FLOW_SPEC_ACTION_COUNT:
|
|
|
|
atomic_inc(&((struct ib_counters *)ibobj)->usecnt);
|
|
|
|
uflow_res->counters[uflow_res->counters_num++] =
|
|
|
|
(struct ib_counters *)ibobj;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WARN_ON(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
uflow_res->num++;
|
2018-03-28 14:27:46 +08:00
|
|
|
}
|
2018-09-06 22:27:06 +08:00
|
|
|
EXPORT_SYMBOL(flow_resources_add);
|
2018-03-28 14:27:46 +08:00
|
|
|
|
2019-02-08 00:44:47 +08:00
|
|
|
static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs,
|
2018-03-28 14:27:46 +08:00
|
|
|
struct ib_uverbs_flow_spec *kern_spec,
|
|
|
|
union ib_flow_spec *ib_spec,
|
|
|
|
struct ib_uflow_resources *uflow_res)
|
2017-01-18 20:59:49 +08:00
|
|
|
{
|
|
|
|
ib_spec->type = kern_spec->type;
|
|
|
|
switch (ib_spec->type) {
|
|
|
|
case IB_FLOW_SPEC_ACTION_TAG:
|
|
|
|
if (kern_spec->flow_tag.size !=
|
|
|
|
sizeof(struct ib_uverbs_flow_spec_action_tag))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
ib_spec->flow_tag.size = sizeof(struct ib_flow_spec_action_tag);
|
|
|
|
ib_spec->flow_tag.tag_id = kern_spec->flow_tag.tag_id;
|
|
|
|
break;
|
2017-04-03 18:13:51 +08:00
|
|
|
case IB_FLOW_SPEC_ACTION_DROP:
|
|
|
|
if (kern_spec->drop.size !=
|
|
|
|
sizeof(struct ib_uverbs_flow_spec_action_drop))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
ib_spec->drop.size = sizeof(struct ib_flow_spec_action_drop);
|
|
|
|
break;
|
2018-03-28 14:27:46 +08:00
|
|
|
case IB_FLOW_SPEC_ACTION_HANDLE:
|
|
|
|
if (kern_spec->action.size !=
|
|
|
|
sizeof(struct ib_uverbs_flow_spec_action_handle))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
ib_spec->action.act = uobj_get_obj_read(flow_action,
|
|
|
|
UVERBS_OBJECT_FLOW_ACTION,
|
|
|
|
kern_spec->action.handle,
|
2018-11-26 02:51:13 +08:00
|
|
|
attrs);
|
2018-03-28 14:27:46 +08:00
|
|
|
if (!ib_spec->action.act)
|
|
|
|
return -EINVAL;
|
|
|
|
ib_spec->action.size =
|
|
|
|
sizeof(struct ib_flow_spec_action_handle);
|
2018-05-31 21:43:37 +08:00
|
|
|
flow_resources_add(uflow_res,
|
|
|
|
IB_FLOW_SPEC_ACTION_HANDLE,
|
|
|
|
ib_spec->action.act);
|
2018-03-28 14:27:46 +08:00
|
|
|
uobj_put_obj_read(ib_spec->action.act);
|
|
|
|
break;
|
2018-05-31 21:43:37 +08:00
|
|
|
case IB_FLOW_SPEC_ACTION_COUNT:
|
|
|
|
if (kern_spec->flow_count.size !=
|
|
|
|
sizeof(struct ib_uverbs_flow_spec_action_count))
|
|
|
|
return -EINVAL;
|
|
|
|
ib_spec->flow_count.counters =
|
|
|
|
uobj_get_obj_read(counters,
|
|
|
|
UVERBS_OBJECT_COUNTERS,
|
|
|
|
kern_spec->flow_count.handle,
|
2018-11-26 02:51:13 +08:00
|
|
|
attrs);
|
2018-05-31 21:43:37 +08:00
|
|
|
if (!ib_spec->flow_count.counters)
|
|
|
|
return -EINVAL;
|
|
|
|
ib_spec->flow_count.size =
|
|
|
|
sizeof(struct ib_flow_spec_action_count);
|
|
|
|
flow_resources_add(uflow_res,
|
|
|
|
IB_FLOW_SPEC_ACTION_COUNT,
|
|
|
|
ib_spec->flow_count.counters);
|
|
|
|
uobj_put_obj_read(ib_spec->flow_count.counters);
|
|
|
|
break;
|
2017-01-18 20:59:49 +08:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-28 14:27:44 +08:00
|
|
|
static ssize_t spec_filter_size(const void *kern_spec_filter, u16 kern_filter_size,
|
2016-08-30 21:58:32 +08:00
|
|
|
u16 ib_real_filter_sz)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* User space filter structures must be 64 bit aligned, otherwise this
|
|
|
|
* may pass, but we won't handle additional new attributes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (kern_filter_size > ib_real_filter_sz) {
|
|
|
|
if (memchr_inv(kern_spec_filter +
|
|
|
|
ib_real_filter_sz, 0,
|
|
|
|
kern_filter_size - ib_real_filter_sz))
|
|
|
|
return -EINVAL;
|
|
|
|
return ib_real_filter_sz;
|
|
|
|
}
|
|
|
|
return kern_filter_size;
|
|
|
|
}
|
|
|
|
|
2018-03-28 14:27:44 +08:00
|
|
|
int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
|
|
|
|
const void *kern_spec_mask,
|
|
|
|
const void *kern_spec_val,
|
|
|
|
size_t kern_filter_sz,
|
|
|
|
union ib_flow_spec *ib_spec)
|
2013-08-14 18:58:30 +08:00
|
|
|
{
|
2016-08-30 21:58:32 +08:00
|
|
|
ssize_t actual_filter_sz;
|
|
|
|
ssize_t ib_filter_sz;
|
|
|
|
|
|
|
|
/* User flow spec size must be aligned to 4 bytes */
|
|
|
|
if (kern_filter_sz != ALIGN(kern_filter_sz, 4))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-03-28 14:27:44 +08:00
|
|
|
ib_spec->type = type;
|
|
|
|
|
2016-11-15 01:04:51 +08:00
|
|
|
if (ib_spec->type == (IB_FLOW_SPEC_INNER | IB_FLOW_SPEC_VXLAN_TUNNEL))
|
|
|
|
return -EINVAL;
|
2016-08-30 21:58:32 +08:00
|
|
|
|
2016-11-15 01:04:51 +08:00
|
|
|
switch (ib_spec->type & ~IB_FLOW_SPEC_INNER) {
|
2013-08-14 18:58:30 +08:00
|
|
|
case IB_FLOW_SPEC_ETH:
|
2016-08-30 21:58:32 +08:00
|
|
|
ib_filter_sz = offsetof(struct ib_flow_eth_filter, real_sz);
|
|
|
|
actual_filter_sz = spec_filter_size(kern_spec_mask,
|
|
|
|
kern_filter_sz,
|
|
|
|
ib_filter_sz);
|
|
|
|
if (actual_filter_sz <= 0)
|
2013-08-14 18:58:30 +08:00
|
|
|
return -EINVAL;
|
2016-08-30 21:58:32 +08:00
|
|
|
ib_spec->size = sizeof(struct ib_flow_spec_eth);
|
|
|
|
memcpy(&ib_spec->eth.val, kern_spec_val, actual_filter_sz);
|
|
|
|
memcpy(&ib_spec->eth.mask, kern_spec_mask, actual_filter_sz);
|
2013-08-14 18:58:30 +08:00
|
|
|
break;
|
|
|
|
case IB_FLOW_SPEC_IPV4:
|
2016-08-30 21:58:32 +08:00
|
|
|
ib_filter_sz = offsetof(struct ib_flow_ipv4_filter, real_sz);
|
|
|
|
actual_filter_sz = spec_filter_size(kern_spec_mask,
|
|
|
|
kern_filter_sz,
|
|
|
|
ib_filter_sz);
|
|
|
|
if (actual_filter_sz <= 0)
|
2013-08-14 18:58:30 +08:00
|
|
|
return -EINVAL;
|
2016-08-30 21:58:32 +08:00
|
|
|
ib_spec->size = sizeof(struct ib_flow_spec_ipv4);
|
|
|
|
memcpy(&ib_spec->ipv4.val, kern_spec_val, actual_filter_sz);
|
|
|
|
memcpy(&ib_spec->ipv4.mask, kern_spec_mask, actual_filter_sz);
|
2013-08-14 18:58:30 +08:00
|
|
|
break;
|
2016-06-17 20:14:50 +08:00
|
|
|
case IB_FLOW_SPEC_IPV6:
|
2016-08-30 21:58:32 +08:00
|
|
|
ib_filter_sz = offsetof(struct ib_flow_ipv6_filter, real_sz);
|
|
|
|
actual_filter_sz = spec_filter_size(kern_spec_mask,
|
|
|
|
kern_filter_sz,
|
|
|
|
ib_filter_sz);
|
|
|
|
if (actual_filter_sz <= 0)
|
2016-06-17 20:14:50 +08:00
|
|
|
return -EINVAL;
|
2016-08-30 21:58:32 +08:00
|
|
|
ib_spec->size = sizeof(struct ib_flow_spec_ipv6);
|
|
|
|
memcpy(&ib_spec->ipv6.val, kern_spec_val, actual_filter_sz);
|
|
|
|
memcpy(&ib_spec->ipv6.mask, kern_spec_mask, actual_filter_sz);
|
2016-08-30 21:58:34 +08:00
|
|
|
|
|
|
|
if ((ntohl(ib_spec->ipv6.mask.flow_label)) >= BIT(20) ||
|
|
|
|
(ntohl(ib_spec->ipv6.val.flow_label)) >= BIT(20))
|
|
|
|
return -EINVAL;
|
2016-06-17 20:14:50 +08:00
|
|
|
break;
|
2013-08-14 18:58:30 +08:00
|
|
|
case IB_FLOW_SPEC_TCP:
|
|
|
|
case IB_FLOW_SPEC_UDP:
|
2016-08-30 21:58:32 +08:00
|
|
|
ib_filter_sz = offsetof(struct ib_flow_tcp_udp_filter, real_sz);
|
|
|
|
actual_filter_sz = spec_filter_size(kern_spec_mask,
|
|
|
|
kern_filter_sz,
|
|
|
|
ib_filter_sz);
|
|
|
|
if (actual_filter_sz <= 0)
|
2013-08-14 18:58:30 +08:00
|
|
|
return -EINVAL;
|
2016-08-30 21:58:32 +08:00
|
|
|
ib_spec->size = sizeof(struct ib_flow_spec_tcp_udp);
|
|
|
|
memcpy(&ib_spec->tcp_udp.val, kern_spec_val, actual_filter_sz);
|
|
|
|
memcpy(&ib_spec->tcp_udp.mask, kern_spec_mask, actual_filter_sz);
|
2013-08-14 18:58:30 +08:00
|
|
|
break;
|
2016-11-15 01:04:47 +08:00
|
|
|
case IB_FLOW_SPEC_VXLAN_TUNNEL:
|
|
|
|
ib_filter_sz = offsetof(struct ib_flow_tunnel_filter, real_sz);
|
|
|
|
actual_filter_sz = spec_filter_size(kern_spec_mask,
|
|
|
|
kern_filter_sz,
|
|
|
|
ib_filter_sz);
|
|
|
|
if (actual_filter_sz <= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
ib_spec->tunnel.size = sizeof(struct ib_flow_spec_tunnel);
|
|
|
|
memcpy(&ib_spec->tunnel.val, kern_spec_val, actual_filter_sz);
|
|
|
|
memcpy(&ib_spec->tunnel.mask, kern_spec_mask, actual_filter_sz);
|
|
|
|
|
|
|
|
if ((ntohl(ib_spec->tunnel.mask.tunnel_id)) >= BIT(24) ||
|
|
|
|
(ntohl(ib_spec->tunnel.val.tunnel_id)) >= BIT(24))
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
2018-03-28 14:27:49 +08:00
|
|
|
case IB_FLOW_SPEC_ESP:
|
|
|
|
ib_filter_sz = offsetof(struct ib_flow_esp_filter, real_sz);
|
|
|
|
actual_filter_sz = spec_filter_size(kern_spec_mask,
|
|
|
|
kern_filter_sz,
|
|
|
|
ib_filter_sz);
|
|
|
|
if (actual_filter_sz <= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
ib_spec->esp.size = sizeof(struct ib_flow_spec_esp);
|
|
|
|
memcpy(&ib_spec->esp.val, kern_spec_val, actual_filter_sz);
|
|
|
|
memcpy(&ib_spec->esp.mask, kern_spec_mask, actual_filter_sz);
|
|
|
|
break;
|
2018-05-13 19:33:30 +08:00
|
|
|
case IB_FLOW_SPEC_GRE:
|
|
|
|
ib_filter_sz = offsetof(struct ib_flow_gre_filter, real_sz);
|
|
|
|
actual_filter_sz = spec_filter_size(kern_spec_mask,
|
|
|
|
kern_filter_sz,
|
|
|
|
ib_filter_sz);
|
|
|
|
if (actual_filter_sz <= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
ib_spec->gre.size = sizeof(struct ib_flow_spec_gre);
|
|
|
|
memcpy(&ib_spec->gre.val, kern_spec_val, actual_filter_sz);
|
|
|
|
memcpy(&ib_spec->gre.mask, kern_spec_mask, actual_filter_sz);
|
|
|
|
break;
|
2018-05-13 19:33:32 +08:00
|
|
|
case IB_FLOW_SPEC_MPLS:
|
|
|
|
ib_filter_sz = offsetof(struct ib_flow_mpls_filter, real_sz);
|
|
|
|
actual_filter_sz = spec_filter_size(kern_spec_mask,
|
|
|
|
kern_filter_sz,
|
|
|
|
ib_filter_sz);
|
|
|
|
if (actual_filter_sz <= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
ib_spec->mpls.size = sizeof(struct ib_flow_spec_mpls);
|
|
|
|
memcpy(&ib_spec->mpls.val, kern_spec_val, actual_filter_sz);
|
|
|
|
memcpy(&ib_spec->mpls.mask, kern_spec_mask, actual_filter_sz);
|
|
|
|
break;
|
2013-08-14 18:58:30 +08:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-28 14:27:44 +08:00
|
|
|
static int kern_spec_to_ib_spec_filter(struct ib_uverbs_flow_spec *kern_spec,
|
|
|
|
union ib_flow_spec *ib_spec)
|
|
|
|
{
|
2020-01-27 01:15:00 +08:00
|
|
|
size_t kern_filter_sz;
|
2018-03-28 14:27:44 +08:00
|
|
|
void *kern_spec_mask;
|
|
|
|
void *kern_spec_val;
|
|
|
|
|
2020-01-27 01:15:00 +08:00
|
|
|
if (check_sub_overflow((size_t)kern_spec->hdr.size,
|
|
|
|
sizeof(struct ib_uverbs_flow_spec_hdr),
|
|
|
|
&kern_filter_sz))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
kern_filter_sz /= 2;
|
2018-03-28 14:27:44 +08:00
|
|
|
|
|
|
|
kern_spec_val = (void *)kern_spec +
|
|
|
|
sizeof(struct ib_uverbs_flow_spec_hdr);
|
|
|
|
kern_spec_mask = kern_spec_val + kern_filter_sz;
|
|
|
|
|
|
|
|
return ib_uverbs_kern_spec_to_ib_spec_filter(kern_spec->type,
|
|
|
|
kern_spec_mask,
|
|
|
|
kern_spec_val,
|
|
|
|
kern_filter_sz, ib_spec);
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
static int kern_spec_to_ib_spec(struct uverbs_attr_bundle *attrs,
|
2018-03-28 14:27:46 +08:00
|
|
|
struct ib_uverbs_flow_spec *kern_spec,
|
|
|
|
union ib_flow_spec *ib_spec,
|
|
|
|
struct ib_uflow_resources *uflow_res)
|
2017-01-18 20:59:49 +08:00
|
|
|
{
|
|
|
|
if (kern_spec->reserved)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (kern_spec->type >= IB_FLOW_SPEC_ACTION_TAG)
|
2018-11-26 02:51:13 +08:00
|
|
|
return kern_spec_to_ib_spec_action(attrs, kern_spec, ib_spec,
|
2018-03-28 14:27:46 +08:00
|
|
|
uflow_res);
|
2017-01-18 20:59:49 +08:00
|
|
|
else
|
|
|
|
return kern_spec_to_ib_spec_filter(kern_spec, ib_spec);
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_create_wq(struct uverbs_attr_bundle *attrs)
|
2016-05-23 20:20:49 +08:00
|
|
|
{
|
2018-11-26 02:58:39 +08:00
|
|
|
struct ib_uverbs_ex_create_wq cmd;
|
2016-05-23 20:20:49 +08:00
|
|
|
struct ib_uverbs_ex_create_wq_resp resp = {};
|
|
|
|
struct ib_uwq_object *obj;
|
|
|
|
int err = 0;
|
|
|
|
struct ib_cq *cq;
|
|
|
|
struct ib_pd *pd;
|
|
|
|
struct ib_wq *wq;
|
|
|
|
struct ib_wq_init_attr wq_init_attr = {};
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2016-05-23 20:20:49 +08:00
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
err = uverbs_request(attrs, &cmd, sizeof(cmd));
|
2016-05-23 20:20:49 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (cmd.comp_mask)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
obj = (struct ib_uwq_object *)uobj_alloc(UVERBS_OBJECT_WQ, attrs,
|
2018-07-26 11:40:17 +08:00
|
|
|
&ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(obj))
|
|
|
|
return PTR_ERR(obj);
|
2016-05-23 20:20:49 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
|
2016-05-23 20:20:49 +08:00
|
|
|
if (!pd) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_uobj;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
|
2016-05-23 20:20:49 +08:00
|
|
|
if (!cq) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_put_pd;
|
|
|
|
}
|
|
|
|
|
|
|
|
wq_init_attr.cq = cq;
|
|
|
|
wq_init_attr.max_sge = cmd.max_sge;
|
|
|
|
wq_init_attr.max_wr = cmd.max_wr;
|
|
|
|
wq_init_attr.wq_type = cmd.wq_type;
|
|
|
|
wq_init_attr.event_handler = ib_uverbs_wq_event_handler;
|
2018-11-26 02:58:39 +08:00
|
|
|
wq_init_attr.create_flags = cmd.create_flags;
|
2016-05-23 20:20:49 +08:00
|
|
|
INIT_LIST_HEAD(&obj->uevent.event_list);
|
2020-05-06 16:24:42 +08:00
|
|
|
obj->uevent.uobject.user_handle = cmd.user_handle;
|
2018-02-14 20:38:43 +08:00
|
|
|
|
2018-12-11 03:09:48 +08:00
|
|
|
wq = pd->device->ops.create_wq(pd, &wq_init_attr, &attrs->driver_udata);
|
2016-05-23 20:20:49 +08:00
|
|
|
if (IS_ERR(wq)) {
|
|
|
|
err = PTR_ERR(wq);
|
|
|
|
goto err_put_cq;
|
|
|
|
}
|
|
|
|
|
2020-01-09 01:22:01 +08:00
|
|
|
wq->uobject = obj;
|
2016-05-23 20:20:49 +08:00
|
|
|
obj->uevent.uobject.object = wq;
|
|
|
|
wq->wq_type = wq_init_attr.wq_type;
|
|
|
|
wq->cq = cq;
|
|
|
|
wq->pd = pd;
|
|
|
|
wq->device = pd->device;
|
|
|
|
atomic_set(&wq->usecnt, 0);
|
|
|
|
atomic_inc(&pd->usecnt);
|
|
|
|
atomic_inc(&cq->usecnt);
|
2020-05-19 15:27:06 +08:00
|
|
|
obj->uevent.event_file = READ_ONCE(attrs->ufile->default_async_file);
|
|
|
|
if (obj->uevent.event_file)
|
|
|
|
uverbs_uobject_get(&obj->uevent.event_file->uobj);
|
2016-05-23 20:20:49 +08:00
|
|
|
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_put_obj_read(pd);
|
|
|
|
rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
|
|
|
uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
|
|
|
|
|
2016-05-23 20:20:49 +08:00
|
|
|
resp.wq_handle = obj->uevent.uobject.id;
|
|
|
|
resp.max_sge = wq_init_attr.max_sge;
|
|
|
|
resp.max_wr = wq_init_attr.max_wr;
|
|
|
|
resp.wqn = wq->wq_num;
|
2018-11-26 02:58:39 +08:00
|
|
|
resp.response_length = uverbs_response_length(attrs, sizeof(resp));
|
2020-07-19 13:22:23 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2016-05-23 20:20:49 +08:00
|
|
|
|
|
|
|
err_put_cq:
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2016-05-23 20:20:49 +08:00
|
|
|
err_put_pd:
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(pd);
|
2016-05-23 20:20:49 +08:00
|
|
|
err_uobj:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(&obj->uevent.uobject, attrs);
|
2016-05-23 20:20:49 +08:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_destroy_wq(struct uverbs_attr_bundle *attrs)
|
2016-05-23 20:20:49 +08:00
|
|
|
{
|
2018-11-26 02:58:39 +08:00
|
|
|
struct ib_uverbs_ex_destroy_wq cmd;
|
2016-05-23 20:20:49 +08:00
|
|
|
struct ib_uverbs_ex_destroy_wq_resp resp = {};
|
|
|
|
struct ib_uobject *uobj;
|
|
|
|
struct ib_uwq_object *obj;
|
|
|
|
int ret;
|
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
2016-05-23 20:20:49 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (cmd.comp_mask)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
resp.response_length = uverbs_response_length(attrs, sizeof(resp));
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_get_destroy(UVERBS_OBJECT_WQ, cmd.wq_handle, attrs);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
2016-05-23 20:20:49 +08:00
|
|
|
|
|
|
|
obj = container_of(uobj, struct ib_uwq_object, uevent.uobject);
|
|
|
|
resp.events_reported = obj->uevent.events_reported;
|
2018-07-26 11:40:11 +08:00
|
|
|
|
|
|
|
uobj_put_destroy(uobj);
|
2016-05-23 20:20:49 +08:00
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2016-05-23 20:20:49 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_modify_wq(struct uverbs_attr_bundle *attrs)
|
2016-05-23 20:20:49 +08:00
|
|
|
{
|
2018-11-26 02:58:39 +08:00
|
|
|
struct ib_uverbs_ex_modify_wq cmd;
|
2016-05-23 20:20:49 +08:00
|
|
|
struct ib_wq *wq;
|
|
|
|
struct ib_wq_attr wq_attr = {};
|
|
|
|
int ret;
|
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
2016-05-23 20:20:49 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (!cmd.attr_mask)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-01-18 21:39:59 +08:00
|
|
|
if (cmd.attr_mask > (IB_WQ_STATE | IB_WQ_CUR_STATE | IB_WQ_FLAGS))
|
2016-05-23 20:20:49 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, cmd.wq_handle, attrs);
|
2016-05-23 20:20:49 +08:00
|
|
|
if (!wq)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-01-18 21:39:59 +08:00
|
|
|
if (cmd.attr_mask & IB_WQ_FLAGS) {
|
|
|
|
wq_attr.flags = cmd.flags;
|
|
|
|
wq_attr.flags_mask = cmd.flags_mask;
|
|
|
|
}
|
2021-05-19 16:37:31 +08:00
|
|
|
|
|
|
|
if (cmd.attr_mask & IB_WQ_CUR_STATE) {
|
|
|
|
if (cmd.curr_wq_state > IB_WQS_ERR)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
wq_attr.curr_wq_state = cmd.curr_wq_state;
|
|
|
|
} else {
|
|
|
|
wq_attr.curr_wq_state = wq->state;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd.attr_mask & IB_WQ_STATE) {
|
|
|
|
if (cmd.wq_state > IB_WQS_ERR)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
wq_attr.wq_state = cmd.wq_state;
|
|
|
|
} else {
|
|
|
|
wq_attr.wq_state = wq_attr.curr_wq_state;
|
|
|
|
}
|
|
|
|
|
2018-12-11 03:09:48 +08:00
|
|
|
ret = wq->device->ops.modify_wq(wq, &wq_attr, cmd.attr_mask,
|
|
|
|
&attrs->driver_udata);
|
2020-01-09 01:22:01 +08:00
|
|
|
rdma_lookup_put_uobject(&wq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2016-05-23 20:20:49 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle *attrs)
|
2016-05-23 20:20:52 +08:00
|
|
|
{
|
2018-11-26 02:58:42 +08:00
|
|
|
struct ib_uverbs_ex_create_rwq_ind_table cmd;
|
2016-05-23 20:20:52 +08:00
|
|
|
struct ib_uverbs_ex_create_rwq_ind_table_resp resp = {};
|
2020-09-02 16:16:23 +08:00
|
|
|
struct ib_uobject *uobj;
|
2018-11-26 02:58:42 +08:00
|
|
|
int err;
|
2016-05-23 20:20:52 +08:00
|
|
|
struct ib_rwq_ind_table_init_attr init_attr = {};
|
|
|
|
struct ib_rwq_ind_table *rwq_ind_tbl;
|
2020-09-02 16:16:23 +08:00
|
|
|
struct ib_wq **wqs = NULL;
|
2016-05-23 20:20:52 +08:00
|
|
|
u32 *wqs_handles = NULL;
|
|
|
|
struct ib_wq *wq = NULL;
|
2020-07-19 13:22:23 +08:00
|
|
|
int i, num_read_wqs;
|
2016-05-23 20:20:52 +08:00
|
|
|
u32 num_wq_handles;
|
2018-11-26 02:58:42 +08:00
|
|
|
struct uverbs_req_iter iter;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2016-05-23 20:20:52 +08:00
|
|
|
|
2018-11-26 02:58:42 +08:00
|
|
|
err = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
|
2016-05-23 20:20:52 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (cmd.comp_mask)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (cmd.log_ind_tbl_size > IB_USER_VERBS_MAX_LOG_IND_TBL_SIZE)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
num_wq_handles = 1 << cmd.log_ind_tbl_size;
|
|
|
|
wqs_handles = kcalloc(num_wq_handles, sizeof(*wqs_handles),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!wqs_handles)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-11-26 02:58:42 +08:00
|
|
|
err = uverbs_request_next(&iter, wqs_handles,
|
|
|
|
num_wq_handles * sizeof(__u32));
|
|
|
|
if (err)
|
|
|
|
goto err_free;
|
|
|
|
|
|
|
|
err = uverbs_request_finish(&iter);
|
2016-05-23 20:20:52 +08:00
|
|
|
if (err)
|
|
|
|
goto err_free;
|
|
|
|
|
|
|
|
wqs = kcalloc(num_wq_handles, sizeof(*wqs), GFP_KERNEL);
|
|
|
|
if (!wqs) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto err_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (num_read_wqs = 0; num_read_wqs < num_wq_handles;
|
|
|
|
num_read_wqs++) {
|
2018-07-04 16:32:09 +08:00
|
|
|
wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ,
|
2018-11-26 02:51:13 +08:00
|
|
|
wqs_handles[num_read_wqs], attrs);
|
2016-05-23 20:20:52 +08:00
|
|
|
if (!wq) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto put_wqs;
|
|
|
|
}
|
|
|
|
|
|
|
|
wqs[num_read_wqs] = wq;
|
2020-07-19 13:22:23 +08:00
|
|
|
atomic_inc(&wqs[num_read_wqs]->usecnt);
|
2016-05-23 20:20:52 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_alloc(UVERBS_OBJECT_RWQ_IND_TBL, attrs, &ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj)) {
|
|
|
|
err = PTR_ERR(uobj);
|
2016-05-23 20:20:52 +08:00
|
|
|
goto put_wqs;
|
|
|
|
}
|
|
|
|
|
2020-09-02 16:16:23 +08:00
|
|
|
rwq_ind_tbl = rdma_zalloc_drv_obj(ib_dev, ib_rwq_ind_table);
|
|
|
|
if (!rwq_ind_tbl) {
|
|
|
|
err = -ENOMEM;
|
2016-05-23 20:20:52 +08:00
|
|
|
goto err_uobj;
|
|
|
|
}
|
|
|
|
|
2020-09-02 16:16:23 +08:00
|
|
|
init_attr.log_ind_tbl_size = cmd.log_ind_tbl_size;
|
|
|
|
init_attr.ind_tbl = wqs;
|
|
|
|
|
2016-05-23 20:20:52 +08:00
|
|
|
rwq_ind_tbl->ind_tbl = wqs;
|
|
|
|
rwq_ind_tbl->log_ind_tbl_size = init_attr.log_ind_tbl_size;
|
|
|
|
rwq_ind_tbl->uobject = uobj;
|
|
|
|
uobj->object = rwq_ind_tbl;
|
|
|
|
rwq_ind_tbl->device = ib_dev;
|
|
|
|
atomic_set(&rwq_ind_tbl->usecnt, 0);
|
|
|
|
|
2020-09-02 16:16:23 +08:00
|
|
|
err = ib_dev->ops.create_rwq_ind_table(rwq_ind_tbl, &init_attr,
|
|
|
|
&attrs->driver_udata);
|
|
|
|
if (err)
|
|
|
|
goto err_create;
|
|
|
|
|
2016-05-23 20:20:52 +08:00
|
|
|
for (i = 0; i < num_wq_handles; i++)
|
2020-07-19 13:22:23 +08:00
|
|
|
rdma_lookup_put_uobject(&wqs[i]->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
|
|
|
kfree(wqs_handles);
|
|
|
|
uobj_finalize_uobj_create(uobj, attrs);
|
2016-05-23 20:20:52 +08:00
|
|
|
|
|
|
|
resp.ind_tbl_handle = uobj->id;
|
|
|
|
resp.ind_tbl_num = rwq_ind_tbl->ind_tbl_num;
|
2018-11-26 02:58:39 +08:00
|
|
|
resp.response_length = uverbs_response_length(attrs, sizeof(resp));
|
2020-07-19 13:22:23 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2016-05-23 20:20:52 +08:00
|
|
|
|
2020-09-02 16:16:23 +08:00
|
|
|
err_create:
|
|
|
|
kfree(rwq_ind_tbl);
|
2016-05-23 20:20:52 +08:00
|
|
|
err_uobj:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(uobj, attrs);
|
2016-05-23 20:20:52 +08:00
|
|
|
put_wqs:
|
2020-07-19 13:22:23 +08:00
|
|
|
for (i = 0; i < num_read_wqs; i++) {
|
|
|
|
rdma_lookup_put_uobject(&wqs[i]->uobject->uevent.uobject,
|
2020-01-09 01:22:01 +08:00
|
|
|
UVERBS_LOOKUP_READ);
|
2020-07-19 13:22:23 +08:00
|
|
|
atomic_dec(&wqs[i]->usecnt);
|
|
|
|
}
|
2016-05-23 20:20:52 +08:00
|
|
|
err_free:
|
|
|
|
kfree(wqs_handles);
|
|
|
|
kfree(wqs);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_destroy_rwq_ind_table(struct uverbs_attr_bundle *attrs)
|
2016-05-23 20:20:52 +08:00
|
|
|
{
|
2018-11-26 02:58:39 +08:00
|
|
|
struct ib_uverbs_ex_destroy_rwq_ind_table cmd;
|
|
|
|
int ret;
|
2016-05-23 20:20:52 +08:00
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
2016-05-23 20:20:52 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (cmd.comp_mask)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2018-07-04 16:32:06 +08:00
|
|
|
return uobj_perform_destroy(UVERBS_OBJECT_RWQ_IND_TBL,
|
2018-11-26 02:51:14 +08:00
|
|
|
cmd.ind_tbl_handle, attrs);
|
2016-05-23 20:20:52 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs)
|
2013-08-14 18:58:30 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_create_flow cmd;
|
2020-07-19 13:22:23 +08:00
|
|
|
struct ib_uverbs_create_flow_resp resp = {};
|
2013-08-14 18:58:30 +08:00
|
|
|
struct ib_uobject *uobj;
|
|
|
|
struct ib_flow *flow_id;
|
2013-11-07 06:21:45 +08:00
|
|
|
struct ib_uverbs_flow_attr *kern_flow_attr;
|
2013-08-14 18:58:30 +08:00
|
|
|
struct ib_flow_attr *flow_attr;
|
|
|
|
struct ib_qp *qp;
|
2018-03-28 14:27:46 +08:00
|
|
|
struct ib_uflow_resources *uflow_res;
|
2018-06-24 16:23:53 +08:00
|
|
|
struct ib_uverbs_flow_spec_hdr *kern_spec;
|
2018-11-26 02:58:42 +08:00
|
|
|
struct uverbs_req_iter iter;
|
|
|
|
int err;
|
2013-08-14 18:58:30 +08:00
|
|
|
void *ib_spec;
|
|
|
|
int i;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2013-08-14 18:58:30 +08:00
|
|
|
|
2018-11-26 02:58:42 +08:00
|
|
|
err = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
|
IB/core: extended command: an improved infrastructure for uverbs commands
Commit 400dbc96583f ("IB/core: Infrastructure for extensible uverbs
commands") added an infrastructure for extensible uverbs commands
while later commit 436f2ad05a0b ("IB/core: Export ib_create/destroy_flow
through uverbs") exported ib_create_flow()/ib_destroy_flow() functions
using this new infrastructure.
According to the commit 400dbc96583f, the purpose of this
infrastructure is to support passing around provider (eg. hardware)
specific buffers when userspace issue commands to the kernel, so that
it would be possible to extend uverbs (eg. core) buffers independently
from the provider buffers.
But the new kernel command function prototypes were not modified to
take advantage of this extension. This issue was exposed by Roland
Dreier in a previous review[1].
So the following patch is an attempt to a revised extensible command
infrastructure.
This improved extensible command infrastructure distinguish between
core (eg. legacy)'s command/response buffers from provider
(eg. hardware)'s command/response buffers: each extended command
implementing function is given a struct ib_udata to hold core
(eg. uverbs) input and output buffers, and another struct ib_udata to
hold the hw (eg. provider) input and output buffers.
Having those buffers identified separately make it easier to increase
one buffer to support extension without having to add some code to
guess the exact size of each command/response parts: This should make
the extended functions more reliable.
Additionally, instead of relying on command identifier being greater
than IB_USER_VERBS_CMD_THRESHOLD, the proposed infrastructure rely on
unused bits in command field: on the 32 bits provided by command
field, only 6 bits are really needed to encode the identifier of
commands currently supported by the kernel. (Even using only 6 bits
leaves room for about 23 new commands).
So this patch makes use of some high order bits in command field to
store flags, leaving enough room for more command identifiers than one
will ever need (eg. 256).
The new flags are used to specify if the command should be processed
as an extended one or a legacy one. While designing the new command
format, care was taken to make usage of flags itself extensible.
Using high order bits of the commands field ensure that newer
libibverbs on older kernel will properly fail when trying to call
extended commands. On the other hand, older libibverbs on newer kernel
will never be able to issue calls to extended commands.
The extended command header includes the optional response pointer so
that output buffer length and output buffer pointer are located
together in the command, allowing proper parameters checking. This
should make implementing functions easier and safer.
Additionally the extended header ensure 64bits alignment, while making
all sizes multiple of 8 bytes, extending the maximum buffer size:
legacy extended
Maximum command buffer: 256KBytes 1024KBytes (512KBytes + 512KBytes)
Maximum response buffer: 256KBytes 1024KBytes (512KBytes + 512KBytes)
For the purpose of doing proper buffer size accounting, the headers
size are no more taken in account in "in_words".
One of the odds of the current extensible infrastructure, reading
twice the "legacy" command header, is fixed by removing the "legacy"
command header from the extended command header: they are processed as
two different parts of the command: memory is read once and
information are not duplicated: it's making clear that's an extended
command scheme and not a different command scheme.
The proposed scheme will format input (command) and output (response)
buffers this way:
- command:
legacy header +
extended header +
command data (core + hw):
+----------------------------------------+
| flags | 00 00 | command |
| in_words | out_words |
+----------------------------------------+
| response |
| response |
| provider_in_words | provider_out_words |
| padding |
+----------------------------------------+
| |
. <uverbs input> .
. (in_words * 8) .
| |
+----------------------------------------+
| |
. <provider input> .
. (provider_in_words * 8) .
| |
+----------------------------------------+
- response, if present:
+----------------------------------------+
| |
. <uverbs output space> .
. (out_words * 8) .
| |
+----------------------------------------+
| |
. <provider output space> .
. (provider_out_words * 8) .
| |
+----------------------------------------+
The overall design is to ensure that the extensible infrastructure is
itself extensible while begin more reliable with more input and bound
checking.
Note:
The unused field in the extended header would be perfect candidate to
hold the command "comp_mask" (eg. bit field used to handle
compatibility). This was suggested by Roland Dreier in a previous
review[2]. But "comp_mask" field is likely to be present in the uverb
input and/or provider input, likewise for the response, as noted by
Matan Barak[3], so it doesn't make sense to put "comp_mask" in the
header.
[1]:
http://marc.info/?i=CAL1RGDWxmM17W2o_era24A-TTDeKyoL6u3NRu_=t_dhV_ZA9MA@mail.gmail.com
[2]:
http://marc.info/?i=CAL1RGDXJtrc849M6_XNZT5xO1+ybKtLWGq6yg6LhoSsKpsmkYA@mail.gmail.com
[3]:
http://marc.info/?i=525C1149.6000701@mellanox.com
Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>
Link: http://marc.info/?i=cover.1383773832.git.ydroneaud@opteya.com
[ Convert "ret ? ret : 0" to the equivalent "ret". - Roland ]
Signed-off-by: Roland Dreier <roland@purestorage.com>
2013-11-07 06:21:49 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2013-09-01 23:39:52 +08:00
|
|
|
if (cmd.comp_mask)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-05-13 23:52:26 +08:00
|
|
|
if (!capable(CAP_NET_RAW))
|
2013-08-14 18:58:30 +08:00
|
|
|
return -EPERM;
|
|
|
|
|
2016-02-19 00:31:05 +08:00
|
|
|
if (cmd.flow_attr.flags >= IB_FLOW_ATTR_FLAGS_RESERVED)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if ((cmd.flow_attr.flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP) &&
|
|
|
|
((cmd.flow_attr.type == IB_FLOW_ATTR_ALL_DEFAULT) ||
|
|
|
|
(cmd.flow_attr.type == IB_FLOW_ATTR_MC_DEFAULT)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2013-11-07 06:21:44 +08:00
|
|
|
if (cmd.flow_attr.num_of_specs > IB_FLOW_SPEC_SUPPORT_LAYERS)
|
2013-09-01 23:39:52 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2018-11-26 02:58:42 +08:00
|
|
|
if (cmd.flow_attr.size >
|
2013-11-07 06:21:46 +08:00
|
|
|
(cmd.flow_attr.num_of_specs * sizeof(struct ib_uverbs_flow_spec)))
|
2013-09-01 23:39:52 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2013-12-12 06:01:49 +08:00
|
|
|
if (cmd.flow_attr.reserved[0] ||
|
|
|
|
cmd.flow_attr.reserved[1])
|
|
|
|
return -EINVAL;
|
|
|
|
|
2013-08-14 18:58:30 +08:00
|
|
|
if (cmd.flow_attr.num_of_specs) {
|
2013-11-07 06:21:44 +08:00
|
|
|
kern_flow_attr = kmalloc(sizeof(*kern_flow_attr) + cmd.flow_attr.size,
|
|
|
|
GFP_KERNEL);
|
2013-08-14 18:58:30 +08:00
|
|
|
if (!kern_flow_attr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-06-24 16:23:53 +08:00
|
|
|
*kern_flow_attr = cmd.flow_attr;
|
2018-11-26 02:58:42 +08:00
|
|
|
err = uverbs_request_next(&iter, &kern_flow_attr->flow_specs,
|
|
|
|
cmd.flow_attr.size);
|
IB/core: extended command: an improved infrastructure for uverbs commands
Commit 400dbc96583f ("IB/core: Infrastructure for extensible uverbs
commands") added an infrastructure for extensible uverbs commands
while later commit 436f2ad05a0b ("IB/core: Export ib_create/destroy_flow
through uverbs") exported ib_create_flow()/ib_destroy_flow() functions
using this new infrastructure.
According to the commit 400dbc96583f, the purpose of this
infrastructure is to support passing around provider (eg. hardware)
specific buffers when userspace issue commands to the kernel, so that
it would be possible to extend uverbs (eg. core) buffers independently
from the provider buffers.
But the new kernel command function prototypes were not modified to
take advantage of this extension. This issue was exposed by Roland
Dreier in a previous review[1].
So the following patch is an attempt to a revised extensible command
infrastructure.
This improved extensible command infrastructure distinguish between
core (eg. legacy)'s command/response buffers from provider
(eg. hardware)'s command/response buffers: each extended command
implementing function is given a struct ib_udata to hold core
(eg. uverbs) input and output buffers, and another struct ib_udata to
hold the hw (eg. provider) input and output buffers.
Having those buffers identified separately make it easier to increase
one buffer to support extension without having to add some code to
guess the exact size of each command/response parts: This should make
the extended functions more reliable.
Additionally, instead of relying on command identifier being greater
than IB_USER_VERBS_CMD_THRESHOLD, the proposed infrastructure rely on
unused bits in command field: on the 32 bits provided by command
field, only 6 bits are really needed to encode the identifier of
commands currently supported by the kernel. (Even using only 6 bits
leaves room for about 23 new commands).
So this patch makes use of some high order bits in command field to
store flags, leaving enough room for more command identifiers than one
will ever need (eg. 256).
The new flags are used to specify if the command should be processed
as an extended one or a legacy one. While designing the new command
format, care was taken to make usage of flags itself extensible.
Using high order bits of the commands field ensure that newer
libibverbs on older kernel will properly fail when trying to call
extended commands. On the other hand, older libibverbs on newer kernel
will never be able to issue calls to extended commands.
The extended command header includes the optional response pointer so
that output buffer length and output buffer pointer are located
together in the command, allowing proper parameters checking. This
should make implementing functions easier and safer.
Additionally the extended header ensure 64bits alignment, while making
all sizes multiple of 8 bytes, extending the maximum buffer size:
legacy extended
Maximum command buffer: 256KBytes 1024KBytes (512KBytes + 512KBytes)
Maximum response buffer: 256KBytes 1024KBytes (512KBytes + 512KBytes)
For the purpose of doing proper buffer size accounting, the headers
size are no more taken in account in "in_words".
One of the odds of the current extensible infrastructure, reading
twice the "legacy" command header, is fixed by removing the "legacy"
command header from the extended command header: they are processed as
two different parts of the command: memory is read once and
information are not duplicated: it's making clear that's an extended
command scheme and not a different command scheme.
The proposed scheme will format input (command) and output (response)
buffers this way:
- command:
legacy header +
extended header +
command data (core + hw):
+----------------------------------------+
| flags | 00 00 | command |
| in_words | out_words |
+----------------------------------------+
| response |
| response |
| provider_in_words | provider_out_words |
| padding |
+----------------------------------------+
| |
. <uverbs input> .
. (in_words * 8) .
| |
+----------------------------------------+
| |
. <provider input> .
. (provider_in_words * 8) .
| |
+----------------------------------------+
- response, if present:
+----------------------------------------+
| |
. <uverbs output space> .
. (out_words * 8) .
| |
+----------------------------------------+
| |
. <provider output space> .
. (provider_out_words * 8) .
| |
+----------------------------------------+
The overall design is to ensure that the extensible infrastructure is
itself extensible while begin more reliable with more input and bound
checking.
Note:
The unused field in the extended header would be perfect candidate to
hold the command "comp_mask" (eg. bit field used to handle
compatibility). This was suggested by Roland Dreier in a previous
review[2]. But "comp_mask" field is likely to be present in the uverb
input and/or provider input, likewise for the response, as noted by
Matan Barak[3], so it doesn't make sense to put "comp_mask" in the
header.
[1]:
http://marc.info/?i=CAL1RGDWxmM17W2o_era24A-TTDeKyoL6u3NRu_=t_dhV_ZA9MA@mail.gmail.com
[2]:
http://marc.info/?i=CAL1RGDXJtrc849M6_XNZT5xO1+ybKtLWGq6yg6LhoSsKpsmkYA@mail.gmail.com
[3]:
http://marc.info/?i=525C1149.6000701@mellanox.com
Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>
Link: http://marc.info/?i=cover.1383773832.git.ydroneaud@opteya.com
[ Convert "ret ? ret : 0" to the equivalent "ret". - Roland ]
Signed-off-by: Roland Dreier <roland@purestorage.com>
2013-11-07 06:21:49 +08:00
|
|
|
if (err)
|
2013-08-14 18:58:30 +08:00
|
|
|
goto err_free_attr;
|
|
|
|
} else {
|
|
|
|
kern_flow_attr = &cmd.flow_attr;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:42 +08:00
|
|
|
err = uverbs_request_finish(&iter);
|
|
|
|
if (err)
|
|
|
|
goto err_free_attr;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_alloc(UVERBS_OBJECT_FLOW, attrs, &ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj)) {
|
|
|
|
err = PTR_ERR(uobj);
|
2013-08-14 18:58:30 +08:00
|
|
|
goto err_free_attr;
|
|
|
|
}
|
|
|
|
|
2021-06-10 15:34:25 +08:00
|
|
|
if (!rdma_is_port_valid(uobj->context->device, cmd.flow_attr.port)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_uobj;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
|
2013-08-14 18:58:30 +08:00
|
|
|
if (!qp) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_uobj;
|
|
|
|
}
|
|
|
|
|
2018-06-24 16:23:42 +08:00
|
|
|
if (qp->qp_type != IB_QPT_UD && qp->qp_type != IB_QPT_RAW_PACKET) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_put;
|
|
|
|
}
|
|
|
|
|
2018-06-07 22:57:16 +08:00
|
|
|
flow_attr = kzalloc(struct_size(flow_attr, flows,
|
|
|
|
cmd.flow_attr.num_of_specs), GFP_KERNEL);
|
2013-08-14 18:58:30 +08:00
|
|
|
if (!flow_attr) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto err_put;
|
|
|
|
}
|
2018-03-28 14:27:46 +08:00
|
|
|
uflow_res = flow_resources_alloc(cmd.flow_attr.num_of_specs);
|
|
|
|
if (!uflow_res) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto err_free_flow_attr;
|
|
|
|
}
|
2013-08-14 18:58:30 +08:00
|
|
|
|
|
|
|
flow_attr->type = kern_flow_attr->type;
|
|
|
|
flow_attr->priority = kern_flow_attr->priority;
|
|
|
|
flow_attr->num_of_specs = kern_flow_attr->num_of_specs;
|
|
|
|
flow_attr->port = kern_flow_attr->port;
|
|
|
|
flow_attr->flags = kern_flow_attr->flags;
|
|
|
|
flow_attr->size = sizeof(*flow_attr);
|
|
|
|
|
2018-06-24 16:23:53 +08:00
|
|
|
kern_spec = kern_flow_attr->flow_specs;
|
2013-08-14 18:58:30 +08:00
|
|
|
ib_spec = flow_attr + 1;
|
2013-11-07 06:21:44 +08:00
|
|
|
for (i = 0; i < flow_attr->num_of_specs &&
|
2018-07-01 20:31:54 +08:00
|
|
|
cmd.flow_attr.size >= sizeof(*kern_spec) &&
|
2018-06-24 16:23:53 +08:00
|
|
|
cmd.flow_attr.size >= kern_spec->size;
|
|
|
|
i++) {
|
|
|
|
err = kern_spec_to_ib_spec(
|
2018-11-26 02:51:13 +08:00
|
|
|
attrs, (struct ib_uverbs_flow_spec *)kern_spec,
|
2018-06-24 16:23:53 +08:00
|
|
|
ib_spec, uflow_res);
|
2013-08-14 18:58:30 +08:00
|
|
|
if (err)
|
|
|
|
goto err_free;
|
2018-05-13 19:33:32 +08:00
|
|
|
|
2013-08-14 18:58:30 +08:00
|
|
|
flow_attr->size +=
|
|
|
|
((union ib_flow_spec *) ib_spec)->size;
|
2018-06-24 16:23:53 +08:00
|
|
|
cmd.flow_attr.size -= kern_spec->size;
|
|
|
|
kern_spec = ((void *)kern_spec) + kern_spec->size;
|
2013-08-14 18:58:30 +08:00
|
|
|
ib_spec += ((union ib_flow_spec *) ib_spec)->size;
|
|
|
|
}
|
2013-11-07 06:21:44 +08:00
|
|
|
if (cmd.flow_attr.size || (i != flow_attr->num_of_specs)) {
|
2021-06-10 19:40:32 +08:00
|
|
|
pr_warn("create flow failed, flow %d: %u bytes left from uverb cmd\n",
|
2013-11-07 06:21:44 +08:00
|
|
|
i, cmd.flow_attr.size);
|
2013-12-12 06:01:50 +08:00
|
|
|
err = -EINVAL;
|
2013-08-14 18:58:30 +08:00
|
|
|
goto err_free;
|
|
|
|
}
|
2018-05-31 21:43:35 +08:00
|
|
|
|
2020-07-30 16:12:35 +08:00
|
|
|
flow_id = qp->device->ops.create_flow(qp, flow_attr,
|
|
|
|
&attrs->driver_udata);
|
2018-05-31 21:43:35 +08:00
|
|
|
|
2013-08-14 18:58:30 +08:00
|
|
|
if (IS_ERR(flow_id)) {
|
|
|
|
err = PTR_ERR(flow_id);
|
2017-04-04 18:31:44 +08:00
|
|
|
goto err_free;
|
2013-08-14 18:58:30 +08:00
|
|
|
}
|
2018-09-06 22:27:02 +08:00
|
|
|
|
|
|
|
ib_set_flow(uobj, flow_id, qp, qp->device, uflow_res);
|
2013-08-14 18:58:30 +08:00
|
|
|
|
2020-01-09 01:21:59 +08:00
|
|
|
rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2013-08-14 18:58:30 +08:00
|
|
|
kfree(flow_attr);
|
2020-07-19 13:22:23 +08:00
|
|
|
|
2013-08-14 18:58:30 +08:00
|
|
|
if (cmd.flow_attr.num_of_specs)
|
|
|
|
kfree(kern_flow_attr);
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_finalize_uobj_create(uobj, attrs);
|
|
|
|
|
|
|
|
resp.flow_handle = uobj->id;
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
|
|
|
|
2013-08-14 18:58:30 +08:00
|
|
|
err_free:
|
2018-03-28 14:27:46 +08:00
|
|
|
ib_uverbs_flow_resources_free(uflow_res);
|
|
|
|
err_free_flow_attr:
|
2013-08-14 18:58:30 +08:00
|
|
|
kfree(flow_attr);
|
|
|
|
err_put:
|
2020-01-09 01:21:59 +08:00
|
|
|
rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2013-08-14 18:58:30 +08:00
|
|
|
err_uobj:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(uobj, attrs);
|
2013-08-14 18:58:30 +08:00
|
|
|
err_free_attr:
|
|
|
|
if (cmd.flow_attr.num_of_specs)
|
|
|
|
kfree(kern_flow_attr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_destroy_flow(struct uverbs_attr_bundle *attrs)
|
IB/core: extended command: an improved infrastructure for uverbs commands
Commit 400dbc96583f ("IB/core: Infrastructure for extensible uverbs
commands") added an infrastructure for extensible uverbs commands
while later commit 436f2ad05a0b ("IB/core: Export ib_create/destroy_flow
through uverbs") exported ib_create_flow()/ib_destroy_flow() functions
using this new infrastructure.
According to the commit 400dbc96583f, the purpose of this
infrastructure is to support passing around provider (eg. hardware)
specific buffers when userspace issue commands to the kernel, so that
it would be possible to extend uverbs (eg. core) buffers independently
from the provider buffers.
But the new kernel command function prototypes were not modified to
take advantage of this extension. This issue was exposed by Roland
Dreier in a previous review[1].
So the following patch is an attempt to a revised extensible command
infrastructure.
This improved extensible command infrastructure distinguish between
core (eg. legacy)'s command/response buffers from provider
(eg. hardware)'s command/response buffers: each extended command
implementing function is given a struct ib_udata to hold core
(eg. uverbs) input and output buffers, and another struct ib_udata to
hold the hw (eg. provider) input and output buffers.
Having those buffers identified separately make it easier to increase
one buffer to support extension without having to add some code to
guess the exact size of each command/response parts: This should make
the extended functions more reliable.
Additionally, instead of relying on command identifier being greater
than IB_USER_VERBS_CMD_THRESHOLD, the proposed infrastructure rely on
unused bits in command field: on the 32 bits provided by command
field, only 6 bits are really needed to encode the identifier of
commands currently supported by the kernel. (Even using only 6 bits
leaves room for about 23 new commands).
So this patch makes use of some high order bits in command field to
store flags, leaving enough room for more command identifiers than one
will ever need (eg. 256).
The new flags are used to specify if the command should be processed
as an extended one or a legacy one. While designing the new command
format, care was taken to make usage of flags itself extensible.
Using high order bits of the commands field ensure that newer
libibverbs on older kernel will properly fail when trying to call
extended commands. On the other hand, older libibverbs on newer kernel
will never be able to issue calls to extended commands.
The extended command header includes the optional response pointer so
that output buffer length and output buffer pointer are located
together in the command, allowing proper parameters checking. This
should make implementing functions easier and safer.
Additionally the extended header ensure 64bits alignment, while making
all sizes multiple of 8 bytes, extending the maximum buffer size:
legacy extended
Maximum command buffer: 256KBytes 1024KBytes (512KBytes + 512KBytes)
Maximum response buffer: 256KBytes 1024KBytes (512KBytes + 512KBytes)
For the purpose of doing proper buffer size accounting, the headers
size are no more taken in account in "in_words".
One of the odds of the current extensible infrastructure, reading
twice the "legacy" command header, is fixed by removing the "legacy"
command header from the extended command header: they are processed as
two different parts of the command: memory is read once and
information are not duplicated: it's making clear that's an extended
command scheme and not a different command scheme.
The proposed scheme will format input (command) and output (response)
buffers this way:
- command:
legacy header +
extended header +
command data (core + hw):
+----------------------------------------+
| flags | 00 00 | command |
| in_words | out_words |
+----------------------------------------+
| response |
| response |
| provider_in_words | provider_out_words |
| padding |
+----------------------------------------+
| |
. <uverbs input> .
. (in_words * 8) .
| |
+----------------------------------------+
| |
. <provider input> .
. (provider_in_words * 8) .
| |
+----------------------------------------+
- response, if present:
+----------------------------------------+
| |
. <uverbs output space> .
. (out_words * 8) .
| |
+----------------------------------------+
| |
. <provider output space> .
. (provider_out_words * 8) .
| |
+----------------------------------------+
The overall design is to ensure that the extensible infrastructure is
itself extensible while begin more reliable with more input and bound
checking.
Note:
The unused field in the extended header would be perfect candidate to
hold the command "comp_mask" (eg. bit field used to handle
compatibility). This was suggested by Roland Dreier in a previous
review[2]. But "comp_mask" field is likely to be present in the uverb
input and/or provider input, likewise for the response, as noted by
Matan Barak[3], so it doesn't make sense to put "comp_mask" in the
header.
[1]:
http://marc.info/?i=CAL1RGDWxmM17W2o_era24A-TTDeKyoL6u3NRu_=t_dhV_ZA9MA@mail.gmail.com
[2]:
http://marc.info/?i=CAL1RGDXJtrc849M6_XNZT5xO1+ybKtLWGq6yg6LhoSsKpsmkYA@mail.gmail.com
[3]:
http://marc.info/?i=525C1149.6000701@mellanox.com
Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>
Link: http://marc.info/?i=cover.1383773832.git.ydroneaud@opteya.com
[ Convert "ret ? ret : 0" to the equivalent "ret". - Roland ]
Signed-off-by: Roland Dreier <roland@purestorage.com>
2013-11-07 06:21:49 +08:00
|
|
|
{
|
2013-08-14 18:58:30 +08:00
|
|
|
struct ib_uverbs_destroy_flow cmd;
|
|
|
|
int ret;
|
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
IB/core: extended command: an improved infrastructure for uverbs commands
Commit 400dbc96583f ("IB/core: Infrastructure for extensible uverbs
commands") added an infrastructure for extensible uverbs commands
while later commit 436f2ad05a0b ("IB/core: Export ib_create/destroy_flow
through uverbs") exported ib_create_flow()/ib_destroy_flow() functions
using this new infrastructure.
According to the commit 400dbc96583f, the purpose of this
infrastructure is to support passing around provider (eg. hardware)
specific buffers when userspace issue commands to the kernel, so that
it would be possible to extend uverbs (eg. core) buffers independently
from the provider buffers.
But the new kernel command function prototypes were not modified to
take advantage of this extension. This issue was exposed by Roland
Dreier in a previous review[1].
So the following patch is an attempt to a revised extensible command
infrastructure.
This improved extensible command infrastructure distinguish between
core (eg. legacy)'s command/response buffers from provider
(eg. hardware)'s command/response buffers: each extended command
implementing function is given a struct ib_udata to hold core
(eg. uverbs) input and output buffers, and another struct ib_udata to
hold the hw (eg. provider) input and output buffers.
Having those buffers identified separately make it easier to increase
one buffer to support extension without having to add some code to
guess the exact size of each command/response parts: This should make
the extended functions more reliable.
Additionally, instead of relying on command identifier being greater
than IB_USER_VERBS_CMD_THRESHOLD, the proposed infrastructure rely on
unused bits in command field: on the 32 bits provided by command
field, only 6 bits are really needed to encode the identifier of
commands currently supported by the kernel. (Even using only 6 bits
leaves room for about 23 new commands).
So this patch makes use of some high order bits in command field to
store flags, leaving enough room for more command identifiers than one
will ever need (eg. 256).
The new flags are used to specify if the command should be processed
as an extended one or a legacy one. While designing the new command
format, care was taken to make usage of flags itself extensible.
Using high order bits of the commands field ensure that newer
libibverbs on older kernel will properly fail when trying to call
extended commands. On the other hand, older libibverbs on newer kernel
will never be able to issue calls to extended commands.
The extended command header includes the optional response pointer so
that output buffer length and output buffer pointer are located
together in the command, allowing proper parameters checking. This
should make implementing functions easier and safer.
Additionally the extended header ensure 64bits alignment, while making
all sizes multiple of 8 bytes, extending the maximum buffer size:
legacy extended
Maximum command buffer: 256KBytes 1024KBytes (512KBytes + 512KBytes)
Maximum response buffer: 256KBytes 1024KBytes (512KBytes + 512KBytes)
For the purpose of doing proper buffer size accounting, the headers
size are no more taken in account in "in_words".
One of the odds of the current extensible infrastructure, reading
twice the "legacy" command header, is fixed by removing the "legacy"
command header from the extended command header: they are processed as
two different parts of the command: memory is read once and
information are not duplicated: it's making clear that's an extended
command scheme and not a different command scheme.
The proposed scheme will format input (command) and output (response)
buffers this way:
- command:
legacy header +
extended header +
command data (core + hw):
+----------------------------------------+
| flags | 00 00 | command |
| in_words | out_words |
+----------------------------------------+
| response |
| response |
| provider_in_words | provider_out_words |
| padding |
+----------------------------------------+
| |
. <uverbs input> .
. (in_words * 8) .
| |
+----------------------------------------+
| |
. <provider input> .
. (provider_in_words * 8) .
| |
+----------------------------------------+
- response, if present:
+----------------------------------------+
| |
. <uverbs output space> .
. (out_words * 8) .
| |
+----------------------------------------+
| |
. <provider output space> .
. (provider_out_words * 8) .
| |
+----------------------------------------+
The overall design is to ensure that the extensible infrastructure is
itself extensible while begin more reliable with more input and bound
checking.
Note:
The unused field in the extended header would be perfect candidate to
hold the command "comp_mask" (eg. bit field used to handle
compatibility). This was suggested by Roland Dreier in a previous
review[2]. But "comp_mask" field is likely to be present in the uverb
input and/or provider input, likewise for the response, as noted by
Matan Barak[3], so it doesn't make sense to put "comp_mask" in the
header.
[1]:
http://marc.info/?i=CAL1RGDWxmM17W2o_era24A-TTDeKyoL6u3NRu_=t_dhV_ZA9MA@mail.gmail.com
[2]:
http://marc.info/?i=CAL1RGDXJtrc849M6_XNZT5xO1+ybKtLWGq6yg6LhoSsKpsmkYA@mail.gmail.com
[3]:
http://marc.info/?i=525C1149.6000701@mellanox.com
Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>
Link: http://marc.info/?i=cover.1383773832.git.ydroneaud@opteya.com
[ Convert "ret ? ret : 0" to the equivalent "ret". - Roland ]
Signed-off-by: Roland Dreier <roland@purestorage.com>
2013-11-07 06:21:49 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2013-08-14 18:58:30 +08:00
|
|
|
|
2013-12-12 06:01:48 +08:00
|
|
|
if (cmd.comp_mask)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return uobj_perform_destroy(UVERBS_OBJECT_FLOW, cmd.flow_handle, attrs);
|
2013-08-14 18:58:30 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
static int __uverbs_create_xsrq(struct uverbs_attr_bundle *attrs,
|
2011-12-07 05:13:10 +08:00
|
|
|
struct ib_uverbs_create_xsrq *cmd,
|
|
|
|
struct ib_udata *udata)
|
2005-08-19 03:24:13 +08:00
|
|
|
{
|
2020-07-19 13:22:23 +08:00
|
|
|
struct ib_uverbs_create_srq_resp resp = {};
|
2011-05-26 08:08:38 +08:00
|
|
|
struct ib_usrq_object *obj;
|
2005-08-19 03:24:13 +08:00
|
|
|
struct ib_pd *pd;
|
|
|
|
struct ib_srq *srq;
|
|
|
|
struct ib_srq_init_attr attr;
|
|
|
|
int ret;
|
2020-07-21 01:56:26 +08:00
|
|
|
struct ib_uobject *xrcd_uobj;
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_device *ib_dev;
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
obj = (struct ib_usrq_object *)uobj_alloc(UVERBS_OBJECT_SRQ, attrs,
|
2018-07-26 11:40:17 +08:00
|
|
|
&ib_dev);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(obj))
|
|
|
|
return PTR_ERR(obj);
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2017-08-17 20:52:07 +08:00
|
|
|
if (cmd->srq_type == IB_SRQT_TM)
|
|
|
|
attr.ext.tag_matching.max_num_tags = cmd->max_num_tags;
|
|
|
|
|
2011-05-26 08:08:38 +08:00
|
|
|
if (cmd->srq_type == IB_SRQT_XRC) {
|
2018-03-19 21:02:33 +08:00
|
|
|
xrcd_uobj = uobj_get_read(UVERBS_OBJECT_XRCD, cmd->xrcd_handle,
|
2018-11-26 02:51:13 +08:00
|
|
|
attrs);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(xrcd_uobj)) {
|
2011-05-26 08:08:38 +08:00
|
|
|
ret = -EINVAL;
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
goto err;
|
2011-05-26 08:08:38 +08:00
|
|
|
}
|
|
|
|
|
2017-04-04 18:31:44 +08:00
|
|
|
attr.ext.xrc.xrcd = (struct ib_xrcd *)xrcd_uobj->object;
|
|
|
|
if (!attr.ext.xrc.xrcd) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put_xrcd;
|
|
|
|
}
|
|
|
|
|
2011-05-26 08:08:38 +08:00
|
|
|
obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object, uobject);
|
|
|
|
atomic_inc(&obj->uxrcd->refcnt);
|
2017-08-17 20:52:04 +08:00
|
|
|
}
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
|
2017-08-17 20:52:04 +08:00
|
|
|
if (ib_srq_has_cq(cmd->srq_type)) {
|
2018-07-04 16:32:09 +08:00
|
|
|
attr.ext.cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
|
2018-11-26 02:51:13 +08:00
|
|
|
cmd->cq_handle, attrs);
|
2017-08-17 20:52:04 +08:00
|
|
|
if (!attr.ext.cq) {
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put_xrcd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, attrs);
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
if (!pd) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_put_cq;
|
2011-05-26 08:08:38 +08:00
|
|
|
}
|
|
|
|
|
2005-08-19 03:24:13 +08:00
|
|
|
attr.event_handler = ib_uverbs_srq_event_handler;
|
2011-05-26 08:08:38 +08:00
|
|
|
attr.srq_type = cmd->srq_type;
|
|
|
|
attr.attr.max_wr = cmd->max_wr;
|
|
|
|
attr.attr.max_sge = cmd->max_sge;
|
|
|
|
attr.attr.srq_limit = cmd->srq_limit;
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2011-05-26 08:08:38 +08:00
|
|
|
INIT_LIST_HEAD(&obj->uevent.event_list);
|
2020-05-06 16:24:39 +08:00
|
|
|
obj->uevent.uobject.user_handle = cmd->user_handle;
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2020-05-06 16:24:39 +08:00
|
|
|
srq = ib_create_srq_user(pd, &attr, obj, udata);
|
|
|
|
if (IS_ERR(srq)) {
|
|
|
|
ret = PTR_ERR(srq);
|
|
|
|
goto err_put_pd;
|
2011-05-26 08:08:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
obj->uevent.uobject.object = srq;
|
2020-05-19 15:27:06 +08:00
|
|
|
obj->uevent.uobject.user_handle = cmd->user_handle;
|
|
|
|
obj->uevent.event_file = READ_ONCE(attrs->ufile->default_async_file);
|
|
|
|
if (obj->uevent.event_file)
|
|
|
|
uverbs_uobject_get(&obj->uevent.event_file->uobj);
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2011-05-26 08:08:38 +08:00
|
|
|
if (cmd->srq_type == IB_SRQT_XRC)
|
|
|
|
resp.srqn = srq->ext.xrc.srq_num;
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2017-08-17 20:52:04 +08:00
|
|
|
if (cmd->srq_type == IB_SRQT_XRC)
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_read(xrcd_uobj);
|
2017-08-17 20:52:04 +08:00
|
|
|
|
|
|
|
if (ib_srq_has_cq(cmd->srq_type))
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&attr.ext.cq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2017-08-17 20:52:04 +08:00
|
|
|
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(pd);
|
2020-07-19 13:22:23 +08:00
|
|
|
uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
|
|
|
|
|
|
|
|
resp.srq_handle = obj->uevent.uobject.id;
|
|
|
|
resp.max_wr = attr.attr.max_wr;
|
|
|
|
resp.max_sge = attr.attr.max_sge;
|
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2020-05-06 16:24:39 +08:00
|
|
|
err_put_pd:
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_obj_read(pd);
|
2011-05-26 08:08:38 +08:00
|
|
|
err_put_cq:
|
2017-08-17 20:52:04 +08:00
|
|
|
if (ib_srq_has_cq(cmd->srq_type))
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&attr.ext.cq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2011-05-26 08:08:38 +08:00
|
|
|
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
err_put_xrcd:
|
|
|
|
if (cmd->srq_type == IB_SRQT_XRC) {
|
|
|
|
atomic_dec(&obj->uxrcd->refcnt);
|
2017-04-04 18:31:44 +08:00
|
|
|
uobj_put_read(xrcd_uobj);
|
IB/uverbs: Lock SRQ / CQ / PD objects in a consistent order
Since XRC support was added, the uverbs code has locked SRQ, CQ and PD
objects needed during QP and SRQ creation in different orders
depending on the the code path. This leads to the (at least
theoretical) possibility of deadlock, and triggers the lockdep splat
below.
Fix this by making sure we always lock the SRQ first, then CQs and
finally the PD.
======================================================
[ INFO: possible circular locking dependency detected ]
3.4.0-rc5+ #34 Not tainted
-------------------------------------------------------
ibv_srq_pingpon/2484 is trying to acquire lock:
(SRQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
but task is already holding lock:
(CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (CQ-uobj){+++++.}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b16c3>] ib_uverbs_create_qp+0x180/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #1 (PD-uobj){++++++}:
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00af8ad>] __uverbs_create_xsrq+0x96/0x386 [ib_uverbs]
[<ffffffffa00b31b9>] ib_uverbs_detach_mcast+0x1cd/0x1e6 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
-> #0 (SRQ-uobj){+++++.}:
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
other info that might help us debug this:
Chain exists of:
SRQ-uobj --> PD-uobj --> CQ-uobj
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(CQ-uobj);
lock(PD-uobj);
lock(CQ-uobj);
lock(SRQ-uobj);
*** DEADLOCK ***
3 locks held by ibv_srq_pingpon/2484:
#0: (QP-uobj){+.+...}, at: [<ffffffffa00b162c>] ib_uverbs_create_qp+0xe9/0x684 [ib_uverbs]
#1: (PD-uobj){++++++}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
#2: (CQ-uobj){+++++.}, at: [<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
stack backtrace:
Pid: 2484, comm: ibv_srq_pingpon Not tainted 3.4.0-rc5+ #34
Call Trace:
[<ffffffff8137eff0>] print_circular_bug+0x1f8/0x209
[<ffffffff81070898>] __lock_acquire+0xa29/0xd06
[<ffffffffa00af37c>] ? __idr_get_uobj+0x20/0x5e [ib_uverbs]
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070fd0>] lock_acquire+0xbf/0xfe
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffff81070eee>] ? lock_release+0x166/0x189
[<ffffffff81384f28>] down_read+0x34/0x43
[<ffffffffa00af51b>] ? idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af51b>] idr_read_uobj+0x2f/0x4d [ib_uverbs]
[<ffffffffa00af542>] idr_read_obj+0x9/0x19 [ib_uverbs]
[<ffffffffa00b1728>] ib_uverbs_create_qp+0x1e5/0x684 [ib_uverbs]
[<ffffffff81070fec>] ? lock_acquire+0xdb/0xfe
[<ffffffff81070c09>] ? lock_release_non_nested+0x94/0x213
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffff810d470f>] ? might_fault+0x40/0x90
[<ffffffffa00ae3dd>] ib_uverbs_write+0xb7/0xc2 [ib_uverbs]
[<ffffffff810fe47f>] vfs_write+0xa7/0xee
[<ffffffff810ff736>] ? fget_light+0x3b/0x99
[<ffffffff810fe65f>] sys_write+0x45/0x69
[<ffffffff8138cdf9>] system_call_fastpath+0x16/0x1b
Reported-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
2012-05-01 03:51:50 +08:00
|
|
|
}
|
2006-07-17 23:20:51 +08:00
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
err:
|
2019-04-01 00:10:04 +08:00
|
|
|
uobj_alloc_abort(&obj->uevent.uobject, attrs);
|
2005-08-19 03:24:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_create_srq(struct uverbs_attr_bundle *attrs)
|
2011-05-26 08:08:38 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_create_srq cmd;
|
|
|
|
struct ib_uverbs_create_xsrq xcmd;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2011-05-26 08:08:38 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2011-05-26 08:08:38 +08:00
|
|
|
|
2017-08-17 20:52:07 +08:00
|
|
|
memset(&xcmd, 0, sizeof(xcmd));
|
2011-05-26 08:08:38 +08:00
|
|
|
xcmd.response = cmd.response;
|
|
|
|
xcmd.user_handle = cmd.user_handle;
|
|
|
|
xcmd.srq_type = IB_SRQT_BASIC;
|
|
|
|
xcmd.pd_handle = cmd.pd_handle;
|
|
|
|
xcmd.max_wr = cmd.max_wr;
|
|
|
|
xcmd.max_sge = cmd.max_sge;
|
|
|
|
xcmd.srq_limit = cmd.srq_limit;
|
|
|
|
|
2018-11-26 02:51:18 +08:00
|
|
|
return __uverbs_create_xsrq(attrs, &xcmd, &attrs->driver_udata);
|
2011-05-26 08:08:38 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_create_xsrq(struct uverbs_attr_bundle *attrs)
|
2011-05-26 08:08:38 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_create_xsrq cmd;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2011-05-26 08:08:38 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2011-05-26 08:08:38 +08:00
|
|
|
|
2018-11-26 02:51:18 +08:00
|
|
|
return __uverbs_create_xsrq(attrs, &cmd, &attrs->driver_udata);
|
2011-05-26 08:08:38 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_modify_srq(struct uverbs_attr_bundle *attrs)
|
2005-08-19 03:24:13 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_modify_srq cmd;
|
|
|
|
struct ib_srq *srq;
|
|
|
|
struct ib_srq_attr attr;
|
|
|
|
int ret;
|
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (!srq)
|
|
|
|
return -EINVAL;
|
2005-08-19 03:24:13 +08:00
|
|
|
|
|
|
|
attr.max_wr = cmd.max_wr;
|
|
|
|
attr.srq_limit = cmd.srq_limit;
|
|
|
|
|
2018-12-11 03:09:48 +08:00
|
|
|
ret = srq->device->ops.modify_srq(srq, &attr, cmd.attr_mask,
|
|
|
|
&attrs->driver_udata);
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2020-01-09 01:22:00 +08:00
|
|
|
rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2018-11-26 02:51:14 +08:00
|
|
|
return ret;
|
2005-08-19 03:24:13 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_query_srq(struct uverbs_attr_bundle *attrs)
|
2006-02-14 08:31:57 +08:00
|
|
|
{
|
|
|
|
struct ib_uverbs_query_srq cmd;
|
|
|
|
struct ib_uverbs_query_srq_resp resp;
|
|
|
|
struct ib_srq_attr attr;
|
|
|
|
struct ib_srq *srq;
|
|
|
|
int ret;
|
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2006-02-14 08:31:57 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
if (!srq)
|
|
|
|
return -EINVAL;
|
2006-02-14 08:31:57 +08:00
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
ret = ib_query_srq(srq, &attr);
|
2006-02-14 08:31:57 +08:00
|
|
|
|
2020-01-09 01:22:00 +08:00
|
|
|
rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2006-02-14 08:31:57 +08:00
|
|
|
|
|
|
|
if (ret)
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
return ret;
|
2006-02-14 08:31:57 +08:00
|
|
|
|
|
|
|
memset(&resp, 0, sizeof resp);
|
|
|
|
|
|
|
|
resp.max_wr = attr.max_wr;
|
|
|
|
resp.max_sge = attr.max_sge;
|
|
|
|
resp.srq_limit = attr.srq_limit;
|
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2006-02-14 08:31:57 +08:00
|
|
|
}
|
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_destroy_srq(struct uverbs_attr_bundle *attrs)
|
2005-08-19 03:24:13 +08:00
|
|
|
{
|
2005-09-10 06:55:08 +08:00
|
|
|
struct ib_uverbs_destroy_srq cmd;
|
|
|
|
struct ib_uverbs_destroy_srq_resp resp;
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
struct ib_uobject *uobj;
|
|
|
|
struct ib_uevent_object *obj;
|
2018-11-26 02:58:38 +08:00
|
|
|
int ret;
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2018-11-26 02:58:38 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-08-19 03:24:13 +08:00
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
uobj = uobj_get_destroy(UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
|
2017-04-04 18:31:44 +08:00
|
|
|
if (IS_ERR(uobj))
|
|
|
|
return PTR_ERR(uobj);
|
|
|
|
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
obj = container_of(uobj, struct ib_uevent_object, uobject);
|
2017-04-04 18:31:44 +08:00
|
|
|
memset(&resp, 0, sizeof(resp));
|
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel
are serialized by ib_uverbs_idr_mutex. This can be a scalability
issue for some workloads, especially for devices driven by the ipath
driver, which needs to call into the kernel even for datapath
operations.
Fix this by adding reference counts to the userspace objects, and then
converting ib_uverbs_idr_mutex into a spinlock that only protects the
idrs long enough to take a reference on the object being looked up.
Because remove operations may fail, we have to do a slightly funky
two-step deletion, which is described in the comments at the top of
uverbs_cmd.c.
This also still leaves ib_uverbs_idr_lock as a single lock that is
possibly subject to contention. However, the lock hold time will only
be a single idr operation, so multiple threads should still be able to
make progress, even if ib_uverbs_idr_lock is being ping-ponged.
Surprisingly, these changes even shrink the object code:
add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60)
Signed-off-by: Roland Dreier <rolandd@cisco.com>
2006-06-18 11:44:49 +08:00
|
|
|
resp.events_reported = obj->events_reported;
|
2018-07-26 11:40:11 +08:00
|
|
|
|
|
|
|
uobj_put_destroy(uobj);
|
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2005-08-19 03:24:13 +08:00
|
|
|
}
|
2015-02-08 19:28:50 +08:00
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_query_device(struct uverbs_attr_bundle *attrs)
|
2015-02-08 19:28:50 +08:00
|
|
|
{
|
2018-11-26 02:58:41 +08:00
|
|
|
struct ib_uverbs_ex_query_device_resp resp = {};
|
2015-02-08 19:28:50 +08:00
|
|
|
struct ib_uverbs_ex_query_device cmd;
|
2016-02-23 16:25:24 +08:00
|
|
|
struct ib_device_attr attr = {0};
|
2018-07-26 11:40:17 +08:00
|
|
|
struct ib_ucontext *ucontext;
|
|
|
|
struct ib_device *ib_dev;
|
2015-02-08 19:28:50 +08:00
|
|
|
int err;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
ucontext = ib_uverbs_get_ucontext(attrs);
|
2018-07-26 11:40:17 +08:00
|
|
|
if (IS_ERR(ucontext))
|
|
|
|
return PTR_ERR(ucontext);
|
|
|
|
ib_dev = ucontext->device;
|
|
|
|
|
2018-11-26 02:58:41 +08:00
|
|
|
err = uverbs_request(attrs, &cmd, sizeof(cmd));
|
2015-02-08 19:28:50 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (cmd.comp_mask)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (cmd.reserved)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-12-11 03:09:48 +08:00
|
|
|
err = ib_dev->ops.query_device(ib_dev, &attr, &attrs->driver_udata);
|
2015-02-08 19:28:50 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2018-07-26 11:40:17 +08:00
|
|
|
copy_query_dev_fields(ucontext, &resp.base, &attr);
|
2015-02-08 19:28:50 +08:00
|
|
|
|
2015-02-08 19:28:51 +08:00
|
|
|
resp.odp_caps.general_caps = attr.odp_caps.general_caps;
|
|
|
|
resp.odp_caps.per_transport_caps.rc_odp_caps =
|
|
|
|
attr.odp_caps.per_transport_caps.rc_odp_caps;
|
|
|
|
resp.odp_caps.per_transport_caps.uc_odp_caps =
|
|
|
|
attr.odp_caps.per_transport_caps.uc_odp_caps;
|
|
|
|
resp.odp_caps.per_transport_caps.ud_odp_caps =
|
|
|
|
attr.odp_caps.per_transport_caps.ud_odp_caps;
|
2019-01-22 14:48:42 +08:00
|
|
|
resp.xrc_odp_caps = attr.odp_caps.per_transport_caps.xrc_odp_caps;
|
2015-06-11 21:35:24 +08:00
|
|
|
|
|
|
|
resp.timestamp_mask = attr.timestamp_mask;
|
|
|
|
resp.hca_core_clock = attr.hca_core_clock;
|
2022-04-04 23:26:42 +08:00
|
|
|
resp.device_cap_flags_ex = attr.device_cap_flags;
|
2016-08-28 16:28:44 +08:00
|
|
|
resp.rss_caps.supported_qpts = attr.rss_caps.supported_qpts;
|
|
|
|
resp.rss_caps.max_rwq_indirection_tables =
|
|
|
|
attr.rss_caps.max_rwq_indirection_tables;
|
|
|
|
resp.rss_caps.max_rwq_indirection_table_size =
|
|
|
|
attr.rss_caps.max_rwq_indirection_table_size;
|
|
|
|
resp.max_wq_type_rq = attr.max_wq_type_rq;
|
2017-01-18 21:39:58 +08:00
|
|
|
resp.raw_packet_caps = attr.raw_packet_caps;
|
2017-09-25 02:46:29 +08:00
|
|
|
resp.tm_caps.max_rndv_hdr_size = attr.tm_caps.max_rndv_hdr_size;
|
|
|
|
resp.tm_caps.max_num_tags = attr.tm_caps.max_num_tags;
|
|
|
|
resp.tm_caps.max_ops = attr.tm_caps.max_ops;
|
|
|
|
resp.tm_caps.max_sge = attr.tm_caps.max_sge;
|
|
|
|
resp.tm_caps.flags = attr.tm_caps.flags;
|
2017-11-13 16:51:16 +08:00
|
|
|
resp.cq_moderation_caps.max_cq_moderation_count =
|
|
|
|
attr.cq_caps.max_cq_moderation_count;
|
|
|
|
resp.cq_moderation_caps.max_cq_moderation_period =
|
|
|
|
attr.cq_caps.max_cq_moderation_period;
|
2018-04-05 23:53:23 +08:00
|
|
|
resp.max_dm_size = attr.max_dm_size;
|
2018-11-26 02:58:41 +08:00
|
|
|
resp.response_length = uverbs_response_length(attrs, sizeof(resp));
|
|
|
|
|
2018-11-26 02:58:37 +08:00
|
|
|
return uverbs_response(attrs, &resp, sizeof(resp));
|
2015-02-08 19:28:50 +08:00
|
|
|
}
|
2017-11-13 16:51:13 +08:00
|
|
|
|
2018-11-26 02:58:45 +08:00
|
|
|
static int ib_uverbs_ex_modify_cq(struct uverbs_attr_bundle *attrs)
|
2017-11-13 16:51:13 +08:00
|
|
|
{
|
2018-11-26 02:58:39 +08:00
|
|
|
struct ib_uverbs_ex_modify_cq cmd;
|
2017-11-13 16:51:13 +08:00
|
|
|
struct ib_cq *cq;
|
|
|
|
int ret;
|
|
|
|
|
2018-11-26 02:58:39 +08:00
|
|
|
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
|
2017-11-13 16:51:13 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (!cmd.attr_mask || cmd.reserved)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (cmd.attr_mask > IB_CQ_MODERATE)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2018-11-26 02:51:13 +08:00
|
|
|
cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
|
2017-11-13 16:51:13 +08:00
|
|
|
if (!cq)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-11-13 16:51:19 +08:00
|
|
|
ret = rdma_set_cq_moderation(cq, cmd.attr.cq_count, cmd.attr.cq_period);
|
2017-11-13 16:51:13 +08:00
|
|
|
|
2020-01-09 01:21:58 +08:00
|
|
|
rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
|
|
|
|
UVERBS_LOOKUP_READ);
|
2017-11-13 16:51:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2018-11-13 04:59:56 +08:00
|
|
|
|
2018-11-26 02:51:16 +08:00
|
|
|
/*
|
|
|
|
* Describe the input structs for write(). Some write methods have an input
|
|
|
|
* only struct, most have an input and output. If the struct has an output then
|
|
|
|
* the 'response' u64 must be the first field in the request structure.
|
|
|
|
*
|
|
|
|
* If udata is present then both the request and response structs have a
|
|
|
|
* trailing driver_data flex array. In this case the size of the base struct
|
|
|
|
* cannot be changed.
|
|
|
|
*/
|
|
|
|
#define UAPI_DEF_WRITE_IO(req, resp) \
|
|
|
|
.write.has_resp = 1 + \
|
|
|
|
BUILD_BUG_ON_ZERO(offsetof(req, response) != 0) + \
|
2020-05-27 22:41:52 +08:00
|
|
|
BUILD_BUG_ON_ZERO(sizeof_field(req, response) != \
|
2018-11-26 02:51:16 +08:00
|
|
|
sizeof(u64)), \
|
|
|
|
.write.req_size = sizeof(req), .write.resp_size = sizeof(resp)
|
|
|
|
|
|
|
|
#define UAPI_DEF_WRITE_I(req) .write.req_size = sizeof(req)
|
|
|
|
|
|
|
|
#define UAPI_DEF_WRITE_UDATA_IO(req, resp) \
|
|
|
|
UAPI_DEF_WRITE_IO(req, resp), \
|
|
|
|
.write.has_udata = \
|
|
|
|
1 + \
|
|
|
|
BUILD_BUG_ON_ZERO(offsetof(req, driver_data) != \
|
|
|
|
sizeof(req)) + \
|
|
|
|
BUILD_BUG_ON_ZERO(offsetof(resp, driver_data) != \
|
|
|
|
sizeof(resp))
|
|
|
|
|
|
|
|
#define UAPI_DEF_WRITE_UDATA_I(req) \
|
|
|
|
UAPI_DEF_WRITE_I(req), \
|
|
|
|
.write.has_udata = \
|
|
|
|
1 + BUILD_BUG_ON_ZERO(offsetof(req, driver_data) != \
|
|
|
|
sizeof(req))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The _EX versions are for use with WRITE_EX and allow the last struct member
|
|
|
|
* to be specified. Buffers that do not include that member will be rejected.
|
|
|
|
*/
|
|
|
|
#define UAPI_DEF_WRITE_IO_EX(req, req_last_member, resp, resp_last_member) \
|
|
|
|
.write.has_resp = 1, \
|
2019-06-14 08:13:51 +08:00
|
|
|
.write.req_size = offsetofend(req, req_last_member), \
|
|
|
|
.write.resp_size = offsetofend(resp, resp_last_member)
|
2018-11-26 02:51:16 +08:00
|
|
|
|
|
|
|
#define UAPI_DEF_WRITE_I_EX(req, req_last_member) \
|
2019-06-14 08:13:51 +08:00
|
|
|
.write.req_size = offsetofend(req, req_last_member)
|
2018-11-26 02:51:16 +08:00
|
|
|
|
2018-11-13 04:59:56 +08:00
|
|
|
const struct uapi_definition uverbs_def_write_intf[] = {
|
2018-11-13 04:59:58 +08:00
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_AH,
|
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_AH,
|
|
|
|
ib_uverbs_create_ah,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_UDATA_IO(
|
|
|
|
struct ib_uverbs_create_ah,
|
2020-10-04 07:20:11 +08:00
|
|
|
struct ib_uverbs_create_ah_resp)),
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_DESTROY_AH,
|
|
|
|
ib_uverbs_destroy_ah,
|
2020-10-04 07:20:11 +08:00
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_destroy_ah)),
|
|
|
|
UAPI_DEF_OBJ_NEEDS_FN(create_user_ah),
|
|
|
|
UAPI_DEF_OBJ_NEEDS_FN(destroy_ah)),
|
2018-11-13 04:59:56 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_COMP_CHANNEL,
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL,
|
|
|
|
ib_uverbs_create_comp_channel,
|
|
|
|
UAPI_DEF_WRITE_IO(
|
|
|
|
struct ib_uverbs_create_comp_channel,
|
|
|
|
struct ib_uverbs_create_comp_channel_resp))),
|
2018-11-13 04:59:56 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_CQ,
|
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_CQ,
|
2018-11-13 04:59:58 +08:00
|
|
|
ib_uverbs_create_cq,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_UDATA_IO(
|
|
|
|
struct ib_uverbs_create_cq,
|
|
|
|
struct ib_uverbs_create_cq_resp),
|
2018-11-13 04:59:58 +08:00
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(create_cq)),
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_DESTROY_CQ,
|
|
|
|
ib_uverbs_destroy_cq,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_destroy_cq,
|
|
|
|
struct ib_uverbs_destroy_cq_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(destroy_cq)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_POLL_CQ,
|
|
|
|
ib_uverbs_poll_cq,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_poll_cq,
|
|
|
|
struct ib_uverbs_poll_cq_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(poll_cq)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_REQ_NOTIFY_CQ,
|
|
|
|
ib_uverbs_req_notify_cq,
|
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_req_notify_cq),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(req_notify_cq)),
|
2018-11-13 04:59:56 +08:00
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_RESIZE_CQ,
|
2018-11-13 04:59:58 +08:00
|
|
|
ib_uverbs_resize_cq,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_UDATA_IO(
|
|
|
|
struct ib_uverbs_resize_cq,
|
|
|
|
struct ib_uverbs_resize_cq_resp),
|
2018-11-13 04:59:58 +08:00
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(resize_cq)),
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_CREATE_CQ,
|
|
|
|
ib_uverbs_ex_create_cq,
|
|
|
|
UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_create_cq,
|
|
|
|
reserved,
|
|
|
|
struct ib_uverbs_ex_create_cq_resp,
|
|
|
|
response_length),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(create_cq)),
|
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_MODIFY_CQ,
|
|
|
|
ib_uverbs_ex_modify_cq,
|
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_ex_modify_cq),
|
2020-10-04 07:20:02 +08:00
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(modify_cq))),
|
2018-11-13 04:59:56 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_DEVICE,
|
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_GET_CONTEXT,
|
2018-11-26 02:51:16 +08:00
|
|
|
ib_uverbs_get_context,
|
|
|
|
UAPI_DEF_WRITE_UDATA_IO(
|
|
|
|
struct ib_uverbs_get_context,
|
|
|
|
struct ib_uverbs_get_context_resp)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_QUERY_DEVICE,
|
|
|
|
ib_uverbs_query_device,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_query_device,
|
|
|
|
struct ib_uverbs_query_device_resp)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_QUERY_PORT,
|
|
|
|
ib_uverbs_query_port,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_query_port,
|
|
|
|
struct ib_uverbs_query_port_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(query_port)),
|
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_QUERY_DEVICE,
|
|
|
|
ib_uverbs_ex_query_device,
|
|
|
|
UAPI_DEF_WRITE_IO_EX(
|
|
|
|
struct ib_uverbs_ex_query_device,
|
|
|
|
reserved,
|
|
|
|
struct ib_uverbs_ex_query_device_resp,
|
|
|
|
response_length),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(query_device)),
|
2018-11-13 04:59:58 +08:00
|
|
|
UAPI_DEF_OBJ_NEEDS_FN(alloc_ucontext),
|
|
|
|
UAPI_DEF_OBJ_NEEDS_FN(dealloc_ucontext)),
|
2018-11-13 04:59:56 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_FLOW,
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_CREATE_FLOW,
|
|
|
|
ib_uverbs_ex_create_flow,
|
|
|
|
UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_create_flow,
|
|
|
|
flow_attr,
|
|
|
|
struct ib_uverbs_create_flow_resp,
|
|
|
|
flow_handle),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(create_flow)),
|
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_DESTROY_FLOW,
|
|
|
|
ib_uverbs_ex_destroy_flow,
|
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_destroy_flow),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(destroy_flow))),
|
2018-11-13 04:59:58 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_MR,
|
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_DEREG_MR,
|
|
|
|
ib_uverbs_dereg_mr,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_dereg_mr),
|
2018-11-13 04:59:58 +08:00
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(dereg_mr)),
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_REG_MR,
|
|
|
|
ib_uverbs_reg_mr,
|
|
|
|
UAPI_DEF_WRITE_UDATA_IO(struct ib_uverbs_reg_mr,
|
|
|
|
struct ib_uverbs_reg_mr_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(reg_user_mr)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_REREG_MR,
|
|
|
|
ib_uverbs_rereg_mr,
|
|
|
|
UAPI_DEF_WRITE_UDATA_IO(struct ib_uverbs_rereg_mr,
|
|
|
|
struct ib_uverbs_rereg_mr_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(rereg_user_mr))),
|
2018-11-13 04:59:58 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_MW,
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_ALLOC_MW,
|
|
|
|
ib_uverbs_alloc_mw,
|
|
|
|
UAPI_DEF_WRITE_UDATA_IO(struct ib_uverbs_alloc_mw,
|
|
|
|
struct ib_uverbs_alloc_mw_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(alloc_mw)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_DEALLOC_MW,
|
|
|
|
ib_uverbs_dealloc_mw,
|
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_dealloc_mw),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(dealloc_mw))),
|
2018-11-13 04:59:58 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_PD,
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_ALLOC_PD,
|
|
|
|
ib_uverbs_alloc_pd,
|
|
|
|
UAPI_DEF_WRITE_UDATA_IO(struct ib_uverbs_alloc_pd,
|
|
|
|
struct ib_uverbs_alloc_pd_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(alloc_pd)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_DEALLOC_PD,
|
|
|
|
ib_uverbs_dealloc_pd,
|
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_dealloc_pd),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(dealloc_pd))),
|
2018-11-13 04:59:56 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_QP,
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_ATTACH_MCAST,
|
|
|
|
ib_uverbs_attach_mcast,
|
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_attach_mcast),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(attach_mcast),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(detach_mcast)),
|
2018-11-13 04:59:56 +08:00
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_QP,
|
2018-11-13 04:59:58 +08:00
|
|
|
ib_uverbs_create_qp,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_UDATA_IO(
|
|
|
|
struct ib_uverbs_create_qp,
|
|
|
|
struct ib_uverbs_create_qp_resp),
|
2018-11-13 04:59:58 +08:00
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(create_qp)),
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_DESTROY_QP,
|
|
|
|
ib_uverbs_destroy_qp,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_destroy_qp,
|
|
|
|
struct ib_uverbs_destroy_qp_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(destroy_qp)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_DETACH_MCAST,
|
|
|
|
ib_uverbs_detach_mcast,
|
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_detach_mcast),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(detach_mcast)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_MODIFY_QP,
|
|
|
|
ib_uverbs_modify_qp,
|
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_modify_qp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(modify_qp)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_POST_RECV,
|
|
|
|
ib_uverbs_post_recv,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_post_recv,
|
|
|
|
struct ib_uverbs_post_recv_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(post_recv)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_POST_SEND,
|
|
|
|
ib_uverbs_post_send,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_post_send,
|
|
|
|
struct ib_uverbs_post_send_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(post_send)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_QUERY_QP,
|
|
|
|
ib_uverbs_query_qp,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_query_qp,
|
|
|
|
struct ib_uverbs_query_qp_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(query_qp)),
|
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_CREATE_QP,
|
|
|
|
ib_uverbs_ex_create_qp,
|
|
|
|
UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_create_qp,
|
|
|
|
comp_mask,
|
|
|
|
struct ib_uverbs_ex_create_qp_resp,
|
|
|
|
response_length),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(create_qp)),
|
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_MODIFY_QP,
|
|
|
|
ib_uverbs_ex_modify_qp,
|
|
|
|
UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_modify_qp,
|
|
|
|
base,
|
|
|
|
struct ib_uverbs_ex_modify_qp_resp,
|
|
|
|
response_length),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(modify_qp))),
|
2018-11-13 04:59:56 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_RWQ_IND_TBL,
|
2018-11-13 04:59:58 +08:00
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL,
|
|
|
|
ib_uverbs_ex_create_rwq_ind_table,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_IO_EX(
|
|
|
|
struct ib_uverbs_ex_create_rwq_ind_table,
|
|
|
|
log_ind_tbl_size,
|
|
|
|
struct ib_uverbs_ex_create_rwq_ind_table_resp,
|
|
|
|
ind_tbl_num),
|
2018-11-13 04:59:58 +08:00
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(create_rwq_ind_table)),
|
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL,
|
|
|
|
ib_uverbs_ex_destroy_rwq_ind_table,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_I(
|
|
|
|
struct ib_uverbs_ex_destroy_rwq_ind_table),
|
2018-11-13 04:59:58 +08:00
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(destroy_rwq_ind_table))),
|
2018-11-13 04:59:56 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_WQ,
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_CREATE_WQ,
|
|
|
|
ib_uverbs_ex_create_wq,
|
|
|
|
UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_create_wq,
|
|
|
|
max_sge,
|
|
|
|
struct ib_uverbs_ex_create_wq_resp,
|
|
|
|
wqn),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(create_wq)),
|
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_DESTROY_WQ,
|
|
|
|
ib_uverbs_ex_destroy_wq,
|
|
|
|
UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_destroy_wq,
|
|
|
|
wq_handle,
|
|
|
|
struct ib_uverbs_ex_destroy_wq_resp,
|
|
|
|
reserved),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(destroy_wq)),
|
|
|
|
DECLARE_UVERBS_WRITE_EX(
|
|
|
|
IB_USER_VERBS_EX_CMD_MODIFY_WQ,
|
|
|
|
ib_uverbs_ex_modify_wq,
|
|
|
|
UAPI_DEF_WRITE_I_EX(struct ib_uverbs_ex_modify_wq,
|
|
|
|
curr_wq_state),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(modify_wq))),
|
2018-11-13 04:59:56 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_SRQ,
|
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_SRQ,
|
2018-11-13 04:59:58 +08:00
|
|
|
ib_uverbs_create_srq,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_UDATA_IO(
|
|
|
|
struct ib_uverbs_create_srq,
|
|
|
|
struct ib_uverbs_create_srq_resp),
|
2018-11-13 04:59:58 +08:00
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(create_srq)),
|
2018-11-13 04:59:56 +08:00
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_XSRQ,
|
2018-11-13 04:59:58 +08:00
|
|
|
ib_uverbs_create_xsrq,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_UDATA_IO(
|
|
|
|
struct ib_uverbs_create_xsrq,
|
|
|
|
struct ib_uverbs_create_srq_resp),
|
2018-11-13 04:59:58 +08:00
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(create_srq)),
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_DESTROY_SRQ,
|
|
|
|
ib_uverbs_destroy_srq,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_destroy_srq,
|
|
|
|
struct ib_uverbs_destroy_srq_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(destroy_srq)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_MODIFY_SRQ,
|
|
|
|
ib_uverbs_modify_srq,
|
|
|
|
UAPI_DEF_WRITE_UDATA_I(struct ib_uverbs_modify_srq),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(modify_srq)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_POST_SRQ_RECV,
|
|
|
|
ib_uverbs_post_srq_recv,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_post_srq_recv,
|
|
|
|
struct ib_uverbs_post_srq_recv_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(post_srq_recv)),
|
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_QUERY_SRQ,
|
|
|
|
ib_uverbs_query_srq,
|
|
|
|
UAPI_DEF_WRITE_IO(struct ib_uverbs_query_srq,
|
|
|
|
struct ib_uverbs_query_srq_resp),
|
|
|
|
UAPI_DEF_METHOD_NEEDS_FN(query_srq))),
|
2018-11-13 04:59:58 +08:00
|
|
|
|
|
|
|
DECLARE_UVERBS_OBJECT(
|
|
|
|
UVERBS_OBJECT_XRCD,
|
2018-11-26 02:51:16 +08:00
|
|
|
DECLARE_UVERBS_WRITE(
|
|
|
|
IB_USER_VERBS_CMD_CLOSE_XRCD,
|
|
|
|
ib_uverbs_close_xrcd,
|
2020-10-04 07:20:04 +08:00
|
|
|
UAPI_DEF_WRITE_I(struct ib_uverbs_close_xrcd)),
|
2018-11-13 04:59:58 +08:00
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_OPEN_QP,
|
2018-11-26 02:51:16 +08:00
|
|
|
ib_uverbs_open_qp,
|
|
|
|
UAPI_DEF_WRITE_UDATA_IO(
|
|
|
|
struct ib_uverbs_open_qp,
|
|
|
|
struct ib_uverbs_create_qp_resp)),
|
2018-11-13 04:59:58 +08:00
|
|
|
DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_OPEN_XRCD,
|
|
|
|
ib_uverbs_open_xrcd,
|
2018-11-26 02:51:16 +08:00
|
|
|
UAPI_DEF_WRITE_UDATA_IO(
|
|
|
|
struct ib_uverbs_open_xrcd,
|
2020-10-04 07:20:04 +08:00
|
|
|
struct ib_uverbs_open_xrcd_resp)),
|
|
|
|
UAPI_DEF_OBJ_NEEDS_FN(alloc_xrcd),
|
|
|
|
UAPI_DEF_OBJ_NEEDS_FN(dealloc_xrcd)),
|
2018-11-13 04:59:56 +08:00
|
|
|
|
|
|
|
{},
|
|
|
|
};
|