RDMA/uverbs: Export XRC SRQs to user space
authorSean Hefty <sean.hefty@intel.com>
Thu, 26 May 2011 00:08:38 +0000 (17:08 -0700)
committerRoland Dreier <roland@purestorage.com>
Thu, 13 Oct 2011 16:29:18 +0000 (09:29 -0700)
We require additional information to create XRC SRQs than we can
exchange using the existing create SRQ ABI.  Provide an enhanced create
ABI for extended SRQ types.

Based on patches by Jack Morgenstein <jackm@dev.mellanox.co.il>
and Roland Dreier <roland@purestorage.com>

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
include/rdma/ib_user_verbs.h

index 461e2f357c1e09d5ff6292abd24c0f1e1ddddd18..00ce032fcead6e147ef19b0ceb2a39be16371b6b 100644 (file)
@@ -127,6 +127,11 @@ struct ib_uxrcd_object {
        atomic_t                refcnt;
 };
 
+struct ib_usrq_object {
+       struct ib_uevent_object uevent;
+       struct ib_uxrcd_object *uxrcd;
+};
+
 struct ib_uqp_object {
        struct ib_uevent_object uevent;
        struct list_head        mcast_list;
@@ -204,6 +209,7 @@ IB_UVERBS_DECLARE_CMD(create_srq);
 IB_UVERBS_DECLARE_CMD(modify_srq);
 IB_UVERBS_DECLARE_CMD(query_srq);
 IB_UVERBS_DECLARE_CMD(destroy_srq);
+IB_UVERBS_DECLARE_CMD(create_xsrq);
 IB_UVERBS_DECLARE_CMD(open_xrcd);
 IB_UVERBS_DECLARE_CMD(close_xrcd);
 
index c8b2a843fa007d1da31f768b0dc283a66a58432a..2e66b14acd4316d5424fd3b5da82d17d993ff08c 100644 (file)
@@ -1400,7 +1400,8 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
        rcq = cmd.recv_cq_handle == cmd.send_cq_handle ?
                scq : idr_read_cq(cmd.recv_cq_handle, file->ucontext, 1);
 
-       if (!pd || !scq || !rcq || (cmd.is_srq && !srq)) {
+       if (!pd || !scq || !rcq ||
+           (cmd.is_srq && (!srq || srq->srq_type != IB_SRQT_BASIC))) {
                ret = -EINVAL;
                goto err_put;
        }
@@ -2293,108 +2294,199 @@ out_put:
        return ret ? ret : in_len;
 }
 
-ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+int __uverbs_create_xsrq(struct ib_uverbs_file *file,
+                        struct ib_uverbs_create_xsrq *cmd,
+                        struct ib_udata *udata)
 {
-       struct ib_uverbs_create_srq      cmd;
        struct ib_uverbs_create_srq_resp resp;
-       struct ib_udata                  udata;
-       struct ib_uevent_object         *obj;
+       struct ib_usrq_object           *obj;
        struct ib_pd                    *pd;
        struct ib_srq                   *srq;
+       struct ib_uobject               *uninitialized_var(xrcd_uobj);
        struct ib_srq_init_attr          attr;
        int ret;
 
-       if (out_len < sizeof resp)
-               return -ENOSPC;
-
-       if (copy_from_user(&cmd, buf, sizeof cmd))
-               return -EFAULT;
-
-       INIT_UDATA(&udata, buf + sizeof cmd,
-                  (unsigned long) cmd.response + sizeof resp,
-                  in_len - sizeof cmd, out_len - sizeof resp);
-
        obj = kmalloc(sizeof *obj, GFP_KERNEL);
        if (!obj)
                return -ENOMEM;
 
-       init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &srq_lock_key);
-       down_write(&obj->uobject.mutex);
+       init_uobj(&obj->uevent.uobject, cmd->user_handle, file->ucontext, &srq_lock_key);
+       down_write(&obj->uevent.uobject.mutex);
 
-       pd  = idr_read_pd(cmd.pd_handle, file->ucontext);
+       pd  = idr_read_pd(cmd->pd_handle, file->ucontext);
        if (!pd) {
                ret = -EINVAL;
                goto err;
        }
 
+       if (cmd->srq_type == IB_SRQT_XRC) {
+               attr.ext.xrc.cq  = idr_read_cq(cmd->cq_handle, file->ucontext, 0);
+               if (!attr.ext.xrc.cq) {
+                       ret = -EINVAL;
+                       goto err_put_pd;
+               }
+
+               attr.ext.xrc.xrcd  = idr_read_xrcd(cmd->xrcd_handle, file->ucontext, &xrcd_uobj);
+               if (!attr.ext.xrc.xrcd) {
+                       ret = -EINVAL;
+                       goto err_put_cq;
+               }
+
+               obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object, uobject);
+               atomic_inc(&obj->uxrcd->refcnt);
+       }
+
        attr.event_handler  = ib_uverbs_srq_event_handler;
        attr.srq_context    = file;
-       attr.srq_type       = IB_SRQT_BASIC;
-       attr.attr.max_wr    = cmd.max_wr;
-       attr.attr.max_sge   = cmd.max_sge;
-       attr.attr.srq_limit = cmd.srq_limit;
+       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;
 
-       obj->events_reported     = 0;
-       INIT_LIST_HEAD(&obj->event_list);
+       obj->uevent.events_reported = 0;
+       INIT_LIST_HEAD(&obj->uevent.event_list);
 
-       srq = pd->device->create_srq(pd, &attr, &udata);
+       srq = pd->device->create_srq(pd, &attr, udata);
        if (IS_ERR(srq)) {
                ret = PTR_ERR(srq);
                goto err_put;
        }
 
-       srq->device        = pd->device;
-       srq->pd            = pd;
-       srq->uobject       = &obj->uobject;
+       srq->device        = pd->device;
+       srq->pd            = pd;
+       srq->srq_type      = cmd->srq_type;
+       srq->uobject       = &obj->uevent.uobject;
        srq->event_handler = attr.event_handler;
        srq->srq_context   = attr.srq_context;
+
+       if (cmd->srq_type == IB_SRQT_XRC) {
+               srq->ext.xrc.cq   = attr.ext.xrc.cq;
+               srq->ext.xrc.xrcd = attr.ext.xrc.xrcd;
+               atomic_inc(&attr.ext.xrc.cq->usecnt);
+               atomic_inc(&attr.ext.xrc.xrcd->usecnt);
+       }
+
        atomic_inc(&pd->usecnt);
        atomic_set(&srq->usecnt, 0);
 
-       obj->uobject.object = srq;
-       ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject);
+       obj->uevent.uobject.object = srq;
+       ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uevent.uobject);
        if (ret)
                goto err_destroy;
 
        memset(&resp, 0, sizeof resp);
-       resp.srq_handle = obj->uobject.id;
+       resp.srq_handle = obj->uevent.uobject.id;
        resp.max_wr     = attr.attr.max_wr;
        resp.max_sge    = attr.attr.max_sge;
+       if (cmd->srq_type == IB_SRQT_XRC)
+               resp.srqn = srq->ext.xrc.srq_num;
 
-       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+       if (copy_to_user((void __user *) (unsigned long) cmd->response,
                         &resp, sizeof resp)) {
                ret = -EFAULT;
                goto err_copy;
        }
 
+       if (cmd->srq_type == IB_SRQT_XRC) {
+               put_uobj_read(xrcd_uobj);
+               put_cq_read(attr.ext.xrc.cq);
+       }
        put_pd_read(pd);
 
        mutex_lock(&file->mutex);
-       list_add_tail(&obj->uobject.list, &file->ucontext->srq_list);
+       list_add_tail(&obj->uevent.uobject.list, &file->ucontext->srq_list);
        mutex_unlock(&file->mutex);
 
-       obj->uobject.live = 1;
+       obj->uevent.uobject.live = 1;
 
-       up_write(&obj->uobject.mutex);
+       up_write(&obj->uevent.uobject.mutex);
 
-       return in_len;
+       return 0;
 
 err_copy:
-       idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject);
+       idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uevent.uobject);
 
 err_destroy:
        ib_destroy_srq(srq);
 
 err_put:
+       if (cmd->srq_type == IB_SRQT_XRC) {
+               atomic_dec(&obj->uxrcd->refcnt);
+               put_uobj_read(xrcd_uobj);
+       }
+
+err_put_cq:
+       if (cmd->srq_type == IB_SRQT_XRC)
+               put_cq_read(attr.ext.xrc.cq);
+
+err_put_pd:
        put_pd_read(pd);
 
 err:
-       put_uobj_write(&obj->uobject);
+       put_uobj_write(&obj->uevent.uobject);
        return ret;
 }
 
+ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
+                            const char __user *buf, int in_len,
+                            int out_len)
+{
+       struct ib_uverbs_create_srq      cmd;
+       struct ib_uverbs_create_xsrq     xcmd;
+       struct ib_uverbs_create_srq_resp resp;
+       struct ib_udata                  udata;
+       int ret;
+
+       if (out_len < sizeof resp)
+               return -ENOSPC;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       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;
+
+       INIT_UDATA(&udata, buf + sizeof cmd,
+                  (unsigned long) cmd.response + sizeof resp,
+                  in_len - sizeof cmd, out_len - sizeof resp);
+
+       ret = __uverbs_create_xsrq(file, &xcmd, &udata);
+       if (ret)
+               return ret;
+
+       return in_len;
+}
+
+ssize_t ib_uverbs_create_xsrq(struct ib_uverbs_file *file,
+                             const char __user *buf, int in_len, int out_len)
+{
+       struct ib_uverbs_create_xsrq     cmd;
+       struct ib_uverbs_create_srq_resp resp;
+       struct ib_udata                  udata;
+       int ret;
+
+       if (out_len < sizeof resp)
+               return -ENOSPC;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       INIT_UDATA(&udata, buf + sizeof cmd,
+                  (unsigned long) cmd.response + sizeof resp,
+                  in_len - sizeof cmd, out_len - sizeof resp);
+
+       ret = __uverbs_create_xsrq(file, &cmd, &udata);
+       if (ret)
+               return ret;
+
+       return in_len;
+}
+
 ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
                             const char __user *buf, int in_len,
                             int out_len)
index bb9dcea8feded3803f1b026ab585acf0c87f6db9..6ad221b87158074ae8f7a81afe462144461778f8 100644 (file)
@@ -110,6 +110,7 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
        [IB_USER_VERBS_CMD_DESTROY_SRQ]         = ib_uverbs_destroy_srq,
        [IB_USER_VERBS_CMD_OPEN_XRCD]           = ib_uverbs_open_xrcd,
        [IB_USER_VERBS_CMD_CLOSE_XRCD]          = ib_uverbs_close_xrcd,
+       [IB_USER_VERBS_CMD_CREATE_XSRQ]         = ib_uverbs_create_xsrq
 };
 
 static void ib_uverbs_add_one(struct ib_device *device);
index b5cb63f41f0f9f239765d2ae4cdeeb8dbdde0afe..100abbbd6e6e78b8bb4a0eb01f2102b74f5b6996 100644 (file)
@@ -83,7 +83,8 @@ enum {
        IB_USER_VERBS_CMD_DESTROY_SRQ,
        IB_USER_VERBS_CMD_POST_SRQ_RECV,
        IB_USER_VERBS_CMD_OPEN_XRCD,
-       IB_USER_VERBS_CMD_CLOSE_XRCD
+       IB_USER_VERBS_CMD_CLOSE_XRCD,
+       IB_USER_VERBS_CMD_CREATE_XSRQ
 };
 
 /*
@@ -665,11 +666,25 @@ struct ib_uverbs_create_srq {
        __u64 driver_data[0];
 };
 
+struct ib_uverbs_create_xsrq {
+       __u64 response;
+       __u64 user_handle;
+       __u32 srq_type;
+       __u32 pd_handle;
+       __u32 max_wr;
+       __u32 max_sge;
+       __u32 srq_limit;
+       __u32 reserved;
+       __u32 xrcd_handle;
+       __u32 cq_handle;
+       __u64 driver_data[0];
+};
+
 struct ib_uverbs_create_srq_resp {
        __u32 srq_handle;
        __u32 max_wr;
        __u32 max_sge;
-       __u32 reserved;
+       __u32 srqn;
 };
 
 struct ib_uverbs_modify_srq {