On Wed, Oct 21, 2015 at 11:34 AM, Haggai Eran <hagg...@mellanox.com> wrote:
> On 15/10/2015 14:44, Eran Ben Elisha wrote:
>> ib_uverbs_ex_create_qp follows the extension verbs
>> mechanism. New features (for example, QP creation flags
>> field which is added in a downstream patch) could used
>> via user-space libraries without breaking the ABI.
>>
>> Signed-off-by: Eran Ben Elisha <era...@mellanox.com>
>> ---
>
>> diff --git a/drivers/infiniband/core/uverbs_cmd.c 
>> b/drivers/infiniband/core/uverbs_cmd.c
>> index be4cb9f..e795d59 100644
>> --- a/drivers/infiniband/core/uverbs_cmd.c
>> +++ b/drivers/infiniband/core/uverbs_cmd.c
>> @@ -1741,66 +1741,65 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file 
>> *file,
>>       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;
>>
>> -     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);
>>       if (!obj)
>>               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);
>>
>> -     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) {
>>                       ret = -EINVAL;
>>                       goto err_put;
>>               }
>>               device = xrcd->device;
>>       } 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 {
>> -                     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) {
>>                                       ret = -EINVAL;
>>                                       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) {
>>                                       ret = -EINVAL;
>>                                       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;
>> -             pd  = idr_read_pd(cmd.pd_handle, file->ucontext);
>> +             pd  = idr_read_pd(cmd->pd_handle, file->ucontext);
>>               if (!pd || !scq) {
>>                       ret = -EINVAL;
>>                       goto err_put;
>> @@ -1825,31 +1824,54 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file 
>> *file,
>>       attr.recv_cq       = rcq;
>>       attr.srq           = srq;
>>       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.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;
>>       INIT_LIST_HEAD(&obj->uevent.event_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;
>> +     }
>> +
>> +     if (cmd->comp_mask) {
> Do you need this check in addition to the check in ib_uverbs_ex_create_qp()?

You are right, I will remove this extra check and resend.

>
>> +             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);
>>       else
>> -             qp = device->create_qp(pd, &attr, &udata);
>> +             qp = device->create_qp(pd, &attr, uhw);
>>
>>       if (IS_ERR(qp)) {
>>               ret = PTR_ERR(qp);
>>               goto err_put;
>>       }
>>
>> -     if (cmd.qp_type != IB_QPT_XRC_TGT) {
>> +     if (cmd->qp_type != IB_QPT_XRC_TGT) {
>>               qp->real_qp       = qp;
>>               qp->device        = device;
>>               qp->pd            = pd;
>> @@ -1875,19 +1897,20 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file 
>> *file,
>>               goto err_destroy;
>>
>>       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) {
>>               obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
>> @@ -1913,9 +1936,8 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file 
>> *file,
>>
>>       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);
>>
>>  err_destroy:
>> @@ -1937,6 +1959,113 @@ err_put:
>>       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;
>
> I would expect a check here that in_len >= sizeof(cmd). But I see the
> previous code didn't have it either. Any reason adding the check would
> break user-space?

This patch just refactor in ib_uverbs_create_qp and doesn't change any
of it's logic or fix any bug. we can consider such a fix for the
future.

>
>> +
>> +     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;
>> +}
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to