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