RDMA/uverbs: Add a simple iterator interface for reading the command

Several methods have a command with a trailing flex array, and they
all open code some extraction scheme. Centralize this into a simple
iterator API.

Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
Jason Gunthorpe 2018-11-25 20:58:42 +02:00 committed by Doug Ledford
parent 7eebced1ba
commit 335708c751
1 changed files with 65 additions and 48 deletions

View File

@ -112,6 +112,51 @@ static u32 uverbs_response_length(struct uverbs_attr_bundle *attrs,
return min_t(size_t, attrs->ucore.outlen, resp_len);
}
/*
* 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;
}
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;
}
static struct ib_uverbs_completion_event_file *
_ib_uverbs_lookup_comp_file(s32 fd, const struct uverbs_attr_bundle *attrs)
{
@ -3060,10 +3105,10 @@ static int ib_uverbs_ex_modify_wq(struct uverbs_attr_bundle *attrs,
static int ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle *attrs,
struct ib_udata *ucore)
{
struct ib_uverbs_ex_create_rwq_ind_table cmd = {};
struct ib_uverbs_ex_create_rwq_ind_table cmd;
struct ib_uverbs_ex_create_rwq_ind_table_resp resp = {};
struct ib_uobject *uobj;
int err = 0;
int err;
struct ib_rwq_ind_table_init_attr init_attr = {};
struct ib_rwq_ind_table *rwq_ind_tbl;
struct ib_wq **wqs = NULL;
@ -3071,27 +3116,13 @@ static int ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle *attrs,
struct ib_wq *wq = NULL;
int i, j, num_read_wqs;
u32 num_wq_handles;
u32 expected_in_size;
size_t required_cmd_sz_header;
size_t required_resp_len;
struct uverbs_req_iter iter;
struct ib_device *ib_dev;
required_cmd_sz_header = offsetof(typeof(cmd), log_ind_tbl_size) + sizeof(cmd.log_ind_tbl_size);
required_resp_len = offsetof(typeof(resp), ind_tbl_num) + sizeof(resp.ind_tbl_num);
if (ucore->inlen < required_cmd_sz_header)
return -EINVAL;
if (ucore->outlen < required_resp_len)
return -ENOSPC;
err = ib_copy_from_udata(&cmd, ucore, required_cmd_sz_header);
err = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
if (err)
return err;
ucore->inbuf += required_cmd_sz_header;
ucore->inlen -= required_cmd_sz_header;
if (cmd.comp_mask)
return -EOPNOTSUPP;
@ -3099,26 +3130,17 @@ static int ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle *attrs,
return -EINVAL;
num_wq_handles = 1 << cmd.log_ind_tbl_size;
expected_in_size = num_wq_handles * sizeof(__u32);
if (num_wq_handles == 1)
/* input size for wq handles is u64 aligned */
expected_in_size += sizeof(__u32);
if (ucore->inlen < expected_in_size)
return -EINVAL;
if (ucore->inlen > expected_in_size &&
!ib_is_udata_cleared(ucore, expected_in_size,
ucore->inlen - expected_in_size))
return -EOPNOTSUPP;
wqs_handles = kcalloc(num_wq_handles, sizeof(*wqs_handles),
GFP_KERNEL);
if (!wqs_handles)
return -ENOMEM;
err = ib_copy_from_udata(wqs_handles, ucore,
num_wq_handles * sizeof(__u32));
err = uverbs_request_next(&iter, wqs_handles,
num_wq_handles * sizeof(__u32));
if (err)
goto err_free;
err = uverbs_request_finish(&iter);
if (err)
goto err_free;
@ -3224,24 +3246,16 @@ static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs,
struct ib_qp *qp;
struct ib_uflow_resources *uflow_res;
struct ib_uverbs_flow_spec_hdr *kern_spec;
int err = 0;
struct uverbs_req_iter iter;
int err;
void *ib_spec;
int i;
struct ib_device *ib_dev;
if (ucore->inlen < sizeof(cmd))
return -EINVAL;
if (ucore->outlen < sizeof(resp))
return -ENOSPC;
err = ib_copy_from_udata(&cmd, ucore, sizeof(cmd));
err = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
if (err)
return err;
ucore->inbuf += sizeof(cmd);
ucore->inlen -= sizeof(cmd);
if (cmd.comp_mask)
return -EINVAL;
@ -3259,8 +3273,7 @@ static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs,
if (cmd.flow_attr.num_of_specs > IB_FLOW_SPEC_SUPPORT_LAYERS)
return -EINVAL;
if (cmd.flow_attr.size > ucore->inlen ||
cmd.flow_attr.size >
if (cmd.flow_attr.size >
(cmd.flow_attr.num_of_specs * sizeof(struct ib_uverbs_flow_spec)))
return -EINVAL;
@ -3275,14 +3288,18 @@ static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs,
return -ENOMEM;
*kern_flow_attr = cmd.flow_attr;
err = ib_copy_from_udata(&kern_flow_attr->flow_specs, ucore,
cmd.flow_attr.size);
err = uverbs_request_next(&iter, &kern_flow_attr->flow_specs,
cmd.flow_attr.size);
if (err)
goto err_free_attr;
} else {
kern_flow_attr = &cmd.flow_attr;
}
err = uverbs_request_finish(&iter);
if (err)
goto err_free_attr;
uobj = uobj_alloc(UVERBS_OBJECT_FLOW, attrs, &ib_dev);
if (IS_ERR(uobj)) {
err = PTR_ERR(uobj);