IB/core: add a simple MR pool
authorChristoph Hellwig <hch@lst.de>
Tue, 3 May 2016 16:01:07 +0000 (18:01 +0200)
committerDoug Ledford <dledford@redhat.com>
Fri, 13 May 2016 17:37:18 +0000 (13:37 -0400)
Signed-off-by: Christoph Hellwig <hch@lst.de>
Tested-by: Steve Wise <swise@opengridcomputing.com>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/core/Makefile
drivers/infiniband/core/mr_pool.c [new file with mode: 0644]
drivers/infiniband/core/verbs.c
include/rdma/ib_verbs.h
include/rdma/mr_pool.h [new file with mode: 0644]

index f818538a7f4e118b309052c3d43a1aa18d5dbe65..48bd9d8292896aabf0738ff667959f0f58751a98 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_INFINIBAND_USER_ACCESS) +=       ib_uverbs.o ib_ucm.o \
 
 ib_core-y :=                   packer.o ud_header.o verbs.o cq.o sysfs.o \
                                device.o fmr_pool.o cache.o netlink.o \
-                               roce_gid_mgmt.o
+                               roce_gid_mgmt.o mr_pool.o
 ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o
 ib_core-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o umem_rbtree.o
 
diff --git a/drivers/infiniband/core/mr_pool.c b/drivers/infiniband/core/mr_pool.c
new file mode 100644 (file)
index 0000000..49d478b
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016 HGST, a Western Digital Company.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#include <rdma/ib_verbs.h>
+#include <rdma/mr_pool.h>
+
+struct ib_mr *ib_mr_pool_get(struct ib_qp *qp, struct list_head *list)
+{
+       struct ib_mr *mr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->mr_lock, flags);
+       mr = list_first_entry_or_null(list, struct ib_mr, qp_entry);
+       if (mr) {
+               list_del(&mr->qp_entry);
+               qp->mrs_used++;
+       }
+       spin_unlock_irqrestore(&qp->mr_lock, flags);
+
+       return mr;
+}
+EXPORT_SYMBOL(ib_mr_pool_get);
+
+void ib_mr_pool_put(struct ib_qp *qp, struct list_head *list, struct ib_mr *mr)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->mr_lock, flags);
+       list_add(&mr->qp_entry, list);
+       qp->mrs_used--;
+       spin_unlock_irqrestore(&qp->mr_lock, flags);
+}
+EXPORT_SYMBOL(ib_mr_pool_put);
+
+int ib_mr_pool_init(struct ib_qp *qp, struct list_head *list, int nr,
+               enum ib_mr_type type, u32 max_num_sg)
+{
+       struct ib_mr *mr;
+       unsigned long flags;
+       int ret, i;
+
+       for (i = 0; i < nr; i++) {
+               mr = ib_alloc_mr(qp->pd, type, max_num_sg);
+               if (IS_ERR(mr)) {
+                       ret = PTR_ERR(mr);
+                       goto out;
+               }
+
+               spin_lock_irqsave(&qp->mr_lock, flags);
+               list_add_tail(&mr->qp_entry, list);
+               spin_unlock_irqrestore(&qp->mr_lock, flags);
+       }
+
+       return 0;
+out:
+       ib_mr_pool_destroy(qp, list);
+       return ret;
+}
+EXPORT_SYMBOL(ib_mr_pool_init);
+
+void ib_mr_pool_destroy(struct ib_qp *qp, struct list_head *list)
+{
+       struct ib_mr *mr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->mr_lock, flags);
+       while (!list_empty(list)) {
+               mr = list_first_entry(list, struct ib_mr, qp_entry);
+               list_del(&mr->qp_entry);
+
+               spin_unlock_irqrestore(&qp->mr_lock, flags);
+               ib_dereg_mr(mr);
+               spin_lock_irqsave(&qp->mr_lock, flags);
+       }
+       spin_unlock_irqrestore(&qp->mr_lock, flags);
+}
+EXPORT_SYMBOL(ib_mr_pool_destroy);
index 8c0f3a067d249b4e8c490818290f891f4bd8f956..8549345c616918c8eb9d03dca6c341f73c292a0c 100644 (file)
@@ -762,6 +762,9 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
        qp->qp_type    = qp_init_attr->qp_type;
 
        atomic_set(&qp->usecnt, 0);
+       qp->mrs_used = 0;
+       spin_lock_init(&qp->mr_lock);
+
        if (qp_init_attr->qp_type == IB_QPT_XRC_TGT)
                return ib_create_xrc_qp(qp, qp_init_attr);
 
@@ -1255,6 +1258,8 @@ int ib_destroy_qp(struct ib_qp *qp)
        struct ib_srq *srq;
        int ret;
 
+       WARN_ON_ONCE(qp->mrs_used > 0);
+
        if (atomic_read(&qp->usecnt))
                return -EBUSY;
 
index 9e8616af68993c38229c7afc9253343111941c61..400a8a0422a4dff5e929c98cc97f26210a86bcac 100644 (file)
@@ -1421,9 +1421,12 @@ struct ib_qp {
        struct ib_pd           *pd;
        struct ib_cq           *send_cq;
        struct ib_cq           *recv_cq;
+       spinlock_t              mr_lock;
+       int                     mrs_used;
        struct ib_srq          *srq;
        struct ib_xrcd         *xrcd; /* XRC TGT QPs only */
        struct list_head        xrcd_list;
+
        /* count times opened, mcast attaches, flow attaches */
        atomic_t                usecnt;
        struct list_head        open_list;
@@ -1438,12 +1441,15 @@ struct ib_qp {
 struct ib_mr {
        struct ib_device  *device;
        struct ib_pd      *pd;
-       struct ib_uobject *uobject;
        u32                lkey;
        u32                rkey;
        u64                iova;
        u32                length;
        unsigned int       page_size;
+       union {
+               struct ib_uobject       *uobject;       /* user */
+               struct list_head        qp_entry;       /* FR */
+       };
 };
 
 struct ib_mw {
diff --git a/include/rdma/mr_pool.h b/include/rdma/mr_pool.h
new file mode 100644 (file)
index 0000000..986010b
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016 HGST, a Western Digital Company.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#ifndef _RDMA_MR_POOL_H
+#define _RDMA_MR_POOL_H 1
+
+#include <rdma/ib_verbs.h>
+
+struct ib_mr *ib_mr_pool_get(struct ib_qp *qp, struct list_head *list);
+void ib_mr_pool_put(struct ib_qp *qp, struct list_head *list, struct ib_mr *mr);
+
+int ib_mr_pool_init(struct ib_qp *qp, struct list_head *list, int nr,
+               enum ib_mr_type type, u32 max_num_sg);
+void ib_mr_pool_destroy(struct ib_qp *qp, struct list_head *list);
+
+#endif /* _RDMA_MR_POOL_H */