11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/net/sunrpc/xprt.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This is a generic RPC call interface supporting congestion avoidance, 51da177e4SLinus Torvalds * and asynchronous calls. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * The interface works like this: 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * - When a process places a call, it allocates a request slot if 101da177e4SLinus Torvalds * one is available. Otherwise, it sleeps on the backlog queue 111da177e4SLinus Torvalds * (xprt_reserve). 121da177e4SLinus Torvalds * - Next, the caller puts together the RPC message, stuffs it into 1355aa4f58SChuck Lever * the request struct, and calls xprt_transmit(). 1455aa4f58SChuck Lever * - xprt_transmit sends the message and installs the caller on the 1555aa4f58SChuck Lever * transport's wait list. At the same time, it installs a timer that 161da177e4SLinus Torvalds * is run after the packet's timeout has expired. 171da177e4SLinus Torvalds * - When a packet arrives, the data_ready handler walks the list of 1855aa4f58SChuck Lever * pending requests for that transport. If a matching XID is found, the 191da177e4SLinus Torvalds * caller is woken up, and the timer removed. 201da177e4SLinus Torvalds * - When no reply arrives within the timeout interval, the timer is 211da177e4SLinus Torvalds * fired by the kernel and runs xprt_timer(). It either adjusts the 221da177e4SLinus Torvalds * timeout values (minor timeout) or wakes up the caller with a status 231da177e4SLinus Torvalds * of -ETIMEDOUT. 241da177e4SLinus Torvalds * - When the caller receives a notification from RPC that a reply arrived, 251da177e4SLinus Torvalds * it should release the RPC slot, and process the reply. 261da177e4SLinus Torvalds * If the call timed out, it may choose to retry the operation by 271da177e4SLinus Torvalds * adjusting the initial timeout value, and simply calling rpc_call 281da177e4SLinus Torvalds * again. 291da177e4SLinus Torvalds * 301da177e4SLinus Torvalds * Support for async RPC is done through a set of RPC-specific scheduling 311da177e4SLinus Torvalds * primitives that `transparently' work for processes as well as async 321da177e4SLinus Torvalds * tasks that rely on callbacks. 331da177e4SLinus Torvalds * 341da177e4SLinus Torvalds * Copyright (C) 1995-1997, Olaf Kirch <okir@monad.swb.de> 3555aa4f58SChuck Lever * 3655aa4f58SChuck Lever * Transport switch API copyright (C) 2005, Chuck Lever <cel@netapp.com> 371da177e4SLinus Torvalds */ 381da177e4SLinus Torvalds 39a246b010SChuck Lever #include <linux/module.h> 40a246b010SChuck Lever 411da177e4SLinus Torvalds #include <linux/types.h> 42a246b010SChuck Lever #include <linux/interrupt.h> 431da177e4SLinus Torvalds #include <linux/workqueue.h> 441da177e4SLinus Torvalds #include <linux/random.h> 451da177e4SLinus Torvalds 46a246b010SChuck Lever #include <linux/sunrpc/clnt.h> 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds /* 491da177e4SLinus Torvalds * Local variables 501da177e4SLinus Torvalds */ 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds #ifdef RPC_DEBUG 531da177e4SLinus Torvalds # undef RPC_DEBUG_DATA 541da177e4SLinus Torvalds # define RPCDBG_FACILITY RPCDBG_XPRT 551da177e4SLinus Torvalds #endif 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 581da177e4SLinus Torvalds * Local functions 591da177e4SLinus Torvalds */ 601da177e4SLinus Torvalds static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); 611da177e4SLinus Torvalds static inline void do_xprt_reserve(struct rpc_task *); 621da177e4SLinus Torvalds static void xprt_connect_status(struct rpc_task *task); 631da177e4SLinus Torvalds static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds static int xprt_clear_backlog(struct rpc_xprt *xprt); 661da177e4SLinus Torvalds 6712a80469SChuck Lever /** 6812a80469SChuck Lever * xprt_reserve_xprt - serialize write access to transports 6912a80469SChuck Lever * @task: task that is requesting access to the transport 7012a80469SChuck Lever * 7112a80469SChuck Lever * This prevents mixing the payload of separate requests, and prevents 7212a80469SChuck Lever * transport connects from colliding with writes. No congestion control 7312a80469SChuck Lever * is provided. 741da177e4SLinus Torvalds */ 7512a80469SChuck Lever int xprt_reserve_xprt(struct rpc_task *task) 761da177e4SLinus Torvalds { 7712a80469SChuck Lever struct rpc_xprt *xprt = task->tk_xprt; 7812a80469SChuck Lever struct rpc_rqst *req = task->tk_rqstp; 7912a80469SChuck Lever 8012a80469SChuck Lever if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { 8112a80469SChuck Lever if (task == xprt->snd_task) 8212a80469SChuck Lever return 1; 8312a80469SChuck Lever if (task == NULL) 8412a80469SChuck Lever return 0; 8512a80469SChuck Lever goto out_sleep; 8612a80469SChuck Lever } 8712a80469SChuck Lever xprt->snd_task = task; 8812a80469SChuck Lever if (req) { 8912a80469SChuck Lever req->rq_bytes_sent = 0; 9012a80469SChuck Lever req->rq_ntrans++; 9112a80469SChuck Lever } 9212a80469SChuck Lever return 1; 9312a80469SChuck Lever 9412a80469SChuck Lever out_sleep: 9512a80469SChuck Lever dprintk("RPC: %4d failed to lock transport %p\n", 9612a80469SChuck Lever task->tk_pid, xprt); 9712a80469SChuck Lever task->tk_timeout = 0; 9812a80469SChuck Lever task->tk_status = -EAGAIN; 9912a80469SChuck Lever if (req && req->rq_ntrans) 10012a80469SChuck Lever rpc_sleep_on(&xprt->resend, task, NULL, NULL); 10112a80469SChuck Lever else 10212a80469SChuck Lever rpc_sleep_on(&xprt->sending, task, NULL, NULL); 10312a80469SChuck Lever return 0; 10412a80469SChuck Lever } 10512a80469SChuck Lever 10612a80469SChuck Lever /* 10712a80469SChuck Lever * xprt_reserve_xprt_cong - serialize write access to transports 10812a80469SChuck Lever * @task: task that is requesting access to the transport 10912a80469SChuck Lever * 11012a80469SChuck Lever * Same as xprt_reserve_xprt, but Van Jacobson congestion control is 11112a80469SChuck Lever * integrated into the decision of whether a request is allowed to be 11212a80469SChuck Lever * woken up and given access to the transport. 11312a80469SChuck Lever */ 11412a80469SChuck Lever int xprt_reserve_xprt_cong(struct rpc_task *task) 11512a80469SChuck Lever { 11612a80469SChuck Lever struct rpc_xprt *xprt = task->tk_xprt; 1171da177e4SLinus Torvalds struct rpc_rqst *req = task->tk_rqstp; 1181da177e4SLinus Torvalds 1192226feb6SChuck Lever if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { 1201da177e4SLinus Torvalds if (task == xprt->snd_task) 1211da177e4SLinus Torvalds return 1; 1221da177e4SLinus Torvalds goto out_sleep; 1231da177e4SLinus Torvalds } 12412a80469SChuck Lever if (__xprt_get_cong(xprt, task)) { 1251da177e4SLinus Torvalds xprt->snd_task = task; 1261da177e4SLinus Torvalds if (req) { 1271da177e4SLinus Torvalds req->rq_bytes_sent = 0; 1281da177e4SLinus Torvalds req->rq_ntrans++; 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds return 1; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds smp_mb__before_clear_bit(); 1332226feb6SChuck Lever clear_bit(XPRT_LOCKED, &xprt->state); 1341da177e4SLinus Torvalds smp_mb__after_clear_bit(); 1351da177e4SLinus Torvalds out_sleep: 13655aa4f58SChuck Lever dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt); 1371da177e4SLinus Torvalds task->tk_timeout = 0; 1381da177e4SLinus Torvalds task->tk_status = -EAGAIN; 1391da177e4SLinus Torvalds if (req && req->rq_ntrans) 1401da177e4SLinus Torvalds rpc_sleep_on(&xprt->resend, task, NULL, NULL); 1411da177e4SLinus Torvalds else 1421da177e4SLinus Torvalds rpc_sleep_on(&xprt->sending, task, NULL, NULL); 1431da177e4SLinus Torvalds return 0; 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 14612a80469SChuck Lever static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) 1471da177e4SLinus Torvalds { 1481da177e4SLinus Torvalds int retval; 1491da177e4SLinus Torvalds 1504a0f8c04SChuck Lever spin_lock_bh(&xprt->transport_lock); 15112a80469SChuck Lever retval = xprt->ops->reserve_xprt(task); 1524a0f8c04SChuck Lever spin_unlock_bh(&xprt->transport_lock); 1531da177e4SLinus Torvalds return retval; 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds 15712a80469SChuck Lever static void __xprt_lock_write_next(struct rpc_xprt *xprt) 1581da177e4SLinus Torvalds { 1591da177e4SLinus Torvalds struct rpc_task *task; 1601da177e4SLinus Torvalds 1612226feb6SChuck Lever if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) 1621da177e4SLinus Torvalds return; 1631da177e4SLinus Torvalds if (!xprt->nocong && RPCXPRT_CONGESTED(xprt)) 1641da177e4SLinus Torvalds goto out_unlock; 1651da177e4SLinus Torvalds task = rpc_wake_up_next(&xprt->resend); 1661da177e4SLinus Torvalds if (!task) { 1671da177e4SLinus Torvalds task = rpc_wake_up_next(&xprt->sending); 1681da177e4SLinus Torvalds if (!task) 1691da177e4SLinus Torvalds goto out_unlock; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds if (xprt->nocong || __xprt_get_cong(xprt, task)) { 1721da177e4SLinus Torvalds struct rpc_rqst *req = task->tk_rqstp; 1731da177e4SLinus Torvalds xprt->snd_task = task; 1741da177e4SLinus Torvalds if (req) { 1751da177e4SLinus Torvalds req->rq_bytes_sent = 0; 1761da177e4SLinus Torvalds req->rq_ntrans++; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds return; 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds out_unlock: 1811da177e4SLinus Torvalds smp_mb__before_clear_bit(); 1822226feb6SChuck Lever clear_bit(XPRT_LOCKED, &xprt->state); 1831da177e4SLinus Torvalds smp_mb__after_clear_bit(); 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds /* 18755aa4f58SChuck Lever * Releases the transport for use by other requests. 1881da177e4SLinus Torvalds */ 1891da177e4SLinus Torvalds static void 1901da177e4SLinus Torvalds __xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) 1911da177e4SLinus Torvalds { 1921da177e4SLinus Torvalds if (xprt->snd_task == task) { 1931da177e4SLinus Torvalds xprt->snd_task = NULL; 1941da177e4SLinus Torvalds smp_mb__before_clear_bit(); 1952226feb6SChuck Lever clear_bit(XPRT_LOCKED, &xprt->state); 1961da177e4SLinus Torvalds smp_mb__after_clear_bit(); 1971da177e4SLinus Torvalds __xprt_lock_write_next(xprt); 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds static inline void 2021da177e4SLinus Torvalds xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) 2031da177e4SLinus Torvalds { 2044a0f8c04SChuck Lever spin_lock_bh(&xprt->transport_lock); 2051da177e4SLinus Torvalds __xprt_release_write(xprt, task); 2064a0f8c04SChuck Lever spin_unlock_bh(&xprt->transport_lock); 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds /* 2101da177e4SLinus Torvalds * Van Jacobson congestion avoidance. Check if the congestion window 2111da177e4SLinus Torvalds * overflowed. Put the task to sleep if this is the case. 2121da177e4SLinus Torvalds */ 2131da177e4SLinus Torvalds static int 2141da177e4SLinus Torvalds __xprt_get_cong(struct rpc_xprt *xprt, struct rpc_task *task) 2151da177e4SLinus Torvalds { 2161da177e4SLinus Torvalds struct rpc_rqst *req = task->tk_rqstp; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds if (req->rq_cong) 2191da177e4SLinus Torvalds return 1; 2201da177e4SLinus Torvalds dprintk("RPC: %4d xprt_cwnd_limited cong = %ld cwnd = %ld\n", 2211da177e4SLinus Torvalds task->tk_pid, xprt->cong, xprt->cwnd); 2221da177e4SLinus Torvalds if (RPCXPRT_CONGESTED(xprt)) 2231da177e4SLinus Torvalds return 0; 2241da177e4SLinus Torvalds req->rq_cong = 1; 2251da177e4SLinus Torvalds xprt->cong += RPC_CWNDSCALE; 2261da177e4SLinus Torvalds return 1; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /* 2301da177e4SLinus Torvalds * Adjust the congestion window, and wake up the next task 2311da177e4SLinus Torvalds * that has been sleeping due to congestion 2321da177e4SLinus Torvalds */ 2331da177e4SLinus Torvalds static void 2341da177e4SLinus Torvalds __xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req) 2351da177e4SLinus Torvalds { 2361da177e4SLinus Torvalds if (!req->rq_cong) 2371da177e4SLinus Torvalds return; 2381da177e4SLinus Torvalds req->rq_cong = 0; 2391da177e4SLinus Torvalds xprt->cong -= RPC_CWNDSCALE; 2401da177e4SLinus Torvalds __xprt_lock_write_next(xprt); 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds /* 2441da177e4SLinus Torvalds * Adjust RPC congestion window 2451da177e4SLinus Torvalds * We use a time-smoothed congestion estimator to avoid heavy oscillation. 2461da177e4SLinus Torvalds */ 2471da177e4SLinus Torvalds static void 2481da177e4SLinus Torvalds xprt_adjust_cwnd(struct rpc_xprt *xprt, int result) 2491da177e4SLinus Torvalds { 2501da177e4SLinus Torvalds unsigned long cwnd; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds cwnd = xprt->cwnd; 2531da177e4SLinus Torvalds if (result >= 0 && cwnd <= xprt->cong) { 2541da177e4SLinus Torvalds /* The (cwnd >> 1) term makes sure 2551da177e4SLinus Torvalds * the result gets rounded properly. */ 2561da177e4SLinus Torvalds cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd; 2571da177e4SLinus Torvalds if (cwnd > RPC_MAXCWND(xprt)) 2581da177e4SLinus Torvalds cwnd = RPC_MAXCWND(xprt); 2591da177e4SLinus Torvalds __xprt_lock_write_next(xprt); 2601da177e4SLinus Torvalds } else if (result == -ETIMEDOUT) { 2611da177e4SLinus Torvalds cwnd >>= 1; 2621da177e4SLinus Torvalds if (cwnd < RPC_CWNDSCALE) 2631da177e4SLinus Torvalds cwnd = RPC_CWNDSCALE; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds dprintk("RPC: cong %ld, cwnd was %ld, now %ld\n", 2661da177e4SLinus Torvalds xprt->cong, xprt->cwnd, cwnd); 2671da177e4SLinus Torvalds xprt->cwnd = cwnd; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 27044fbac22SChuck Lever /** 27144fbac22SChuck Lever * xprt_wake_pending_tasks - wake all tasks on a transport's pending queue 27244fbac22SChuck Lever * @xprt: transport with waiting tasks 27344fbac22SChuck Lever * @status: result code to plant in each task before waking it 27444fbac22SChuck Lever * 27544fbac22SChuck Lever */ 27644fbac22SChuck Lever void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status) 27744fbac22SChuck Lever { 27844fbac22SChuck Lever if (status < 0) 27944fbac22SChuck Lever rpc_wake_up_status(&xprt->pending, status); 28044fbac22SChuck Lever else 28144fbac22SChuck Lever rpc_wake_up(&xprt->pending); 28244fbac22SChuck Lever } 28344fbac22SChuck Lever 284c7b2cae8SChuck Lever /** 285c7b2cae8SChuck Lever * xprt_wait_for_buffer_space - wait for transport output buffer to clear 286c7b2cae8SChuck Lever * @task: task to be put to sleep 287c7b2cae8SChuck Lever * 288c7b2cae8SChuck Lever */ 289c7b2cae8SChuck Lever void xprt_wait_for_buffer_space(struct rpc_task *task) 290c7b2cae8SChuck Lever { 291c7b2cae8SChuck Lever struct rpc_rqst *req = task->tk_rqstp; 292c7b2cae8SChuck Lever struct rpc_xprt *xprt = req->rq_xprt; 293c7b2cae8SChuck Lever 294c7b2cae8SChuck Lever task->tk_timeout = req->rq_timeout; 295c7b2cae8SChuck Lever rpc_sleep_on(&xprt->pending, task, NULL, NULL); 296c7b2cae8SChuck Lever } 297c7b2cae8SChuck Lever 298c7b2cae8SChuck Lever /** 299c7b2cae8SChuck Lever * xprt_write_space - wake the task waiting for transport output buffer space 300c7b2cae8SChuck Lever * @xprt: transport with waiting tasks 301c7b2cae8SChuck Lever * 302c7b2cae8SChuck Lever * Can be called in a soft IRQ context, so xprt_write_space never sleeps. 303c7b2cae8SChuck Lever */ 304c7b2cae8SChuck Lever void xprt_write_space(struct rpc_xprt *xprt) 305c7b2cae8SChuck Lever { 306c7b2cae8SChuck Lever if (unlikely(xprt->shutdown)) 307c7b2cae8SChuck Lever return; 308c7b2cae8SChuck Lever 309c7b2cae8SChuck Lever spin_lock_bh(&xprt->transport_lock); 310c7b2cae8SChuck Lever if (xprt->snd_task) { 311c7b2cae8SChuck Lever dprintk("RPC: write space: waking waiting task on xprt %p\n", 312c7b2cae8SChuck Lever xprt); 313c7b2cae8SChuck Lever rpc_wake_up_task(xprt->snd_task); 314c7b2cae8SChuck Lever } 315c7b2cae8SChuck Lever spin_unlock_bh(&xprt->transport_lock); 316c7b2cae8SChuck Lever } 317c7b2cae8SChuck Lever 318fe3aca29SChuck Lever /** 319fe3aca29SChuck Lever * xprt_set_retrans_timeout_def - set a request's retransmit timeout 320fe3aca29SChuck Lever * @task: task whose timeout is to be set 321fe3aca29SChuck Lever * 322fe3aca29SChuck Lever * Set a request's retransmit timeout based on the transport's 323fe3aca29SChuck Lever * default timeout parameters. Used by transports that don't adjust 324fe3aca29SChuck Lever * the retransmit timeout based on round-trip time estimation. 325fe3aca29SChuck Lever */ 326fe3aca29SChuck Lever void xprt_set_retrans_timeout_def(struct rpc_task *task) 327fe3aca29SChuck Lever { 328fe3aca29SChuck Lever task->tk_timeout = task->tk_rqstp->rq_timeout; 329fe3aca29SChuck Lever } 330fe3aca29SChuck Lever 331fe3aca29SChuck Lever /* 332fe3aca29SChuck Lever * xprt_set_retrans_timeout_rtt - set a request's retransmit timeout 333fe3aca29SChuck Lever * @task: task whose timeout is to be set 334fe3aca29SChuck Lever * 335fe3aca29SChuck Lever * Set a request's retransmit timeout using the RTT estimator. 336fe3aca29SChuck Lever */ 337fe3aca29SChuck Lever void xprt_set_retrans_timeout_rtt(struct rpc_task *task) 338fe3aca29SChuck Lever { 339fe3aca29SChuck Lever int timer = task->tk_msg.rpc_proc->p_timer; 340fe3aca29SChuck Lever struct rpc_rtt *rtt = task->tk_client->cl_rtt; 341fe3aca29SChuck Lever struct rpc_rqst *req = task->tk_rqstp; 342fe3aca29SChuck Lever unsigned long max_timeout = req->rq_xprt->timeout.to_maxval; 343fe3aca29SChuck Lever 344fe3aca29SChuck Lever task->tk_timeout = rpc_calc_rto(rtt, timer); 345fe3aca29SChuck Lever task->tk_timeout <<= rpc_ntimeo(rtt, timer) + req->rq_retries; 346fe3aca29SChuck Lever if (task->tk_timeout > max_timeout || task->tk_timeout == 0) 347fe3aca29SChuck Lever task->tk_timeout = max_timeout; 348fe3aca29SChuck Lever } 349fe3aca29SChuck Lever 3501da177e4SLinus Torvalds static void xprt_reset_majortimeo(struct rpc_rqst *req) 3511da177e4SLinus Torvalds { 3521da177e4SLinus Torvalds struct rpc_timeout *to = &req->rq_xprt->timeout; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds req->rq_majortimeo = req->rq_timeout; 3551da177e4SLinus Torvalds if (to->to_exponential) 3561da177e4SLinus Torvalds req->rq_majortimeo <<= to->to_retries; 3571da177e4SLinus Torvalds else 3581da177e4SLinus Torvalds req->rq_majortimeo += to->to_increment * to->to_retries; 3591da177e4SLinus Torvalds if (req->rq_majortimeo > to->to_maxval || req->rq_majortimeo == 0) 3601da177e4SLinus Torvalds req->rq_majortimeo = to->to_maxval; 3611da177e4SLinus Torvalds req->rq_majortimeo += jiffies; 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds 3649903cd1cSChuck Lever /** 3659903cd1cSChuck Lever * xprt_adjust_timeout - adjust timeout values for next retransmit 3669903cd1cSChuck Lever * @req: RPC request containing parameters to use for the adjustment 3679903cd1cSChuck Lever * 3681da177e4SLinus Torvalds */ 3691da177e4SLinus Torvalds int xprt_adjust_timeout(struct rpc_rqst *req) 3701da177e4SLinus Torvalds { 3711da177e4SLinus Torvalds struct rpc_xprt *xprt = req->rq_xprt; 3721da177e4SLinus Torvalds struct rpc_timeout *to = &xprt->timeout; 3731da177e4SLinus Torvalds int status = 0; 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds if (time_before(jiffies, req->rq_majortimeo)) { 3761da177e4SLinus Torvalds if (to->to_exponential) 3771da177e4SLinus Torvalds req->rq_timeout <<= 1; 3781da177e4SLinus Torvalds else 3791da177e4SLinus Torvalds req->rq_timeout += to->to_increment; 3801da177e4SLinus Torvalds if (to->to_maxval && req->rq_timeout >= to->to_maxval) 3811da177e4SLinus Torvalds req->rq_timeout = to->to_maxval; 3821da177e4SLinus Torvalds req->rq_retries++; 3831da177e4SLinus Torvalds pprintk("RPC: %lu retrans\n", jiffies); 3841da177e4SLinus Torvalds } else { 3851da177e4SLinus Torvalds req->rq_timeout = to->to_initval; 3861da177e4SLinus Torvalds req->rq_retries = 0; 3871da177e4SLinus Torvalds xprt_reset_majortimeo(req); 3881da177e4SLinus Torvalds /* Reset the RTT counters == "slow start" */ 3894a0f8c04SChuck Lever spin_lock_bh(&xprt->transport_lock); 3901da177e4SLinus Torvalds rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval); 3914a0f8c04SChuck Lever spin_unlock_bh(&xprt->transport_lock); 3921da177e4SLinus Torvalds pprintk("RPC: %lu timeout\n", jiffies); 3931da177e4SLinus Torvalds status = -ETIMEDOUT; 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds if (req->rq_timeout == 0) { 3971da177e4SLinus Torvalds printk(KERN_WARNING "xprt_adjust_timeout: rq_timeout = 0!\n"); 3981da177e4SLinus Torvalds req->rq_timeout = 5 * HZ; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds return status; 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds 40355aa4f58SChuck Lever static void xprt_autoclose(void *args) 4041da177e4SLinus Torvalds { 4051da177e4SLinus Torvalds struct rpc_xprt *xprt = (struct rpc_xprt *)args; 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds xprt_disconnect(xprt); 408a246b010SChuck Lever xprt->ops->close(xprt); 4091da177e4SLinus Torvalds xprt_release_write(xprt, NULL); 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds 4129903cd1cSChuck Lever /** 4139903cd1cSChuck Lever * xprt_disconnect - mark a transport as disconnected 4149903cd1cSChuck Lever * @xprt: transport to flag for disconnect 4159903cd1cSChuck Lever * 4161da177e4SLinus Torvalds */ 417a246b010SChuck Lever void xprt_disconnect(struct rpc_xprt *xprt) 4181da177e4SLinus Torvalds { 4191da177e4SLinus Torvalds dprintk("RPC: disconnected transport %p\n", xprt); 4204a0f8c04SChuck Lever spin_lock_bh(&xprt->transport_lock); 4211da177e4SLinus Torvalds xprt_clear_connected(xprt); 42244fbac22SChuck Lever xprt_wake_pending_tasks(xprt, -ENOTCONN); 4234a0f8c04SChuck Lever spin_unlock_bh(&xprt->transport_lock); 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds static void 4271da177e4SLinus Torvalds xprt_init_autodisconnect(unsigned long data) 4281da177e4SLinus Torvalds { 4291da177e4SLinus Torvalds struct rpc_xprt *xprt = (struct rpc_xprt *)data; 4301da177e4SLinus Torvalds 4314a0f8c04SChuck Lever spin_lock(&xprt->transport_lock); 4321da177e4SLinus Torvalds if (!list_empty(&xprt->recv) || xprt->shutdown) 4331da177e4SLinus Torvalds goto out_abort; 4342226feb6SChuck Lever if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) 4351da177e4SLinus Torvalds goto out_abort; 4364a0f8c04SChuck Lever spin_unlock(&xprt->transport_lock); 4372226feb6SChuck Lever if (xprt_connecting(xprt)) 4381da177e4SLinus Torvalds xprt_release_write(xprt, NULL); 4391da177e4SLinus Torvalds else 4401da177e4SLinus Torvalds schedule_work(&xprt->task_cleanup); 4411da177e4SLinus Torvalds return; 4421da177e4SLinus Torvalds out_abort: 4434a0f8c04SChuck Lever spin_unlock(&xprt->transport_lock); 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4469903cd1cSChuck Lever /** 4479903cd1cSChuck Lever * xprt_connect - schedule a transport connect operation 4489903cd1cSChuck Lever * @task: RPC task that is requesting the connect 4491da177e4SLinus Torvalds * 4501da177e4SLinus Torvalds */ 4511da177e4SLinus Torvalds void xprt_connect(struct rpc_task *task) 4521da177e4SLinus Torvalds { 4531da177e4SLinus Torvalds struct rpc_xprt *xprt = task->tk_xprt; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid, 4561da177e4SLinus Torvalds xprt, (xprt_connected(xprt) ? "is" : "is not")); 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds if (xprt->shutdown) { 4591da177e4SLinus Torvalds task->tk_status = -EIO; 4601da177e4SLinus Torvalds return; 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds if (!xprt->addr.sin_port) { 4631da177e4SLinus Torvalds task->tk_status = -EIO; 4641da177e4SLinus Torvalds return; 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds if (!xprt_lock_write(xprt, task)) 4671da177e4SLinus Torvalds return; 4681da177e4SLinus Torvalds if (xprt_connected(xprt)) 469a246b010SChuck Lever xprt_release_write(xprt, task); 470a246b010SChuck Lever else { 4711da177e4SLinus Torvalds if (task->tk_rqstp) 4721da177e4SLinus Torvalds task->tk_rqstp->rq_bytes_sent = 0; 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds task->tk_timeout = RPC_CONNECT_TIMEOUT; 4751da177e4SLinus Torvalds rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); 476a246b010SChuck Lever xprt->ops->connect(task); 4771da177e4SLinus Torvalds } 4781da177e4SLinus Torvalds return; 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds 4819903cd1cSChuck Lever static void xprt_connect_status(struct rpc_task *task) 4821da177e4SLinus Torvalds { 4831da177e4SLinus Torvalds struct rpc_xprt *xprt = task->tk_xprt; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds if (task->tk_status >= 0) { 4861da177e4SLinus Torvalds dprintk("RPC: %4d xprt_connect_status: connection established\n", 4871da177e4SLinus Torvalds task->tk_pid); 4881da177e4SLinus Torvalds return; 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds switch (task->tk_status) { 4921da177e4SLinus Torvalds case -ECONNREFUSED: 4931da177e4SLinus Torvalds case -ECONNRESET: 49423475d66SChuck Lever dprintk("RPC: %4d xprt_connect_status: server %s refused connection\n", 49523475d66SChuck Lever task->tk_pid, task->tk_client->cl_server); 49623475d66SChuck Lever break; 4971da177e4SLinus Torvalds case -ENOTCONN: 49823475d66SChuck Lever dprintk("RPC: %4d xprt_connect_status: connection broken\n", 49923475d66SChuck Lever task->tk_pid); 50023475d66SChuck Lever break; 5011da177e4SLinus Torvalds case -ETIMEDOUT: 50223475d66SChuck Lever dprintk("RPC: %4d xprt_connect_status: connect attempt timed out\n", 5031da177e4SLinus Torvalds task->tk_pid); 5041da177e4SLinus Torvalds break; 5051da177e4SLinus Torvalds default: 50623475d66SChuck Lever dprintk("RPC: %4d xprt_connect_status: error %d connecting to server %s\n", 50723475d66SChuck Lever task->tk_pid, -task->tk_status, task->tk_client->cl_server); 5081da177e4SLinus Torvalds xprt_release_write(xprt, task); 50923475d66SChuck Lever task->tk_status = -EIO; 51023475d66SChuck Lever return; 51123475d66SChuck Lever } 51223475d66SChuck Lever 51323475d66SChuck Lever /* if soft mounted, just cause this RPC to fail */ 51423475d66SChuck Lever if (RPC_IS_SOFT(task)) { 51523475d66SChuck Lever xprt_release_write(xprt, task); 51623475d66SChuck Lever task->tk_status = -EIO; 51723475d66SChuck Lever } 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds 5209903cd1cSChuck Lever /** 5219903cd1cSChuck Lever * xprt_lookup_rqst - find an RPC request corresponding to an XID 5229903cd1cSChuck Lever * @xprt: transport on which the original request was transmitted 5239903cd1cSChuck Lever * @xid: RPC XID of incoming reply 5249903cd1cSChuck Lever * 5251da177e4SLinus Torvalds */ 526a246b010SChuck Lever struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) 5271da177e4SLinus Torvalds { 5281da177e4SLinus Torvalds struct list_head *pos; 5291da177e4SLinus Torvalds struct rpc_rqst *req = NULL; 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds list_for_each(pos, &xprt->recv) { 5321da177e4SLinus Torvalds struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list); 5331da177e4SLinus Torvalds if (entry->rq_xid == xid) { 5341da177e4SLinus Torvalds req = entry; 5351da177e4SLinus Torvalds break; 5361da177e4SLinus Torvalds } 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds return req; 5391da177e4SLinus Torvalds } 5401da177e4SLinus Torvalds 5419903cd1cSChuck Lever /** 5429903cd1cSChuck Lever * xprt_complete_rqst - called when reply processing is complete 5439903cd1cSChuck Lever * @xprt: controlling transport 5449903cd1cSChuck Lever * @req: RPC request that just completed 5459903cd1cSChuck Lever * @copied: actual number of bytes received from the transport 5469903cd1cSChuck Lever * 5471da177e4SLinus Torvalds */ 548a246b010SChuck Lever void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) 5491da177e4SLinus Torvalds { 5501da177e4SLinus Torvalds struct rpc_task *task = req->rq_task; 5511da177e4SLinus Torvalds struct rpc_clnt *clnt = task->tk_client; 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds /* Adjust congestion window */ 5541da177e4SLinus Torvalds if (!xprt->nocong) { 5551da177e4SLinus Torvalds unsigned timer = task->tk_msg.rpc_proc->p_timer; 5561da177e4SLinus Torvalds xprt_adjust_cwnd(xprt, copied); 5571da177e4SLinus Torvalds __xprt_put_cong(xprt, req); 5581da177e4SLinus Torvalds if (timer) { 5591da177e4SLinus Torvalds if (req->rq_ntrans == 1) 5601da177e4SLinus Torvalds rpc_update_rtt(clnt->cl_rtt, timer, 5611da177e4SLinus Torvalds (long)jiffies - req->rq_xtime); 5621da177e4SLinus Torvalds rpc_set_timeo(clnt->cl_rtt, timer, req->rq_ntrans - 1); 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds #ifdef RPC_PROFILE 5671da177e4SLinus Torvalds /* Profile only reads for now */ 5681da177e4SLinus Torvalds if (copied > 1024) { 5691da177e4SLinus Torvalds static unsigned long nextstat; 5701da177e4SLinus Torvalds static unsigned long pkt_rtt, pkt_len, pkt_cnt; 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds pkt_cnt++; 5731da177e4SLinus Torvalds pkt_len += req->rq_slen + copied; 5741da177e4SLinus Torvalds pkt_rtt += jiffies - req->rq_xtime; 5751da177e4SLinus Torvalds if (time_before(nextstat, jiffies)) { 5761da177e4SLinus Torvalds printk("RPC: %lu %ld cwnd\n", jiffies, xprt->cwnd); 5771da177e4SLinus Torvalds printk("RPC: %ld %ld %ld %ld stat\n", 5781da177e4SLinus Torvalds jiffies, pkt_cnt, pkt_len, pkt_rtt); 5791da177e4SLinus Torvalds pkt_rtt = pkt_len = pkt_cnt = 0; 5801da177e4SLinus Torvalds nextstat = jiffies + 5 * HZ; 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds #endif 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied); 5861da177e4SLinus Torvalds list_del_init(&req->rq_list); 5871da177e4SLinus Torvalds req->rq_received = req->rq_private_buf.len = copied; 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds /* ... and wake up the process. */ 5901da177e4SLinus Torvalds rpc_wake_up_task(task); 5911da177e4SLinus Torvalds return; 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds /* 5951da177e4SLinus Torvalds * RPC receive timeout handler. 5961da177e4SLinus Torvalds */ 5971da177e4SLinus Torvalds static void 5981da177e4SLinus Torvalds xprt_timer(struct rpc_task *task) 5991da177e4SLinus Torvalds { 6001da177e4SLinus Torvalds struct rpc_rqst *req = task->tk_rqstp; 6011da177e4SLinus Torvalds struct rpc_xprt *xprt = req->rq_xprt; 6021da177e4SLinus Torvalds 6034a0f8c04SChuck Lever spin_lock(&xprt->transport_lock); 6041da177e4SLinus Torvalds if (req->rq_received) 6051da177e4SLinus Torvalds goto out; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds xprt_adjust_cwnd(req->rq_xprt, -ETIMEDOUT); 6081da177e4SLinus Torvalds __xprt_put_cong(xprt, req); 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds dprintk("RPC: %4d xprt_timer (%s request)\n", 6111da177e4SLinus Torvalds task->tk_pid, req ? "pending" : "backlogged"); 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds task->tk_status = -ETIMEDOUT; 6141da177e4SLinus Torvalds out: 6151da177e4SLinus Torvalds task->tk_timeout = 0; 6161da177e4SLinus Torvalds rpc_wake_up_task(task); 6174a0f8c04SChuck Lever spin_unlock(&xprt->transport_lock); 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds 6209903cd1cSChuck Lever /** 6219903cd1cSChuck Lever * xprt_prepare_transmit - reserve the transport before sending a request 6229903cd1cSChuck Lever * @task: RPC task about to send a request 6239903cd1cSChuck Lever * 6241da177e4SLinus Torvalds */ 6259903cd1cSChuck Lever int xprt_prepare_transmit(struct rpc_task *task) 6261da177e4SLinus Torvalds { 6271da177e4SLinus Torvalds struct rpc_rqst *req = task->tk_rqstp; 6281da177e4SLinus Torvalds struct rpc_xprt *xprt = req->rq_xprt; 6291da177e4SLinus Torvalds int err = 0; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds dprintk("RPC: %4d xprt_prepare_transmit\n", task->tk_pid); 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds if (xprt->shutdown) 6341da177e4SLinus Torvalds return -EIO; 6351da177e4SLinus Torvalds 6364a0f8c04SChuck Lever spin_lock_bh(&xprt->transport_lock); 6371da177e4SLinus Torvalds if (req->rq_received && !req->rq_bytes_sent) { 6381da177e4SLinus Torvalds err = req->rq_received; 6391da177e4SLinus Torvalds goto out_unlock; 6401da177e4SLinus Torvalds } 64112a80469SChuck Lever if (!xprt->ops->reserve_xprt(task)) { 6421da177e4SLinus Torvalds err = -EAGAIN; 6431da177e4SLinus Torvalds goto out_unlock; 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds if (!xprt_connected(xprt)) { 6471da177e4SLinus Torvalds err = -ENOTCONN; 6481da177e4SLinus Torvalds goto out_unlock; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds out_unlock: 6514a0f8c04SChuck Lever spin_unlock_bh(&xprt->transport_lock); 6521da177e4SLinus Torvalds return err; 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds 6559903cd1cSChuck Lever /** 6569903cd1cSChuck Lever * xprt_transmit - send an RPC request on a transport 6579903cd1cSChuck Lever * @task: controlling RPC task 6589903cd1cSChuck Lever * 6599903cd1cSChuck Lever * We have to copy the iovec because sendmsg fiddles with its contents. 6609903cd1cSChuck Lever */ 6619903cd1cSChuck Lever void xprt_transmit(struct rpc_task *task) 6621da177e4SLinus Torvalds { 6631da177e4SLinus Torvalds struct rpc_rqst *req = task->tk_rqstp; 6641da177e4SLinus Torvalds struct rpc_xprt *xprt = req->rq_xprt; 665a246b010SChuck Lever int status; 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds dprintk("RPC: %4d xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds smp_rmb(); 6701da177e4SLinus Torvalds if (!req->rq_received) { 6711da177e4SLinus Torvalds if (list_empty(&req->rq_list)) { 6724a0f8c04SChuck Lever spin_lock_bh(&xprt->transport_lock); 6731da177e4SLinus Torvalds /* Update the softirq receive buffer */ 6741da177e4SLinus Torvalds memcpy(&req->rq_private_buf, &req->rq_rcv_buf, 6751da177e4SLinus Torvalds sizeof(req->rq_private_buf)); 6761da177e4SLinus Torvalds /* Add request to the receive list */ 6771da177e4SLinus Torvalds list_add_tail(&req->rq_list, &xprt->recv); 6784a0f8c04SChuck Lever spin_unlock_bh(&xprt->transport_lock); 6791da177e4SLinus Torvalds xprt_reset_majortimeo(req); 6800f9dc2b1STrond Myklebust /* Turn off autodisconnect */ 6810f9dc2b1STrond Myklebust del_singleshot_timer_sync(&xprt->timer); 6821da177e4SLinus Torvalds } 6831da177e4SLinus Torvalds } else if (!req->rq_bytes_sent) 6841da177e4SLinus Torvalds return; 6851da177e4SLinus Torvalds 686a246b010SChuck Lever status = xprt->ops->send_request(task); 687fe3aca29SChuck Lever if (status == 0) { 688fe3aca29SChuck Lever dprintk("RPC: %4d xmit complete\n", task->tk_pid); 689fe3aca29SChuck Lever spin_lock_bh(&xprt->transport_lock); 690fe3aca29SChuck Lever xprt->ops->set_retrans_timeout(task); 691fe3aca29SChuck Lever /* Don't race with disconnect */ 692fe3aca29SChuck Lever if (!xprt_connected(xprt)) 693fe3aca29SChuck Lever task->tk_status = -ENOTCONN; 694fe3aca29SChuck Lever else if (!req->rq_received) 695fe3aca29SChuck Lever rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); 696fe3aca29SChuck Lever __xprt_release_write(xprt, task); 697fe3aca29SChuck Lever spin_unlock_bh(&xprt->transport_lock); 698fe3aca29SChuck Lever return; 699fe3aca29SChuck Lever } 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds /* Note: at this point, task->tk_sleeping has not yet been set, 7021da177e4SLinus Torvalds * hence there is no danger of the waking up task being put on 7031da177e4SLinus Torvalds * schedq, and being picked up by a parallel run of rpciod(). 7041da177e4SLinus Torvalds */ 7051da177e4SLinus Torvalds task->tk_status = status; 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds switch (status) { 7081da177e4SLinus Torvalds case -ECONNREFUSED: 7091da177e4SLinus Torvalds task->tk_timeout = RPC_REESTABLISH_TIMEOUT; 7101da177e4SLinus Torvalds rpc_sleep_on(&xprt->sending, task, NULL, NULL); 711a246b010SChuck Lever case -EAGAIN: 7121da177e4SLinus Torvalds case -ENOTCONN: 7131da177e4SLinus Torvalds return; 7141da177e4SLinus Torvalds default: 71543118c29SChuck Lever break; 7161da177e4SLinus Torvalds } 7171da177e4SLinus Torvalds xprt_release_write(xprt, task); 7181da177e4SLinus Torvalds return; 7191da177e4SLinus Torvalds } 7201da177e4SLinus Torvalds 7219903cd1cSChuck Lever static inline void do_xprt_reserve(struct rpc_task *task) 7221da177e4SLinus Torvalds { 7231da177e4SLinus Torvalds struct rpc_xprt *xprt = task->tk_xprt; 7241da177e4SLinus Torvalds 7251da177e4SLinus Torvalds task->tk_status = 0; 7261da177e4SLinus Torvalds if (task->tk_rqstp) 7271da177e4SLinus Torvalds return; 7281da177e4SLinus Torvalds if (!list_empty(&xprt->free)) { 7291da177e4SLinus Torvalds struct rpc_rqst *req = list_entry(xprt->free.next, struct rpc_rqst, rq_list); 7301da177e4SLinus Torvalds list_del_init(&req->rq_list); 7311da177e4SLinus Torvalds task->tk_rqstp = req; 7321da177e4SLinus Torvalds xprt_request_init(task, xprt); 7331da177e4SLinus Torvalds return; 7341da177e4SLinus Torvalds } 7351da177e4SLinus Torvalds dprintk("RPC: waiting for request slot\n"); 7361da177e4SLinus Torvalds task->tk_status = -EAGAIN; 7371da177e4SLinus Torvalds task->tk_timeout = 0; 7381da177e4SLinus Torvalds rpc_sleep_on(&xprt->backlog, task, NULL, NULL); 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 7419903cd1cSChuck Lever /** 7429903cd1cSChuck Lever * xprt_reserve - allocate an RPC request slot 7439903cd1cSChuck Lever * @task: RPC task requesting a slot allocation 7449903cd1cSChuck Lever * 7459903cd1cSChuck Lever * If no more slots are available, place the task on the transport's 7469903cd1cSChuck Lever * backlog queue. 7479903cd1cSChuck Lever */ 7489903cd1cSChuck Lever void xprt_reserve(struct rpc_task *task) 7491da177e4SLinus Torvalds { 7501da177e4SLinus Torvalds struct rpc_xprt *xprt = task->tk_xprt; 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds task->tk_status = -EIO; 7531da177e4SLinus Torvalds if (!xprt->shutdown) { 7545dc07727SChuck Lever spin_lock(&xprt->reserve_lock); 7551da177e4SLinus Torvalds do_xprt_reserve(task); 7565dc07727SChuck Lever spin_unlock(&xprt->reserve_lock); 7571da177e4SLinus Torvalds } 7581da177e4SLinus Torvalds } 7591da177e4SLinus Torvalds 7601da177e4SLinus Torvalds static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt) 7611da177e4SLinus Torvalds { 7621da177e4SLinus Torvalds return xprt->xid++; 7631da177e4SLinus Torvalds } 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds static inline void xprt_init_xid(struct rpc_xprt *xprt) 7661da177e4SLinus Torvalds { 7671da177e4SLinus Torvalds get_random_bytes(&xprt->xid, sizeof(xprt->xid)); 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds 7709903cd1cSChuck Lever static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) 7711da177e4SLinus Torvalds { 7721da177e4SLinus Torvalds struct rpc_rqst *req = task->tk_rqstp; 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds req->rq_timeout = xprt->timeout.to_initval; 7751da177e4SLinus Torvalds req->rq_task = task; 7761da177e4SLinus Torvalds req->rq_xprt = xprt; 7771da177e4SLinus Torvalds req->rq_xid = xprt_alloc_xid(xprt); 7781da177e4SLinus Torvalds dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, 7791da177e4SLinus Torvalds req, ntohl(req->rq_xid)); 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds 7829903cd1cSChuck Lever /** 7839903cd1cSChuck Lever * xprt_release - release an RPC request slot 7849903cd1cSChuck Lever * @task: task which is finished with the slot 7859903cd1cSChuck Lever * 7861da177e4SLinus Torvalds */ 7879903cd1cSChuck Lever void xprt_release(struct rpc_task *task) 7881da177e4SLinus Torvalds { 7891da177e4SLinus Torvalds struct rpc_xprt *xprt = task->tk_xprt; 7901da177e4SLinus Torvalds struct rpc_rqst *req; 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds if (!(req = task->tk_rqstp)) 7931da177e4SLinus Torvalds return; 7944a0f8c04SChuck Lever spin_lock_bh(&xprt->transport_lock); 7951da177e4SLinus Torvalds __xprt_release_write(xprt, task); 7961da177e4SLinus Torvalds __xprt_put_cong(xprt, req); 7971da177e4SLinus Torvalds if (!list_empty(&req->rq_list)) 7981da177e4SLinus Torvalds list_del(&req->rq_list); 7991da177e4SLinus Torvalds xprt->last_used = jiffies; 8001da177e4SLinus Torvalds if (list_empty(&xprt->recv) && !xprt->shutdown) 801a246b010SChuck Lever mod_timer(&xprt->timer, 802a246b010SChuck Lever xprt->last_used + RPC_IDLE_DISCONNECT_TIMEOUT); 8034a0f8c04SChuck Lever spin_unlock_bh(&xprt->transport_lock); 8041da177e4SLinus Torvalds task->tk_rqstp = NULL; 8051da177e4SLinus Torvalds memset(req, 0, sizeof(*req)); /* mark unused */ 8061da177e4SLinus Torvalds 8071da177e4SLinus Torvalds dprintk("RPC: %4d release request %p\n", task->tk_pid, req); 8081da177e4SLinus Torvalds 8095dc07727SChuck Lever spin_lock(&xprt->reserve_lock); 8101da177e4SLinus Torvalds list_add(&req->rq_list, &xprt->free); 8111da177e4SLinus Torvalds xprt_clear_backlog(xprt); 8125dc07727SChuck Lever spin_unlock(&xprt->reserve_lock); 8131da177e4SLinus Torvalds } 8141da177e4SLinus Torvalds 8159903cd1cSChuck Lever /** 8169903cd1cSChuck Lever * xprt_set_timeout - set constant RPC timeout 8179903cd1cSChuck Lever * @to: RPC timeout parameters to set up 8189903cd1cSChuck Lever * @retr: number of retries 8199903cd1cSChuck Lever * @incr: amount of increase after each retry 8209903cd1cSChuck Lever * 8211da177e4SLinus Torvalds */ 8229903cd1cSChuck Lever void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr) 8231da177e4SLinus Torvalds { 8241da177e4SLinus Torvalds to->to_initval = 8251da177e4SLinus Torvalds to->to_increment = incr; 826eab5c084SChuck Lever to->to_maxval = to->to_initval + (incr * retr); 8271da177e4SLinus Torvalds to->to_retries = retr; 8281da177e4SLinus Torvalds to->to_exponential = 0; 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds 8319903cd1cSChuck Lever static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) 8321da177e4SLinus Torvalds { 833a246b010SChuck Lever int result; 8341da177e4SLinus Torvalds struct rpc_xprt *xprt; 8351da177e4SLinus Torvalds struct rpc_rqst *req; 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) 8381da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 8391da177e4SLinus Torvalds memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */ 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds xprt->addr = *ap; 842a246b010SChuck Lever 843a246b010SChuck Lever switch (proto) { 844a246b010SChuck Lever case IPPROTO_UDP: 845a246b010SChuck Lever result = xs_setup_udp(xprt, to); 846a246b010SChuck Lever break; 847a246b010SChuck Lever case IPPROTO_TCP: 848a246b010SChuck Lever result = xs_setup_tcp(xprt, to); 849a246b010SChuck Lever break; 850a246b010SChuck Lever default: 851a246b010SChuck Lever printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n", 852a246b010SChuck Lever proto); 853a246b010SChuck Lever result = -EIO; 854a246b010SChuck Lever break; 8551da177e4SLinus Torvalds } 856a246b010SChuck Lever if (result) { 857a246b010SChuck Lever kfree(xprt); 858a246b010SChuck Lever return ERR_PTR(result); 859a246b010SChuck Lever } 860a246b010SChuck Lever 8614a0f8c04SChuck Lever spin_lock_init(&xprt->transport_lock); 8625dc07727SChuck Lever spin_lock_init(&xprt->reserve_lock); 8631da177e4SLinus Torvalds init_waitqueue_head(&xprt->cong_wait); 8641da177e4SLinus Torvalds 8651da177e4SLinus Torvalds INIT_LIST_HEAD(&xprt->free); 8661da177e4SLinus Torvalds INIT_LIST_HEAD(&xprt->recv); 86755aa4f58SChuck Lever INIT_WORK(&xprt->task_cleanup, xprt_autoclose, xprt); 8681da177e4SLinus Torvalds init_timer(&xprt->timer); 8691da177e4SLinus Torvalds xprt->timer.function = xprt_init_autodisconnect; 8701da177e4SLinus Torvalds xprt->timer.data = (unsigned long) xprt; 8711da177e4SLinus Torvalds xprt->last_used = jiffies; 8721da177e4SLinus Torvalds 8731da177e4SLinus Torvalds rpc_init_wait_queue(&xprt->pending, "xprt_pending"); 8741da177e4SLinus Torvalds rpc_init_wait_queue(&xprt->sending, "xprt_sending"); 8751da177e4SLinus Torvalds rpc_init_wait_queue(&xprt->resend, "xprt_resend"); 8761da177e4SLinus Torvalds rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog"); 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds /* initialize free list */ 879a246b010SChuck Lever for (req = &xprt->slot[xprt->max_reqs-1]; req >= &xprt->slot[0]; req--) 8801da177e4SLinus Torvalds list_add(&req->rq_list, &xprt->free); 8811da177e4SLinus Torvalds 8821da177e4SLinus Torvalds xprt_init_xid(xprt); 8831da177e4SLinus Torvalds 8841da177e4SLinus Torvalds dprintk("RPC: created transport %p with %u slots\n", xprt, 8851da177e4SLinus Torvalds xprt->max_reqs); 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds return xprt; 8881da177e4SLinus Torvalds } 8891da177e4SLinus Torvalds 8909903cd1cSChuck Lever /** 8919903cd1cSChuck Lever * xprt_create_proto - create an RPC client transport 8929903cd1cSChuck Lever * @proto: requested transport protocol 8939903cd1cSChuck Lever * @sap: remote peer's address 8949903cd1cSChuck Lever * @to: timeout parameters for new transport 8959903cd1cSChuck Lever * 8961da177e4SLinus Torvalds */ 8979903cd1cSChuck Lever struct rpc_xprt *xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) 8981da177e4SLinus Torvalds { 8991da177e4SLinus Torvalds struct rpc_xprt *xprt; 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds xprt = xprt_setup(proto, sap, to); 9021da177e4SLinus Torvalds if (IS_ERR(xprt)) 9031da177e4SLinus Torvalds dprintk("RPC: xprt_create_proto failed\n"); 9041da177e4SLinus Torvalds else 9051da177e4SLinus Torvalds dprintk("RPC: xprt_create_proto created xprt %p\n", xprt); 9061da177e4SLinus Torvalds return xprt; 9071da177e4SLinus Torvalds } 9081da177e4SLinus Torvalds 9099903cd1cSChuck Lever static void xprt_shutdown(struct rpc_xprt *xprt) 9101da177e4SLinus Torvalds { 9111da177e4SLinus Torvalds xprt->shutdown = 1; 9121da177e4SLinus Torvalds rpc_wake_up(&xprt->sending); 9131da177e4SLinus Torvalds rpc_wake_up(&xprt->resend); 91444fbac22SChuck Lever xprt_wake_pending_tasks(xprt, -EIO); 9151da177e4SLinus Torvalds rpc_wake_up(&xprt->backlog); 9161da177e4SLinus Torvalds wake_up(&xprt->cong_wait); 9171da177e4SLinus Torvalds del_timer_sync(&xprt->timer); 9181da177e4SLinus Torvalds } 9191da177e4SLinus Torvalds 9209903cd1cSChuck Lever static int xprt_clear_backlog(struct rpc_xprt *xprt) { 9211da177e4SLinus Torvalds rpc_wake_up_next(&xprt->backlog); 9221da177e4SLinus Torvalds wake_up(&xprt->cong_wait); 9231da177e4SLinus Torvalds return 1; 9241da177e4SLinus Torvalds } 9251da177e4SLinus Torvalds 9269903cd1cSChuck Lever /** 9279903cd1cSChuck Lever * xprt_destroy - destroy an RPC transport, killing off all requests. 9289903cd1cSChuck Lever * @xprt: transport to destroy 9299903cd1cSChuck Lever * 9301da177e4SLinus Torvalds */ 9319903cd1cSChuck Lever int xprt_destroy(struct rpc_xprt *xprt) 9321da177e4SLinus Torvalds { 9331da177e4SLinus Torvalds dprintk("RPC: destroying transport %p\n", xprt); 9341da177e4SLinus Torvalds xprt_shutdown(xprt); 935a246b010SChuck Lever xprt->ops->destroy(xprt); 9361da177e4SLinus Torvalds kfree(xprt); 9371da177e4SLinus Torvalds 9381da177e4SLinus Torvalds return 0; 9391da177e4SLinus Torvalds } 940