18c2ecf20Sopenharmony_ci/******************************************************************************
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci(c) 2007 Network Appliance, Inc.  All Rights Reserved.
48c2ecf20Sopenharmony_ci(c) 2009 NetApp.  All Rights Reserved.
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ciNetApp provides this source code under the GPL v2 License.
78c2ecf20Sopenharmony_ciThe GPL v2 license is available at
88c2ecf20Sopenharmony_cihttps://opensource.org/licenses/gpl-license.php.
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ciTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
118c2ecf20Sopenharmony_ci"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
128c2ecf20Sopenharmony_ciLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
138c2ecf20Sopenharmony_ciA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
148c2ecf20Sopenharmony_ciCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
158c2ecf20Sopenharmony_ciEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
168c2ecf20Sopenharmony_ciPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
178c2ecf20Sopenharmony_ciPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
188c2ecf20Sopenharmony_ciLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
198c2ecf20Sopenharmony_ciNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
208c2ecf20Sopenharmony_ciSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci******************************************************************************/
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <linux/tcp.h>
258c2ecf20Sopenharmony_ci#include <linux/slab.h>
268c2ecf20Sopenharmony_ci#include <linux/sunrpc/xprt.h>
278c2ecf20Sopenharmony_ci#include <linux/export.h>
288c2ecf20Sopenharmony_ci#include <linux/sunrpc/bc_xprt.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
318c2ecf20Sopenharmony_ci#define RPCDBG_FACILITY	RPCDBG_TRANS
328c2ecf20Sopenharmony_ci#endif
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define BC_MAX_SLOTS	64U
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciunsigned int xprt_bc_max_slots(struct rpc_xprt *xprt)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	return BC_MAX_SLOTS;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/*
428c2ecf20Sopenharmony_ci * Helper routines that track the number of preallocation elements
438c2ecf20Sopenharmony_ci * on the transport.
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_cistatic inline int xprt_need_to_requeue(struct rpc_xprt *xprt)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	return xprt->bc_alloc_count < xprt->bc_alloc_max;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * Free the preallocated rpc_rqst structure and the memory
528c2ecf20Sopenharmony_ci * buffers hanging off of it.
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_cistatic void xprt_free_allocation(struct rpc_rqst *req)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct xdr_buf *xbufp;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	dprintk("RPC:        free allocations for req= %p\n", req);
598c2ecf20Sopenharmony_ci	WARN_ON_ONCE(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
608c2ecf20Sopenharmony_ci	xbufp = &req->rq_rcv_buf;
618c2ecf20Sopenharmony_ci	free_page((unsigned long)xbufp->head[0].iov_base);
628c2ecf20Sopenharmony_ci	xbufp = &req->rq_snd_buf;
638c2ecf20Sopenharmony_ci	free_page((unsigned long)xbufp->head[0].iov_base);
648c2ecf20Sopenharmony_ci	kfree(req);
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic void xprt_bc_reinit_xdr_buf(struct xdr_buf *buf)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	buf->head[0].iov_len = PAGE_SIZE;
708c2ecf20Sopenharmony_ci	buf->tail[0].iov_len = 0;
718c2ecf20Sopenharmony_ci	buf->pages = NULL;
728c2ecf20Sopenharmony_ci	buf->page_len = 0;
738c2ecf20Sopenharmony_ci	buf->flags = 0;
748c2ecf20Sopenharmony_ci	buf->len = 0;
758c2ecf20Sopenharmony_ci	buf->buflen = PAGE_SIZE;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic int xprt_alloc_xdr_buf(struct xdr_buf *buf, gfp_t gfp_flags)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct page *page;
818c2ecf20Sopenharmony_ci	/* Preallocate one XDR receive buffer */
828c2ecf20Sopenharmony_ci	page = alloc_page(gfp_flags);
838c2ecf20Sopenharmony_ci	if (page == NULL)
848c2ecf20Sopenharmony_ci		return -ENOMEM;
858c2ecf20Sopenharmony_ci	xdr_buf_init(buf, page_address(page), PAGE_SIZE);
868c2ecf20Sopenharmony_ci	return 0;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic
908c2ecf20Sopenharmony_cistruct rpc_rqst *xprt_alloc_bc_req(struct rpc_xprt *xprt, gfp_t gfp_flags)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct rpc_rqst *req;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* Pre-allocate one backchannel rpc_rqst */
958c2ecf20Sopenharmony_ci	req = kzalloc(sizeof(*req), gfp_flags);
968c2ecf20Sopenharmony_ci	if (req == NULL)
978c2ecf20Sopenharmony_ci		return NULL;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	req->rq_xprt = xprt;
1008c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&req->rq_bc_list);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/* Preallocate one XDR receive buffer */
1038c2ecf20Sopenharmony_ci	if (xprt_alloc_xdr_buf(&req->rq_rcv_buf, gfp_flags) < 0) {
1048c2ecf20Sopenharmony_ci		printk(KERN_ERR "Failed to create bc receive xbuf\n");
1058c2ecf20Sopenharmony_ci		goto out_free;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci	req->rq_rcv_buf.len = PAGE_SIZE;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* Preallocate one XDR send buffer */
1108c2ecf20Sopenharmony_ci	if (xprt_alloc_xdr_buf(&req->rq_snd_buf, gfp_flags) < 0) {
1118c2ecf20Sopenharmony_ci		printk(KERN_ERR "Failed to create bc snd xbuf\n");
1128c2ecf20Sopenharmony_ci		goto out_free;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	return req;
1158c2ecf20Sopenharmony_ciout_free:
1168c2ecf20Sopenharmony_ci	xprt_free_allocation(req);
1178c2ecf20Sopenharmony_ci	return NULL;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/*
1218c2ecf20Sopenharmony_ci * Preallocate up to min_reqs structures and related buffers for use
1228c2ecf20Sopenharmony_ci * by the backchannel.  This function can be called multiple times
1238c2ecf20Sopenharmony_ci * when creating new sessions that use the same rpc_xprt.  The
1248c2ecf20Sopenharmony_ci * preallocated buffers are added to the pool of resources used by
1258c2ecf20Sopenharmony_ci * the rpc_xprt.  Any one of these resources may be used by an
1268c2ecf20Sopenharmony_ci * incoming callback request.  It's up to the higher levels in the
1278c2ecf20Sopenharmony_ci * stack to enforce that the maximum number of session slots is not
1288c2ecf20Sopenharmony_ci * being exceeded.
1298c2ecf20Sopenharmony_ci *
1308c2ecf20Sopenharmony_ci * Some callback arguments can be large.  For example, a pNFS server
1318c2ecf20Sopenharmony_ci * using multiple deviceids.  The list can be unbound, but the client
1328c2ecf20Sopenharmony_ci * has the ability to tell the server the maximum size of the callback
1338c2ecf20Sopenharmony_ci * requests.  Each deviceID is 16 bytes, so allocate one page
1348c2ecf20Sopenharmony_ci * for the arguments to have enough room to receive a number of these
1358c2ecf20Sopenharmony_ci * deviceIDs.  The NFS client indicates to the pNFS server that its
1368c2ecf20Sopenharmony_ci * callback requests can be up to 4096 bytes in size.
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_ciint xprt_setup_backchannel(struct rpc_xprt *xprt, unsigned int min_reqs)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	if (!xprt->ops->bc_setup)
1418c2ecf20Sopenharmony_ci		return 0;
1428c2ecf20Sopenharmony_ci	return xprt->ops->bc_setup(xprt, min_reqs);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_setup_backchannel);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ciint xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	struct rpc_rqst *req;
1498c2ecf20Sopenharmony_ci	struct list_head tmp_list;
1508c2ecf20Sopenharmony_ci	int i;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	dprintk("RPC:       setup backchannel transport\n");
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (min_reqs > BC_MAX_SLOTS)
1558c2ecf20Sopenharmony_ci		min_reqs = BC_MAX_SLOTS;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/*
1588c2ecf20Sopenharmony_ci	 * We use a temporary list to keep track of the preallocated
1598c2ecf20Sopenharmony_ci	 * buffers.  Once we're done building the list we splice it
1608c2ecf20Sopenharmony_ci	 * into the backchannel preallocation list off of the rpc_xprt
1618c2ecf20Sopenharmony_ci	 * struct.  This helps minimize the amount of time the list
1628c2ecf20Sopenharmony_ci	 * lock is held on the rpc_xprt struct.  It also makes cleanup
1638c2ecf20Sopenharmony_ci	 * easier in case of memory allocation errors.
1648c2ecf20Sopenharmony_ci	 */
1658c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&tmp_list);
1668c2ecf20Sopenharmony_ci	for (i = 0; i < min_reqs; i++) {
1678c2ecf20Sopenharmony_ci		/* Pre-allocate one backchannel rpc_rqst */
1688c2ecf20Sopenharmony_ci		req = xprt_alloc_bc_req(xprt, GFP_KERNEL);
1698c2ecf20Sopenharmony_ci		if (req == NULL) {
1708c2ecf20Sopenharmony_ci			printk(KERN_ERR "Failed to create bc rpc_rqst\n");
1718c2ecf20Sopenharmony_ci			goto out_free;
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		/* Add the allocated buffer to the tmp list */
1758c2ecf20Sopenharmony_ci		dprintk("RPC:       adding req= %p\n", req);
1768c2ecf20Sopenharmony_ci		list_add(&req->rq_bc_pa_list, &tmp_list);
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/*
1808c2ecf20Sopenharmony_ci	 * Add the temporary list to the backchannel preallocation list
1818c2ecf20Sopenharmony_ci	 */
1828c2ecf20Sopenharmony_ci	spin_lock(&xprt->bc_pa_lock);
1838c2ecf20Sopenharmony_ci	list_splice(&tmp_list, &xprt->bc_pa_list);
1848c2ecf20Sopenharmony_ci	xprt->bc_alloc_count += min_reqs;
1858c2ecf20Sopenharmony_ci	xprt->bc_alloc_max += min_reqs;
1868c2ecf20Sopenharmony_ci	atomic_add(min_reqs, &xprt->bc_slot_count);
1878c2ecf20Sopenharmony_ci	spin_unlock(&xprt->bc_pa_lock);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	dprintk("RPC:       setup backchannel transport done\n");
1908c2ecf20Sopenharmony_ci	return 0;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ciout_free:
1938c2ecf20Sopenharmony_ci	/*
1948c2ecf20Sopenharmony_ci	 * Memory allocation failed, free the temporary list
1958c2ecf20Sopenharmony_ci	 */
1968c2ecf20Sopenharmony_ci	while (!list_empty(&tmp_list)) {
1978c2ecf20Sopenharmony_ci		req = list_first_entry(&tmp_list,
1988c2ecf20Sopenharmony_ci				struct rpc_rqst,
1998c2ecf20Sopenharmony_ci				rq_bc_pa_list);
2008c2ecf20Sopenharmony_ci		list_del(&req->rq_bc_pa_list);
2018c2ecf20Sopenharmony_ci		xprt_free_allocation(req);
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	dprintk("RPC:       setup backchannel transport failed\n");
2058c2ecf20Sopenharmony_ci	return -ENOMEM;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci/**
2098c2ecf20Sopenharmony_ci * xprt_destroy_backchannel - Destroys the backchannel preallocated structures.
2108c2ecf20Sopenharmony_ci * @xprt:	the transport holding the preallocated strucures
2118c2ecf20Sopenharmony_ci * @max_reqs:	the maximum number of preallocated structures to destroy
2128c2ecf20Sopenharmony_ci *
2138c2ecf20Sopenharmony_ci * Since these structures may have been allocated by multiple calls
2148c2ecf20Sopenharmony_ci * to xprt_setup_backchannel, we only destroy up to the maximum number
2158c2ecf20Sopenharmony_ci * of reqs specified by the caller.
2168c2ecf20Sopenharmony_ci */
2178c2ecf20Sopenharmony_civoid xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	if (xprt->ops->bc_destroy)
2208c2ecf20Sopenharmony_ci		xprt->ops->bc_destroy(xprt, max_reqs);
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xprt_destroy_backchannel);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_civoid xprt_destroy_bc(struct rpc_xprt *xprt, unsigned int max_reqs)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	struct rpc_rqst *req = NULL, *tmp = NULL;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	dprintk("RPC:        destroy backchannel transport\n");
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (max_reqs == 0)
2318c2ecf20Sopenharmony_ci		goto out;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	spin_lock_bh(&xprt->bc_pa_lock);
2348c2ecf20Sopenharmony_ci	xprt->bc_alloc_max -= min(max_reqs, xprt->bc_alloc_max);
2358c2ecf20Sopenharmony_ci	list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) {
2368c2ecf20Sopenharmony_ci		dprintk("RPC:        req=%p\n", req);
2378c2ecf20Sopenharmony_ci		list_del(&req->rq_bc_pa_list);
2388c2ecf20Sopenharmony_ci		xprt_free_allocation(req);
2398c2ecf20Sopenharmony_ci		xprt->bc_alloc_count--;
2408c2ecf20Sopenharmony_ci		atomic_dec(&xprt->bc_slot_count);
2418c2ecf20Sopenharmony_ci		if (--max_reqs == 0)
2428c2ecf20Sopenharmony_ci			break;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci	spin_unlock_bh(&xprt->bc_pa_lock);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciout:
2478c2ecf20Sopenharmony_ci	dprintk("RPC:        backchannel list empty= %s\n",
2488c2ecf20Sopenharmony_ci		list_empty(&xprt->bc_pa_list) ? "true" : "false");
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic struct rpc_rqst *xprt_get_bc_request(struct rpc_xprt *xprt, __be32 xid,
2528c2ecf20Sopenharmony_ci		struct rpc_rqst *new)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct rpc_rqst *req = NULL;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	dprintk("RPC:       allocate a backchannel request\n");
2578c2ecf20Sopenharmony_ci	if (list_empty(&xprt->bc_pa_list)) {
2588c2ecf20Sopenharmony_ci		if (!new)
2598c2ecf20Sopenharmony_ci			goto not_found;
2608c2ecf20Sopenharmony_ci		if (atomic_read(&xprt->bc_slot_count) >= BC_MAX_SLOTS)
2618c2ecf20Sopenharmony_ci			goto not_found;
2628c2ecf20Sopenharmony_ci		list_add_tail(&new->rq_bc_pa_list, &xprt->bc_pa_list);
2638c2ecf20Sopenharmony_ci		xprt->bc_alloc_count++;
2648c2ecf20Sopenharmony_ci		atomic_inc(&xprt->bc_slot_count);
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci	req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
2678c2ecf20Sopenharmony_ci				rq_bc_pa_list);
2688c2ecf20Sopenharmony_ci	req->rq_reply_bytes_recvd = 0;
2698c2ecf20Sopenharmony_ci	memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
2708c2ecf20Sopenharmony_ci			sizeof(req->rq_private_buf));
2718c2ecf20Sopenharmony_ci	req->rq_xid = xid;
2728c2ecf20Sopenharmony_ci	req->rq_connect_cookie = xprt->connect_cookie;
2738c2ecf20Sopenharmony_ci	dprintk("RPC:       backchannel req=%p\n", req);
2748c2ecf20Sopenharmony_cinot_found:
2758c2ecf20Sopenharmony_ci	return req;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/*
2798c2ecf20Sopenharmony_ci * Return the preallocated rpc_rqst structure and XDR buffers
2808c2ecf20Sopenharmony_ci * associated with this rpc_task.
2818c2ecf20Sopenharmony_ci */
2828c2ecf20Sopenharmony_civoid xprt_free_bc_request(struct rpc_rqst *req)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	xprt->ops->bc_free_rqst(req);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_civoid xprt_free_bc_rqst(struct rpc_rqst *req)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	dprintk("RPC:       free backchannel req=%p\n", req);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	req->rq_connect_cookie = xprt->connect_cookie - 1;
2968c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
2978c2ecf20Sopenharmony_ci	clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
2988c2ecf20Sopenharmony_ci	smp_mb__after_atomic();
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/*
3018c2ecf20Sopenharmony_ci	 * Return it to the list of preallocations so that it
3028c2ecf20Sopenharmony_ci	 * may be reused by a new callback request.
3038c2ecf20Sopenharmony_ci	 */
3048c2ecf20Sopenharmony_ci	spin_lock_bh(&xprt->bc_pa_lock);
3058c2ecf20Sopenharmony_ci	if (xprt_need_to_requeue(xprt)) {
3068c2ecf20Sopenharmony_ci		xprt_bc_reinit_xdr_buf(&req->rq_snd_buf);
3078c2ecf20Sopenharmony_ci		xprt_bc_reinit_xdr_buf(&req->rq_rcv_buf);
3088c2ecf20Sopenharmony_ci		req->rq_rcv_buf.len = PAGE_SIZE;
3098c2ecf20Sopenharmony_ci		list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list);
3108c2ecf20Sopenharmony_ci		xprt->bc_alloc_count++;
3118c2ecf20Sopenharmony_ci		atomic_inc(&xprt->bc_slot_count);
3128c2ecf20Sopenharmony_ci		req = NULL;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci	spin_unlock_bh(&xprt->bc_pa_lock);
3158c2ecf20Sopenharmony_ci	if (req != NULL) {
3168c2ecf20Sopenharmony_ci		/*
3178c2ecf20Sopenharmony_ci		 * The last remaining session was destroyed while this
3188c2ecf20Sopenharmony_ci		 * entry was in use.  Free the entry and don't attempt
3198c2ecf20Sopenharmony_ci		 * to add back to the list because there is no need to
3208c2ecf20Sopenharmony_ci		 * have anymore preallocated entries.
3218c2ecf20Sopenharmony_ci		 */
3228c2ecf20Sopenharmony_ci		dprintk("RPC:       Last session removed req=%p\n", req);
3238c2ecf20Sopenharmony_ci		xprt_free_allocation(req);
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci	xprt_put(xprt);
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/*
3298c2ecf20Sopenharmony_ci * One or more rpc_rqst structure have been preallocated during the
3308c2ecf20Sopenharmony_ci * backchannel setup.  Buffer space for the send and private XDR buffers
3318c2ecf20Sopenharmony_ci * has been preallocated as well.  Use xprt_alloc_bc_request to allocate
3328c2ecf20Sopenharmony_ci * to this request.  Use xprt_free_bc_request to return it.
3338c2ecf20Sopenharmony_ci *
3348c2ecf20Sopenharmony_ci * We know that we're called in soft interrupt context, grab the spin_lock
3358c2ecf20Sopenharmony_ci * since there is no need to grab the bottom half spin_lock.
3368c2ecf20Sopenharmony_ci *
3378c2ecf20Sopenharmony_ci * Return an available rpc_rqst, otherwise NULL if non are available.
3388c2ecf20Sopenharmony_ci */
3398c2ecf20Sopenharmony_cistruct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct rpc_rqst *req, *new = NULL;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	do {
3448c2ecf20Sopenharmony_ci		spin_lock(&xprt->bc_pa_lock);
3458c2ecf20Sopenharmony_ci		list_for_each_entry(req, &xprt->bc_pa_list, rq_bc_pa_list) {
3468c2ecf20Sopenharmony_ci			if (req->rq_connect_cookie != xprt->connect_cookie)
3478c2ecf20Sopenharmony_ci				continue;
3488c2ecf20Sopenharmony_ci			if (req->rq_xid == xid)
3498c2ecf20Sopenharmony_ci				goto found;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci		req = xprt_get_bc_request(xprt, xid, new);
3528c2ecf20Sopenharmony_cifound:
3538c2ecf20Sopenharmony_ci		spin_unlock(&xprt->bc_pa_lock);
3548c2ecf20Sopenharmony_ci		if (new) {
3558c2ecf20Sopenharmony_ci			if (req != new)
3568c2ecf20Sopenharmony_ci				xprt_free_allocation(new);
3578c2ecf20Sopenharmony_ci			break;
3588c2ecf20Sopenharmony_ci		} else if (req)
3598c2ecf20Sopenharmony_ci			break;
3608c2ecf20Sopenharmony_ci		new = xprt_alloc_bc_req(xprt, GFP_KERNEL);
3618c2ecf20Sopenharmony_ci	} while (new);
3628c2ecf20Sopenharmony_ci	return req;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci/*
3668c2ecf20Sopenharmony_ci * Add callback request to callback list.  The callback
3678c2ecf20Sopenharmony_ci * service sleeps on the sv_cb_waitq waiting for new
3688c2ecf20Sopenharmony_ci * requests.  Wake it up after adding enqueing the
3698c2ecf20Sopenharmony_ci * request.
3708c2ecf20Sopenharmony_ci */
3718c2ecf20Sopenharmony_civoid xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = req->rq_xprt;
3748c2ecf20Sopenharmony_ci	struct svc_serv *bc_serv = xprt->bc_serv;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	spin_lock(&xprt->bc_pa_lock);
3778c2ecf20Sopenharmony_ci	list_del(&req->rq_bc_pa_list);
3788c2ecf20Sopenharmony_ci	xprt->bc_alloc_count--;
3798c2ecf20Sopenharmony_ci	spin_unlock(&xprt->bc_pa_lock);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	req->rq_private_buf.len = copied;
3828c2ecf20Sopenharmony_ci	set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	dprintk("RPC:       add callback request to list\n");
3858c2ecf20Sopenharmony_ci	xprt_get(xprt);
3868c2ecf20Sopenharmony_ci	spin_lock(&bc_serv->sv_cb_lock);
3878c2ecf20Sopenharmony_ci	list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
3888c2ecf20Sopenharmony_ci	wake_up(&bc_serv->sv_cb_waitq);
3898c2ecf20Sopenharmony_ci	spin_unlock(&bc_serv->sv_cb_lock);
3908c2ecf20Sopenharmony_ci}
391