File Index
Files and directories
Sign in
FILE

restrack.c

File preview with syntax highlighting.

linux-6.19.14/drivers/infiniband/core/restrack.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2/*
  3 * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
  4 */
  5
  6#include <rdma/rdma_cm.h>
  7#include <rdma/ib_verbs.h>
  8#include <rdma/restrack.h>
  9#include <rdma/rdma_counter.h>
 10#include <linux/mutex.h>
 11#include <linux/sched/task.h>
 12#include <linux/pid_namespace.h>
 13
 14#include "cma_priv.h"
 15#include "restrack.h"
 16
 17/**
 18 * rdma_restrack_init() - initialize and allocate resource tracking
 19 * @dev:  IB device
 20 *
 21 * Return: 0 on success
 22 */
 23int rdma_restrack_init(struct ib_device *dev)
 24{
 25	struct rdma_restrack_root *rt;
 26	int i;
 27
 28	dev->res = kcalloc(RDMA_RESTRACK_MAX, sizeof(*rt), GFP_KERNEL);
 29	if (!dev->res)
 30		return -ENOMEM;
 31
 32	rt = dev->res;
 33
 34	for (i = 0; i < RDMA_RESTRACK_MAX; i++)
 35		xa_init_flags(&rt[i].xa, XA_FLAGS_ALLOC);
 36
 37	return 0;
 38}
 39
 40/**
 41 * rdma_restrack_clean() - clean resource tracking
 42 * @dev:  IB device
 43 */
 44void rdma_restrack_clean(struct ib_device *dev)
 45{
 46	struct rdma_restrack_root *rt = dev->res;
 47	int i;
 48
 49	for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) {
 50		struct xarray *xa = &dev->res[i].xa;
 51
 52		WARN_ON(!xa_empty(xa));
 53		xa_destroy(xa);
 54	}
 55	kfree(rt);
 56}
 57
 58/**
 59 * rdma_restrack_count() - the current usage of specific object
 60 * @dev:  IB device
 61 * @type: actual type of object to operate
 62 * @show_details: count driver specific objects
 63 */
 64int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
 65			bool show_details)
 66{
 67	struct rdma_restrack_root *rt = &dev->res[type];
 68	struct rdma_restrack_entry *e;
 69	XA_STATE(xas, &rt->xa, 0);
 70	u32 cnt = 0;
 71
 72	xa_lock(&rt->xa);
 73	xas_for_each(&xas, e, U32_MAX) {
 74		if (xa_get_mark(&rt->xa, e->id, RESTRACK_DD) && !show_details)
 75			continue;
 76		cnt++;
 77	}
 78	xa_unlock(&rt->xa);
 79	return cnt;
 80}
 81EXPORT_SYMBOL(rdma_restrack_count);
 82
 83static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
 84{
 85	switch (res->type) {
 86	case RDMA_RESTRACK_PD:
 87		return container_of(res, struct ib_pd, res)->device;
 88	case RDMA_RESTRACK_CQ:
 89		return container_of(res, struct ib_cq, res)->device;
 90	case RDMA_RESTRACK_QP:
 91		return container_of(res, struct ib_qp, res)->device;
 92	case RDMA_RESTRACK_CM_ID:
 93		return container_of(res, struct rdma_id_private,
 94				    res)->id.device;
 95	case RDMA_RESTRACK_MR:
 96		return container_of(res, struct ib_mr, res)->device;
 97	case RDMA_RESTRACK_CTX:
 98		return container_of(res, struct ib_ucontext, res)->device;
 99	case RDMA_RESTRACK_COUNTER:
100		return container_of(res, struct rdma_counter, res)->device;
101	case RDMA_RESTRACK_SRQ:
102		return container_of(res, struct ib_srq, res)->device;
103	case RDMA_RESTRACK_DMAH:
104		return container_of(res, struct ib_dmah, res)->device;
105	default:
106		WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
107		return NULL;
108	}
109}
110
111/**
112 * rdma_restrack_attach_task() - attach the task onto this resource,
113 * valid for user space restrack entries.
114 * @res:  resource entry
115 * @task: the task to attach
116 */
117static void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
118				      struct task_struct *task)
119{
120	if (WARN_ON_ONCE(!task))
121		return;
122
123	if (res->task)
124		put_task_struct(res->task);
125	get_task_struct(task);
126	res->task = task;
127	res->user = true;
128}
129
130/**
131 * rdma_restrack_set_name() - set the task for this resource
132 * @res:  resource entry
133 * @caller: kernel name, the current task will be used if the caller is NULL.
134 */
135void rdma_restrack_set_name(struct rdma_restrack_entry *res, const char *caller)
136{
137	if (caller) {
138		res->kern_name = caller;
139		return;
140	}
141
142	rdma_restrack_attach_task(res, current);
143}
144EXPORT_SYMBOL(rdma_restrack_set_name);
145
146/**
147 * rdma_restrack_parent_name() - set the restrack name properties based
148 * on parent restrack
149 * @dst: destination resource entry
150 * @parent: parent resource entry
151 */
152void rdma_restrack_parent_name(struct rdma_restrack_entry *dst,
153			       const struct rdma_restrack_entry *parent)
154{
155	if (rdma_is_kernel_res(parent))
156		dst->kern_name = parent->kern_name;
157	else
158		rdma_restrack_attach_task(dst, parent->task);
159}
160EXPORT_SYMBOL(rdma_restrack_parent_name);
161
162/**
163 * rdma_restrack_new() - Initializes new restrack entry to allow _put() interface
164 * to release memory in fully automatic way.
165 * @res: Entry to initialize
166 * @type: REstrack type
167 */
168void rdma_restrack_new(struct rdma_restrack_entry *res,
169		       enum rdma_restrack_type type)
170{
171	kref_init(&res->kref);
172	init_completion(&res->comp);
173	res->type = type;
174}
175EXPORT_SYMBOL(rdma_restrack_new);
176
177/**
178 * rdma_restrack_add() - add object to the resource tracking database
179 * @res:  resource entry
180 */
181void rdma_restrack_add(struct rdma_restrack_entry *res)
182{
183	struct ib_device *dev = res_to_dev(res);
184	struct rdma_restrack_root *rt;
185	int ret = 0;
186
187	if (!dev)
188		return;
189
190	if (res->no_track)
191		goto out;
192
193	rt = &dev->res[res->type];
194
195	if (res->type == RDMA_RESTRACK_QP) {
196		/* Special case to ensure that LQPN points to right QP */
197		struct ib_qp *qp = container_of(res, struct ib_qp, res);
198
199		WARN_ONCE(qp->qp_num >> 24 || qp->port >> 8,
200			  "QP number 0x%0X and port 0x%0X", qp->qp_num,
201			  qp->port);
202		res->id = qp->qp_num;
203		if (qp->qp_type == IB_QPT_SMI || qp->qp_type == IB_QPT_GSI)
204			res->id |= qp->port << 24;
205		ret = xa_insert(&rt->xa, res->id, res, GFP_KERNEL);
206		if (ret)
207			res->id = 0;
208
209		if (qp->qp_type >= IB_QPT_DRIVER)
210			xa_set_mark(&rt->xa, res->id, RESTRACK_DD);
211	} else if (res->type == RDMA_RESTRACK_COUNTER) {
212		/* Special case to ensure that cntn points to right counter */
213		struct rdma_counter *counter;
214
215		counter = container_of(res, struct rdma_counter, res);
216		ret = xa_insert(&rt->xa, counter->id, res, GFP_KERNEL);
217		res->id = ret ? 0 : counter->id;
218	} else {
219		ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
220				      &rt->next_id, GFP_KERNEL);
221		ret = (ret < 0) ? ret : 0;
222	}
223
224out:
225	if (!ret)
226		res->valid = true;
227}
228EXPORT_SYMBOL(rdma_restrack_add);
229
230int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
231{
232	return kref_get_unless_zero(&res->kref);
233}
234EXPORT_SYMBOL(rdma_restrack_get);
235
236/**
237 * rdma_restrack_get_byid() - translate from ID to restrack object
238 * @dev: IB device
239 * @type: resource track type
240 * @id: ID to take a look
241 *
242 * Return: Pointer to restrack entry or -ENOENT in case of error.
243 */
244struct rdma_restrack_entry *
245rdma_restrack_get_byid(struct ib_device *dev,
246		       enum rdma_restrack_type type, u32 id)
247{
248	struct rdma_restrack_root *rt = &dev->res[type];
249	struct rdma_restrack_entry *res;
250
251	xa_lock(&rt->xa);
252	res = xa_load(&rt->xa, id);
253	if (!res || !rdma_restrack_get(res))
254		res = ERR_PTR(-ENOENT);
255	xa_unlock(&rt->xa);
256
257	return res;
258}
259EXPORT_SYMBOL(rdma_restrack_get_byid);
260
261static void restrack_release(struct kref *kref)
262{
263	struct rdma_restrack_entry *res;
264
265	res = container_of(kref, struct rdma_restrack_entry, kref);
266	if (res->task) {
267		put_task_struct(res->task);
268		res->task = NULL;
269	}
270	complete(&res->comp);
271}
272
273int rdma_restrack_put(struct rdma_restrack_entry *res)
274{
275	return kref_put(&res->kref, restrack_release);
276}
277EXPORT_SYMBOL(rdma_restrack_put);
278
279/**
280 * rdma_restrack_del() - delete object from the resource tracking database
281 * @res:  resource entry
282 */
283void rdma_restrack_del(struct rdma_restrack_entry *res)
284{
285	struct rdma_restrack_entry *old;
286	struct rdma_restrack_root *rt;
287	struct ib_device *dev;
288
289	if (!res->valid) {
290		if (res->task) {
291			put_task_struct(res->task);
292			res->task = NULL;
293		}
294		return;
295	}
296
297	if (res->no_track)
298		goto out;
299
300	dev = res_to_dev(res);
301	if (WARN_ON(!dev))
302		return;
303
304	rt = &dev->res[res->type];
305
306	old = xa_erase(&rt->xa, res->id);
307	WARN_ON(old != res);
308
309out:
310	res->valid = false;
311	rdma_restrack_put(res);
312	wait_for_completion(&res->comp);
313}
314EXPORT_SYMBOL(rdma_restrack_del);
~/ Read-only file preview.