linux/drivers/infiniband/core/restrack.c
<<
>>
Prefs
   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
  40static 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 */
  59void 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 */
 111int 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}
 127EXPORT_SYMBOL(rdma_restrack_count);
 128
 129static 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
 155static 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
 179void 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}
 192EXPORT_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 */
 199void 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
 208static 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 */
 247void 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}
 254EXPORT_SYMBOL(rdma_restrack_kadd);
 255
 256/**
 257 * rdma_restrack_uadd() - add user object to the reource tracking database
 258 * @res:  resource entry
 259 */
 260void 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}
 273EXPORT_SYMBOL(rdma_restrack_uadd);
 274
 275int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
 276{
 277        return kref_get_unless_zero(&res->kref);
 278}
 279EXPORT_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 */
 289struct rdma_restrack_entry *
 290rdma_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}
 304EXPORT_SYMBOL(rdma_restrack_get_byid);
 305
 306static 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
 314int rdma_restrack_put(struct rdma_restrack_entry *res)
 315{
 316        return kref_put(&res->kref, restrack_release);
 317}
 318EXPORT_SYMBOL(rdma_restrack_put);
 319
 320void 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
 342out:
 343        if (res->task) {
 344                put_task_struct(res->task);
 345                res->task = NULL;
 346        }
 347}
 348EXPORT_SYMBOL(rdma_restrack_del);
 349
 350bool 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}
 364