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