xref: /linux/drivers/infiniband/core/restrack.c (revision 7ce4de1cdaf11c39b507008dfb5a4e59079d4e8a)
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  */
rdma_restrack_init(struct ib_device * dev)23 int 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  */
rdma_restrack_clean(struct ib_device * dev)44 void 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  */
rdma_restrack_count(struct ib_device * dev,enum rdma_restrack_type type,bool show_details)64 int 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 }
81 EXPORT_SYMBOL(rdma_restrack_count);
82 
res_to_dev(struct rdma_restrack_entry * res)83 static 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  */
rdma_restrack_attach_task(struct rdma_restrack_entry * res,struct task_struct * task)117 static 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  */
rdma_restrack_set_name(struct rdma_restrack_entry * res,const char * caller)135 void 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 }
144 EXPORT_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  */
rdma_restrack_parent_name(struct rdma_restrack_entry * dst,const struct rdma_restrack_entry * parent)152 void 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 }
160 EXPORT_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  */
rdma_restrack_new(struct rdma_restrack_entry * res,enum rdma_restrack_type type)168 void 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 }
175 EXPORT_SYMBOL(rdma_restrack_new);
176 
177 /**
178  * rdma_restrack_add() - add object to the reource tracking database
179  * @res:  resource entry
180  */
rdma_restrack_add(struct rdma_restrack_entry * res)181 void 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 
224 out:
225 	if (!ret)
226 		res->valid = true;
227 }
228 EXPORT_SYMBOL(rdma_restrack_add);
229 
rdma_restrack_get(struct rdma_restrack_entry * res)230 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
231 {
232 	return kref_get_unless_zero(&res->kref);
233 }
234 EXPORT_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  */
244 struct rdma_restrack_entry *
rdma_restrack_get_byid(struct ib_device * dev,enum rdma_restrack_type type,u32 id)245 rdma_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 }
259 EXPORT_SYMBOL(rdma_restrack_get_byid);
260 
restrack_release(struct kref * kref)261 static 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 
rdma_restrack_put(struct rdma_restrack_entry * res)273 int rdma_restrack_put(struct rdma_restrack_entry *res)
274 {
275 	return kref_put(&res->kref, restrack_release);
276 }
277 EXPORT_SYMBOL(rdma_restrack_put);
278 
279 /**
280  * rdma_restrack_del() - delete object from the reource tracking database
281  * @res:  resource entry
282  */
rdma_restrack_del(struct rdma_restrack_entry * res)283 void 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 
309 out:
310 	res->valid = false;
311 	rdma_restrack_put(res);
312 	wait_for_completion(&res->comp);
313 }
314 EXPORT_SYMBOL(rdma_restrack_del);
315