xref: /openbmc/linux/drivers/infiniband/core/restrack.c (revision e33bbe69149b802c0c77bfb822685772f85388ca)
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 static const char *type2str(enum rdma_restrack_type type)
21 {
22 	static const char * const names[RDMA_RESTRACK_MAX] = {
23 		[RDMA_RESTRACK_PD] = "PD",
24 		[RDMA_RESTRACK_CQ] = "CQ",
25 		[RDMA_RESTRACK_QP] = "QP",
26 		[RDMA_RESTRACK_CM_ID] = "CM_ID",
27 		[RDMA_RESTRACK_MR] = "MR",
28 	};
29 
30 	return names[type];
31 };
32 
33 void rdma_restrack_clean(struct rdma_restrack_root *res)
34 {
35 	struct rdma_restrack_entry *e;
36 	char buf[TASK_COMM_LEN];
37 	struct ib_device *dev;
38 	const char *owner;
39 	int bkt;
40 
41 	if (hash_empty(res->hash))
42 		return;
43 
44 	dev = container_of(res, struct ib_device, res);
45 	pr_err("restrack: %s", CUT_HERE);
46 	pr_err("restrack: BUG: RESTRACK detected leak of resources on %s\n",
47 	       dev->name);
48 	hash_for_each(res->hash, bkt, e, node) {
49 		if (rdma_is_kernel_res(e)) {
50 			owner = e->kern_name;
51 		} else {
52 			/*
53 			 * There is no need to call get_task_struct here,
54 			 * because we can be here only if there are more
55 			 * get_task_struct() call than put_task_struct().
56 			 */
57 			get_task_comm(buf, e->task);
58 			owner = buf;
59 		}
60 
61 		pr_err("restrack: %s %s object allocated by %s is not freed\n",
62 		       rdma_is_kernel_res(e) ? "Kernel" : "User",
63 		       type2str(e->type), owner);
64 	}
65 	pr_err("restrack: %s", CUT_HERE);
66 }
67 
68 int rdma_restrack_count(struct rdma_restrack_root *res,
69 			enum rdma_restrack_type type,
70 			struct pid_namespace *ns)
71 {
72 	struct rdma_restrack_entry *e;
73 	u32 cnt = 0;
74 
75 	down_read(&res->rwsem);
76 	hash_for_each_possible(res->hash, e, node, type) {
77 		if (ns == &init_pid_ns ||
78 		    (!rdma_is_kernel_res(e) &&
79 		     ns == task_active_pid_ns(e->task)))
80 			cnt++;
81 	}
82 	up_read(&res->rwsem);
83 	return cnt;
84 }
85 EXPORT_SYMBOL(rdma_restrack_count);
86 
87 static void set_kern_name(struct rdma_restrack_entry *res)
88 {
89 	struct ib_pd *pd;
90 
91 	switch (res->type) {
92 	case RDMA_RESTRACK_QP:
93 		pd = container_of(res, struct ib_qp, res)->pd;
94 		if (!pd) {
95 			WARN_ONCE(true, "XRC QPs are not supported\n");
96 			/* Survive, despite the programmer's error */
97 			res->kern_name = " ";
98 		}
99 		break;
100 	case RDMA_RESTRACK_MR:
101 		pd = container_of(res, struct ib_mr, res)->pd;
102 		break;
103 	default:
104 		/* Other types set kern_name directly */
105 		pd = NULL;
106 		break;
107 	}
108 
109 	if (pd)
110 		res->kern_name = pd->res.kern_name;
111 }
112 
113 static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
114 {
115 	switch (res->type) {
116 	case RDMA_RESTRACK_PD:
117 		return container_of(res, struct ib_pd, res)->device;
118 	case RDMA_RESTRACK_CQ:
119 		return container_of(res, struct ib_cq, res)->device;
120 	case RDMA_RESTRACK_QP:
121 		return container_of(res, struct ib_qp, res)->device;
122 	case RDMA_RESTRACK_CM_ID:
123 		return container_of(res, struct rdma_id_private,
124 				    res)->id.device;
125 	case RDMA_RESTRACK_MR:
126 		return container_of(res, struct ib_mr, res)->device;
127 	default:
128 		WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
129 		return NULL;
130 	}
131 }
132 
133 static bool res_is_user(struct rdma_restrack_entry *res)
134 {
135 	switch (res->type) {
136 	case RDMA_RESTRACK_PD:
137 		return container_of(res, struct ib_pd, res)->uobject;
138 	case RDMA_RESTRACK_CQ:
139 		return container_of(res, struct ib_cq, res)->uobject;
140 	case RDMA_RESTRACK_QP:
141 		return container_of(res, struct ib_qp, res)->uobject;
142 	case RDMA_RESTRACK_CM_ID:
143 		return !res->kern_name;
144 	case RDMA_RESTRACK_MR:
145 		return container_of(res, struct ib_mr, res)->pd->uobject;
146 	default:
147 		WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
148 		return false;
149 	}
150 }
151 
152 void rdma_restrack_add(struct rdma_restrack_entry *res)
153 {
154 	struct ib_device *dev = res_to_dev(res);
155 
156 	if (!dev)
157 		return;
158 
159 	if (res->type != RDMA_RESTRACK_CM_ID || !res_is_user(res))
160 		res->task = NULL;
161 
162 	if (res_is_user(res)) {
163 		if (!res->task)
164 			rdma_restrack_set_task(res, current);
165 		res->kern_name = NULL;
166 	} else {
167 		set_kern_name(res);
168 	}
169 
170 	kref_init(&res->kref);
171 	init_completion(&res->comp);
172 	res->valid = true;
173 
174 	down_write(&dev->res.rwsem);
175 	hash_add(dev->res.hash, &res->node, res->type);
176 	up_write(&dev->res.rwsem);
177 }
178 EXPORT_SYMBOL(rdma_restrack_add);
179 
180 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
181 {
182 	return kref_get_unless_zero(&res->kref);
183 }
184 EXPORT_SYMBOL(rdma_restrack_get);
185 
186 static void restrack_release(struct kref *kref)
187 {
188 	struct rdma_restrack_entry *res;
189 
190 	res = container_of(kref, struct rdma_restrack_entry, kref);
191 	complete(&res->comp);
192 }
193 
194 int rdma_restrack_put(struct rdma_restrack_entry *res)
195 {
196 	return kref_put(&res->kref, restrack_release);
197 }
198 EXPORT_SYMBOL(rdma_restrack_put);
199 
200 void rdma_restrack_del(struct rdma_restrack_entry *res)
201 {
202 	struct ib_device *dev;
203 
204 	if (!res->valid)
205 		return;
206 
207 	dev = res_to_dev(res);
208 	if (!dev)
209 		return;
210 
211 	rdma_restrack_put(res);
212 
213 	wait_for_completion(&res->comp);
214 
215 	down_write(&dev->res.rwsem);
216 	hash_del(&res->node);
217 	res->valid = false;
218 	if (res->task)
219 		put_task_struct(res->task);
220 	up_write(&dev->res.rwsem);
221 }
222 EXPORT_SYMBOL(rdma_restrack_del);
223