313 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB2/*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 tracking19 * @dev: IB device20 *21 * Return: 0 on success22 */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 tracking42 * @dev: IB device43 */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 object60 * @dev: IB device61 * @type: actual type of object to operate62 * @show_details: count driver specific objects63 */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 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 entry113 * @task: the task to attach114 */115static 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 resource130 * @res: resource entry131 * @caller: kernel name, the current task will be used if the caller is NULL.132 */133void 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}142EXPORT_SYMBOL(rdma_restrack_set_name);143 144/**145 * rdma_restrack_parent_name() - set the restrack name properties based146 * on parent restrack147 * @dst: destination resource entry148 * @parent: parent resource entry149 */150void 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 else156 rdma_restrack_attach_task(dst, parent->task);157}158EXPORT_SYMBOL(rdma_restrack_parent_name);159 160/**161 * rdma_restrack_new() - Initializes new restrack entry to allow _put() interface162 * to release memory in fully automatic way.163 * @res: Entry to initialize164 * @type: REstrack type165 */166void 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}173EXPORT_SYMBOL(rdma_restrack_new);174 175/**176 * rdma_restrack_add() - add object to the reource tracking database177 * @res: resource entry178 */179void 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 222out:223 if (!ret)224 res->valid = true;225}226EXPORT_SYMBOL(rdma_restrack_add);227 228int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)229{230 return kref_get_unless_zero(&res->kref);231}232EXPORT_SYMBOL(rdma_restrack_get);233 234/**235 * rdma_restrack_get_byid() - translate from ID to restrack object236 * @dev: IB device237 * @type: resource track type238 * @id: ID to take a look239 *240 * Return: Pointer to restrack entry or -ENOENT in case of error.241 */242struct rdma_restrack_entry *243rdma_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}257EXPORT_SYMBOL(rdma_restrack_get_byid);258 259static 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 271int rdma_restrack_put(struct rdma_restrack_entry *res)272{273 return kref_put(&res->kref, restrack_release);274}275EXPORT_SYMBOL(rdma_restrack_put);276 277/**278 * rdma_restrack_del() - delete object from the reource tracking database279 * @res: resource entry280 */281void 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 307out:308 res->valid = false;309 rdma_restrack_put(res);310 wait_for_completion(&res->comp);311}312EXPORT_SYMBOL(rdma_restrack_del);313