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 */
rdma_restrack_count(struct ib_device * dev,enum rdma_restrack_type type)63 int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type)
64 {
65 struct rdma_restrack_root *rt = &dev->res[type];
66 struct rdma_restrack_entry *e;
67 XA_STATE(xas, &rt->xa, 0);
68 u32 cnt = 0;
69
70 xa_lock(&rt->xa);
71 xas_for_each(&xas, e, U32_MAX)
72 cnt++;
73 xa_unlock(&rt->xa);
74 return cnt;
75 }
76 EXPORT_SYMBOL(rdma_restrack_count);
77
res_to_dev(struct rdma_restrack_entry * res)78 static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
79 {
80 switch (res->type) {
81 case RDMA_RESTRACK_PD:
82 return container_of(res, struct ib_pd, res)->device;
83 case RDMA_RESTRACK_CQ:
84 return container_of(res, struct ib_cq, res)->device;
85 case RDMA_RESTRACK_QP:
86 return container_of(res, struct ib_qp, res)->device;
87 case RDMA_RESTRACK_CM_ID:
88 return container_of(res, struct rdma_id_private,
89 res)->id.device;
90 case RDMA_RESTRACK_MR:
91 return container_of(res, struct ib_mr, res)->device;
92 case RDMA_RESTRACK_CTX:
93 return container_of(res, struct ib_ucontext, res)->device;
94 case RDMA_RESTRACK_COUNTER:
95 return container_of(res, struct rdma_counter, res)->device;
96 case RDMA_RESTRACK_SRQ:
97 return container_of(res, struct ib_srq, res)->device;
98 default:
99 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
100 return NULL;
101 }
102 }
103
104 /**
105 * rdma_restrack_attach_task() - attach the task onto this resource,
106 * valid for user space restrack entries.
107 * @res: resource entry
108 * @task: the task to attach
109 */
rdma_restrack_attach_task(struct rdma_restrack_entry * res,struct task_struct * task)110 static void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
111 struct task_struct *task)
112 {
113 if (WARN_ON_ONCE(!task))
114 return;
115
116 if (res->task)
117 put_task_struct(res->task);
118 get_task_struct(task);
119 res->task = task;
120 res->user = true;
121 }
122
123 /**
124 * rdma_restrack_set_name() - set the task for this resource
125 * @res: resource entry
126 * @caller: kernel name, the current task will be used if the caller is NULL.
127 */
rdma_restrack_set_name(struct rdma_restrack_entry * res,const char * caller)128 void rdma_restrack_set_name(struct rdma_restrack_entry *res, const char *caller)
129 {
130 if (caller) {
131 res->kern_name = caller;
132 return;
133 }
134
135 rdma_restrack_attach_task(res, current);
136 }
137 EXPORT_SYMBOL(rdma_restrack_set_name);
138
139 /**
140 * rdma_restrack_parent_name() - set the restrack name properties based
141 * on parent restrack
142 * @dst: destination resource entry
143 * @parent: parent resource entry
144 */
rdma_restrack_parent_name(struct rdma_restrack_entry * dst,const struct rdma_restrack_entry * parent)145 void rdma_restrack_parent_name(struct rdma_restrack_entry *dst,
146 const struct rdma_restrack_entry *parent)
147 {
148 if (rdma_is_kernel_res(parent))
149 dst->kern_name = parent->kern_name;
150 else
151 rdma_restrack_attach_task(dst, parent->task);
152 }
153 EXPORT_SYMBOL(rdma_restrack_parent_name);
154
155 /**
156 * rdma_restrack_new() - Initializes new restrack entry to allow _put() interface
157 * to release memory in fully automatic way.
158 * @res: Entry to initialize
159 * @type: REstrack type
160 */
rdma_restrack_new(struct rdma_restrack_entry * res,enum rdma_restrack_type type)161 void rdma_restrack_new(struct rdma_restrack_entry *res,
162 enum rdma_restrack_type type)
163 {
164 kref_init(&res->kref);
165 init_completion(&res->comp);
166 res->type = type;
167 }
168 EXPORT_SYMBOL(rdma_restrack_new);
169
170 /**
171 * rdma_restrack_add() - add object to the reource tracking database
172 * @res: resource entry
173 */
rdma_restrack_add(struct rdma_restrack_entry * res)174 void rdma_restrack_add(struct rdma_restrack_entry *res)
175 {
176 struct ib_device *dev = res_to_dev(res);
177 struct rdma_restrack_root *rt;
178 int ret = 0;
179
180 if (!dev)
181 return;
182
183 if (res->no_track)
184 goto out;
185
186 rt = &dev->res[res->type];
187
188 if (res->type == RDMA_RESTRACK_QP) {
189 /* Special case to ensure that LQPN points to right QP */
190 struct ib_qp *qp = container_of(res, struct ib_qp, res);
191
192 WARN_ONCE(qp->qp_num >> 24 || qp->port >> 8,
193 "QP number 0x%0X and port 0x%0X", qp->qp_num,
194 qp->port);
195 res->id = qp->qp_num;
196 if (qp->qp_type == IB_QPT_SMI || qp->qp_type == IB_QPT_GSI)
197 res->id |= qp->port << 24;
198 ret = xa_insert(&rt->xa, res->id, res, GFP_KERNEL);
199 if (ret)
200 res->id = 0;
201 } else if (res->type == RDMA_RESTRACK_COUNTER) {
202 /* Special case to ensure that cntn points to right counter */
203 struct rdma_counter *counter;
204
205 counter = container_of(res, struct rdma_counter, res);
206 ret = xa_insert(&rt->xa, counter->id, res, GFP_KERNEL);
207 res->id = ret ? 0 : counter->id;
208 } else {
209 ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
210 &rt->next_id, GFP_KERNEL);
211 ret = (ret < 0) ? ret : 0;
212 }
213
214 out:
215 if (!ret)
216 res->valid = true;
217 }
218 EXPORT_SYMBOL(rdma_restrack_add);
219
rdma_restrack_get(struct rdma_restrack_entry * res)220 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
221 {
222 return kref_get_unless_zero(&res->kref);
223 }
224 EXPORT_SYMBOL(rdma_restrack_get);
225
226 /**
227 * rdma_restrack_get_byid() - translate from ID to restrack object
228 * @dev: IB device
229 * @type: resource track type
230 * @id: ID to take a look
231 *
232 * Return: Pointer to restrack entry or -ENOENT in case of error.
233 */
234 struct rdma_restrack_entry *
rdma_restrack_get_byid(struct ib_device * dev,enum rdma_restrack_type type,u32 id)235 rdma_restrack_get_byid(struct ib_device *dev,
236 enum rdma_restrack_type type, u32 id)
237 {
238 struct rdma_restrack_root *rt = &dev->res[type];
239 struct rdma_restrack_entry *res;
240
241 xa_lock(&rt->xa);
242 res = xa_load(&rt->xa, id);
243 if (!res || !rdma_restrack_get(res))
244 res = ERR_PTR(-ENOENT);
245 xa_unlock(&rt->xa);
246
247 return res;
248 }
249 EXPORT_SYMBOL(rdma_restrack_get_byid);
250
restrack_release(struct kref * kref)251 static void restrack_release(struct kref *kref)
252 {
253 struct rdma_restrack_entry *res;
254
255 res = container_of(kref, struct rdma_restrack_entry, kref);
256 if (res->task) {
257 put_task_struct(res->task);
258 res->task = NULL;
259 }
260 complete(&res->comp);
261 }
262
rdma_restrack_put(struct rdma_restrack_entry * res)263 int rdma_restrack_put(struct rdma_restrack_entry *res)
264 {
265 return kref_put(&res->kref, restrack_release);
266 }
267 EXPORT_SYMBOL(rdma_restrack_put);
268
269 /**
270 * rdma_restrack_del() - delete object from the reource tracking database
271 * @res: resource entry
272 */
rdma_restrack_del(struct rdma_restrack_entry * res)273 void rdma_restrack_del(struct rdma_restrack_entry *res)
274 {
275 struct rdma_restrack_entry *old;
276 struct rdma_restrack_root *rt;
277 struct ib_device *dev;
278
279 if (!res->valid) {
280 if (res->task) {
281 put_task_struct(res->task);
282 res->task = NULL;
283 }
284 return;
285 }
286
287 if (res->no_track)
288 goto out;
289
290 dev = res_to_dev(res);
291 if (WARN_ON(!dev))
292 return;
293
294 rt = &dev->res[res->type];
295
296 old = xa_erase(&rt->xa, res->id);
297 WARN_ON(old != res);
298
299 out:
300 res->valid = false;
301 rdma_restrack_put(res);
302 wait_for_completion(&res->comp);
303 }
304 EXPORT_SYMBOL(rdma_restrack_del);
305