1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
3 * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
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>
18 * rdma_restrack_init() - initialize and allocate resource tracking
21 * Return: 0 on success
23 int rdma_restrack_init(struct ib_device
*dev
)
25 struct rdma_restrack_root
*rt
;
28 dev
->res
= kcalloc(RDMA_RESTRACK_MAX
, sizeof(*rt
), GFP_KERNEL
);
34 for (i
= 0; i
< RDMA_RESTRACK_MAX
; i
++)
35 xa_init_flags(&rt
[i
].xa
, XA_FLAGS_ALLOC
);
40 static const char *type2str(enum rdma_restrack_type type
)
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",
56 * rdma_restrack_clean() - clean resource tracking
59 void rdma_restrack_clean(struct ib_device
*dev
)
61 struct rdma_restrack_root
*rt
= dev
->res
;
62 struct rdma_restrack_entry
*e
;
63 char buf
[TASK_COMM_LEN
];
68 for (i
= 0 ; i
< RDMA_RESTRACK_MAX
; i
++) {
69 struct xarray
*xa
= &dev
->res
[i
].xa
;
75 pr_err("restrack: %s", CUT_HERE
);
76 dev_err(&dev
->dev
, "BUG: RESTRACK detected leak of resources\n");
78 xa_for_each(xa
, index
, e
) {
79 if (rdma_is_kernel_res(e
)) {
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().
87 get_task_comm(buf
, e
->task
);
91 pr_err("restrack: %s %s object allocated by %s is not freed\n",
92 rdma_is_kernel_res(e
) ? "Kernel" :
94 type2str(e
->type
), owner
);
101 pr_err("restrack: %s", CUT_HERE
);
107 * rdma_restrack_count() - the current usage of specific object
109 * @type: actual type of object to operate
111 int rdma_restrack_count(struct ib_device
*dev
, enum rdma_restrack_type type
)
113 struct rdma_restrack_root
*rt
= &dev
->res
[type
];
114 struct rdma_restrack_entry
*e
;
115 XA_STATE(xas
, &rt
->xa
, 0);
119 xas_for_each(&xas
, e
, U32_MAX
)
124 EXPORT_SYMBOL(rdma_restrack_count
);
126 static struct ib_device
*res_to_dev(struct rdma_restrack_entry
*res
)
129 case RDMA_RESTRACK_PD
:
130 return container_of(res
, struct ib_pd
, res
)->device
;
131 case RDMA_RESTRACK_CQ
:
132 return container_of(res
, struct ib_cq
, res
)->device
;
133 case RDMA_RESTRACK_QP
:
134 return container_of(res
, struct ib_qp
, res
)->device
;
135 case RDMA_RESTRACK_CM_ID
:
136 return container_of(res
, struct rdma_id_private
,
138 case RDMA_RESTRACK_MR
:
139 return container_of(res
, struct ib_mr
, res
)->device
;
140 case RDMA_RESTRACK_CTX
:
141 return container_of(res
, struct ib_ucontext
, res
)->device
;
142 case RDMA_RESTRACK_COUNTER
:
143 return container_of(res
, struct rdma_counter
, res
)->device
;
145 WARN_ONCE(true, "Wrong resource tracking type %u\n", res
->type
);
151 * rdma_restrack_attach_task() - attach the task onto this resource,
152 * valid for user space restrack entries.
153 * @res: resource entry
154 * @task: the task to attach
156 static void rdma_restrack_attach_task(struct rdma_restrack_entry
*res
,
157 struct task_struct
*task
)
159 if (WARN_ON_ONCE(!task
))
163 put_task_struct(res
->task
);
164 get_task_struct(task
);
170 * rdma_restrack_set_name() - set the task for this resource
171 * @res: resource entry
172 * @caller: kernel name, the current task will be used if the caller is NULL.
174 void rdma_restrack_set_name(struct rdma_restrack_entry
*res
, const char *caller
)
177 res
->kern_name
= caller
;
181 rdma_restrack_attach_task(res
, current
);
183 EXPORT_SYMBOL(rdma_restrack_set_name
);
186 * rdma_restrack_parent_name() - set the restrack name properties based
188 * @dst: destination resource entry
189 * @parent: parent resource entry
191 void rdma_restrack_parent_name(struct rdma_restrack_entry
*dst
,
192 const struct rdma_restrack_entry
*parent
)
194 if (rdma_is_kernel_res(parent
))
195 dst
->kern_name
= parent
->kern_name
;
197 rdma_restrack_attach_task(dst
, parent
->task
);
199 EXPORT_SYMBOL(rdma_restrack_parent_name
);
202 * rdma_restrack_new() - Initializes new restrack entry to allow _put() interface
203 * to release memory in fully automatic way.
204 * @res - Entry to initialize
205 * @type - REstrack type
207 void rdma_restrack_new(struct rdma_restrack_entry
*res
,
208 enum rdma_restrack_type type
)
210 kref_init(&res
->kref
);
211 init_completion(&res
->comp
);
214 EXPORT_SYMBOL(rdma_restrack_new
);
217 * rdma_restrack_add() - add object to the reource tracking database
218 * @res: resource entry
220 void rdma_restrack_add(struct rdma_restrack_entry
*res
)
222 struct ib_device
*dev
= res_to_dev(res
);
223 struct rdma_restrack_root
*rt
;
232 rt
= &dev
->res
[res
->type
];
234 if (res
->type
== RDMA_RESTRACK_QP
) {
235 /* Special case to ensure that LQPN points to right QP */
236 struct ib_qp
*qp
= container_of(res
, struct ib_qp
, res
);
238 WARN_ONCE(qp
->qp_num
>> 24 || qp
->port
>> 8,
239 "QP number 0x%0X and port 0x%0X", qp
->qp_num
,
241 res
->id
= qp
->qp_num
;
242 if (qp
->qp_type
== IB_QPT_SMI
|| qp
->qp_type
== IB_QPT_GSI
)
243 res
->id
|= qp
->port
<< 24;
244 ret
= xa_insert(&rt
->xa
, res
->id
, res
, GFP_KERNEL
);
247 } else if (res
->type
== RDMA_RESTRACK_COUNTER
) {
248 /* Special case to ensure that cntn points to right counter */
249 struct rdma_counter
*counter
;
251 counter
= container_of(res
, struct rdma_counter
, res
);
252 ret
= xa_insert(&rt
->xa
, counter
->id
, res
, GFP_KERNEL
);
253 res
->id
= ret
? 0 : counter
->id
;
255 ret
= xa_alloc_cyclic(&rt
->xa
, &res
->id
, res
, xa_limit_32b
,
256 &rt
->next_id
, GFP_KERNEL
);
263 EXPORT_SYMBOL(rdma_restrack_add
);
265 int __must_check
rdma_restrack_get(struct rdma_restrack_entry
*res
)
267 return kref_get_unless_zero(&res
->kref
);
269 EXPORT_SYMBOL(rdma_restrack_get
);
272 * rdma_restrack_get_byid() - translate from ID to restrack object
274 * @type: resource track type
275 * @id: ID to take a look
277 * Return: Pointer to restrack entry or -ENOENT in case of error.
279 struct rdma_restrack_entry
*
280 rdma_restrack_get_byid(struct ib_device
*dev
,
281 enum rdma_restrack_type type
, u32 id
)
283 struct rdma_restrack_root
*rt
= &dev
->res
[type
];
284 struct rdma_restrack_entry
*res
;
287 res
= xa_load(&rt
->xa
, id
);
288 if (!res
|| !rdma_restrack_get(res
))
289 res
= ERR_PTR(-ENOENT
);
294 EXPORT_SYMBOL(rdma_restrack_get_byid
);
296 static void restrack_release(struct kref
*kref
)
298 struct rdma_restrack_entry
*res
;
300 res
= container_of(kref
, struct rdma_restrack_entry
, kref
);
302 put_task_struct(res
->task
);
305 complete(&res
->comp
);
308 int rdma_restrack_put(struct rdma_restrack_entry
*res
)
310 return kref_put(&res
->kref
, restrack_release
);
312 EXPORT_SYMBOL(rdma_restrack_put
);
315 * rdma_restrack_del() - delete object from the reource tracking database
316 * @res: resource entry
318 void rdma_restrack_del(struct rdma_restrack_entry
*res
)
320 struct rdma_restrack_entry
*old
;
321 struct rdma_restrack_root
*rt
;
322 struct ib_device
*dev
;
326 put_task_struct(res
->task
);
335 dev
= res_to_dev(res
);
339 rt
= &dev
->res
[res
->type
];
341 old
= xa_erase(&rt
->xa
, res
->id
);
342 if (res
->type
== RDMA_RESTRACK_MR
|| res
->type
== RDMA_RESTRACK_QP
)
348 rdma_restrack_put(res
);
349 wait_for_completion(&res
->comp
);
351 EXPORT_SYMBOL(rdma_restrack_del
);