root/drivers/infiniband/core/restrack.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rdma_restrack_init
  2. type2str
  3. rdma_restrack_clean
  4. rdma_restrack_count
  5. set_kern_name
  6. res_to_dev
  7. rdma_restrack_set_task
  8. rdma_restrack_attach_task
  9. rdma_restrack_add
  10. rdma_restrack_kadd
  11. rdma_restrack_uadd
  12. rdma_restrack_get
  13. rdma_restrack_get_byid
  14. restrack_release
  15. rdma_restrack_put
  16. rdma_restrack_del
  17. rdma_is_visible_in_pid_ns

   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 static const char *type2str(enum rdma_restrack_type type)
  41 {
  42         static const char * const names[RDMA_RESTRACK_MAX] = {
  43                 [RDMA_RESTRACK_PD] = "PD",
  44                 [RDMA_RESTRACK_CQ] = "CQ",
  45                 [RDMA_RESTRACK_QP] = "QP",
  46                 [RDMA_RESTRACK_CM_ID] = "CM_ID",
  47                 [RDMA_RESTRACK_MR] = "MR",
  48                 [RDMA_RESTRACK_CTX] = "CTX",
  49                 [RDMA_RESTRACK_COUNTER] = "COUNTER",
  50         };
  51 
  52         return names[type];
  53 };
  54 
  55 /**
  56  * rdma_restrack_clean() - clean resource tracking
  57  * @dev:  IB device
  58  */
  59 void rdma_restrack_clean(struct ib_device *dev)
  60 {
  61         struct rdma_restrack_root *rt = dev->res;
  62         struct rdma_restrack_entry *e;
  63         char buf[TASK_COMM_LEN];
  64         bool found = false;
  65         const char *owner;
  66         int i;
  67 
  68         for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) {
  69                 struct xarray *xa = &dev->res[i].xa;
  70 
  71                 if (!xa_empty(xa)) {
  72                         unsigned long index;
  73 
  74                         if (!found) {
  75                                 pr_err("restrack: %s", CUT_HERE);
  76                                 dev_err(&dev->dev, "BUG: RESTRACK detected leak of resources\n");
  77                         }
  78                         xa_for_each(xa, index, e) {
  79                                 if (rdma_is_kernel_res(e)) {
  80                                         owner = e->kern_name;
  81                                 } else {
  82                                         /*
  83                                          * There is no need to call get_task_struct here,
  84                                          * because we can be here only if there are more
  85                                          * get_task_struct() call than put_task_struct().
  86                                          */
  87                                         get_task_comm(buf, e->task);
  88                                         owner = buf;
  89                                 }
  90 
  91                                 pr_err("restrack: %s %s object allocated by %s is not freed\n",
  92                                        rdma_is_kernel_res(e) ? "Kernel" :
  93                                                                "User",
  94                                        type2str(e->type), owner);
  95                         }
  96                         found = true;
  97                 }
  98                 xa_destroy(xa);
  99         }
 100         if (found)
 101                 pr_err("restrack: %s", CUT_HERE);
 102 
 103         kfree(rt);
 104 }
 105 
 106 /**
 107  * rdma_restrack_count() - the current usage of specific object
 108  * @dev:  IB device
 109  * @type: actual type of object to operate
 110  */
 111 int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type)
 112 {
 113         struct rdma_restrack_root *rt = &dev->res[type];
 114         struct rdma_restrack_entry *e;
 115         XA_STATE(xas, &rt->xa, 0);
 116         u32 cnt = 0;
 117 
 118         xa_lock(&rt->xa);
 119         xas_for_each(&xas, e, U32_MAX) {
 120                 if (!rdma_is_visible_in_pid_ns(e))
 121                         continue;
 122                 cnt++;
 123         }
 124         xa_unlock(&rt->xa);
 125         return cnt;
 126 }
 127 EXPORT_SYMBOL(rdma_restrack_count);
 128 
 129 static void set_kern_name(struct rdma_restrack_entry *res)
 130 {
 131         struct ib_pd *pd;
 132 
 133         switch (res->type) {
 134         case RDMA_RESTRACK_QP:
 135                 pd = container_of(res, struct ib_qp, res)->pd;
 136                 if (!pd) {
 137                         WARN_ONCE(true, "XRC QPs are not supported\n");
 138                         /* Survive, despite the programmer's error */
 139                         res->kern_name = " ";
 140                 }
 141                 break;
 142         case RDMA_RESTRACK_MR:
 143                 pd = container_of(res, struct ib_mr, res)->pd;
 144                 break;
 145         default:
 146                 /* Other types set kern_name directly */
 147                 pd = NULL;
 148                 break;
 149         }
 150 
 151         if (pd)
 152                 res->kern_name = pd->res.kern_name;
 153 }
 154 
 155 static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
 156 {
 157         switch (res->type) {
 158         case RDMA_RESTRACK_PD:
 159                 return container_of(res, struct ib_pd, res)->device;
 160         case RDMA_RESTRACK_CQ:
 161                 return container_of(res, struct ib_cq, res)->device;
 162         case RDMA_RESTRACK_QP:
 163                 return container_of(res, struct ib_qp, res)->device;
 164         case RDMA_RESTRACK_CM_ID:
 165                 return container_of(res, struct rdma_id_private,
 166                                     res)->id.device;
 167         case RDMA_RESTRACK_MR:
 168                 return container_of(res, struct ib_mr, res)->device;
 169         case RDMA_RESTRACK_CTX:
 170                 return container_of(res, struct ib_ucontext, res)->device;
 171         case RDMA_RESTRACK_COUNTER:
 172                 return container_of(res, struct rdma_counter, res)->device;
 173         default:
 174                 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
 175                 return NULL;
 176         }
 177 }
 178 
 179 void rdma_restrack_set_task(struct rdma_restrack_entry *res,
 180                             const char *caller)
 181 {
 182         if (caller) {
 183                 res->kern_name = caller;
 184                 return;
 185         }
 186 
 187         if (res->task)
 188                 put_task_struct(res->task);
 189         get_task_struct(current);
 190         res->task = current;
 191 }
 192 EXPORT_SYMBOL(rdma_restrack_set_task);
 193 
 194 /**
 195  * rdma_restrack_attach_task() - attach the task onto this resource
 196  * @res:  resource entry
 197  * @task: the task to attach, the current task will be used if it is NULL.
 198  */
 199 void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
 200                                struct task_struct *task)
 201 {
 202         if (res->task)
 203                 put_task_struct(res->task);
 204         get_task_struct(task);
 205         res->task = task;
 206 }
 207 
 208 static void rdma_restrack_add(struct rdma_restrack_entry *res)
 209 {
 210         struct ib_device *dev = res_to_dev(res);
 211         struct rdma_restrack_root *rt;
 212         int ret;
 213 
 214         if (!dev)
 215                 return;
 216 
 217         rt = &dev->res[res->type];
 218 
 219         kref_init(&res->kref);
 220         init_completion(&res->comp);
 221         if (res->type == RDMA_RESTRACK_QP) {
 222                 /* Special case to ensure that LQPN points to right QP */
 223                 struct ib_qp *qp = container_of(res, struct ib_qp, res);
 224 
 225                 ret = xa_insert(&rt->xa, qp->qp_num, res, GFP_KERNEL);
 226                 res->id = ret ? 0 : qp->qp_num;
 227         } else if (res->type == RDMA_RESTRACK_COUNTER) {
 228                 /* Special case to ensure that cntn points to right counter */
 229                 struct rdma_counter *counter;
 230 
 231                 counter = container_of(res, struct rdma_counter, res);
 232                 ret = xa_insert(&rt->xa, counter->id, res, GFP_KERNEL);
 233                 res->id = ret ? 0 : counter->id;
 234         } else {
 235                 ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
 236                                       &rt->next_id, GFP_KERNEL);
 237         }
 238 
 239         if (!ret)
 240                 res->valid = true;
 241 }
 242 
 243 /**
 244  * rdma_restrack_kadd() - add kernel object to the reource tracking database
 245  * @res:  resource entry
 246  */
 247 void rdma_restrack_kadd(struct rdma_restrack_entry *res)
 248 {
 249         res->task = NULL;
 250         set_kern_name(res);
 251         res->user = false;
 252         rdma_restrack_add(res);
 253 }
 254 EXPORT_SYMBOL(rdma_restrack_kadd);
 255 
 256 /**
 257  * rdma_restrack_uadd() - add user object to the reource tracking database
 258  * @res:  resource entry
 259  */
 260 void rdma_restrack_uadd(struct rdma_restrack_entry *res)
 261 {
 262         if ((res->type != RDMA_RESTRACK_CM_ID) &&
 263             (res->type != RDMA_RESTRACK_COUNTER))
 264                 res->task = NULL;
 265 
 266         if (!res->task)
 267                 rdma_restrack_set_task(res, NULL);
 268         res->kern_name = NULL;
 269 
 270         res->user = true;
 271         rdma_restrack_add(res);
 272 }
 273 EXPORT_SYMBOL(rdma_restrack_uadd);
 274 
 275 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
 276 {
 277         return kref_get_unless_zero(&res->kref);
 278 }
 279 EXPORT_SYMBOL(rdma_restrack_get);
 280 
 281 /**
 282  * rdma_restrack_get_byid() - translate from ID to restrack object
 283  * @dev: IB device
 284  * @type: resource track type
 285  * @id: ID to take a look
 286  *
 287  * Return: Pointer to restrack entry or -ENOENT in case of error.
 288  */
 289 struct rdma_restrack_entry *
 290 rdma_restrack_get_byid(struct ib_device *dev,
 291                        enum rdma_restrack_type type, u32 id)
 292 {
 293         struct rdma_restrack_root *rt = &dev->res[type];
 294         struct rdma_restrack_entry *res;
 295 
 296         xa_lock(&rt->xa);
 297         res = xa_load(&rt->xa, id);
 298         if (!res || !rdma_restrack_get(res))
 299                 res = ERR_PTR(-ENOENT);
 300         xa_unlock(&rt->xa);
 301 
 302         return res;
 303 }
 304 EXPORT_SYMBOL(rdma_restrack_get_byid);
 305 
 306 static void restrack_release(struct kref *kref)
 307 {
 308         struct rdma_restrack_entry *res;
 309 
 310         res = container_of(kref, struct rdma_restrack_entry, kref);
 311         complete(&res->comp);
 312 }
 313 
 314 int rdma_restrack_put(struct rdma_restrack_entry *res)
 315 {
 316         return kref_put(&res->kref, restrack_release);
 317 }
 318 EXPORT_SYMBOL(rdma_restrack_put);
 319 
 320 void rdma_restrack_del(struct rdma_restrack_entry *res)
 321 {
 322         struct rdma_restrack_entry *old;
 323         struct rdma_restrack_root *rt;
 324         struct ib_device *dev;
 325 
 326         if (!res->valid)
 327                 goto out;
 328 
 329         dev = res_to_dev(res);
 330         if (WARN_ON(!dev))
 331                 return;
 332 
 333         rt = &dev->res[res->type];
 334 
 335         old = xa_erase(&rt->xa, res->id);
 336         WARN_ON(old != res);
 337         res->valid = false;
 338 
 339         rdma_restrack_put(res);
 340         wait_for_completion(&res->comp);
 341 
 342 out:
 343         if (res->task) {
 344                 put_task_struct(res->task);
 345                 res->task = NULL;
 346         }
 347 }
 348 EXPORT_SYMBOL(rdma_restrack_del);
 349 
 350 bool rdma_is_visible_in_pid_ns(struct rdma_restrack_entry *res)
 351 {
 352         /*
 353          * 1. Kern resources should be visible in init
 354          *    namespace only
 355          * 2. Present only resources visible in the current
 356          *     namespace
 357          */
 358         if (rdma_is_kernel_res(res))
 359                 return task_active_pid_ns(current) == &init_pid_ns;
 360 
 361         /* PID 0 means that resource is not found in current namespace */
 362         return task_pid_vnr(res->task);
 363 }

/* [<][>][^][v][top][bottom][index][help] */