FILE
restrack.c
File preview with syntax highlighting.
linux-6.19.14/drivers/infiniband/core/restrack.c
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 */ 23int 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 */ 44void 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 */ 64int 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} 81EXPORT_SYMBOL(rdma_restrack_count); 82 83static 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 */ 117static 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 */ 135void 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} 144EXPORT_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 */ 152void 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} 160EXPORT_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 */ 168void 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} 175EXPORT_SYMBOL(rdma_restrack_new); 176 177/** 178 * rdma_restrack_add() - add object to the resource tracking database 179 * @res: resource entry 180 */ 181void 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 224out: 225 if (!ret) 226 res->valid = true; 227} 228EXPORT_SYMBOL(rdma_restrack_add); 229 230int __must_check rdma_restrack_get(struct rdma_restrack_entry *res) 231{ 232 return kref_get_unless_zero(&res->kref); 233} 234EXPORT_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 */ 244struct rdma_restrack_entry * 245rdma_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} 259EXPORT_SYMBOL(rdma_restrack_get_byid); 260 261static 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 273int rdma_restrack_put(struct rdma_restrack_entry *res) 274{ 275 return kref_put(&res->kref, restrack_release); 276} 277EXPORT_SYMBOL(rdma_restrack_put); 278 279/** 280 * rdma_restrack_del() - delete object from the resource tracking database 281 * @res: resource entry 282 */ 283void 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 309out: 310 res->valid = false; 311 rdma_restrack_put(res); 312 wait_for_completion(&res->comp); 313} 314EXPORT_SYMBOL(rdma_restrack_del);
~/
Read-only file preview.