[PATCH rdma-next 05/16] RDMA/restrack: Convert internal DB from hash to XArray

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Leon Romanovsky <leonro@xxxxxxxxxxxx>

The additions of .doit callbacks posses new access pattern to the
resource entries by some user visible index. Back then, the legacy
DB was implemented as hash because per-index access wasn't needed
and XArray wasn't accepted yet.

Acceptance of XArray together with per-index access requires the refresh
of DB implementation.

Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxxxx>
---
 drivers/infiniband/core/nldev.c    |  3 +-
 drivers/infiniband/core/restrack.c | 95 +++++++++++++++++++++---------
 include/rdma/restrack.h            | 14 ++---
 3 files changed, 77 insertions(+), 35 deletions(-)

diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c
index 8a795d027dab..0869285e8949 100644
--- a/drivers/infiniband/core/nldev.c
+++ b/drivers/infiniband/core/nldev.c
@@ -977,6 +977,7 @@ static int res_get_common_dumpit(struct sk_buff *skb,
 	int start = cb->args[0];
 	bool has_cap_net_admin;
 	struct nlmsghdr *nlh;
+	unsigned long id = 0;
 	u32 index, port = 0;
 	bool filled = false;
 
@@ -1027,7 +1028,7 @@ static int res_get_common_dumpit(struct sk_buff *skb,
 	has_cap_net_admin = netlink_capable(cb->skb, CAP_NET_ADMIN);
 
 	down_read(&device->res.rwsem);
-	hash_for_each_possible(device->res.hash, res, node, res_type) {
+	xa_for_each(&device->res.xa[res_type], res, id, ULONG_MAX, XA_PRESENT) {
 		if (idx < start)
 			goto next;
 
diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c
index 46a5c553c624..2812c18c0fd3 100644
--- a/drivers/infiniband/core/restrack.c
+++ b/drivers/infiniband/core/restrack.c
@@ -20,6 +20,11 @@ static int fill_res_noop(struct sk_buff *msg,
 
 void rdma_restrack_init(struct rdma_restrack_root *res)
 {
+	int i;
+
+	for (i = 0 ; i < RDMA_RESTRACK_MAX; i++)
+		xa_init_flags(&res->xa[i], XA_FLAGS_ALLOC);
+
 	init_rwsem(&res->rwsem);
 	res->fill_res_entry = fill_res_noop;
 }
@@ -43,33 +48,43 @@ void rdma_restrack_clean(struct rdma_restrack_root *res)
 	struct rdma_restrack_entry *e;
 	char buf[TASK_COMM_LEN];
 	struct ib_device *dev;
+	bool found = false;
 	const char *owner;
-	int bkt;
-
-	if (hash_empty(res->hash))
-		return;
-
-	dev = container_of(res, struct ib_device, res);
-	pr_err("restrack: %s", CUT_HERE);
-	dev_err(&dev->dev, "BUG: RESTRACK detected leak of resources\n");
-	hash_for_each(res->hash, bkt, e, node) {
-		if (rdma_is_kernel_res(e)) {
-			owner = e->kern_name;
-		} else {
-			/*
-			 * There is no need to call get_task_struct here,
-			 * because we can be here only if there are more
-			 * get_task_struct() call than put_task_struct().
-			 */
-			get_task_comm(buf, e->task);
-			owner = buf;
+	int i;
+
+	for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) {
+		if (!xa_empty(&res->xa[i])) {
+			unsigned long index = 0;
+
+			if (!found) {
+				dev = container_of(res, struct ib_device, res);
+				pr_err("restrack: %s", CUT_HERE);
+				dev_err(&dev->dev, "BUG: RESTRACK detected leak of resources\n");
+			}
+			xa_for_each(&res->xa[i], e, index, ULONG_MAX, XA_PRESENT) {
+				if (rdma_is_kernel_res(e)) {
+					owner = e->kern_name;
+				} else {
+					/*
+					 * There is no need to call get_task_struct here,
+					 * because we can be here only if there are more
+					 * get_task_struct() call than put_task_struct().
+					 */
+					get_task_comm(buf, e->task);
+					owner = buf;
+				}
+
+				pr_err("restrack: %s %s object allocated by %s is not freed\n",
+				       rdma_is_kernel_res(e) ? "Kernel" :
+							       "User",
+				       type2str(e->type), owner);
+			}
+			found = true;
 		}
-
-		pr_err("restrack: %s %s object allocated by %s is not freed\n",
-		       rdma_is_kernel_res(e) ? "Kernel" : "User",
-		       type2str(e->type), owner);
+		xa_destroy(&res->xa[i]);
 	}
-	pr_err("restrack: %s", CUT_HERE);
+	if (found)
+		pr_err("restrack: %s", CUT_HERE);
 }
 
 int rdma_restrack_count(struct rdma_restrack_root *res,
@@ -77,10 +92,11 @@ int rdma_restrack_count(struct rdma_restrack_root *res,
 			struct pid_namespace *ns)
 {
 	struct rdma_restrack_entry *e;
+	unsigned long index = 0;
 	u32 cnt = 0;
 
 	down_read(&res->rwsem);
-	hash_for_each_possible(res->hash, e, node, type) {
+	xa_for_each(&res->xa[type], e, index, ULONG_MAX, XA_PRESENT) {
 		if (ns == &init_pid_ns ||
 		    (!rdma_is_kernel_res(e) &&
 		     ns == task_active_pid_ns(e->task)))
@@ -154,9 +170,27 @@ void rdma_restrack_set_task(struct rdma_restrack_entry *res,
 }
 EXPORT_SYMBOL(rdma_restrack_set_task);
 
+static unsigned long res_to_id(struct rdma_restrack_entry *res)
+{
+	switch (res->type) {
+	case RDMA_RESTRACK_PD:
+	case RDMA_RESTRACK_MR:
+	case RDMA_RESTRACK_CM_ID:
+	case RDMA_RESTRACK_CTX:
+	case RDMA_RESTRACK_CQ:
+	case RDMA_RESTRACK_QP:
+		return (unsigned long)res;
+	default:
+		WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
+		return 0;
+	}
+}
+
 static void rdma_restrack_add(struct rdma_restrack_entry *res)
 {
 	struct ib_device *dev = res_to_dev(res);
+	unsigned long id;
+	int ret;
 
 	if (!dev)
 		return;
@@ -177,7 +211,12 @@ static void rdma_restrack_add(struct rdma_restrack_entry *res)
 	res->valid = true;
 
 	down_write(&dev->res.rwsem);
-	hash_add(dev->res.hash, &res->node, res->type);
+	id = res_to_id(res);
+	ret = xa_insert(&dev->res.xa[res->type], id, res, GFP_KERNEL);
+	WARN_ONCE(ret == -EEXIST, "Tried to add non-unique type %d entry\n",
+		  res->type);
+	if (ret)
+		res->valid = false;
 	up_write(&dev->res.rwsem);
 }
 
@@ -226,6 +265,7 @@ EXPORT_SYMBOL(rdma_restrack_put);
 void rdma_restrack_del(struct rdma_restrack_entry *res)
 {
 	struct ib_device *dev;
+	unsigned long id;
 
 	if (!res->valid)
 		goto out;
@@ -237,9 +277,10 @@ void rdma_restrack_del(struct rdma_restrack_entry *res)
 	rdma_restrack_put(res);
 
 	wait_for_completion(&res->comp);
+	id = res_to_id(res);
 
 	down_write(&dev->res.rwsem);
-	hash_del(&res->node);
+	xa_erase(&dev->res.xa[res->type], id);
 	res->valid = false;
 	up_write(&dev->res.rwsem);
 
diff --git a/include/rdma/restrack.h b/include/rdma/restrack.h
index 8f179be9d9a9..4b7a9634ca52 100644
--- a/include/rdma/restrack.h
+++ b/include/rdma/restrack.h
@@ -13,6 +13,7 @@
 #include <linux/completion.h>
 #include <linux/sched/task.h>
 #include <uapi/rdma/rdma_netlink.h>
+#include <linux/xarray.h>
 
 /**
  * enum rdma_restrack_type - HW objects to track
@@ -48,7 +49,6 @@ enum rdma_restrack_type {
 	RDMA_RESTRACK_MAX
 };
 
-#define RDMA_RESTRACK_HASH_BITS	8
 struct rdma_restrack_entry;
 
 /**
@@ -61,9 +61,13 @@ struct rdma_restrack_root {
 	 */
 	struct rw_semaphore	rwsem;
 	/**
-	 * @hash: global database for all resources per-device
+	 * @xa: Array of XArray structures to hold restrack entries.
+	 * We want to use array of XArrays because insertion is type
+	 * dependent. For types with xisiting unique ID (like QPN),
+	 * we will insert to that unique index. For other types,
+	 * we insert based on pointers and auto-allocate unique index.
 	 */
-	DECLARE_HASHTABLE(hash, RDMA_RESTRACK_HASH_BITS);
+	struct xarray xa[RDMA_RESTRACK_MAX];
 	/**
 	 * @fill_res_entry: driver-specific fill function
 	 *
@@ -108,10 +112,6 @@ struct rdma_restrack_entry {
 	 * @kern_name: name of owner for the kernel created entities.
 	 */
 	const char		*kern_name;
-	/**
-	 * @node: hash table entry
-	 */
-	struct hlist_node	node;
 	/**
 	 * @type: various objects in restrack database
 	 */
-- 
2.19.1




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux