diff -urN nfs/include/linux/sunrpc/xprt.h nfs-back/include/linux/sunrpc/xprt.h --- nfs/include/linux/sunrpc/xprt.h Fri Mar 29 21:42:44 2002 +++ nfs-back/include/linux/sunrpc/xprt.h Fri Mar 29 21:43:46 2002 @@ -132,6 +132,7 @@ unsigned long cong; /* current congestion */ unsigned long cwnd; /* congestion window */ + unsigned long congtime; /* hold cwnd until then */ int sndsize; /* length send buffer */ int rcvsize; /* length receive buffer */ diff -urN nfs/net/sunrpc/xprt.c nfs-back/net/sunrpc/xprt.c --- nfs/net/sunrpc/xprt.c Fri Mar 29 21:42:44 2002 +++ nfs-back/net/sunrpc/xprt.c Fri Mar 29 21:46:58 2002 @@ -323,16 +323,32 @@ */ spin_lock(&xprt->xprt_lock); cwnd = xprt->cwnd; - if (result >= 0 && cwnd < RPC_MAXCWND && xprt->cong == cwnd) { - cwnd += RPC_CWNDSCALE; - xprt_clear_backlog(xprt); - } else if (result == -ETIMEDOUT && cwnd > RPC_CWNDSCALE) - cwnd -= RPC_CWNDSCALE; - - dprintk("RPC: cong %08lx, cwnd was %08lx, now %08lx\n", - xprt->cong, xprt->cwnd, 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 %4ld, cwnd was %4ld, now %4ld, " + "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 %4ld, cwnd was %4ld, now %4ld, " + "time %ld ms\n", xprt->cong, xprt->cwnd, cwnd, + (xprt->congtime-jiffies)*1000/HZ); + pprintk("RPC: %lu %ld cwnd\n", jiffies, cwnd); + } xprt->cwnd = cwnd; + out: spin_unlock(&xprt->xprt_lock); } @@ -1497,6 +1513,7 @@ xprt->nocong = 1; } else xprt->cwnd = RPC_INITCWND; + xprt->congtime = jiffies; spin_lock_init(&xprt->sock_lock); spin_lock_init(&xprt->xprt_lock); init_waitqueue_head(&xprt->cong_wait);