diff mbox series

[rdma-next,v6,06/10] RDMA/restrack: Prepare restrack_root to addition of extra fields per-type

Message ID 20190218202552.24502-7-leon@kernel.org (mailing list archive)
State Accepted
Delegated to: Jason Gunthorpe
Headers show
Series Provide per-ID access to restrack objects | expand

Commit Message

Leon Romanovsky Feb. 18, 2019, 8:25 p.m. UTC
From: Leon Romanovsky <leonro@mellanox.com>

As a preparation to extension of rdma_restrack_root to provide
software IDs, which will be per-type too. We convert the
rdma_restrack_root from struct with arrays to array of structs.

Such conversion allows us to drop rwsem lock in favour of internal
XArray lock.

Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
---
 drivers/infiniband/core/nldev.c    | 39 +++++++-----------
 drivers/infiniband/core/restrack.c | 63 ++++++++++++------------------
 drivers/infiniband/core/restrack.h | 17 ++------
 3 files changed, 42 insertions(+), 77 deletions(-)
diff mbox series

Patch

diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c
index 54312f9626a1..49847fabdd03 100644
--- a/drivers/infiniband/core/nldev.c
+++ b/drivers/infiniband/core/nldev.c
@@ -1018,6 +1018,7 @@  static int res_get_common_dumpit(struct sk_buff *skb,
 	const struct nldev_fill_res_entry *fe = &fill_entries[res_type];
 	struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
 	struct rdma_restrack_entry *res;
+	struct rdma_restrack_root *rt;
 	int err, ret = 0, idx = 0;
 	struct nlattr *table_attr;
 	struct nlattr *entry_attr;
@@ -1028,7 +1029,6 @@  static int res_get_common_dumpit(struct sk_buff *skb,
 	unsigned long id;
 	u32 index, port = 0;
 	bool filled = false;
-	struct xarray *xa;
 
 	err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
 			  nldev_policy, NULL);
@@ -1076,14 +1076,14 @@  static int res_get_common_dumpit(struct sk_buff *skb,
 
 	has_cap_net_admin = netlink_capable(cb->skb, CAP_NET_ADMIN);
 
-	xa = &device->res->xa[res_type];
-	down_read(&device->res->rwsem);
+	rt = &device->res[res_type];
+	xa_lock(&rt->xa);
 	/*
 	 * FIXME: if the skip ahead is something common this loop should
 	 * use xas_for_each & xas_pause to optimize, we can have a lot of
 	 * objects.
 	 */
-	xa_for_each(xa, id, res) {
+	xa_for_each(&rt->xa, id, res) {
 		if (idx < start)
 			goto next;
 
@@ -1091,45 +1091,37 @@  static int res_get_common_dumpit(struct sk_buff *skb,
 			goto next;
 
 		if (!rdma_restrack_get(res))
-			/*
-			 * Resource is under release now, but we are not
-			 * relesing lock now, so it will be released in
-			 * our next pass, once we will get ->next pointer.
-			 */
 			goto next;
 
+		xa_unlock(&rt->xa);
+
 		filled = true;
 
 		entry_attr = nla_nest_start(skb, fe->entry);
 		if (!entry_attr) {
 			ret = -EMSGSIZE;
 			rdma_restrack_put(res);
-			up_read(&device->res->rwsem);
 			break;
 		}
 
-		up_read(&device->res->rwsem);
 		ret = fe->fill_res_func(skb, has_cap_net_admin, res, port);
-		down_read(&device->res->rwsem);
-		/*
-		 * Return resource back, but it won't be released till
-		 * the &device->res.rwsem will be released for write.
-		 */
 		rdma_restrack_put(res);
 
-		if (ret)
+		if (ret) {
 			nla_nest_cancel(skb, entry_attr);
-		if (ret == -EMSGSIZE)
-			break;
-		if (ret == -EAGAIN)
-			goto next;
-		if (ret)
+			if (ret == -EMSGSIZE)
+				goto msg_full;
+			if (ret == -EAGAIN)
+				goto again;
 			goto res_err;
+		}
 		nla_nest_end(skb, entry_attr);
+again:		xa_lock(&rt->xa);
 next:		idx++;
 	}
-	up_read(&device->res->rwsem);
+	xa_unlock(&rt->xa);
 
+msg_full:
 	nla_nest_end(skb, table_attr);
 	nlmsg_end(skb, nlh);
 	cb->args[0] = idx;
@@ -1146,7 +1138,6 @@  next:		idx++;
 
 res_err:
 	nla_nest_cancel(skb, table_attr);
-	up_read(&device->res->rwsem);
 
 err:
 	nlmsg_cancel(skb, nlh);
diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c
index 6a4b76c66bcb..a5ea3988b4c3 100644
--- a/drivers/infiniband/core/restrack.c
+++ b/drivers/infiniband/core/restrack.c
@@ -9,7 +9,6 @@ 
 #include <linux/mutex.h>
 #include <linux/sched/task.h>
 #include <linux/pid_namespace.h>
-#include <linux/rwsem.h>
 
 #include "cma_priv.h"
 #include "restrack.h"
@@ -47,15 +46,14 @@  int rdma_restrack_init(struct ib_device *dev)
 	struct rdma_restrack_root *rt;
 	int i;
 
-	dev->res = kzalloc(sizeof(*rt), GFP_KERNEL);
+	dev->res = kcalloc(RDMA_RESTRACK_MAX, sizeof(*rt), GFP_KERNEL);
 	if (!dev->res)
 		return -ENOMEM;
 
 	rt = dev->res;
 
-	for (i = 0 ; i < RDMA_RESTRACK_MAX; i++)
-		xa_init_flags(&rt->xa[i], XA_FLAGS_ALLOC);
-	init_rwsem(&rt->rwsem);
+	for (i = 0; i < RDMA_RESTRACK_MAX; i++)
+		xa_init_flags(&rt[i].xa, XA_FLAGS_ALLOC);
 
 	return 0;
 }
@@ -88,7 +86,7 @@  void rdma_restrack_clean(struct ib_device *dev)
 	int i;
 
 	for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) {
-		struct xarray *xa = &dev->res->xa[i];
+		struct xarray *xa = &dev->res[i].xa;
 
 		if (!xa_empty(xa)) {
 			unsigned long index;
@@ -134,19 +132,19 @@  void rdma_restrack_clean(struct ib_device *dev)
 int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
 			struct pid_namespace *ns)
 {
-	struct xarray *xa = &dev->res->xa[type];
+	struct rdma_restrack_root *rt = &dev->res[type];
 	struct rdma_restrack_entry *e;
-	unsigned long index = 0;
+	XA_STATE(xas, &rt->xa, 0);
 	u32 cnt = 0;
 
-	down_read(&dev->res->rwsem);
-	xa_for_each(xa, index, e) {
+	xa_lock(&rt->xa);
+	xas_for_each(&xas, e, U32_MAX) {
 		if (ns == &init_pid_ns ||
 		    (!rdma_is_kernel_res(e) &&
 		     ns == task_active_pid_ns(e->task)))
 			cnt++;
 	}
-	up_read(&dev->res->rwsem);
+	xa_unlock(&rt->xa);
 	return cnt;
 }
 EXPORT_SYMBOL(rdma_restrack_count);
@@ -218,18 +216,16 @@  static void rdma_restrack_add(struct rdma_restrack_entry *res)
 {
 	struct ib_device *dev = res_to_dev(res);
 	struct rdma_restrack_root *rt;
-	struct xarray *xa;
 	int ret;
 
 	if (!dev)
 		return;
 
-	rt = dev->res;
-	xa = &dev->res->xa[res->type];
+	rt = &dev->res[res->type];
 
 	kref_init(&res->kref);
 	init_completion(&res->comp);
-	ret = rt_xa_alloc_cyclic(xa, &res->id, res, &rt->next_id[res->type]);
+	ret = rt_xa_alloc_cyclic(&rt->xa, &res->id, res, &rt->next_id);
 	if (!ret)
 		res->valid = true;
 }
@@ -283,14 +279,14 @@  struct rdma_restrack_entry *
 rdma_restrack_get_byid(struct ib_device *dev,
 		       enum rdma_restrack_type type, u32 id)
 {
-	struct xarray *xa = &dev->res->xa[type];
+	struct rdma_restrack_root *rt = &dev->res[type];
 	struct rdma_restrack_entry *res;
 
-	down_read(&dev->res->rwsem);
-	res = xa_load(xa, id);
+	xa_lock(&rt->xa);
+	res = xa_load(&rt->xa, id);
 	if (!res || !rdma_restrack_get(res))
 		res = ERR_PTR(-ENOENT);
-	up_read(&dev->res->rwsem);
+	xa_unlock(&rt->xa);
 
 	return res;
 }
@@ -312,33 +308,22 @@  EXPORT_SYMBOL(rdma_restrack_put);
 
 void rdma_restrack_del(struct rdma_restrack_entry *res)
 {
-	struct ib_device *dev = res_to_dev(res);
-	struct xarray *xa;
+	struct rdma_restrack_entry *old;
+	struct rdma_restrack_root *rt;
+	struct ib_device *dev;
 
 	if (!res->valid)
 		goto out;
 
-	/*
-	 * All objects except CM_ID set valid device immediately
-	 * after new object is created, it means that for not valid
-	 * objects will still have "dev".
-	 *
-	 * It is not the case for CM_ID, newly created object has
-	 * this field set to NULL and it is set in _cma_attach_to_dev()
-	 * only.
-	 *
-	 * Because we don't want to add any conditions on call
-	 * to rdma_restrack_del(), the check below protects from
-	 * NULL-dereference.
-	 */
-	if (!dev)
+	dev = res_to_dev(res);
+	if (WARN_ON(!dev))
 		return;
 
-	xa = &dev->res->xa[res->type];
-	down_write(&dev->res->rwsem);
-	xa_erase(xa, res->id);
+	rt = &dev->res[res->type];
+
+	old = xa_erase(&rt->xa, res->id);
+	WARN_ON(old != res);
 	res->valid = false;
-	up_write(&dev->res->rwsem);
 
 	rdma_restrack_put(res);
 	wait_for_completion(&res->comp);
diff --git a/drivers/infiniband/core/restrack.h b/drivers/infiniband/core/restrack.h
index cf89ef0b8ed5..09a1fbdf578e 100644
--- a/drivers/infiniband/core/restrack.h
+++ b/drivers/infiniband/core/restrack.h
@@ -7,33 +7,22 @@ 
 #define _RDMA_CORE_RESTRACK_H_
 
 #include <linux/mutex.h>
-#include <linux/rwsem.h>
 
 /**
  * struct rdma_restrack_root - main resource tracking management
  * entity, per-device
  */
 struct rdma_restrack_root {
-	/*
-	 * @rwsem: Read/write lock to protect erase of entry.
-	 * Lists and insertions are protected by XArray internal lock.
-	 */
-	struct rw_semaphore	rwsem;
 	/**
-	 * @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.
+	 * @xa: Array of XArray structure to hold restrack entries.
 	 */
-	struct xarray xa[RDMA_RESTRACK_MAX];
+	struct xarray xa;
 	/**
 	 * @next_id: Next ID to support cyclic allocation
 	 */
-	u32 next_id[RDMA_RESTRACK_MAX];
+	u32 next_id;
 };
 
-
 int rdma_restrack_init(struct ib_device *dev);
 void rdma_restrack_clean(struct ib_device *dev);
 #endif /* _RDMA_CORE_RESTRACK_H_ */