]> Git Repo - J-linux.git/blob - drivers/infiniband/core/restrack.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / infiniband / core / restrack.c
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  */
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  */
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  */
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
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         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  */
115 static 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  */
133 void 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 }
142 EXPORT_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  */
150 void 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 }
158 EXPORT_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  */
166 void 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 }
173 EXPORT_SYMBOL(rdma_restrack_new);
174
175 /**
176  * rdma_restrack_add() - add object to the reource tracking database
177  * @res:  resource entry
178  */
179 void 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
222 out:
223         if (!ret)
224                 res->valid = true;
225 }
226 EXPORT_SYMBOL(rdma_restrack_add);
227
228 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
229 {
230         return kref_get_unless_zero(&res->kref);
231 }
232 EXPORT_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  */
242 struct rdma_restrack_entry *
243 rdma_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 }
257 EXPORT_SYMBOL(rdma_restrack_get_byid);
258
259 static 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
271 int rdma_restrack_put(struct rdma_restrack_entry *res)
272 {
273         return kref_put(&res->kref, restrack_release);
274 }
275 EXPORT_SYMBOL(rdma_restrack_put);
276
277 /**
278  * rdma_restrack_del() - delete object from the reource tracking database
279  * @res:  resource entry
280  */
281 void 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
307 out:
308         res->valid = false;
309         rdma_restrack_put(res);
310         wait_for_completion(&res->comp);
311 }
312 EXPORT_SYMBOL(rdma_restrack_del);
This page took 0.042449 seconds and 4 git commands to generate.