cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

restrack.c (8568B)


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