Commit 13ef5539 authored by Leon Romanovsky's avatar Leon Romanovsky Committed by Jason Gunthorpe
Browse files

RDMA/restrack: Count references to the verbs objects

Refactor the restrack code to make sure the kref inside the restrack entry
properly kref's the object in which it is embedded. This slight change is
needed for future conversions of MR and QP which are refcounted before the
release and kfree.

The ideal flow from ib_core perspective as follows:
* Allocate ib_* structure with rdma_zalloc_*.
* Set everything that is known to ib_core to that newly created object.
* Initialize kref with restrack help
* Call to driver specific allocation functions.
* Insert into restrack DB
....
* Return and release restrack with restrack_put.

Largely this means a rdma_restrack_new() should be called near allocating
the containing structure.

Link: https://lore.kernel.org/r/20200922091106.2152715-4-leon@kernel.org


Signed-off-by: default avatarLeon Romanovsky <leonro@mellanox.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent d7ecab1e
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -833,8 +833,6 @@ struct rdma_cm_id *__rdma_create_id(struct net *net,
	if (!id_priv)
		return ERR_PTR(-ENOMEM);

	rdma_restrack_set_task(&id_priv->res, caller);
	id_priv->res.type = RDMA_RESTRACK_CM_ID;
	id_priv->state = RDMA_CM_IDLE;
	id_priv->id.context = context;
	id_priv->id.event_handler = event_handler;
@@ -854,6 +852,9 @@ struct rdma_cm_id *__rdma_create_id(struct net *net,
	id_priv->id.route.addr.dev_addr.net = get_net(net);
	id_priv->seq_num &= 0x00ffffff;

	rdma_restrack_new(&id_priv->res, RDMA_RESTRACK_CM_ID);
	rdma_restrack_set_task(&id_priv->res, caller);

	return &id_priv->id;
}
EXPORT_SYMBOL(__rdma_create_id);
+2 −1
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#include <rdma/ib_mad.h>
#include <rdma/restrack.h>
#include "mad_priv.h"
#include "restrack.h"

/* Total number of ports combined across all struct ib_devices's */
#define RDMA_MAX_PORTS 8192
@@ -352,6 +353,7 @@ static inline struct ib_qp *_ib_create_qp(struct ib_device *dev,
	INIT_LIST_HEAD(&qp->rdma_mrs);
	INIT_LIST_HEAD(&qp->sig_mrs);

	rdma_restrack_new(&qp->res, RDMA_RESTRACK_QP);
	/*
	 * We don't track XRC QPs for now, because they don't have PD
	 * and more importantly they are created internaly by driver,
@@ -359,7 +361,6 @@ static inline struct ib_qp *_ib_create_qp(struct ib_device *dev,
	 */
	is_xrc = qp_type == IB_QPT_XRC_INI || qp_type == IB_QPT_XRC_TGT;
	if ((qp_type < IB_QPT_MAX && !is_xrc) || qp_type == IB_QPT_DRIVER) {
		qp->res.type = RDMA_RESTRACK_QP;
		if (uobj)
			rdma_restrack_uadd(&qp->res);
		else
+4 −2
Original line number Diff line number Diff line
@@ -80,7 +80,8 @@ static struct rdma_counter *rdma_counter_alloc(struct ib_device *dev, u8 port,

	counter->device    = dev;
	counter->port      = port;
	counter->res.type  = RDMA_RESTRACK_COUNTER;

	rdma_restrack_new(&counter->res, RDMA_RESTRACK_COUNTER);
	counter->stats = dev->ops.counter_alloc_stats(counter);
	if (!counter->stats)
		goto err_stats;
@@ -107,6 +108,7 @@ static struct rdma_counter *rdma_counter_alloc(struct ib_device *dev, u8 port,
	mutex_unlock(&port_counter->lock);
	kfree(counter->stats);
err_stats:
	rdma_restrack_put(&counter->res);
	kfree(counter);
	return NULL;
}
+3 −4
Original line number Diff line number Diff line
@@ -235,15 +235,13 @@ struct ib_cq *__ib_alloc_cq(struct ib_device *dev, void *private, int nr_cqe,
	if (!cq->wc)
		goto out_free_cq;

	cq->res.type = RDMA_RESTRACK_CQ;
	rdma_restrack_new(&cq->res, RDMA_RESTRACK_CQ);
	rdma_restrack_set_task(&cq->res, caller);

	ret = dev->ops.create_cq(cq, &cq_attr, NULL);
	if (ret)
		goto out_free_wc;

	rdma_restrack_kadd(&cq->res);

	rdma_dim_init(cq);

	switch (cq->poll_ctx) {
@@ -269,14 +267,15 @@ struct ib_cq *__ib_alloc_cq(struct ib_device *dev, void *private, int nr_cqe,
		goto out_destroy_cq;
	}

	rdma_restrack_kadd(&cq->res);
	trace_cq_alloc(cq, nr_cqe, comp_vector, poll_ctx);
	return cq;

out_destroy_cq:
	rdma_dim_destroy(cq);
	rdma_restrack_del(&cq->res);
	cq->device->ops.destroy_cq(cq, NULL);
out_free_wc:
	rdma_restrack_put(&cq->res);
	kfree(cq->wc);
out_free_cq:
	kfree(cq);
+32 −10
Original line number Diff line number Diff line
@@ -202,6 +202,21 @@ void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
	res->task = task;
}

/**
 * rdma_restrack_new() - Initializes new restrack entry to allow _put() interface
 * to release memory in fully automatic way.
 * @res - Entry to initialize
 * @type - REstrack type
 */
void rdma_restrack_new(struct rdma_restrack_entry *res,
		       enum rdma_restrack_type type)
{
	kref_init(&res->kref);
	init_completion(&res->comp);
	res->type = type;
}
EXPORT_SYMBOL(rdma_restrack_new);

static void rdma_restrack_add(struct rdma_restrack_entry *res)
{
	struct ib_device *dev = res_to_dev(res);
@@ -213,8 +228,6 @@ static void rdma_restrack_add(struct rdma_restrack_entry *res)

	rt = &dev->res[res->type];

	kref_init(&res->kref);
	init_completion(&res->comp);
	if (res->type == RDMA_RESTRACK_QP) {
		/* Special case to ensure that LQPN points to right QP */
		struct ib_qp *qp = container_of(res, struct ib_qp, res);
@@ -305,6 +318,10 @@ static void restrack_release(struct kref *kref)
	struct rdma_restrack_entry *res;

	res = container_of(kref, struct rdma_restrack_entry, kref);
	if (res->task) {
		put_task_struct(res->task);
		res->task = NULL;
	}
	complete(&res->comp);
}

@@ -314,14 +331,23 @@ int rdma_restrack_put(struct rdma_restrack_entry *res)
}
EXPORT_SYMBOL(rdma_restrack_put);

/**
 * rdma_restrack_del() - delete object from the reource tracking database
 * @res:  resource entry
 */
void rdma_restrack_del(struct rdma_restrack_entry *res)
{
	struct rdma_restrack_entry *old;
	struct rdma_restrack_root *rt;
	struct ib_device *dev;

	if (!res->valid)
		goto out;
	if (!res->valid) {
		if (res->task) {
			put_task_struct(res->task);
			res->task = NULL;
		}
		return;
	}

	dev = res_to_dev(res);
	if (WARN_ON(!dev))
@@ -330,16 +356,12 @@ void rdma_restrack_del(struct rdma_restrack_entry *res)
	rt = &dev->res[res->type];

	old = xa_erase(&rt->xa, res->id);
	if (res->type == RDMA_RESTRACK_MR || res->type == RDMA_RESTRACK_QP)
		return;
	WARN_ON(old != res);
	res->valid = false;

	rdma_restrack_put(res);
	wait_for_completion(&res->comp);

out:
	if (res->task) {
		put_task_struct(res->task);
		res->task = NULL;
	}
}
EXPORT_SYMBOL(rdma_restrack_del);
Loading