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