| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
- /*
- * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
- */
- #include <rdma/rdma_cm.h>
- #include <rdma/ib_verbs.h>
- #include <rdma/restrack.h>
- #include <rdma/rdma_counter.h>
- #include <linux/mutex.h>
- #include <linux/sched/task.h>
- #include <linux/pid_namespace.h>
- #include "cma_priv.h"
- #include "restrack.h"
- /**
- * rdma_restrack_init() - initialize and allocate resource tracking
- * @dev: IB device
- *
- * Return: 0 on success
- */
- int rdma_restrack_init(struct ib_device *dev)
- {
- struct rdma_restrack_root *rt;
- int i;
- dev->res = kzalloc_objs(*rt, RDMA_RESTRACK_MAX);
- if (!dev->res)
- return -ENOMEM;
- rt = dev->res;
- for (i = 0; i < RDMA_RESTRACK_MAX; i++)
- xa_init_flags(&rt[i].xa, XA_FLAGS_ALLOC);
- return 0;
- }
- /**
- * rdma_restrack_clean() - clean resource tracking
- * @dev: IB device
- */
- void rdma_restrack_clean(struct ib_device *dev)
- {
- struct rdma_restrack_root *rt = dev->res;
- int i;
- for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) {
- struct xarray *xa = &dev->res[i].xa;
- WARN_ON(!xa_empty(xa));
- xa_destroy(xa);
- }
- kfree(rt);
- }
- /**
- * rdma_restrack_count() - the current usage of specific object
- * @dev: IB device
- * @type: actual type of object to operate
- * @show_details: count driver specific objects
- */
- int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
- bool show_details)
- {
- struct rdma_restrack_root *rt = &dev->res[type];
- struct rdma_restrack_entry *e;
- XA_STATE(xas, &rt->xa, 0);
- u32 cnt = 0;
- xa_lock(&rt->xa);
- xas_for_each(&xas, e, U32_MAX) {
- if (xa_get_mark(&rt->xa, e->id, RESTRACK_DD) && !show_details)
- continue;
- cnt++;
- }
- xa_unlock(&rt->xa);
- return cnt;
- }
- EXPORT_SYMBOL(rdma_restrack_count);
- static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
- {
- switch (res->type) {
- case RDMA_RESTRACK_PD:
- return container_of(res, struct ib_pd, res)->device;
- case RDMA_RESTRACK_CQ:
- return container_of(res, struct ib_cq, res)->device;
- case RDMA_RESTRACK_QP:
- return container_of(res, struct ib_qp, res)->device;
- case RDMA_RESTRACK_CM_ID:
- return container_of(res, struct rdma_id_private,
- res)->id.device;
- case RDMA_RESTRACK_MR:
- return container_of(res, struct ib_mr, res)->device;
- case RDMA_RESTRACK_CTX:
- return container_of(res, struct ib_ucontext, res)->device;
- case RDMA_RESTRACK_COUNTER:
- return container_of(res, struct rdma_counter, res)->device;
- case RDMA_RESTRACK_SRQ:
- return container_of(res, struct ib_srq, res)->device;
- case RDMA_RESTRACK_DMAH:
- return container_of(res, struct ib_dmah, res)->device;
- default:
- WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
- return NULL;
- }
- }
- /**
- * rdma_restrack_attach_task() - attach the task onto this resource,
- * valid for user space restrack entries.
- * @res: resource entry
- * @task: the task to attach
- */
- static void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
- struct task_struct *task)
- {
- if (WARN_ON_ONCE(!task))
- return;
- if (res->task)
- put_task_struct(res->task);
- get_task_struct(task);
- res->task = task;
- res->user = true;
- }
- /**
- * rdma_restrack_set_name() - set the task for this resource
- * @res: resource entry
- * @caller: kernel name, the current task will be used if the caller is NULL.
- */
- void rdma_restrack_set_name(struct rdma_restrack_entry *res, const char *caller)
- {
- if (caller) {
- res->kern_name = caller;
- return;
- }
- rdma_restrack_attach_task(res, current);
- }
- EXPORT_SYMBOL(rdma_restrack_set_name);
- /**
- * rdma_restrack_parent_name() - set the restrack name properties based
- * on parent restrack
- * @dst: destination resource entry
- * @parent: parent resource entry
- */
- void rdma_restrack_parent_name(struct rdma_restrack_entry *dst,
- const struct rdma_restrack_entry *parent)
- {
- if (rdma_is_kernel_res(parent))
- dst->kern_name = parent->kern_name;
- else
- rdma_restrack_attach_task(dst, parent->task);
- }
- EXPORT_SYMBOL(rdma_restrack_parent_name);
- /**
- * rdma_restrack_new() - Initializes new restrack entry to allow _put() interface
- * to release memory in fully automatic way.
- * @res: Entry to initialize
- * @type: REstrack type
- */
- void rdma_restrack_new(struct rdma_restrack_entry *res,
- enum rdma_restrack_type type)
- {
- kref_init(&res->kref);
- init_completion(&res->comp);
- res->type = type;
- }
- EXPORT_SYMBOL(rdma_restrack_new);
- /**
- * rdma_restrack_add() - add object to the resource tracking database
- * @res: resource entry
- */
- void rdma_restrack_add(struct rdma_restrack_entry *res)
- {
- struct ib_device *dev = res_to_dev(res);
- struct rdma_restrack_root *rt;
- int ret = 0;
- if (!dev)
- return;
- if (res->no_track)
- goto out;
- rt = &dev->res[res->type];
- if (res->type == RDMA_RESTRACK_QP) {
- /* Special case to ensure that LQPN points to right QP */
- struct ib_qp *qp = container_of(res, struct ib_qp, res);
- WARN_ONCE(qp->qp_num >> 24 || qp->port >> 8,
- "QP number 0x%0X and port 0x%0X", qp->qp_num,
- qp->port);
- res->id = qp->qp_num;
- if (qp->qp_type == IB_QPT_SMI || qp->qp_type == IB_QPT_GSI)
- res->id |= qp->port << 24;
- ret = xa_insert(&rt->xa, res->id, res, GFP_KERNEL);
- if (ret)
- res->id = 0;
- if (qp->qp_type >= IB_QPT_DRIVER)
- xa_set_mark(&rt->xa, res->id, RESTRACK_DD);
- } else if (res->type == RDMA_RESTRACK_COUNTER) {
- /* Special case to ensure that cntn points to right counter */
- struct rdma_counter *counter;
- counter = container_of(res, struct rdma_counter, res);
- ret = xa_insert(&rt->xa, counter->id, res, GFP_KERNEL);
- res->id = ret ? 0 : counter->id;
- } else {
- ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
- &rt->next_id, GFP_KERNEL);
- ret = (ret < 0) ? ret : 0;
- }
- out:
- if (!ret)
- res->valid = true;
- }
- EXPORT_SYMBOL(rdma_restrack_add);
- int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
- {
- return kref_get_unless_zero(&res->kref);
- }
- EXPORT_SYMBOL(rdma_restrack_get);
- /**
- * rdma_restrack_get_byid() - translate from ID to restrack object
- * @dev: IB device
- * @type: resource track type
- * @id: ID to take a look
- *
- * Return: Pointer to restrack entry or -ENOENT in case of error.
- */
- 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[type];
- struct rdma_restrack_entry *res;
- xa_lock(&rt->xa);
- res = xa_load(&rt->xa, id);
- if (!res || !rdma_restrack_get(res))
- res = ERR_PTR(-ENOENT);
- xa_unlock(&rt->xa);
- return res;
- }
- EXPORT_SYMBOL(rdma_restrack_get_byid);
- static void restrack_release(struct kref *kref)
- {
- struct rdma_restrack_entry *res;
- res = container_of(kref, struct rdma_restrack_entry, kref);
- if (res->task) {
- put_task_struct(res->task);
- res->task = NULL;
- }
- complete(&res->comp);
- }
- int rdma_restrack_put(struct rdma_restrack_entry *res)
- {
- return kref_put(&res->kref, restrack_release);
- }
- EXPORT_SYMBOL(rdma_restrack_put);
- /**
- * rdma_restrack_del() - delete object from the resource tracking database
- * @res: resource entry
- */
- void rdma_restrack_del(struct rdma_restrack_entry *res)
- {
- struct rdma_restrack_entry *old;
- struct rdma_restrack_root *rt;
- struct ib_device *dev;
- if (!res->valid) {
- if (res->task) {
- put_task_struct(res->task);
- res->task = NULL;
- }
- return;
- }
- if (res->no_track)
- goto out;
- dev = res_to_dev(res);
- if (WARN_ON(!dev))
- return;
- rt = &dev->res[res->type];
- old = xa_erase(&rt->xa, res->id);
- WARN_ON(old != res);
- out:
- res->valid = false;
- rdma_restrack_put(res);
- wait_for_completion(&res->comp);
- }
- EXPORT_SYMBOL(rdma_restrack_del);
|