Loading...
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 default:
104 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
105 return NULL;
106 }
107}
108
109/**
110 * rdma_restrack_attach_task() - attach the task onto this resource,
111 * valid for user space restrack entries.
112 * @res: resource entry
113 * @task: the task to attach
114 */
115static void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
116 struct task_struct *task)
117{
118 if (WARN_ON_ONCE(!task))
119 return;
120
121 if (res->task)
122 put_task_struct(res->task);
123 get_task_struct(task);
124 res->task = task;
125 res->user = true;
126}
127
128/**
129 * rdma_restrack_set_name() - set the task for this resource
130 * @res: resource entry
131 * @caller: kernel name, the current task will be used if the caller is NULL.
132 */
133void rdma_restrack_set_name(struct rdma_restrack_entry *res, const char *caller)
134{
135 if (caller) {
136 res->kern_name = caller;
137 return;
138 }
139
140 rdma_restrack_attach_task(res, current);
141}
142EXPORT_SYMBOL(rdma_restrack_set_name);
143
144/**
145 * rdma_restrack_parent_name() - set the restrack name properties based
146 * on parent restrack
147 * @dst: destination resource entry
148 * @parent: parent resource entry
149 */
150void rdma_restrack_parent_name(struct rdma_restrack_entry *dst,
151 const struct rdma_restrack_entry *parent)
152{
153 if (rdma_is_kernel_res(parent))
154 dst->kern_name = parent->kern_name;
155 else
156 rdma_restrack_attach_task(dst, parent->task);
157}
158EXPORT_SYMBOL(rdma_restrack_parent_name);
159
160/**
161 * rdma_restrack_new() - Initializes new restrack entry to allow _put() interface
162 * to release memory in fully automatic way.
163 * @res: Entry to initialize
164 * @type: REstrack type
165 */
166void rdma_restrack_new(struct rdma_restrack_entry *res,
167 enum rdma_restrack_type type)
168{
169 kref_init(&res->kref);
170 init_completion(&res->comp);
171 res->type = type;
172}
173EXPORT_SYMBOL(rdma_restrack_new);
174
175/**
176 * rdma_restrack_add() - add object to the reource tracking database
177 * @res: resource entry
178 */
179void rdma_restrack_add(struct rdma_restrack_entry *res)
180{
181 struct ib_device *dev = res_to_dev(res);
182 struct rdma_restrack_root *rt;
183 int ret = 0;
184
185 if (!dev)
186 return;
187
188 if (res->no_track)
189 goto out;
190
191 rt = &dev->res[res->type];
192
193 if (res->type == RDMA_RESTRACK_QP) {
194 /* Special case to ensure that LQPN points to right QP */
195 struct ib_qp *qp = container_of(res, struct ib_qp, res);
196
197 WARN_ONCE(qp->qp_num >> 24 || qp->port >> 8,
198 "QP number 0x%0X and port 0x%0X", qp->qp_num,
199 qp->port);
200 res->id = qp->qp_num;
201 if (qp->qp_type == IB_QPT_SMI || qp->qp_type == IB_QPT_GSI)
202 res->id |= qp->port << 24;
203 ret = xa_insert(&rt->xa, res->id, res, GFP_KERNEL);
204 if (ret)
205 res->id = 0;
206
207 if (qp->qp_type >= IB_QPT_DRIVER)
208 xa_set_mark(&rt->xa, res->id, RESTRACK_DD);
209 } else if (res->type == RDMA_RESTRACK_COUNTER) {
210 /* Special case to ensure that cntn points to right counter */
211 struct rdma_counter *counter;
212
213 counter = container_of(res, struct rdma_counter, res);
214 ret = xa_insert(&rt->xa, counter->id, res, GFP_KERNEL);
215 res->id = ret ? 0 : counter->id;
216 } else {
217 ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
218 &rt->next_id, GFP_KERNEL);
219 ret = (ret < 0) ? ret : 0;
220 }
221
222out:
223 if (!ret)
224 res->valid = true;
225}
226EXPORT_SYMBOL(rdma_restrack_add);
227
228int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
229{
230 return kref_get_unless_zero(&res->kref);
231}
232EXPORT_SYMBOL(rdma_restrack_get);
233
234/**
235 * rdma_restrack_get_byid() - translate from ID to restrack object
236 * @dev: IB device
237 * @type: resource track type
238 * @id: ID to take a look
239 *
240 * Return: Pointer to restrack entry or -ENOENT in case of error.
241 */
242struct rdma_restrack_entry *
243rdma_restrack_get_byid(struct ib_device *dev,
244 enum rdma_restrack_type type, u32 id)
245{
246 struct rdma_restrack_root *rt = &dev->res[type];
247 struct rdma_restrack_entry *res;
248
249 xa_lock(&rt->xa);
250 res = xa_load(&rt->xa, id);
251 if (!res || !rdma_restrack_get(res))
252 res = ERR_PTR(-ENOENT);
253 xa_unlock(&rt->xa);
254
255 return res;
256}
257EXPORT_SYMBOL(rdma_restrack_get_byid);
258
259static void restrack_release(struct kref *kref)
260{
261 struct rdma_restrack_entry *res;
262
263 res = container_of(kref, struct rdma_restrack_entry, kref);
264 if (res->task) {
265 put_task_struct(res->task);
266 res->task = NULL;
267 }
268 complete(&res->comp);
269}
270
271int rdma_restrack_put(struct rdma_restrack_entry *res)
272{
273 return kref_put(&res->kref, restrack_release);
274}
275EXPORT_SYMBOL(rdma_restrack_put);
276
277/**
278 * rdma_restrack_del() - delete object from the reource tracking database
279 * @res: resource entry
280 */
281void rdma_restrack_del(struct rdma_restrack_entry *res)
282{
283 struct rdma_restrack_entry *old;
284 struct rdma_restrack_root *rt;
285 struct ib_device *dev;
286
287 if (!res->valid) {
288 if (res->task) {
289 put_task_struct(res->task);
290 res->task = NULL;
291 }
292 return;
293 }
294
295 if (res->no_track)
296 goto out;
297
298 dev = res_to_dev(res);
299 if (WARN_ON(!dev))
300 return;
301
302 rt = &dev->res[res->type];
303
304 old = xa_erase(&rt->xa, res->id);
305 WARN_ON(old != res);
306
307out:
308 res->valid = false;
309 rdma_restrack_put(res);
310 wait_for_completion(&res->comp);
311}
312EXPORT_SYMBOL(rdma_restrack_del);
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
40static const char *type2str(enum rdma_restrack_type type)
41{
42 static const char * const names[RDMA_RESTRACK_MAX] = {
43 [RDMA_RESTRACK_PD] = "PD",
44 [RDMA_RESTRACK_CQ] = "CQ",
45 [RDMA_RESTRACK_QP] = "QP",
46 [RDMA_RESTRACK_CM_ID] = "CM_ID",
47 [RDMA_RESTRACK_MR] = "MR",
48 [RDMA_RESTRACK_CTX] = "CTX",
49 [RDMA_RESTRACK_COUNTER] = "COUNTER",
50 };
51
52 return names[type];
53};
54
55/**
56 * rdma_restrack_clean() - clean resource tracking
57 * @dev: IB device
58 */
59void rdma_restrack_clean(struct ib_device *dev)
60{
61 struct rdma_restrack_root *rt = dev->res;
62 struct rdma_restrack_entry *e;
63 char buf[TASK_COMM_LEN];
64 bool found = false;
65 const char *owner;
66 int i;
67
68 for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) {
69 struct xarray *xa = &dev->res[i].xa;
70
71 if (!xa_empty(xa)) {
72 unsigned long index;
73
74 if (!found) {
75 pr_err("restrack: %s", CUT_HERE);
76 dev_err(&dev->dev, "BUG: RESTRACK detected leak of resources\n");
77 }
78 xa_for_each(xa, index, e) {
79 if (rdma_is_kernel_res(e)) {
80 owner = e->kern_name;
81 } else {
82 /*
83 * There is no need to call get_task_struct here,
84 * because we can be here only if there are more
85 * get_task_struct() call than put_task_struct().
86 */
87 get_task_comm(buf, e->task);
88 owner = buf;
89 }
90
91 pr_err("restrack: %s %s object allocated by %s is not freed\n",
92 rdma_is_kernel_res(e) ? "Kernel" :
93 "User",
94 type2str(e->type), owner);
95 }
96 found = true;
97 }
98 xa_destroy(xa);
99 }
100 if (found)
101 pr_err("restrack: %s", CUT_HERE);
102
103 kfree(rt);
104}
105
106/**
107 * rdma_restrack_count() - the current usage of specific object
108 * @dev: IB device
109 * @type: actual type of object to operate
110 */
111int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type)
112{
113 struct rdma_restrack_root *rt = &dev->res[type];
114 struct rdma_restrack_entry *e;
115 XA_STATE(xas, &rt->xa, 0);
116 u32 cnt = 0;
117
118 xa_lock(&rt->xa);
119 xas_for_each(&xas, e, U32_MAX)
120 cnt++;
121 xa_unlock(&rt->xa);
122 return cnt;
123}
124EXPORT_SYMBOL(rdma_restrack_count);
125
126static void set_kern_name(struct rdma_restrack_entry *res)
127{
128 struct ib_pd *pd;
129
130 switch (res->type) {
131 case RDMA_RESTRACK_QP:
132 pd = container_of(res, struct ib_qp, res)->pd;
133 if (!pd) {
134 WARN_ONCE(true, "XRC QPs are not supported\n");
135 /* Survive, despite the programmer's error */
136 res->kern_name = " ";
137 }
138 break;
139 case RDMA_RESTRACK_MR:
140 pd = container_of(res, struct ib_mr, res)->pd;
141 break;
142 default:
143 /* Other types set kern_name directly */
144 pd = NULL;
145 break;
146 }
147
148 if (pd)
149 res->kern_name = pd->res.kern_name;
150}
151
152static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
153{
154 switch (res->type) {
155 case RDMA_RESTRACK_PD:
156 return container_of(res, struct ib_pd, res)->device;
157 case RDMA_RESTRACK_CQ:
158 return container_of(res, struct ib_cq, res)->device;
159 case RDMA_RESTRACK_QP:
160 return container_of(res, struct ib_qp, res)->device;
161 case RDMA_RESTRACK_CM_ID:
162 return container_of(res, struct rdma_id_private,
163 res)->id.device;
164 case RDMA_RESTRACK_MR:
165 return container_of(res, struct ib_mr, res)->device;
166 case RDMA_RESTRACK_CTX:
167 return container_of(res, struct ib_ucontext, res)->device;
168 case RDMA_RESTRACK_COUNTER:
169 return container_of(res, struct rdma_counter, res)->device;
170 default:
171 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
172 return NULL;
173 }
174}
175
176void rdma_restrack_set_task(struct rdma_restrack_entry *res,
177 const char *caller)
178{
179 if (caller) {
180 res->kern_name = caller;
181 return;
182 }
183
184 if (res->task)
185 put_task_struct(res->task);
186 get_task_struct(current);
187 res->task = current;
188}
189EXPORT_SYMBOL(rdma_restrack_set_task);
190
191/**
192 * rdma_restrack_attach_task() - attach the task onto this resource
193 * @res: resource entry
194 * @task: the task to attach, the current task will be used if it is NULL.
195 */
196void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
197 struct task_struct *task)
198{
199 if (res->task)
200 put_task_struct(res->task);
201 get_task_struct(task);
202 res->task = task;
203}
204
205static void rdma_restrack_add(struct rdma_restrack_entry *res)
206{
207 struct ib_device *dev = res_to_dev(res);
208 struct rdma_restrack_root *rt;
209 int ret;
210
211 if (!dev)
212 return;
213
214 rt = &dev->res[res->type];
215
216 kref_init(&res->kref);
217 init_completion(&res->comp);
218 if (res->type == RDMA_RESTRACK_QP) {
219 /* Special case to ensure that LQPN points to right QP */
220 struct ib_qp *qp = container_of(res, struct ib_qp, res);
221
222 ret = xa_insert(&rt->xa, qp->qp_num, res, GFP_KERNEL);
223 res->id = ret ? 0 : qp->qp_num;
224 } else if (res->type == RDMA_RESTRACK_COUNTER) {
225 /* Special case to ensure that cntn points to right counter */
226 struct rdma_counter *counter;
227
228 counter = container_of(res, struct rdma_counter, res);
229 ret = xa_insert(&rt->xa, counter->id, res, GFP_KERNEL);
230 res->id = ret ? 0 : counter->id;
231 } else {
232 ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
233 &rt->next_id, GFP_KERNEL);
234 }
235
236 if (!ret)
237 res->valid = true;
238}
239
240/**
241 * rdma_restrack_kadd() - add kernel object to the reource tracking database
242 * @res: resource entry
243 */
244void rdma_restrack_kadd(struct rdma_restrack_entry *res)
245{
246 res->task = NULL;
247 set_kern_name(res);
248 res->user = false;
249 rdma_restrack_add(res);
250}
251EXPORT_SYMBOL(rdma_restrack_kadd);
252
253/**
254 * rdma_restrack_uadd() - add user object to the reource tracking database
255 * @res: resource entry
256 */
257void rdma_restrack_uadd(struct rdma_restrack_entry *res)
258{
259 if ((res->type != RDMA_RESTRACK_CM_ID) &&
260 (res->type != RDMA_RESTRACK_COUNTER))
261 res->task = NULL;
262
263 if (!res->task)
264 rdma_restrack_set_task(res, NULL);
265 res->kern_name = NULL;
266
267 res->user = true;
268 rdma_restrack_add(res);
269}
270EXPORT_SYMBOL(rdma_restrack_uadd);
271
272int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
273{
274 return kref_get_unless_zero(&res->kref);
275}
276EXPORT_SYMBOL(rdma_restrack_get);
277
278/**
279 * rdma_restrack_get_byid() - translate from ID to restrack object
280 * @dev: IB device
281 * @type: resource track type
282 * @id: ID to take a look
283 *
284 * Return: Pointer to restrack entry or -ENOENT in case of error.
285 */
286struct rdma_restrack_entry *
287rdma_restrack_get_byid(struct ib_device *dev,
288 enum rdma_restrack_type type, u32 id)
289{
290 struct rdma_restrack_root *rt = &dev->res[type];
291 struct rdma_restrack_entry *res;
292
293 xa_lock(&rt->xa);
294 res = xa_load(&rt->xa, id);
295 if (!res || !rdma_restrack_get(res))
296 res = ERR_PTR(-ENOENT);
297 xa_unlock(&rt->xa);
298
299 return res;
300}
301EXPORT_SYMBOL(rdma_restrack_get_byid);
302
303static void restrack_release(struct kref *kref)
304{
305 struct rdma_restrack_entry *res;
306
307 res = container_of(kref, struct rdma_restrack_entry, kref);
308 complete(&res->comp);
309}
310
311int rdma_restrack_put(struct rdma_restrack_entry *res)
312{
313 return kref_put(&res->kref, restrack_release);
314}
315EXPORT_SYMBOL(rdma_restrack_put);
316
317void rdma_restrack_del(struct rdma_restrack_entry *res)
318{
319 struct rdma_restrack_entry *old;
320 struct rdma_restrack_root *rt;
321 struct ib_device *dev;
322
323 if (!res->valid)
324 goto out;
325
326 dev = res_to_dev(res);
327 if (WARN_ON(!dev))
328 return;
329
330 rt = &dev->res[res->type];
331
332 old = xa_erase(&rt->xa, res->id);
333 WARN_ON(old != res);
334 res->valid = false;
335
336 rdma_restrack_put(res);
337 wait_for_completion(&res->comp);
338
339out:
340 if (res->task) {
341 put_task_struct(res->task);
342 res->task = NULL;
343 }
344}
345EXPORT_SYMBOL(rdma_restrack_del);