Merge tag 'drm-misc-next-fixes-2018-04-04' of git://anongit.freedesktop.org/drm/drm...
[platform/kernel/linux-rpi.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/ib_verbs.h>
7 #include <rdma/restrack.h>
8 #include <linux/mutex.h>
9 #include <linux/sched/task.h>
10 #include <linux/pid_namespace.h>
11
12 void rdma_restrack_init(struct rdma_restrack_root *res)
13 {
14         init_rwsem(&res->rwsem);
15 }
16
17 void rdma_restrack_clean(struct rdma_restrack_root *res)
18 {
19         WARN_ON_ONCE(!hash_empty(res->hash));
20 }
21
22 int rdma_restrack_count(struct rdma_restrack_root *res,
23                         enum rdma_restrack_type type,
24                         struct pid_namespace *ns)
25 {
26         struct rdma_restrack_entry *e;
27         u32 cnt = 0;
28
29         down_read(&res->rwsem);
30         hash_for_each_possible(res->hash, e, node, type) {
31                 if (ns == &init_pid_ns ||
32                     (!rdma_is_kernel_res(e) &&
33                      ns == task_active_pid_ns(e->task)))
34                         cnt++;
35         }
36         up_read(&res->rwsem);
37         return cnt;
38 }
39 EXPORT_SYMBOL(rdma_restrack_count);
40
41 static void set_kern_name(struct rdma_restrack_entry *res)
42 {
43         enum rdma_restrack_type type = res->type;
44         struct ib_qp *qp;
45
46         if (type != RDMA_RESTRACK_QP)
47                 /* PD and CQ types already have this name embedded in */
48                 return;
49
50         qp = container_of(res, struct ib_qp, res);
51         if (!qp->pd) {
52                 WARN_ONCE(true, "XRC QPs are not supported\n");
53                 /* Survive, despite the programmer's error */
54                 res->kern_name = " ";
55                 return;
56         }
57
58         res->kern_name = qp->pd->res.kern_name;
59 }
60
61 static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
62 {
63         enum rdma_restrack_type type = res->type;
64         struct ib_device *dev;
65         struct ib_pd *pd;
66         struct ib_cq *cq;
67         struct ib_qp *qp;
68
69         switch (type) {
70         case RDMA_RESTRACK_PD:
71                 pd = container_of(res, struct ib_pd, res);
72                 dev = pd->device;
73                 break;
74         case RDMA_RESTRACK_CQ:
75                 cq = container_of(res, struct ib_cq, res);
76                 dev = cq->device;
77                 break;
78         case RDMA_RESTRACK_QP:
79                 qp = container_of(res, struct ib_qp, res);
80                 dev = qp->device;
81                 break;
82         default:
83                 WARN_ONCE(true, "Wrong resource tracking type %u\n", type);
84                 return NULL;
85         }
86
87         return dev;
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         default:
100                 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
101                 return false;
102         }
103 }
104
105 void rdma_restrack_add(struct rdma_restrack_entry *res)
106 {
107         struct ib_device *dev = res_to_dev(res);
108
109         if (!dev)
110                 return;
111
112         if (res_is_user(res)) {
113                 get_task_struct(current);
114                 res->task = current;
115                 res->kern_name = NULL;
116         } else {
117                 set_kern_name(res);
118                 res->task = NULL;
119         }
120
121         kref_init(&res->kref);
122         init_completion(&res->comp);
123         res->valid = true;
124
125         down_write(&dev->res.rwsem);
126         hash_add(dev->res.hash, &res->node, res->type);
127         up_write(&dev->res.rwsem);
128 }
129 EXPORT_SYMBOL(rdma_restrack_add);
130
131 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
132 {
133         return kref_get_unless_zero(&res->kref);
134 }
135 EXPORT_SYMBOL(rdma_restrack_get);
136
137 static void restrack_release(struct kref *kref)
138 {
139         struct rdma_restrack_entry *res;
140
141         res = container_of(kref, struct rdma_restrack_entry, kref);
142         complete(&res->comp);
143 }
144
145 int rdma_restrack_put(struct rdma_restrack_entry *res)
146 {
147         return kref_put(&res->kref, restrack_release);
148 }
149 EXPORT_SYMBOL(rdma_restrack_put);
150
151 void rdma_restrack_del(struct rdma_restrack_entry *res)
152 {
153         struct ib_device *dev;
154
155         if (!res->valid)
156                 return;
157
158         dev = res_to_dev(res);
159         if (!dev)
160                 return;
161
162         rdma_restrack_put(res);
163
164         wait_for_completion(&res->comp);
165
166         down_write(&dev->res.rwsem);
167         hash_del(&res->node);
168         res->valid = false;
169         if (res->task)
170                 put_task_struct(res->task);
171         up_write(&dev->res.rwsem);
172 }
173 EXPORT_SYMBOL(rdma_restrack_del);