162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci(c) 2007 Network Appliance, Inc.  All Rights Reserved.
562306a36Sopenharmony_ci(c) 2009 NetApp.  All Rights Reserved.
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci******************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/tcp.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/sunrpc/xprt.h>
1362306a36Sopenharmony_ci#include <linux/export.h>
1462306a36Sopenharmony_ci#include <linux/sunrpc/bc_xprt.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
1762306a36Sopenharmony_ci#define RPCDBG_FACILITY	RPCDBG_TRANS
1862306a36Sopenharmony_ci#endif
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define BC_MAX_SLOTS	64U
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciunsigned int xprt_bc_max_slots(struct rpc_xprt *xprt)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	return BC_MAX_SLOTS;
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * Helper routines that track the number of preallocation elements
2962306a36Sopenharmony_ci * on the transport.
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_cistatic inline int xprt_need_to_requeue(struct rpc_xprt *xprt)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	return xprt->bc_alloc_count < xprt->bc_alloc_max;
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * Free the preallocated rpc_rqst structure and the memory
3862306a36Sopenharmony_ci * buffers hanging off of it.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_cistatic void xprt_free_allocation(struct rpc_rqst *req)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct xdr_buf *xbufp;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	dprintk("RPC:        free allocations for req= %p\n", req);
4562306a36Sopenharmony_ci	WARN_ON_ONCE(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
4662306a36Sopenharmony_ci	xbufp = &req->rq_rcv_buf;
4762306a36Sopenharmony_ci	free_page((unsigned long)xbufp->head[0].iov_base);
4862306a36Sopenharmony_ci	xbufp = &req->rq_snd_buf;
4962306a36Sopenharmony_ci	free_page((unsigned long)xbufp->head[0].iov_base);
5062306a36Sopenharmony_ci	kfree(req);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic void xprt_bc_reinit_xdr_buf(struct xdr_buf *buf)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	buf->head[0].iov_len = PAGE_SIZE;
5662306a36Sopenharmony_ci	buf->tail[0].iov_len = 0;
5762306a36Sopenharmony_ci	buf->pages = NULL;
5862306a36Sopenharmony_ci	buf->page_len = 0;
5962306a36Sopenharmony_ci	buf->flags = 0;
6062306a36Sopenharmony_ci	buf->len = 0;
6162306a36Sopenharmony_ci	buf->buflen = PAGE_SIZE;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic int xprt_alloc_xdr_buf(struct xdr_buf *buf, gfp_t gfp_flags)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct page *page;
6762306a36Sopenharmony_ci	/* Preallocate one XDR receive buffer */
6862306a36Sopenharmony_ci	page = alloc_page(gfp_flags);
6962306a36Sopenharmony_ci	if (page == NULL)
7062306a36Sopenharmony_ci		return -ENOMEM;
7162306a36Sopenharmony_ci	xdr_buf_init(buf, page_address(page), PAGE_SIZE);
7262306a36Sopenharmony_ci	return 0;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic struct rpc_rqst *xprt_alloc_bc_req(struct rpc_xprt *xprt)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	gfp_t gfp_flags = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
7862306a36Sopenharmony_ci	struct rpc_rqst *req;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* Pre-allocate one backchannel rpc_rqst */
8162306a36Sopenharmony_ci	req = kzalloc(sizeof(*req), gfp_flags);
8262306a36Sopenharmony_ci	if (req == NULL)
8362306a36Sopenharmony_ci		return NULL;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	req->rq_xprt = xprt;
8662306a36Sopenharmony_ci	INIT_LIST_HEAD(&req->rq_bc_list);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* Preallocate one XDR receive buffer */
8962306a36Sopenharmony_ci	if (xprt_alloc_xdr_buf(&req->rq_rcv_buf, gfp_flags) < 0) {
9062306a36Sopenharmony_ci		printk(KERN_ERR "Failed to create bc receive xbuf\n");
9162306a36Sopenharmony_ci		goto out_free;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci	req->rq_rcv_buf.len = PAGE_SIZE;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* Preallocate one XDR send buffer */
9662306a36Sopenharmony_ci	if (xprt_alloc_xdr_buf(&req->rq_snd_buf, gfp_flags) < 0) {
9762306a36Sopenharmony_ci		printk(KERN_ERR "Failed to create bc snd xbuf\n");
9862306a36Sopenharmony_ci		goto out_free;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci	return req;
10162306a36Sopenharmony_ciout_free:
10262306a36Sopenharmony_ci	xprt_free_allocation(req);
10362306a36Sopenharmony_ci	return NULL;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/*
10762306a36Sopenharmony_ci * Preallocate up to min_reqs structures and related buffers for use
10862306a36Sopenharmony_ci * by the backchannel.  This function can be called multiple times
10962306a36Sopenharmony_ci * when creating new sessions that use the same rpc_xprt.  The
11062306a36Sopenharmony_ci * preallocated buffers are added to the pool of resources used by
11162306a36Sopenharmony_ci * the rpc_xprt.  Any one of these resources may be used by an
11262306a36Sopenharmony_ci * incoming callback request.  It's up to the higher levels in the
11362306a36Sopenharmony_ci * stack to enforce that the maximum number of session slots is not
11462306a36Sopenharmony_ci * being exceeded.
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * Some callback arguments can be large.  For example, a pNFS server
11762306a36Sopenharmony_ci * using multiple deviceids.  The list can be unbound, but the client
11862306a36Sopenharmony_ci * has the ability to tell the server the maximum size of the callback
11962306a36Sopenharmony_ci * requests.  Each deviceID is 16 bytes, so allocate one page
12062306a36Sopenharmony_ci * for the arguments to have enough room to receive a number of these
12162306a36Sopenharmony_ci * deviceIDs.  The NFS client indicates to the pNFS server that its
12262306a36Sopenharmony_ci * callback requests can be up to 4096 bytes in size.
12362306a36Sopenharmony_ci */
12462306a36Sopenharmony_ciint xprt_setup_backchannel(struct rpc_xprt *xprt, unsigned int min_reqs)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	if (!xprt->ops->bc_setup)
12762306a36Sopenharmony_ci		return 0;
12862306a36Sopenharmony_ci	return xprt->ops->bc_setup(xprt, min_reqs);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_setup_backchannel);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ciint xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct rpc_rqst *req;
13562306a36Sopenharmony_ci	struct list_head tmp_list;
13662306a36Sopenharmony_ci	int i;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	dprintk("RPC:       setup backchannel transport\n");
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (min_reqs > BC_MAX_SLOTS)
14162306a36Sopenharmony_ci		min_reqs = BC_MAX_SLOTS;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/*
14462306a36Sopenharmony_ci	 * We use a temporary list to keep track of the preallocated
14562306a36Sopenharmony_ci	 * buffers.  Once we're done building the list we splice it
14662306a36Sopenharmony_ci	 * into the backchannel preallocation list off of the rpc_xprt
14762306a36Sopenharmony_ci	 * struct.  This helps minimize the amount of time the list
14862306a36Sopenharmony_ci	 * lock is held on the rpc_xprt struct.  It also makes cleanup
14962306a36Sopenharmony_ci	 * easier in case of memory allocation errors.
15062306a36Sopenharmony_ci	 */
15162306a36Sopenharmony_ci	INIT_LIST_HEAD(&tmp_list);
15262306a36Sopenharmony_ci	for (i = 0; i < min_reqs; i++) {
15362306a36Sopenharmony_ci		/* Pre-allocate one backchannel rpc_rqst */
15462306a36Sopenharmony_ci		req = xprt_alloc_bc_req(xprt);
15562306a36Sopenharmony_ci		if (req == NULL) {
15662306a36Sopenharmony_ci			printk(KERN_ERR "Failed to create bc rpc_rqst\n");
15762306a36Sopenharmony_ci			goto out_free;
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci		/* Add the allocated buffer to the tmp list */
16162306a36Sopenharmony_ci		dprintk("RPC:       adding req= %p\n", req);
16262306a36Sopenharmony_ci		list_add(&req->rq_bc_pa_list, &tmp_list);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/*
16662306a36Sopenharmony_ci	 * Add the temporary list to the backchannel preallocation list
16762306a36Sopenharmony_ci	 */
16862306a36Sopenharmony_ci	spin_lock(&xprt->bc_pa_lock);
16962306a36Sopenharmony_ci	list_splice(&tmp_list, &xprt->bc_pa_list);
17062306a36Sopenharmony_ci	xprt->bc_alloc_count += min_reqs;
17162306a36Sopenharmony_ci	xprt->bc_alloc_max += min_reqs;
17262306a36Sopenharmony_ci	atomic_add(min_reqs, &xprt->bc_slot_count);
17362306a36Sopenharmony_ci	spin_unlock(&xprt->bc_pa_lock);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	dprintk("RPC:       setup backchannel transport done\n");
17662306a36Sopenharmony_ci	return 0;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ciout_free:
17962306a36Sopenharmony_ci	/*
18062306a36Sopenharmony_ci	 * Memory allocation failed, free the temporary list
18162306a36Sopenharmony_ci	 */
18262306a36Sopenharmony_ci	while (!list_empty(&tmp_list)) {
18362306a36Sopenharmony_ci		req = list_first_entry(&tmp_list,
18462306a36Sopenharmony_ci				struct rpc_rqst,
18562306a36Sopenharmony_ci				rq_bc_pa_list);
18662306a36Sopenharmony_ci		list_del(&req->rq_bc_pa_list);
18762306a36Sopenharmony_ci		xprt_free_allocation(req);
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	dprintk("RPC:       setup backchannel transport failed\n");
19162306a36Sopenharmony_ci	return -ENOMEM;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/**
19562306a36Sopenharmony_ci * xprt_destroy_backchannel - Destroys the backchannel preallocated structures.
19662306a36Sopenharmony_ci * @xprt:	the transport holding the preallocated strucures
19762306a36Sopenharmony_ci * @max_reqs:	the maximum number of preallocated structures to destroy
19862306a36Sopenharmony_ci *
19962306a36Sopenharmony_ci * Since these structures may have been allocated by multiple calls
20062306a36Sopenharmony_ci * to xprt_setup_backchannel, we only destroy up to the maximum number
20162306a36Sopenharmony_ci * of reqs specified by the caller.
20262306a36Sopenharmony_ci */
20362306a36Sopenharmony_civoid xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	if (xprt->ops->bc_destroy)
20662306a36Sopenharmony_ci		xprt->ops->bc_destroy(xprt, max_reqs);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_destroy_backchannel);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_civoid xprt_destroy_bc(struct rpc_xprt *xprt, unsigned int max_reqs)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct rpc_rqst *req = NULL, *tmp = NULL;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	dprintk("RPC:        destroy backchannel transport\n");
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (max_reqs == 0)
21762306a36Sopenharmony_ci		goto out;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	spin_lock_bh(&xprt->bc_pa_lock);
22062306a36Sopenharmony_ci	xprt->bc_alloc_max -= min(max_reqs, xprt->bc_alloc_max);
22162306a36Sopenharmony_ci	list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) {
22262306a36Sopenharmony_ci		dprintk("RPC:        req=%p\n", req);
22362306a36Sopenharmony_ci		list_del(&req->rq_bc_pa_list);
22462306a36Sopenharmony_ci		xprt_free_allocation(req);
22562306a36Sopenharmony_ci		xprt->bc_alloc_count--;
22662306a36Sopenharmony_ci		atomic_dec(&xprt->bc_slot_count);
22762306a36Sopenharmony_ci		if (--max_reqs == 0)
22862306a36Sopenharmony_ci			break;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci	spin_unlock_bh(&xprt->bc_pa_lock);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ciout:
23362306a36Sopenharmony_ci	dprintk("RPC:        backchannel list empty= %s\n",
23462306a36Sopenharmony_ci		list_empty(&xprt->bc_pa_list) ? "true" : "false");
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic struct rpc_rqst *xprt_get_bc_request(struct rpc_xprt *xprt, __be32 xid,
23862306a36Sopenharmony_ci		struct rpc_rqst *new)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	struct rpc_rqst *req = NULL;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	dprintk("RPC:       allocate a backchannel request\n");
24362306a36Sopenharmony_ci	if (list_empty(&xprt->bc_pa_list)) {
24462306a36Sopenharmony_ci		if (!new)
24562306a36Sopenharmony_ci			goto not_found;
24662306a36Sopenharmony_ci		if (atomic_read(&xprt->bc_slot_count) >= BC_MAX_SLOTS)
24762306a36Sopenharmony_ci			goto not_found;
24862306a36Sopenharmony_ci		list_add_tail(&new->rq_bc_pa_list, &xprt->bc_pa_list);
24962306a36Sopenharmony_ci		xprt->bc_alloc_count++;
25062306a36Sopenharmony_ci		atomic_inc(&xprt->bc_slot_count);
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci	req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
25362306a36Sopenharmony_ci				rq_bc_pa_list);
25462306a36Sopenharmony_ci	req->rq_reply_bytes_recvd = 0;
25562306a36Sopenharmony_ci	memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
25662306a36Sopenharmony_ci			sizeof(req->rq_private_buf));
25762306a36Sopenharmony_ci	req->rq_xid = xid;
25862306a36Sopenharmony_ci	req->rq_connect_cookie = xprt->connect_cookie;
25962306a36Sopenharmony_ci	dprintk("RPC:       backchannel req=%p\n", req);
26062306a36Sopenharmony_cinot_found:
26162306a36Sopenharmony_ci	return req;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/*
26562306a36Sopenharmony_ci * Return the preallocated rpc_rqst structure and XDR buffers
26662306a36Sopenharmony_ci * associated with this rpc_task.
26762306a36Sopenharmony_ci */
26862306a36Sopenharmony_civoid xprt_free_bc_request(struct rpc_rqst *req)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	xprt->ops->bc_free_rqst(req);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_civoid xprt_free_bc_rqst(struct rpc_rqst *req)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	dprintk("RPC:       free backchannel req=%p\n", req);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	req->rq_connect_cookie = xprt->connect_cookie - 1;
28262306a36Sopenharmony_ci	smp_mb__before_atomic();
28362306a36Sopenharmony_ci	clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
28462306a36Sopenharmony_ci	smp_mb__after_atomic();
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/*
28762306a36Sopenharmony_ci	 * Return it to the list of preallocations so that it
28862306a36Sopenharmony_ci	 * may be reused by a new callback request.
28962306a36Sopenharmony_ci	 */
29062306a36Sopenharmony_ci	spin_lock_bh(&xprt->bc_pa_lock);
29162306a36Sopenharmony_ci	if (xprt_need_to_requeue(xprt)) {
29262306a36Sopenharmony_ci		xprt_bc_reinit_xdr_buf(&req->rq_snd_buf);
29362306a36Sopenharmony_ci		xprt_bc_reinit_xdr_buf(&req->rq_rcv_buf);
29462306a36Sopenharmony_ci		req->rq_rcv_buf.len = PAGE_SIZE;
29562306a36Sopenharmony_ci		list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list);
29662306a36Sopenharmony_ci		xprt->bc_alloc_count++;
29762306a36Sopenharmony_ci		atomic_inc(&xprt->bc_slot_count);
29862306a36Sopenharmony_ci		req = NULL;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci	spin_unlock_bh(&xprt->bc_pa_lock);
30162306a36Sopenharmony_ci	if (req != NULL) {
30262306a36Sopenharmony_ci		/*
30362306a36Sopenharmony_ci		 * The last remaining session was destroyed while this
30462306a36Sopenharmony_ci		 * entry was in use.  Free the entry and don't attempt
30562306a36Sopenharmony_ci		 * to add back to the list because there is no need to
30662306a36Sopenharmony_ci		 * have anymore preallocated entries.
30762306a36Sopenharmony_ci		 */
30862306a36Sopenharmony_ci		dprintk("RPC:       Last session removed req=%p\n", req);
30962306a36Sopenharmony_ci		xprt_free_allocation(req);
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci	xprt_put(xprt);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/*
31562306a36Sopenharmony_ci * One or more rpc_rqst structure have been preallocated during the
31662306a36Sopenharmony_ci * backchannel setup.  Buffer space for the send and private XDR buffers
31762306a36Sopenharmony_ci * has been preallocated as well.  Use xprt_alloc_bc_request to allocate
31862306a36Sopenharmony_ci * to this request.  Use xprt_free_bc_request to return it.
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci * We know that we're called in soft interrupt context, grab the spin_lock
32162306a36Sopenharmony_ci * since there is no need to grab the bottom half spin_lock.
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci * Return an available rpc_rqst, otherwise NULL if non are available.
32462306a36Sopenharmony_ci */
32562306a36Sopenharmony_cistruct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct rpc_rqst *req, *new = NULL;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	do {
33062306a36Sopenharmony_ci		spin_lock(&xprt->bc_pa_lock);
33162306a36Sopenharmony_ci		list_for_each_entry(req, &xprt->bc_pa_list, rq_bc_pa_list) {
33262306a36Sopenharmony_ci			if (req->rq_connect_cookie != xprt->connect_cookie)
33362306a36Sopenharmony_ci				continue;
33462306a36Sopenharmony_ci			if (req->rq_xid == xid)
33562306a36Sopenharmony_ci				goto found;
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci		req = xprt_get_bc_request(xprt, xid, new);
33862306a36Sopenharmony_cifound:
33962306a36Sopenharmony_ci		spin_unlock(&xprt->bc_pa_lock);
34062306a36Sopenharmony_ci		if (new) {
34162306a36Sopenharmony_ci			if (req != new)
34262306a36Sopenharmony_ci				xprt_free_allocation(new);
34362306a36Sopenharmony_ci			break;
34462306a36Sopenharmony_ci		} else if (req)
34562306a36Sopenharmony_ci			break;
34662306a36Sopenharmony_ci		new = xprt_alloc_bc_req(xprt);
34762306a36Sopenharmony_ci	} while (new);
34862306a36Sopenharmony_ci	return req;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/*
35262306a36Sopenharmony_ci * Add callback request to callback list.  The callback
35362306a36Sopenharmony_ci * service sleeps on the sv_cb_waitq waiting for new
35462306a36Sopenharmony_ci * requests.  Wake it up after adding enqueing the
35562306a36Sopenharmony_ci * request.
35662306a36Sopenharmony_ci */
35762306a36Sopenharmony_civoid xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
36062306a36Sopenharmony_ci	struct svc_serv *bc_serv = xprt->bc_serv;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	spin_lock(&xprt->bc_pa_lock);
36362306a36Sopenharmony_ci	list_del(&req->rq_bc_pa_list);
36462306a36Sopenharmony_ci	xprt->bc_alloc_count--;
36562306a36Sopenharmony_ci	spin_unlock(&xprt->bc_pa_lock);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	req->rq_private_buf.len = copied;
36862306a36Sopenharmony_ci	set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	dprintk("RPC:       add callback request to list\n");
37162306a36Sopenharmony_ci	xprt_get(xprt);
37262306a36Sopenharmony_ci	spin_lock(&bc_serv->sv_cb_lock);
37362306a36Sopenharmony_ci	list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
37462306a36Sopenharmony_ci	wake_up(&bc_serv->sv_cb_waitq);
37562306a36Sopenharmony_ci	spin_unlock(&bc_serv->sv_cb_lock);
37662306a36Sopenharmony_ci}
377