From: Leon Romanovsky <leonro@xxxxxxxxxxxx> There is no need to expose internals of restrack DB to IB/core. Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxxxx> --- drivers/infiniband/core/device.c | 5 +- drivers/infiniband/core/nldev.c | 16 ++-- drivers/infiniband/core/restrack.c | 144 ++++++++++++++++++++++++----- include/rdma/ib_verbs.h | 7 +- include/rdma/restrack.h | 32 +------ 5 files changed, 140 insertions(+), 64 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index fa8d79548ee7..d13491b416dc 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -288,7 +288,10 @@ struct ib_device *ib_alloc_device(size_t size) if (!device) return NULL; - rdma_restrack_init(device); + if (rdma_restrack_init(device)) { + kfree(device); + return NULL; + } device->dev.class = &ib_class; device_initialize(&device->dev); diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c index 57ce5dde6679..fed891e60686 100644 --- a/drivers/infiniband/core/nldev.c +++ b/drivers/infiniband/core/nldev.c @@ -1029,6 +1029,7 @@ static int res_get_common_dumpit(struct sk_buff *skb, unsigned long id = 0; 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,8 +1077,9 @@ 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); - xa_for_each(&device->res.xa[res_type], id, res) { + xa = rdma_dev_to_xa(device, res_type); + rdma_rt_read_lock(device, res_type); + xa_for_each(xa, id, res) { if (idx < start) goto next; @@ -1098,13 +1100,13 @@ static int res_get_common_dumpit(struct sk_buff *skb, if (!entry_attr) { ret = -EMSGSIZE; rdma_restrack_put(res); - up_read(&device->res.rwsem); + rdma_rt_read_unlock(device, res_type); break; } - up_read(&device->res.rwsem); + rdma_rt_read_unlock(device, res_type); ret = fe->fill_res_func(skb, has_cap_net_admin, res, port); - down_read(&device->res.rwsem); + rdma_rt_read_lock(device, res_type); /* * Return resource back, but it won't be released till * the &device->res.rwsem will be released for write. @@ -1125,7 +1127,7 @@ static int res_get_common_dumpit(struct sk_buff *skb, nla_nest_end(skb, entry_attr); next: idx++; } - up_read(&device->res.rwsem); + rdma_rt_read_unlock(device, res_type); nla_nest_end(skb, table_attr); nlmsg_end(skb, nlh); @@ -1143,7 +1145,7 @@ next: idx++; res_err: nla_nest_cancel(skb, table_attr); - up_read(&device->res.rwsem); + rdma_rt_read_unlock(device, res_type); err: nlmsg_cancel(skb, nlh); diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c index fce51c2f156a..284d087d7785 100644 --- a/drivers/infiniband/core/restrack.c +++ b/drivers/infiniband/core/restrack.c @@ -9,6 +9,7 @@ #include <linux/mutex.h> #include <linux/sched/task.h> #include <linux/pid_namespace.h> +#include <linux/rwsem.h> #include "cma_priv.h" @@ -35,18 +36,51 @@ static int rt_xa_alloc_cyclic(struct xarray *xa, u32 *id, void *entry, } /** - * rdma_restrack_init() - initialize resource tracking + * 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. + */ + struct xarray xa[RDMA_RESTRACK_MAX]; + /** + * #next_id: Next ID to support cyclic allocation + */ + u32 next_id[RDMA_RESTRACK_MAX]; +}; + +/** + * rdma_restrack_init() - initialize and allocate resource tracking * @dev: IB device + * + * Return: 0 on success */ -void rdma_restrack_init(struct ib_device *dev) +int rdma_restrack_init(struct ib_device *dev) { - struct rdma_restrack_root *res = &dev->res; + struct rdma_restrack_root *rt; int i; + dev->res = kzalloc(sizeof(*rt), GFP_KERNEL); + if (!dev->res) + return -ENOMEM; + + rt = dev->res; + for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) - xa_init_flags(&res->xa[i], XA_FLAGS_ALLOC); + xa_init_flags(&rt->xa[i], XA_FLAGS_ALLOC); + init_rwsem(&rt->rwsem); - init_rwsem(&res->rwsem); + return 0; } static const char *type2str(enum rdma_restrack_type type) @@ -63,13 +97,52 @@ static const char *type2str(enum rdma_restrack_type type) return names[type]; }; +/** + * rdma_dev_to_xa() - translate from device to XArray DB + * @dev: IB device to work + * @type: resource track type + * + * Return: XArray DB to use for xa_for_each() iterations + */ +struct xarray *rdma_dev_to_xa(struct ib_device *dev, + enum rdma_restrack_type type) +{ + return &dev->res->xa[type]; + +} +EXPORT_SYMBOL(rdma_dev_to_xa); + +/** + * rdma_rt_read_lock() - Lock XArray for read, needed while iterating + * with xa_for_each() + * @dev: IB device to work + * @type: resource track type + */ +void rdma_rt_read_lock(struct ib_device *dev, enum rdma_restrack_type type) +{ + down_read(&dev->res->rwsem); +} +EXPORT_SYMBOL(rdma_rt_read_lock); + +/** + * rdma_rt_read_unlock() - Unlock XArray for read, needed while iterating + * with xa_for_each() + * @dev: IB device to work + * @type: resource track type + */ +void rdma_rt_read_unlock(struct ib_device *dev, enum rdma_restrack_type type) +{ + up_read(&dev->res->rwsem); +} +EXPORT_SYMBOL(rdma_rt_read_unlock); + /** * rdma_restrack_clean() - clean resource tracking * @dev: IB device */ void rdma_restrack_clean(struct ib_device *dev) { - struct rdma_restrack_root *res = &dev->res; + struct rdma_restrack_root *rt = dev->res; struct rdma_restrack_entry *e; char buf[TASK_COMM_LEN]; bool found = false; @@ -77,14 +150,16 @@ void rdma_restrack_clean(struct ib_device *dev) int i; for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) { - if (!xa_empty(&res->xa[i])) { + struct xarray *xa = rdma_dev_to_xa(dev, i); + + if (!xa_empty(xa)) { unsigned long index = 0; if (!found) { pr_err("restrack: %s", CUT_HERE); dev_err(&dev->dev, "BUG: RESTRACK detected leak of resources\n"); } - xa_for_each(&res->xa[i], index, e) { + xa_for_each(xa, index, e) { if (rdma_is_kernel_res(e)) { owner = e->kern_name; } else { @@ -104,10 +179,12 @@ void rdma_restrack_clean(struct ib_device *dev) } found = true; } - xa_destroy(&res->xa[i]); + xa_destroy(xa); } if (found) pr_err("restrack: %s", CUT_HERE); + + kfree(rt); } /** @@ -119,19 +196,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 rdma_restrack_root *res = &dev->res; + struct xarray *xa = rdma_dev_to_xa(dev, type); struct rdma_restrack_entry *e; unsigned long index = 0; u32 cnt = 0; - down_read(&res->rwsem); - xa_for_each(&res->xa[type], index, e) { + rdma_rt_read_lock(dev, type); + xa_for_each(xa, index, e) { if (ns == &init_pid_ns || (!rdma_is_kernel_res(e) && ns == task_active_pid_ns(e->task))) cnt++; } - up_read(&res->rwsem); + rdma_rt_read_unlock(dev, type); return cnt; } EXPORT_SYMBOL(rdma_restrack_count); @@ -202,11 +279,16 @@ EXPORT_SYMBOL(rdma_restrack_set_task); 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 = rdma_dev_to_xa(dev, res->type); + if (res->type != RDMA_RESTRACK_CM_ID || rdma_is_kernel_res(res)) res->task = NULL; @@ -220,10 +302,7 @@ static void rdma_restrack_add(struct rdma_restrack_entry *res) kref_init(&res->kref); init_completion(&res->comp); - - ret = rt_xa_alloc_cyclic(&dev->res.xa[res->type], &res->id, res, - &dev->res.next_id[res->type]); - + ret = rt_xa_alloc_cyclic(xa, &res->id, res, &rt->next_id[res->type]); if (!ret) res->valid = true; } @@ -268,10 +347,10 @@ struct rdma_restrack_entry * rdma_restrack_get_byid(struct ib_device *dev, enum rdma_restrack_type type, u32 id) { - struct rdma_restrack_root *rt = &dev->res; + struct xarray *xa = rdma_dev_to_xa(dev, type); struct rdma_restrack_entry *res; - res = xa_load(&rt->xa[type], id); + res = xa_load(xa, id); if (!res || !rdma_restrack_get(res)) return ERR_PTR(-ENOENT); return res; @@ -294,26 +373,41 @@ EXPORT_SYMBOL(rdma_restrack_put); void rdma_restrack_del(struct rdma_restrack_entry *res) { - struct ib_device *dev; + struct ib_device *dev = res_to_dev(res); + struct xarray *xa; if (!res->valid) goto out; - dev = res_to_dev(res); + /* + * 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. + * + * Becasue we don't want to add any conditions on call + * to rdma_restrack_del(), the check below protects from + * NULL-dereference. + */ if (!dev) return; - if (!xa_load(&dev->res.xa[res->type], res->id)) + xa = rdma_dev_to_xa(dev, res->type); + + if (!xa_load(xa, res->id)) goto out; rdma_restrack_put(res); wait_for_completion(&res->comp); - down_write(&dev->res.rwsem); - xa_erase(&dev->res.xa[res->type], res->id); + down_write(&dev->res->rwsem); + xa_erase(xa, res->id); res->valid = false; - up_write(&dev->res.rwsem); + up_write(&dev->res->rwsem); out: if (res->task) { diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 9d593c89f541..d54c87640f89 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2519,6 +2519,8 @@ struct ib_device_ops { struct rdma_restrack_entry *entry); }; +struct rdma_restrack_root; + struct ib_device { /* Do not access @dma_device directly from ULP nor from HW drivers. */ struct device *dma_device; @@ -2583,10 +2585,7 @@ struct ib_device { #endif u32 index; - /* - * Implementation details of the RDMA core, don't use in drivers - */ - struct rdma_restrack_root res; + struct rdma_restrack_root *res; const struct uapi_definition *driver_def; enum rdma_driver_id driver_id; diff --git a/include/rdma/restrack.h b/include/rdma/restrack.h index 50c963b0046f..92d11c35221a 100644 --- a/include/rdma/restrack.h +++ b/include/rdma/restrack.h @@ -7,7 +7,6 @@ #define _RDMA_RESTRACK_H_ #include <linux/typecheck.h> -#include <linux/rwsem.h> #include <linux/sched.h> #include <linux/kref.h> #include <linux/completion.h> @@ -50,31 +49,6 @@ enum rdma_restrack_type { }; struct ib_device; -struct rdma_restrack_entry; - -/** - * 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. - */ - struct xarray xa[RDMA_RESTRACK_MAX]; - /** - * #next_id: Next ID to support cyclic allocation - */ - u32 next_id[RDMA_RESTRACK_MAX]; -}; /** * struct rdma_restrack_entry - metadata per-entry @@ -125,7 +99,7 @@ struct rdma_restrack_entry { u32 id; }; -void rdma_restrack_init(struct ib_device *dev); +int rdma_restrack_init(struct ib_device *dev); void rdma_restrack_clean(struct ib_device *dev); int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type, @@ -183,4 +157,8 @@ int rdma_nl_put_driver_u64_hex(struct sk_buff *msg, const char *name, struct rdma_restrack_entry *rdma_restrack_get_byid(struct ib_device *dev, enum rdma_restrack_type type, u32 id); +struct xarray *rdma_dev_to_xa(struct ib_device *dev, + enum rdma_restrack_type type); +void rdma_rt_read_lock(struct ib_device *dev, enum rdma_restrack_type type); +void rdma_rt_read_unlock(struct ib_device *dev, enum rdma_restrack_type type); #endif /* _RDMA_RESTRACK_H_ */ -- 2.19.1