[PATCH] NFS: use a constant value for TCP retransmit timeouts
authorChuck Lever <cel@citi.umich.edu>
Thu, 11 Aug 2005 20:25:14 +0000 (16:25 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 23 Sep 2005 16:38:06 +0000 (12:38 -0400)
 Implement a best practice: don't use exponential backoff when computing
 retransmit timeout values on TCP connections, but simply retransmit
 at regular intervals.

 This also fixes a bug introduced when xprt_reset_majortimeo() was added.

 Test-plan:
 Enable RPC debugging and watch timeout behavior on a NFS/TCP mount.

 Version: Thu, 11 Aug 2005 16:02:19 -0400

Signed-off-by: Chuck Lever <cel@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/inode.c
net/sunrpc/xprt.c

index 6922469..b6a1ca5 100644 (file)
@@ -358,6 +358,35 @@ out_no_root:
        return no_root_error;
 }
 
+static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans)
+{
+       to->to_initval = timeo * HZ / 10;
+       to->to_retries = retrans;
+       if (!to->to_retries)
+               to->to_retries = 2;
+
+       switch (proto) {
+       case IPPROTO_TCP:
+               if (!to->to_initval)
+                       to->to_initval = 60 * HZ;
+               if (to->to_initval > RPC_MAX_TCP_TIMEOUT)
+                       to->to_initval = RPC_MAX_TCP_TIMEOUT;
+               to->to_increment = to->to_initval;
+               to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
+               to->to_exponential = 0;
+               break;
+       case IPPROTO_UDP:
+       default:
+               if (!to->to_initval)
+                       to->to_initval = 11 * HZ / 10;
+               if (to->to_initval > RPC_MAX_UDP_TIMEOUT)
+                       to->to_initval = RPC_MAX_UDP_TIMEOUT;
+               to->to_maxval = RPC_MAX_UDP_TIMEOUT;
+               to->to_exponential = 1;
+               break;
+       }
+}
+
 /*
  * Create an RPC client handle.
  */
@@ -367,22 +396,12 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
        struct rpc_timeout      timeparms;
        struct rpc_xprt         *xprt = NULL;
        struct rpc_clnt         *clnt = NULL;
-       int                     tcp   = (data->flags & NFS_MOUNT_TCP);
-
-       /* Initialize timeout values */
-       timeparms.to_initval = data->timeo * HZ / 10;
-       timeparms.to_retries = data->retrans;
-       timeparms.to_maxval  = tcp ? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT;
-       timeparms.to_exponential = 1;
+       int                     proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
 
-       if (!timeparms.to_initval)
-               timeparms.to_initval = (tcp ? 600 : 11) * HZ / 10;
-       if (!timeparms.to_retries)
-               timeparms.to_retries = 5;
+       nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans);
 
        /* create transport and client */
-       xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP,
-                                &server->addr, &timeparms);
+       xprt = xprt_create_proto(proto, &server->addr, &timeparms);
        if (IS_ERR(xprt)) {
                dprintk("%s: cannot create RPC transport. Error = %ld\n",
                                __FUNCTION__, PTR_ERR(xprt));
@@ -1674,7 +1693,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
        struct rpc_clnt *clnt = NULL;
        struct rpc_timeout timeparms;
        rpc_authflavor_t authflavour;
-       int proto, err = -EIO;
+       int err = -EIO;
 
        sb->s_blocksize_bits = 0;
        sb->s_blocksize = 0;
@@ -1692,30 +1711,8 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
        server->acdirmax = data->acdirmax*HZ;
 
        server->rpc_ops = &nfs_v4_clientops;
-       /* Initialize timeout values */
-
-       timeparms.to_initval = data->timeo * HZ / 10;
-       timeparms.to_retries = data->retrans;
-       timeparms.to_exponential = 1;
-       if (!timeparms.to_retries)
-               timeparms.to_retries = 5;
 
-       proto = data->proto;
-       /* Which IP protocol do we use? */
-       switch (proto) {
-       case IPPROTO_TCP:
-               timeparms.to_maxval  = RPC_MAX_TCP_TIMEOUT;
-               if (!timeparms.to_initval)
-                       timeparms.to_initval = 600 * HZ / 10;
-               break;
-       case IPPROTO_UDP:
-               timeparms.to_maxval  = RPC_MAX_UDP_TIMEOUT;
-               if (!timeparms.to_initval)
-                       timeparms.to_initval = 11 * HZ / 10;
-               break;
-       default:
-               return -EINVAL;
-       }
+       nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans);
 
        clp = nfs4_get_client(&server->addr.sin_addr);
        if (!clp) {
@@ -1740,7 +1737,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
 
        down_write(&clp->cl_sem);
        if (IS_ERR(clp->cl_rpcclient)) {
-               xprt = xprt_create_proto(proto, &server->addr, &timeparms);
+               xprt = xprt_create_proto(data->proto, &server->addr, &timeparms);
                if (IS_ERR(xprt)) {
                        up_write(&clp->cl_sem);
                        err = PTR_ERR(xprt);
index b28ea0c..0e4ffda 100644 (file)
@@ -1453,7 +1453,7 @@ xprt_default_timeout(struct rpc_timeout *to, int proto)
        if (proto == IPPROTO_UDP)
                xprt_set_timeout(to, 5,  5 * HZ);
        else
-               xprt_set_timeout(to, 5, 60 * HZ);
+               xprt_set_timeout(to, 2, 60 * HZ);
 }
 
 /*
@@ -1464,7 +1464,7 @@ xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr)
 {
        to->to_initval   = 
        to->to_increment = incr;
-       to->to_maxval    = incr * retr;
+       to->to_maxval    = to->to_initval + (incr * retr);
        to->to_retries   = retr;
        to->to_exponential = 0;
 }