net/sunrpc/xprtrdma/svc_rdma_rw.c

Source file repositories/reference/linux-study-clean/net/sunrpc/xprtrdma/svc_rdma_rw.c

File Facts

System
Linux kernel
Corpus path
net/sunrpc/xprtrdma/svc_rdma_rw.c
Extension
.c
Size
33456 bytes
Lines
1177
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct svc_rdma_rw_ctxt {
	struct llist_node	rw_node;
	struct list_head	rw_list;
	struct rdma_rw_ctx	rw_ctx;
	unsigned int		rw_nents;
	unsigned int		rw_first_bvec_nents;
	struct bio_vec		*rw_bvec;
	struct bio_vec		rw_first_bvec[];
};

static void svc_rdma_put_rw_ctxt(struct svcxprt_rdma *rdma,
				 struct svc_rdma_rw_ctxt *ctxt);

static inline struct svc_rdma_rw_ctxt *
svc_rdma_next_ctxt(struct list_head *list)
{
	return list_first_entry_or_null(list, struct svc_rdma_rw_ctxt,
					rw_list);
}

static struct svc_rdma_rw_ctxt *
svc_rdma_get_rw_ctxt(struct svcxprt_rdma *rdma, unsigned int nr_bvec)
{
	struct ib_device *dev = rdma->sc_cm_id->device;
	unsigned int first_bvec_nents = dev->attrs.max_send_sge;
	struct svc_rdma_rw_ctxt *ctxt;
	struct llist_node *node;

	spin_lock(&rdma->sc_rw_ctxt_lock);
	node = llist_del_first(&rdma->sc_rw_ctxts);
	spin_unlock(&rdma->sc_rw_ctxt_lock);
	if (node) {
		ctxt = llist_entry(node, struct svc_rdma_rw_ctxt, rw_node);
	} else {
		ctxt = kmalloc_node(struct_size(ctxt, rw_first_bvec,
						first_bvec_nents),
				    GFP_KERNEL, ibdev_to_node(dev));
		if (!ctxt)
			goto out_noctx;

		INIT_LIST_HEAD(&ctxt->rw_list);
		ctxt->rw_first_bvec_nents = first_bvec_nents;
	}

	if (nr_bvec <= ctxt->rw_first_bvec_nents) {
		ctxt->rw_bvec = ctxt->rw_first_bvec;
	} else {
		ctxt->rw_bvec = kmalloc_array_node(nr_bvec,
						   sizeof(*ctxt->rw_bvec),
						   GFP_KERNEL,
						   ibdev_to_node(dev));
		if (!ctxt->rw_bvec)
			goto out_free;
	}
	return ctxt;

out_free:
	/* Return cached contexts to cache; free freshly allocated ones */
	if (node)
		svc_rdma_put_rw_ctxt(rdma, ctxt);
	else
		kfree(ctxt);
out_noctx:
	trace_svcrdma_rwctx_empty(rdma, nr_bvec);
	return NULL;
}

static void __svc_rdma_put_rw_ctxt(struct svc_rdma_rw_ctxt *ctxt,
				   struct llist_head *list)
{
	if (ctxt->rw_bvec != ctxt->rw_first_bvec)
		kfree(ctxt->rw_bvec);
	llist_add(&ctxt->rw_node, list);
}

static void svc_rdma_put_rw_ctxt(struct svcxprt_rdma *rdma,
				 struct svc_rdma_rw_ctxt *ctxt)
{
	__svc_rdma_put_rw_ctxt(ctxt, &rdma->sc_rw_ctxts);
}

/**
 * svc_rdma_destroy_rw_ctxts - Free accumulated R/W contexts
 * @rdma: transport about to be destroyed
 *
 */
void svc_rdma_destroy_rw_ctxts(struct svcxprt_rdma *rdma)
{
	struct svc_rdma_rw_ctxt *ctxt;
	struct llist_node *node;

Annotation

Implementation Notes