]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/infiniband/core/restrack.c
RDMA/nldev: provide detailed MR information
[linux.git] / drivers / infiniband / core / restrack.c
1 /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
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 <linux/mutex.h>
10 #include <linux/sched/task.h>
11 #include <linux/pid_namespace.h>
12
13 #include "cma_priv.h"
14
15 void rdma_restrack_init(struct rdma_restrack_root *res)
16 {
17         init_rwsem(&res->rwsem);
18 }
19
20 void rdma_restrack_clean(struct rdma_restrack_root *res)
21 {
22         WARN_ON_ONCE(!hash_empty(res->hash));
23 }
24
25 int rdma_restrack_count(struct rdma_restrack_root *res,
26                         enum rdma_restrack_type type,
27                         struct pid_namespace *ns)
28 {
29         struct rdma_restrack_entry *e;
30         u32 cnt = 0;
31
32         down_read(&res->rwsem);
33         hash_for_each_possible(res->hash, e, node, type) {
34                 if (ns == &init_pid_ns ||
35                     (!rdma_is_kernel_res(e) &&
36                      ns == task_active_pid_ns(e->task)))
37                         cnt++;
38         }
39         up_read(&res->rwsem);
40         return cnt;
41 }
42 EXPORT_SYMBOL(rdma_restrack_count);
43
44 static void set_kern_name(struct rdma_restrack_entry *res)
45 {
46         struct ib_pd *pd;
47
48         switch (res->type) {
49         case RDMA_RESTRACK_QP:
50                 pd = container_of(res, struct ib_qp, res)->pd;
51                 if (!pd) {
52                         WARN_ONCE(true, "XRC QPs are not supported\n");
53                         /* Survive, despite the programmer's error */
54                         res->kern_name = " ";
55                 }
56                 break;
57         case RDMA_RESTRACK_MR:
58                 pd = container_of(res, struct ib_mr, res)->pd;
59                 break;
60         default:
61                 /* Other types set kern_name directly */
62                 pd = NULL;
63                 break;
64         }
65
66         if (pd)
67                 res->kern_name = pd->res.kern_name;
68 }
69
70 static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
71 {
72         switch (res->type) {
73         case RDMA_RESTRACK_PD:
74                 return container_of(res, struct ib_pd, res)->device;
75         case RDMA_RESTRACK_CQ:
76                 return container_of(res, struct ib_cq, res)->device;
77         case RDMA_RESTRACK_QP:
78                 return container_of(res, struct ib_qp, res)->device;
79         case RDMA_RESTRACK_CM_ID:
80                 return container_of(res, struct rdma_id_private,
81                                     res)->id.device;
82         case RDMA_RESTRACK_MR:
83                 return container_of(res, struct ib_mr, res)->device;
84         default:
85                 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
86                 return NULL;
87         }
88 }
89
90 static bool res_is_user(struct rdma_restrack_entry *res)
91 {
92         switch (res->type) {
93         case RDMA_RESTRACK_PD:
94                 return container_of(res, struct ib_pd, res)->uobject;
95         case RDMA_RESTRACK_CQ:
96                 return container_of(res, struct ib_cq, res)->uobject;
97         case RDMA_RESTRACK_QP:
98                 return container_of(res, struct ib_qp, res)->uobject;
99         case RDMA_RESTRACK_CM_ID:
100                 return !res->kern_name;
101         case RDMA_RESTRACK_MR:
102                 return container_of(res, struct ib_mr, res)->pd->uobject;
103         default:
104                 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
105                 return false;
106         }
107 }
108
109 void rdma_restrack_add(struct rdma_restrack_entry *res)
110 {
111         struct ib_device *dev = res_to_dev(res);
112
113         if (!dev)
114                 return;
115
116         if (res_is_user(res)) {
117                 if (!res->task)
118                         rdma_restrack_set_task(res, current);
119                 res->kern_name = NULL;
120         } else {
121                 set_kern_name(res);
122                 res->task = NULL;
123         }
124
125         kref_init(&res->kref);
126         init_completion(&res->comp);
127         res->valid = true;
128
129         down_write(&dev->res.rwsem);
130         hash_add(dev->res.hash, &res->node, res->type);
131         up_write(&dev->res.rwsem);
132 }
133 EXPORT_SYMBOL(rdma_restrack_add);
134
135 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
136 {
137         return kref_get_unless_zero(&res->kref);
138 }
139 EXPORT_SYMBOL(rdma_restrack_get);
140
141 static void restrack_release(struct kref *kref)
142 {
143         struct rdma_restrack_entry *res;
144
145         res = container_of(kref, struct rdma_restrack_entry, kref);
146         complete(&res->comp);
147 }
148
149 int rdma_restrack_put(struct rdma_restrack_entry *res)
150 {
151         return kref_put(&res->kref, restrack_release);
152 }
153 EXPORT_SYMBOL(rdma_restrack_put);
154
155 void rdma_restrack_del(struct rdma_restrack_entry *res)
156 {
157         struct ib_device *dev;
158
159         if (!res->valid)
160                 return;
161
162         dev = res_to_dev(res);
163         if (!dev)
164                 return;
165
166         rdma_restrack_put(res);
167
168         wait_for_completion(&res->comp);
169
170         down_write(&dev->res.rwsem);
171         hash_del(&res->node);
172         res->valid = false;
173         if (res->task)
174                 put_task_struct(res->task);
175         up_write(&dev->res.rwsem);
176 }
177 EXPORT_SYMBOL(rdma_restrack_del);