brintos

brintos / linux-shallow public Read only

0
0
Text · 7.3 KiB · 3313410 Raw
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