IB/core: Add user MR re-registration support
authorMatan Barak <matanb@mellanox.com>
Thu, 31 Jul 2014 08:01:28 +0000 (11:01 +0300)
committerRoland Dreier <roland@purestorage.com>
Fri, 1 Aug 2014 22:11:13 +0000 (15:11 -0700)
Memory re-registration is a feature that enables changing the
attributes of a memory region registered by user-space, including PD,
translation (address and length) and access flags.

Add the required support in uverbs and the kernel verbs API.

Signed-off-by: Matan Barak <matanb@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.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_verbs.h
include/uapi/rdma/ib_user_verbs.h

index a283274a5a09fa17b0dede8f5819ef9dfaf4458b..643c08a025a52d015431b8a27be1ddcacbd36845 100644 (file)
@@ -221,6 +221,7 @@ IB_UVERBS_DECLARE_CMD(query_port);
 IB_UVERBS_DECLARE_CMD(alloc_pd);
 IB_UVERBS_DECLARE_CMD(dealloc_pd);
 IB_UVERBS_DECLARE_CMD(reg_mr);
+IB_UVERBS_DECLARE_CMD(rereg_mr);
 IB_UVERBS_DECLARE_CMD(dereg_mr);
 IB_UVERBS_DECLARE_CMD(alloc_mw);
 IB_UVERBS_DECLARE_CMD(dealloc_mw);
index ea6203ee7bccb23279a70a67c740c4fd61a85701..0600c50e62151246e163751bd41a081b328bba38 100644 (file)
@@ -1002,6 +1002,99 @@ err_free:
        return ret;
 }
 
+ssize_t ib_uverbs_rereg_mr(struct ib_uverbs_file *file,
+                          const char __user *buf, int in_len,
+                          int out_len)
+{
+       struct ib_uverbs_rereg_mr      cmd;
+       struct ib_uverbs_rereg_mr_resp resp;
+       struct ib_udata              udata;
+       struct ib_pd                *pd = NULL;
+       struct ib_mr                *mr;
+       struct ib_pd                *old_pd;
+       int                          ret;
+       struct ib_uobject           *uobj;
+
+       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));
+
+       if (cmd.flags & ~IB_MR_REREG_SUPPORTED || !cmd.flags)
+               return -EINVAL;
+
+       if ((cmd.flags & IB_MR_REREG_TRANS) &&
+           (!cmd.start || !cmd.hca_va || 0 >= cmd.length ||
+            (cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK)))
+                       return -EINVAL;
+
+       uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle,
+                             file->ucontext);
+
+       if (!uobj)
+               return -EINVAL;
+
+       mr = uobj->object;
+
+       if (cmd.flags & IB_MR_REREG_ACCESS) {
+               ret = ib_check_mr_access(cmd.access_flags);
+               if (ret)
+                       goto put_uobjs;
+       }
+
+       if (cmd.flags & IB_MR_REREG_PD) {
+               pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+               if (!pd) {
+                       ret = -EINVAL;
+                       goto put_uobjs;
+               }
+       }
+
+       if (atomic_read(&mr->usecnt)) {
+               ret = -EBUSY;
+               goto put_uobj_pd;
+       }
+
+       old_pd = mr->pd;
+       ret = mr->device->rereg_user_mr(mr, cmd.flags, cmd.start,
+                                       cmd.length, cmd.hca_va,
+                                       cmd.access_flags, pd, &udata);
+       if (!ret) {
+               if (cmd.flags & IB_MR_REREG_PD) {
+                       atomic_inc(&pd->usecnt);
+                       mr->pd = pd;
+                       atomic_dec(&old_pd->usecnt);
+               }
+       } else {
+               goto put_uobj_pd;
+       }
+
+       memset(&resp, 0, sizeof(resp));
+       resp.lkey      = mr->lkey;
+       resp.rkey      = mr->rkey;
+
+       if (copy_to_user((void __user *)(unsigned long)cmd.response,
+                        &resp, sizeof(resp)))
+               ret = -EFAULT;
+       else
+               ret = in_len;
+
+put_uobj_pd:
+       if (cmd.flags & IB_MR_REREG_PD)
+               put_pd_read(pd);
+
+put_uobjs:
+
+       put_uobj_write(mr->uobject);
+
+       return ret;
+}
+
 ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
                           const char __user *buf, int in_len,
                           int out_len)
index 08219fb3338b0652f350da1af864b4cfb355ff3c..c73b22a257fe3c92c9398e5318acbc4ffa569b90 100644 (file)
@@ -87,6 +87,7 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
        [IB_USER_VERBS_CMD_ALLOC_PD]            = ib_uverbs_alloc_pd,
        [IB_USER_VERBS_CMD_DEALLOC_PD]          = ib_uverbs_dealloc_pd,
        [IB_USER_VERBS_CMD_REG_MR]              = ib_uverbs_reg_mr,
+       [IB_USER_VERBS_CMD_REREG_MR]            = ib_uverbs_rereg_mr,
        [IB_USER_VERBS_CMD_DEREG_MR]            = ib_uverbs_dereg_mr,
        [IB_USER_VERBS_CMD_ALLOC_MW]            = ib_uverbs_alloc_mw,
        [IB_USER_VERBS_CMD_DEALLOC_MW]          = ib_uverbs_dealloc_mw,
index 7ccef342f72420a1c54a14341793a99ff59bd047..ed44cc07a7b3d8659eecf8a99aefb846b37d7f74 100644 (file)
@@ -1097,7 +1097,8 @@ struct ib_mr_attr {
 enum ib_mr_rereg_flags {
        IB_MR_REREG_TRANS       = 1,
        IB_MR_REREG_PD          = (1<<1),
-       IB_MR_REREG_ACCESS      = (1<<2)
+       IB_MR_REREG_ACCESS      = (1<<2),
+       IB_MR_REREG_SUPPORTED   = ((IB_MR_REREG_ACCESS << 1) - 1)
 };
 
 /**
@@ -1547,6 +1548,13 @@ struct ib_device {
                                                  u64 virt_addr,
                                                  int mr_access_flags,
                                                  struct ib_udata *udata);
+       int                        (*rereg_user_mr)(struct ib_mr *mr,
+                                                   int flags,
+                                                   u64 start, u64 length,
+                                                   u64 virt_addr,
+                                                   int mr_access_flags,
+                                                   struct ib_pd *pd,
+                                                   struct ib_udata *udata);
        int                        (*query_mr)(struct ib_mr *mr,
                                               struct ib_mr_attr *mr_attr);
        int                        (*dereg_mr)(struct ib_mr *mr);
index cbfdd4ca951021854ff70843143ec8e1fabda358..26daf55ff76ead65f47801620d4697b10e17151c 100644 (file)
@@ -276,6 +276,22 @@ struct ib_uverbs_reg_mr_resp {
        __u32 rkey;
 };
 
+struct ib_uverbs_rereg_mr {
+       __u64 response;
+       __u32 mr_handle;
+       __u32 flags;
+       __u64 start;
+       __u64 length;
+       __u64 hca_va;
+       __u32 pd_handle;
+       __u32 access_flags;
+};
+
+struct ib_uverbs_rereg_mr_resp {
+       __u32 lkey;
+       __u32 rkey;
+};
+
 struct ib_uverbs_dereg_mr {
        __u32 mr_handle;
 };