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 | 96 +++++++++++++++++++++--------- include/rdma/restrack.h | 14 ++--- 3 files changed, 78 insertions(+), 35 deletions(-) diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c index aa1af89a8452..1a9b03fa0832 100644 --- a/drivers/infiniband/core/nldev.c +++ b/drivers/infiniband/core/nldev.c @@ -981,6 +981,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; @@ -1031,7 +1032,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..473422da0856 100644 --- a/drivers/infiniband/core/restrack.c +++ b/drivers/infiniband/core/restrack.c @@ -20,8 +20,14 @@ 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(&res->xa[i]); + init_rwsem(&res->rwsem); res->fill_res_entry = fill_res_noop; + } static const char *type2str(enum rdma_restrack_type type) @@ -43,33 +49,42 @@ 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,29 @@ 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: + return container_of(res, struct ib_pd, res)->pdn; + case RDMA_RESTRACK_MR: + case RDMA_RESTRACK_CM_ID: + case RDMA_RESTRACK_CTX: + case RDMA_RESTRACK_CQ: + return (unsigned long)res; + case RDMA_RESTRACK_QP: + return container_of(res, struct ib_qp, res)->qp_num; + 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 +213,11 @@ 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 +266,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 +278,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..606a0f763e50 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 becasue insertion is type + * dependant. 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