|
@@ -1741,66 +1741,65 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
|
|
return in_len;
|
|
return in_len;
|
|
}
|
|
}
|
|
|
|
|
|
-ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
|
|
|
|
- struct ib_device *ib_dev,
|
|
|
|
- const char __user *buf, int in_len,
|
|
|
|
- int out_len)
|
|
|
|
-{
|
|
|
|
- struct ib_uverbs_create_qp cmd;
|
|
|
|
- struct ib_uverbs_create_qp_resp resp;
|
|
|
|
- struct ib_udata udata;
|
|
|
|
- struct ib_uqp_object *obj;
|
|
|
|
- struct ib_device *device;
|
|
|
|
- struct ib_pd *pd = NULL;
|
|
|
|
- struct ib_xrcd *xrcd = NULL;
|
|
|
|
- struct ib_uobject *uninitialized_var(xrcd_uobj);
|
|
|
|
- struct ib_cq *scq = NULL, *rcq = NULL;
|
|
|
|
- struct ib_srq *srq = NULL;
|
|
|
|
- struct ib_qp *qp;
|
|
|
|
- struct ib_qp_init_attr attr;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- if (out_len < sizeof resp)
|
|
|
|
- return -ENOSPC;
|
|
|
|
-
|
|
|
|
- if (copy_from_user(&cmd, buf, sizeof cmd))
|
|
|
|
- return -EFAULT;
|
|
|
|
|
|
+static int create_qp(struct ib_uverbs_file *file,
|
|
|
|
+ struct ib_udata *ucore,
|
|
|
|
+ struct ib_udata *uhw,
|
|
|
|
+ struct ib_uverbs_ex_create_qp *cmd,
|
|
|
|
+ size_t cmd_sz,
|
|
|
|
+ int (*cb)(struct ib_uverbs_file *file,
|
|
|
|
+ struct ib_uverbs_ex_create_qp_resp *resp,
|
|
|
|
+ struct ib_udata *udata),
|
|
|
|
+ void *context)
|
|
|
|
+{
|
|
|
|
+ struct ib_uqp_object *obj;
|
|
|
|
+ struct ib_device *device;
|
|
|
|
+ struct ib_pd *pd = NULL;
|
|
|
|
+ struct ib_xrcd *xrcd = NULL;
|
|
|
|
+ struct ib_uobject *uninitialized_var(xrcd_uobj);
|
|
|
|
+ struct ib_cq *scq = NULL, *rcq = NULL;
|
|
|
|
+ struct ib_srq *srq = NULL;
|
|
|
|
+ struct ib_qp *qp;
|
|
|
|
+ char *buf;
|
|
|
|
+ struct ib_qp_init_attr attr;
|
|
|
|
+ struct ib_uverbs_ex_create_qp_resp resp;
|
|
|
|
+ int ret;
|
|
|
|
|
|
- if (cmd.qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
|
|
|
|
|
|
+ if (cmd->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
|
|
return -EPERM;
|
|
return -EPERM;
|
|
|
|
|
|
- INIT_UDATA(&udata, buf + sizeof cmd,
|
|
|
|
- (unsigned long) cmd.response + sizeof resp,
|
|
|
|
- in_len - sizeof cmd, out_len - sizeof resp);
|
|
|
|
-
|
|
|
|
obj = kzalloc(sizeof *obj, GFP_KERNEL);
|
|
obj = kzalloc(sizeof *obj, GFP_KERNEL);
|
|
if (!obj)
|
|
if (!obj)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
- init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_class);
|
|
|
|
|
|
+ init_uobj(&obj->uevent.uobject, cmd->user_handle, file->ucontext,
|
|
|
|
+ &qp_lock_class);
|
|
down_write(&obj->uevent.uobject.mutex);
|
|
down_write(&obj->uevent.uobject.mutex);
|
|
|
|
|
|
- if (cmd.qp_type == IB_QPT_XRC_TGT) {
|
|
|
|
- xrcd = idr_read_xrcd(cmd.pd_handle, file->ucontext, &xrcd_uobj);
|
|
|
|
|
|
+ if (cmd->qp_type == IB_QPT_XRC_TGT) {
|
|
|
|
+ xrcd = idr_read_xrcd(cmd->pd_handle, file->ucontext,
|
|
|
|
+ &xrcd_uobj);
|
|
if (!xrcd) {
|
|
if (!xrcd) {
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
goto err_put;
|
|
goto err_put;
|
|
}
|
|
}
|
|
device = xrcd->device;
|
|
device = xrcd->device;
|
|
} else {
|
|
} else {
|
|
- if (cmd.qp_type == IB_QPT_XRC_INI) {
|
|
|
|
- cmd.max_recv_wr = cmd.max_recv_sge = 0;
|
|
|
|
|
|
+ if (cmd->qp_type == IB_QPT_XRC_INI) {
|
|
|
|
+ cmd->max_recv_wr = 0;
|
|
|
|
+ cmd->max_recv_sge = 0;
|
|
} else {
|
|
} else {
|
|
- if (cmd.is_srq) {
|
|
|
|
- srq = idr_read_srq(cmd.srq_handle, file->ucontext);
|
|
|
|
|
|
+ if (cmd->is_srq) {
|
|
|
|
+ srq = idr_read_srq(cmd->srq_handle,
|
|
|
|
+ file->ucontext);
|
|
if (!srq || srq->srq_type != IB_SRQT_BASIC) {
|
|
if (!srq || srq->srq_type != IB_SRQT_BASIC) {
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
goto err_put;
|
|
goto err_put;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (cmd.recv_cq_handle != cmd.send_cq_handle) {
|
|
|
|
- rcq = idr_read_cq(cmd.recv_cq_handle, file->ucontext, 0);
|
|
|
|
|
|
+ if (cmd->recv_cq_handle != cmd->send_cq_handle) {
|
|
|
|
+ rcq = idr_read_cq(cmd->recv_cq_handle,
|
|
|
|
+ file->ucontext, 0);
|
|
if (!rcq) {
|
|
if (!rcq) {
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
goto err_put;
|
|
goto err_put;
|
|
@@ -1808,9 +1807,9 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- scq = idr_read_cq(cmd.send_cq_handle, file->ucontext, !!rcq);
|
|
|
|
|
|
+ scq = idr_read_cq(cmd->send_cq_handle, file->ucontext, !!rcq);
|
|
rcq = rcq ?: scq;
|
|
rcq = rcq ?: scq;
|
|
- pd = idr_read_pd(cmd.pd_handle, file->ucontext);
|
|
|
|
|
|
+ pd = idr_read_pd(cmd->pd_handle, file->ucontext);
|
|
if (!pd || !scq) {
|
|
if (!pd || !scq) {
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
goto err_put;
|
|
goto err_put;
|
|
@@ -1825,31 +1824,49 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
|
|
attr.recv_cq = rcq;
|
|
attr.recv_cq = rcq;
|
|
attr.srq = srq;
|
|
attr.srq = srq;
|
|
attr.xrcd = xrcd;
|
|
attr.xrcd = xrcd;
|
|
- attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
|
|
|
|
- attr.qp_type = cmd.qp_type;
|
|
|
|
|
|
+ attr.sq_sig_type = cmd->sq_sig_all ? IB_SIGNAL_ALL_WR :
|
|
|
|
+ IB_SIGNAL_REQ_WR;
|
|
|
|
+ attr.qp_type = cmd->qp_type;
|
|
attr.create_flags = 0;
|
|
attr.create_flags = 0;
|
|
|
|
|
|
- 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;
|
|
|
|
|
|
+ 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;
|
|
|
|
|
|
obj->uevent.events_reported = 0;
|
|
obj->uevent.events_reported = 0;
|
|
INIT_LIST_HEAD(&obj->uevent.event_list);
|
|
INIT_LIST_HEAD(&obj->uevent.event_list);
|
|
INIT_LIST_HEAD(&obj->mcast_list);
|
|
INIT_LIST_HEAD(&obj->mcast_list);
|
|
|
|
|
|
- if (cmd.qp_type == IB_QPT_XRC_TGT)
|
|
|
|
|
|
+ if (cmd_sz >= offsetof(typeof(*cmd), create_flags) +
|
|
|
|
+ sizeof(cmd->create_flags))
|
|
|
|
+ attr.create_flags = cmd->create_flags;
|
|
|
|
+
|
|
|
|
+ if (attr.create_flags) {
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto err_put;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ buf = (void *)cmd + sizeof(*cmd);
|
|
|
|
+ if (cmd_sz > sizeof(*cmd))
|
|
|
|
+ if (!(buf[0] == 0 && !memcmp(buf, buf + 1,
|
|
|
|
+ cmd_sz - sizeof(*cmd) - 1))) {
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto err_put;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (cmd->qp_type == IB_QPT_XRC_TGT)
|
|
qp = ib_create_qp(pd, &attr);
|
|
qp = ib_create_qp(pd, &attr);
|
|
else
|
|
else
|
|
- qp = device->create_qp(pd, &attr, &udata);
|
|
|
|
|
|
+ qp = device->create_qp(pd, &attr, uhw);
|
|
|
|
|
|
if (IS_ERR(qp)) {
|
|
if (IS_ERR(qp)) {
|
|
ret = PTR_ERR(qp);
|
|
ret = PTR_ERR(qp);
|
|
goto err_put;
|
|
goto err_put;
|
|
}
|
|
}
|
|
|
|
|
|
- if (cmd.qp_type != IB_QPT_XRC_TGT) {
|
|
|
|
|
|
+ if (cmd->qp_type != IB_QPT_XRC_TGT) {
|
|
qp->real_qp = qp;
|
|
qp->real_qp = qp;
|
|
qp->device = device;
|
|
qp->device = device;
|
|
qp->pd = pd;
|
|
qp->pd = pd;
|
|
@@ -1875,19 +1892,20 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
|
|
goto err_destroy;
|
|
goto err_destroy;
|
|
|
|
|
|
memset(&resp, 0, sizeof resp);
|
|
memset(&resp, 0, sizeof resp);
|
|
- resp.qpn = qp->qp_num;
|
|
|
|
- resp.qp_handle = obj->uevent.uobject.id;
|
|
|
|
- resp.max_recv_sge = attr.cap.max_recv_sge;
|
|
|
|
- resp.max_send_sge = attr.cap.max_send_sge;
|
|
|
|
- resp.max_recv_wr = attr.cap.max_recv_wr;
|
|
|
|
- resp.max_send_wr = attr.cap.max_send_wr;
|
|
|
|
- resp.max_inline_data = attr.cap.max_inline_data;
|
|
|
|
|
|
+ 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;
|
|
|
|
|
|
- if (copy_to_user((void __user *) (unsigned long) cmd.response,
|
|
|
|
- &resp, sizeof resp)) {
|
|
|
|
- ret = -EFAULT;
|
|
|
|
- goto err_copy;
|
|
|
|
- }
|
|
|
|
|
|
+ resp.response_length = offsetof(typeof(resp), response_length) +
|
|
|
|
+ sizeof(resp.response_length);
|
|
|
|
+
|
|
|
|
+ ret = cb(file, &resp, ucore);
|
|
|
|
+ if (ret)
|
|
|
|
+ goto err_cb;
|
|
|
|
|
|
if (xrcd) {
|
|
if (xrcd) {
|
|
obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
|
|
obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
|
|
@@ -1913,9 +1931,8 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
|
|
|
|
|
|
up_write(&obj->uevent.uobject.mutex);
|
|
up_write(&obj->uevent.uobject.mutex);
|
|
|
|
|
|
- return in_len;
|
|
|
|
-
|
|
|
|
-err_copy:
|
|
|
|
|
|
+ return 0;
|
|
|
|
+err_cb:
|
|
idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
|
|
idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
|
|
|
|
|
|
err_destroy:
|
|
err_destroy:
|
|
@@ -1937,6 +1954,113 @@ err_put:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int ib_uverbs_create_qp_cb(struct ib_uverbs_file *file,
|
|
|
|
+ struct ib_uverbs_ex_create_qp_resp *resp,
|
|
|
|
+ struct ib_udata *ucore)
|
|
|
|
+{
|
|
|
|
+ if (ib_copy_to_udata(ucore, &resp->base, sizeof(resp->base)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
|
|
|
|
+ struct ib_device *ib_dev,
|
|
|
|
+ const char __user *buf, int in_len,
|
|
|
|
+ int out_len)
|
|
|
|
+{
|
|
|
|
+ struct ib_uverbs_create_qp cmd;
|
|
|
|
+ struct ib_uverbs_ex_create_qp cmd_ex;
|
|
|
|
+ struct ib_udata ucore;
|
|
|
|
+ struct ib_udata uhw;
|
|
|
|
+ ssize_t resp_size = sizeof(struct ib_uverbs_create_qp_resp);
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ if (out_len < resp_size)
|
|
|
|
+ return -ENOSPC;
|
|
|
|
+
|
|
|
|
+ if (copy_from_user(&cmd, buf, sizeof(cmd)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ INIT_UDATA(&ucore, buf, (unsigned long)cmd.response, sizeof(cmd),
|
|
|
|
+ resp_size);
|
|
|
|
+ INIT_UDATA(&uhw, buf + sizeof(cmd),
|
|
|
|
+ (unsigned long)cmd.response + resp_size,
|
|
|
|
+ in_len - sizeof(cmd), out_len - resp_size);
|
|
|
|
+
|
|
|
|
+ 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;
|
|
|
|
+
|
|
|
|
+ err = create_qp(file, &ucore, &uhw, &cmd_ex,
|
|
|
|
+ offsetof(typeof(cmd_ex), is_srq) +
|
|
|
|
+ sizeof(cmd.is_srq), ib_uverbs_create_qp_cb,
|
|
|
|
+ NULL);
|
|
|
|
+
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ return in_len;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int ib_uverbs_ex_create_qp_cb(struct ib_uverbs_file *file,
|
|
|
|
+ struct ib_uverbs_ex_create_qp_resp *resp,
|
|
|
|
+ struct ib_udata *ucore)
|
|
|
|
+{
|
|
|
|
+ if (ib_copy_to_udata(ucore, resp, resp->response_length))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int ib_uverbs_ex_create_qp(struct ib_uverbs_file *file,
|
|
|
|
+ struct ib_device *ib_dev,
|
|
|
|
+ struct ib_udata *ucore,
|
|
|
|
+ struct ib_udata *uhw)
|
|
|
|
+{
|
|
|
|
+ struct ib_uverbs_ex_create_qp_resp resp;
|
|
|
|
+ struct ib_uverbs_ex_create_qp cmd = {0};
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ if (ucore->inlen < (offsetof(typeof(cmd), comp_mask) +
|
|
|
|
+ sizeof(cmd.comp_mask)))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ err = ib_copy_from_udata(&cmd, ucore, min(sizeof(cmd), ucore->inlen));
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ if (cmd.comp_mask)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if (cmd.reserved)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if (ucore->outlen < (offsetof(typeof(resp), response_length) +
|
|
|
|
+ sizeof(resp.response_length)))
|
|
|
|
+ return -ENOSPC;
|
|
|
|
+
|
|
|
|
+ err = create_qp(file, ucore, uhw, &cmd,
|
|
|
|
+ min(ucore->inlen, sizeof(cmd)),
|
|
|
|
+ ib_uverbs_ex_create_qp_cb, NULL);
|
|
|
|
+
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
|
|
ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
|
|
struct ib_device *ib_dev,
|
|
struct ib_device *ib_dev,
|
|
const char __user *buf, int in_len, int out_len)
|
|
const char __user *buf, int in_len, int out_len)
|