diff -u --recursive --new-file linux-2.4.18-svc_tcp/fs/nfs/write.c linux-2.4.18-rpc_tweak/fs/nfs/write.c --- linux-2.4.18-svc_tcp/fs/nfs/write.c Sun Jan 20 18:52:06 2002 +++ linux-2.4.18-rpc_tweak/fs/nfs/write.c Sun Jan 20 18:52:23 2002 @@ -740,6 +740,8 @@ if (dirty >= NFS_STRATEGY_PAGES * wpages) nfs_flush_file(inode, NULL, 0, 0, 0); #endif + if (current->need_resched) + schedule(); } int diff -u --recursive --new-file linux-2.4.18-svc_tcp/include/linux/nfsd/const.h linux-2.4.18-rpc_tweak/include/linux/nfsd/const.h --- linux-2.4.18-svc_tcp/include/linux/nfsd/const.h Sat Apr 1 18:04:27 2000 +++ linux-2.4.18-rpc_tweak/include/linux/nfsd/const.h Fri Jan 11 23:09:30 2002 @@ -21,7 +21,7 @@ /* * Maximum blocksize supported by daemon currently at 8K */ -#define NFSSVC_MAXBLKSIZE 8192 +#define NFSSVC_MAXBLKSIZE (32*1024) #ifdef __KERNEL__ diff -u --recursive --new-file linux-2.4.18-svc_tcp/net/sunrpc/clnt.c linux-2.4.18-rpc_tweak/net/sunrpc/clnt.c --- linux-2.4.18-svc_tcp/net/sunrpc/clnt.c Fri Jan 11 23:08:48 2002 +++ linux-2.4.18-rpc_tweak/net/sunrpc/clnt.c Sun Jan 13 14:50:32 2002 @@ -371,7 +371,6 @@ task->tk_status = 0; task->tk_action = call_reserveresult; task->tk_timeout = clnt->cl_timeout.to_resrvval; - clnt->cl_stats->rpccnt++; xprt_reserve(task); } @@ -395,21 +394,20 @@ task->tk_status, task->tk_rqstp); if (task->tk_status >= 0) { + task->tk_client->cl_stats->rpccnt++; task->tk_action = call_allocate; return; } task->tk_status = 0; switch (status) { + case -ETIMEDOUT: + dprintk("RPC: task timed out\n"); case -EAGAIN: case -ENOBUFS: task->tk_timeout = task->tk_client->cl_timeout.to_resrvval; task->tk_action = call_reserve; break; - case -ETIMEDOUT: - dprintk("RPC: task timed out\n"); - task->tk_action = call_timeout; - break; default: if (!task->tk_rqstp) { printk(KERN_INFO "RPC: task has no request, exit EIO\n"); @@ -444,8 +442,7 @@ printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) { - xprt_release(task); - task->tk_action = call_reserve; + task->tk_action = call_allocate; rpc_delay(task, HZ>>4); return; } diff -u --recursive --new-file linux-2.4.18-svc_tcp/net/sunrpc/sched.c linux-2.4.18-rpc_tweak/net/sunrpc/sched.c --- linux-2.4.18-svc_tcp/net/sunrpc/sched.c Sun Jan 13 15:20:45 2002 +++ linux-2.4.18-rpc_tweak/net/sunrpc/sched.c Sun Jan 20 17:38:03 2002 @@ -104,7 +104,11 @@ static inline void __rpc_disable_timer(struct rpc_task *task) { + struct timer_list *timer = &task->tk_timer; + dprintk("RPC: %4d disabling timer\n", task->tk_pid); + if (timer_pending(timer)) + del_timer(timer); task->tk_timeout_fn = NULL; task->tk_timeout = 0; } @@ -625,6 +629,11 @@ rpc_wake_up_task(task); } } +#if 0 + /* Note: sync_page() is called with TASK_UNINTERRUPTIBLE set */ + if (current->need_resched && current->state == TASK_RUNNING) + schedule(); +#endif } if (task->tk_exit) { @@ -1075,7 +1084,7 @@ } __rpc_schedule(); - if (++rounds >= 64) { /* safeguard */ + if (++rounds >= 64 || current->need_resched) { /* safeguard */ schedule(); rounds = 0; } @@ -1216,12 +1225,12 @@ spin_unlock(&rpc_sched_lock); return; } - printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout " + printk("-pid- proc flgs runs status -client- -prog- --rqstp- -timeout " "-rpcwait -action- --exit--\n"); for (; t; t = next) { next = t->tk_next_task; - printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n", - t->tk_pid, t->tk_msg.rpc_proc, t->tk_flags, t->tk_status, + printk("%05d %04d %04x %04lx %06d %8p %6d %8p %08ld %8s %8p %8p\n", + t->tk_pid, t->tk_msg.rpc_proc, t->tk_flags, t->tk_runstate, t->tk_status, t->tk_client, t->tk_client->cl_prog, t->tk_rqstp, t->tk_timeout, t->tk_rpcwait ? rpc_qname(t->tk_rpcwait) : " ", diff -u --recursive --new-file linux-2.4.18-svc_tcp/net/sunrpc/svcsock.c linux-2.4.18-rpc_tweak/net/sunrpc/svcsock.c --- linux-2.4.18-svc_tcp/net/sunrpc/svcsock.c Mon Jan 14 21:32:51 2002 +++ linux-2.4.18-rpc_tweak/net/sunrpc/svcsock.c Sun Jan 20 23:29:52 2002 @@ -442,7 +442,7 @@ struct svc_serv *serv = svsk->sk_server; struct sk_buff *skb; u32 *data; - int err, len; + int err, len = 0; svsk->sk_data = 0; while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { @@ -455,28 +455,25 @@ /* Sorry. */ if (skb_is_nonlinear(skb)) { - if (skb_linearize(skb, GFP_KERNEL) != 0) { - kfree_skb(skb); - svc_sock_received(svsk, 0); - return 0; - } + if (skb_linearize(skb, GFP_KERNEL) != 0) + goto out; } if (skb->ip_summed != CHECKSUM_UNNECESSARY) { - if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { - skb_free_datagram(svsk->sk_sk, skb); - svc_sock_received(svsk, 0); - return 0; - } + if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) + goto out; } + dst_confirm(skb->dst); + + if (!(rqstp->rq_skbuff = skb_clone(skb, GFP_KERNEL))) + goto out; /* There may be more data */ svsk->sk_data = 1; len = skb->len - sizeof(struct udphdr); data = (u32 *) (skb->data + sizeof(struct udphdr)); - rqstp->rq_skbuff = skb; rqstp->rq_argbuf.base = data; rqstp->rq_argbuf.buf = data; rqstp->rq_argbuf.len = (len >> 2); @@ -496,6 +493,8 @@ /* One down, maybe more to go... */ svsk->sk_sk->stamp = skb->stamp; +out: + skb_free_datagram(svsk->sk_sk, skb); svc_sock_received(svsk, 0); return len; diff -u --recursive --new-file linux-2.4.18-svc_tcp/net/sunrpc/xprt.c linux-2.4.18-rpc_tweak/net/sunrpc/xprt.c --- linux-2.4.18-svc_tcp/net/sunrpc/xprt.c Fri Jan 11 23:07:27 2002 +++ linux-2.4.18-rpc_tweak/net/sunrpc/xprt.c Sun Jan 20 17:23:08 2002 @@ -68,6 +68,8 @@ /* Following value should be > 32k + RPC overhead */ #define XPRT_MIN_WRITE_SPACE (35000 + SOCK_MIN_WRITE_SPACE) +#define XPRT_TCP_DEFAULT_SOCKSIZE (64*1024) +#define XPRT_UDP_DEFAULT_SOCKSIZE (128*1024) extern spinlock_t rpc_queue_lock; @@ -324,29 +326,18 @@ */ spin_lock(&xprt->xprt_lock); cwnd = xprt->cwnd; - if (result >= 0) { - if (xprt->cong < cwnd || time_before(jiffies, xprt->congtime)) - goto out; - /* The (cwnd >> 1) term makes sure - * the result gets rounded properly. */ - cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd; - if (cwnd > RPC_MAXCWND) - cwnd = RPC_MAXCWND; - else - pprintk("RPC: %lu %ld cwnd\n", jiffies, cwnd); - xprt->congtime = jiffies + ((cwnd * HZ) << 2) / RPC_CWNDSCALE; - dprintk("RPC: cong %08lx, cwnd was %08lx, now %08lx, " - "time %ld ms\n", xprt->cong, xprt->cwnd, cwnd, - (xprt->congtime-jiffies)*1000/HZ); - } else if (result == -ETIMEDOUT) { - if ((cwnd >>= 1) < RPC_CWNDSCALE) - cwnd = RPC_CWNDSCALE; - xprt->congtime = jiffies + ((cwnd * HZ) << 3) / RPC_CWNDSCALE; - dprintk("RPC: cong %ld, cwnd was %ld, now %ld, " - "time %ld ms\n", xprt->cong, xprt->cwnd, cwnd, - (xprt->congtime-jiffies)*1000/HZ); - pprintk("RPC: %lu %ld cwnd\n", jiffies, cwnd); - } + /* Ignore if the window is overfull */ + if (xprt->cong > cwnd) + goto out; + if (result >= 0 && cwnd < RPC_MAXCWND) { + cwnd += RPC_CWNDSCALE; + xprt_clear_backlog(xprt); + } else if (result == -ETIMEDOUT) + cwnd = ((cwnd + RPC_CWNDSCALE) >> 1) & ~(RPC_CWNDSCALE - 1); + + dprintk("RPC: cong %08lx, cwnd was %08lx, now %08lx, " + "time %ld ms\n", xprt->cong, xprt->cwnd, cwnd, + (xprt->congtime-jiffies)*1000/HZ); xprt->cwnd = cwnd; out: @@ -729,6 +720,22 @@ } /* + * Check input queue length + */ +static int +tcp_recv_available(struct socket *sock) +{ + mm_segment_t oldfs; + int avail, err; + + oldfs = get_fs(); set_fs(KERNEL_DS); + err = sock->ops->ioctl(sock, TIOCINQ, (unsigned long) &avail); + set_fs(oldfs); + + return (err >= 0)? avail : err; +} + +/* * TCP read fragment marker */ static inline int @@ -883,6 +890,9 @@ if (!(avail = result)) goto out_ok; + if (tcp_recv_available(xprt->sock) < avail) + return -EAGAIN; + /* Find and lock the request corresponding to this xid */ req = xprt_lookup_rqst(xprt, xprt->tcp_xid); if (req) { @@ -1365,9 +1375,6 @@ req->rq_next = NULL; task->tk_rqstp = req; xprt_request_init(task, xprt); - - if (xprt->free) - xprt_clear_backlog(xprt); return; out_nofree: @@ -1587,6 +1594,20 @@ } /* + * Set socket buffer length + */ +static void +xprt_sock_setbufsize(struct socket *sock, unsigned int size) +{ + mm_segment_t oldfs; + + oldfs = get_fs(); set_fs(KERNEL_DS); + sock_setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)); + sock_setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)); + set_fs(oldfs); +} + +/* * Create a client socket given the protocol and peer address. */ static struct socket * @@ -1609,6 +1630,11 @@ if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0) goto failed; + if (proto == IPPROTO_UDP) + xprt_sock_setbufsize(sock, XPRT_UDP_DEFAULT_SOCKSIZE); + else + xprt_sock_setbufsize(sock, XPRT_TCP_DEFAULT_SOCKSIZE); + return sock; failed: