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); 313