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