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 case RDMA_RESTRACK_DMAH: 104 return container_of(res, struct ib_dmah, res)->device; 105 default: 106 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type); 107 return NULL; 108 } 109 } 110 111 /** 112 * rdma_restrack_attach_task() - attach the task onto this resource, 113 * valid for user space restrack entries. 114 * @res: resource entry 115 * @task: the task to attach 116 */ 117 static void rdma_restrack_attach_task(struct rdma_restrack_entry *res, 118 struct task_struct *task) 119 { 120 if (WARN_ON_ONCE(!task)) 121 return; 122 123 if (res->task) 124 put_task_struct(res->task); 125 get_task_struct(task); 126 res->task = task; 127 res->user = true; 128 } 129 130 /** 131 * rdma_restrack_set_name() - set the task for this resource 132 * @res: resource entry 133 * @caller: kernel name, the current task will be used if the caller is NULL. 134 */ 135 void rdma_restrack_set_name(struct rdma_restrack_entry *res, const char *caller) 136 { 137 if (caller) { 138 res->kern_name = caller; 139 return; 140 } 141 142 rdma_restrack_attach_task(res, current); 143 } 144 EXPORT_SYMBOL(rdma_restrack_set_name); 145 146 /** 147 * rdma_restrack_parent_name() - set the restrack name properties based 148 * on parent restrack 149 * @dst: destination resource entry 150 * @parent: parent resource entry 151 */ 152 void rdma_restrack_parent_name(struct rdma_restrack_entry *dst, 153 const struct rdma_restrack_entry *parent) 154 { 155 if (rdma_is_kernel_res(parent)) 156 dst->kern_name = parent->kern_name; 157 else 158 rdma_restrack_attach_task(dst, parent->task); 159 } 160 EXPORT_SYMBOL(rdma_restrack_parent_name); 161 162 /** 163 * rdma_restrack_new() - Initializes new restrack entry to allow _put() interface 164 * to release memory in fully automatic way. 165 * @res: Entry to initialize 166 * @type: REstrack type 167 */ 168 void rdma_restrack_new(struct rdma_restrack_entry *res, 169 enum rdma_restrack_type type) 170 { 171 kref_init(&res->kref); 172 init_completion(&res->comp); 173 res->type = type; 174 } 175 EXPORT_SYMBOL(rdma_restrack_new); 176 177 /** 178 * rdma_restrack_add() - add object to the reource tracking database 179 * @res: resource entry 180 */ 181 void rdma_restrack_add(struct rdma_restrack_entry *res) 182 { 183 struct ib_device *dev = res_to_dev(res); 184 struct rdma_restrack_root *rt; 185 int ret = 0; 186 187 if (!dev) 188 return; 189 190 if (res->no_track) 191 goto out; 192 193 rt = &dev->res[res->type]; 194 195 if (res->type == RDMA_RESTRACK_QP) { 196 /* Special case to ensure that LQPN points to right QP */ 197 struct ib_qp *qp = container_of(res, struct ib_qp, res); 198 199 WARN_ONCE(qp->qp_num >> 24 || qp->port >> 8, 200 "QP number 0x%0X and port 0x%0X", qp->qp_num, 201 qp->port); 202 res->id = qp->qp_num; 203 if (qp->qp_type == IB_QPT_SMI || qp->qp_type == IB_QPT_GSI) 204 res->id |= qp->port << 24; 205 ret = xa_insert(&rt->xa, res->id, res, GFP_KERNEL); 206 if (ret) 207 res->id = 0; 208 209 if (qp->qp_type >= IB_QPT_DRIVER) 210 xa_set_mark(&rt->xa, res->id, RESTRACK_DD); 211 } else if (res->type == RDMA_RESTRACK_COUNTER) { 212 /* Special case to ensure that cntn points to right counter */ 213 struct rdma_counter *counter; 214 215 counter = container_of(res, struct rdma_counter, res); 216 ret = xa_insert(&rt->xa, counter->id, res, GFP_KERNEL); 217 res->id = ret ? 0 : counter->id; 218 } else { 219 ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b, 220 &rt->next_id, GFP_KERNEL); 221 ret = (ret < 0) ? ret : 0; 222 } 223 224 out: 225 if (!ret) 226 res->valid = true; 227 } 228 EXPORT_SYMBOL(rdma_restrack_add); 229 230 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res) 231 { 232 return kref_get_unless_zero(&res->kref); 233 } 234 EXPORT_SYMBOL(rdma_restrack_get); 235 236 /** 237 * rdma_restrack_get_byid() - translate from ID to restrack object 238 * @dev: IB device 239 * @type: resource track type 240 * @id: ID to take a look 241 * 242 * Return: Pointer to restrack entry or -ENOENT in case of error. 243 */ 244 struct rdma_restrack_entry * 245 rdma_restrack_get_byid(struct ib_device *dev, 246 enum rdma_restrack_type type, u32 id) 247 { 248 struct rdma_restrack_root *rt = &dev->res[type]; 249 struct rdma_restrack_entry *res; 250 251 xa_lock(&rt->xa); 252 res = xa_load(&rt->xa, id); 253 if (!res || !rdma_restrack_get(res)) 254 res = ERR_PTR(-ENOENT); 255 xa_unlock(&rt->xa); 256 257 return res; 258 } 259 EXPORT_SYMBOL(rdma_restrack_get_byid); 260 261 static void restrack_release(struct kref *kref) 262 { 263 struct rdma_restrack_entry *res; 264 265 res = container_of(kref, struct rdma_restrack_entry, kref); 266 if (res->task) { 267 put_task_struct(res->task); 268 res->task = NULL; 269 } 270 complete(&res->comp); 271 } 272 273 int rdma_restrack_put(struct rdma_restrack_entry *res) 274 { 275 return kref_put(&res->kref, restrack_release); 276 } 277 EXPORT_SYMBOL(rdma_restrack_put); 278 279 /** 280 * rdma_restrack_del() - delete object from the reource tracking database 281 * @res: resource entry 282 */ 283 void rdma_restrack_del(struct rdma_restrack_entry *res) 284 { 285 struct rdma_restrack_entry *old; 286 struct rdma_restrack_root *rt; 287 struct ib_device *dev; 288 289 if (!res->valid) { 290 if (res->task) { 291 put_task_struct(res->task); 292 res->task = NULL; 293 } 294 return; 295 } 296 297 if (res->no_track) 298 goto out; 299 300 dev = res_to_dev(res); 301 if (WARN_ON(!dev)) 302 return; 303 304 rt = &dev->res[res->type]; 305 306 old = xa_erase(&rt->xa, res->id); 307 WARN_ON(old != res); 308 309 out: 310 res->valid = false; 311 rdma_restrack_put(res); 312 wait_for_completion(&res->comp); 313 } 314 EXPORT_SYMBOL(rdma_restrack_del); 315