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
);
41 * rdma_restrack_clean() - clean resource tracking
44 void rdma_restrack_clean(struct ib_device
*dev
)
46 struct rdma_restrack_root
*rt
= dev
->res
;
49 for (i
= 0 ; i
< RDMA_RESTRACK_MAX
; i
++) {
50 struct xarray
*xa
= &dev
->res
[i
].xa
;
52 WARN_ON(!xa_empty(xa
));
59 * rdma_restrack_count() - the current usage of specific object
61 * @type: actual type of object to operate
62 * @show_details: count driver specific objects
64 int rdma_restrack_count(struct ib_device
*dev
, enum rdma_restrack_type type
,
67 struct rdma_restrack_root
*rt
= &dev
->res
[type
];
68 struct rdma_restrack_entry
*e
;
69 XA_STATE(xas
, &rt
->xa
, 0);
73 xas_for_each(&xas
, e
, U32_MAX
) {
74 if (xa_get_mark(&rt
->xa
, e
->id
, RESTRACK_DD
) && !show_details
)
81 EXPORT_SYMBOL(rdma_restrack_count
);
83 static struct ib_device
*res_to_dev(struct rdma_restrack_entry
*res
)
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
,
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
;
104 WARN_ONCE(true, "Wrong resource tracking type %u\n", res
->type
);
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
115 static void rdma_restrack_attach_task(struct rdma_restrack_entry
*res
,
116 struct task_struct
*task
)
118 if (WARN_ON_ONCE(!task
))
122 put_task_struct(res
->task
);
123 get_task_struct(task
);
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.
133 void rdma_restrack_set_name(struct rdma_restrack_entry
*res
, const char *caller
)
136 res
->kern_name
= caller
;
140 rdma_restrack_attach_task(res
, current
);
142 EXPORT_SYMBOL(rdma_restrack_set_name
);
145 * rdma_restrack_parent_name() - set the restrack name properties based
147 * @dst: destination resource entry
148 * @parent: parent resource entry
150 void rdma_restrack_parent_name(struct rdma_restrack_entry
*dst
,
151 const struct rdma_restrack_entry
*parent
)
153 if (rdma_is_kernel_res(parent
))
154 dst
->kern_name
= parent
->kern_name
;
156 rdma_restrack_attach_task(dst
, parent
->task
);
158 EXPORT_SYMBOL(rdma_restrack_parent_name
);
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
166 void rdma_restrack_new(struct rdma_restrack_entry
*res
,
167 enum rdma_restrack_type type
)
169 kref_init(&res
->kref
);
170 init_completion(&res
->comp
);
173 EXPORT_SYMBOL(rdma_restrack_new
);
176 * rdma_restrack_add() - add object to the reource tracking database
177 * @res: resource entry
179 void rdma_restrack_add(struct rdma_restrack_entry
*res
)
181 struct ib_device
*dev
= res_to_dev(res
);
182 struct rdma_restrack_root
*rt
;
191 rt
= &dev
->res
[res
->type
];
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
);
197 WARN_ONCE(qp
->qp_num
>> 24 || qp
->port
>> 8,
198 "QP number 0x%0X and port 0x%0X", qp
->qp_num
,
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
);
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
;
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
;
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;
226 EXPORT_SYMBOL(rdma_restrack_add
);
228 int __must_check
rdma_restrack_get(struct rdma_restrack_entry
*res
)
230 return kref_get_unless_zero(&res
->kref
);
232 EXPORT_SYMBOL(rdma_restrack_get
);
235 * rdma_restrack_get_byid() - translate from ID to restrack object
237 * @type: resource track type
238 * @id: ID to take a look
240 * Return: Pointer to restrack entry or -ENOENT in case of error.
242 struct rdma_restrack_entry
*
243 rdma_restrack_get_byid(struct ib_device
*dev
,
244 enum rdma_restrack_type type
, u32 id
)
246 struct rdma_restrack_root
*rt
= &dev
->res
[type
];
247 struct rdma_restrack_entry
*res
;
250 res
= xa_load(&rt
->xa
, id
);
251 if (!res
|| !rdma_restrack_get(res
))
252 res
= ERR_PTR(-ENOENT
);
257 EXPORT_SYMBOL(rdma_restrack_get_byid
);
259 static void restrack_release(struct kref
*kref
)
261 struct rdma_restrack_entry
*res
;
263 res
= container_of(kref
, struct rdma_restrack_entry
, kref
);
265 put_task_struct(res
->task
);
268 complete(&res
->comp
);
271 int rdma_restrack_put(struct rdma_restrack_entry
*res
)
273 return kref_put(&res
->kref
, restrack_release
);
275 EXPORT_SYMBOL(rdma_restrack_put
);
278 * rdma_restrack_del() - delete object from the reource tracking database
279 * @res: resource entry
281 void rdma_restrack_del(struct rdma_restrack_entry
*res
)
283 struct rdma_restrack_entry
*old
;
284 struct rdma_restrack_root
*rt
;
285 struct ib_device
*dev
;
289 put_task_struct(res
->task
);
298 dev
= res_to_dev(res
);
302 rt
= &dev
->res
[res
->type
];
304 old
= xa_erase(&rt
->xa
, res
->id
);
309 rdma_restrack_put(res
);
310 wait_for_completion(&res
->comp
);
312 EXPORT_SYMBOL(rdma_restrack_del
);