diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2007-02-06 18:26:11 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-02-12 22:40:45 -0800 |
commit | 43d78ef2ba5bec26d0315859e8324bfc0be23766 (patch) | |
tree | 6ea576e0a20a11745c7a45b2a15dd855a45b655a | |
parent | a301b777714087ea1d63dbec0173a13d416cd7a9 (diff) | |
download | linux-3.10-43d78ef2ba5bec26d0315859e8324bfc0be23766.tar.gz linux-3.10-43d78ef2ba5bec26d0315859e8324bfc0be23766.tar.bz2 linux-3.10-43d78ef2ba5bec26d0315859e8324bfc0be23766.zip |
NFS: disconnect before retrying NFSv4 requests over TCP
RFC3530 section 3.1.1 states an NFSv4 client MUST NOT send a request
twice on the same connection unless it is the NULL procedure. Section
3.1.1 suggests that the client should disconnect and reconnect if it
wants to retry a request.
Implement this by adding an rpc_clnt flag that an ULP can use to
specify that the underlying transport should be disconnected on a
major timeout. The NFSv4 client asserts this new flag, and requests
no retries after a minor retransmit timeout.
Note that disconnecting on a retransmit is in general not safe to do
if the RPC client does not reuse the TCP port number when reconnecting.
See http://bugzilla.linux-nfs.org/show_bug.cgi?id=6
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/client.c | 9 | ||||
-rw-r--r-- | include/linux/sunrpc/clnt.h | 2 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 2 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 10 |
4 files changed, 20 insertions, 3 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index a3191f02349..c46e94fed9e 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -394,7 +394,8 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, static int nfs_create_rpc_client(struct nfs_client *clp, int proto, unsigned int timeo, unsigned int retrans, - rpc_authflavor_t flavor) + rpc_authflavor_t flavor, + int flags) { struct rpc_timeout timeparms; struct rpc_clnt *clnt = NULL; @@ -407,6 +408,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto, .program = &nfs_program, .version = clp->rpc_ops->version, .authflavor = flavor, + .flags = flags, }; if (!IS_ERR(clp->cl_rpcclient)) @@ -548,7 +550,7 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data * * - RFC 2623, sec 2.3.2 */ error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans, - RPC_AUTH_UNIX); + RPC_AUTH_UNIX, 0); if (error < 0) goto error; nfs_mark_client_ready(clp, NFS_CS_READY); @@ -868,7 +870,8 @@ static int nfs4_init_client(struct nfs_client *clp, /* Check NFS protocol revision and initialize RPC op vector */ clp->rpc_ops = &nfs_v4_clientops; - error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour); + error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour, + RPC_CLNT_CREATE_DISCRTRY); if (error < 0) goto error; memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index a1be89deb3a..c7a78eef2b4 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -40,6 +40,7 @@ struct rpc_clnt { unsigned int cl_softrtry : 1,/* soft timeouts */ cl_intr : 1,/* interruptible */ + cl_discrtry : 1,/* disconnect before retry */ cl_autobind : 1,/* use getport() */ cl_oneshot : 1,/* dispose after use */ cl_dead : 1;/* abandoned */ @@ -111,6 +112,7 @@ struct rpc_create_args { #define RPC_CLNT_CREATE_ONESHOT (1UL << 3) #define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4) #define RPC_CLNT_CREATE_NOPING (1UL << 5) +#define RPC_CLNT_CREATE_DISCRTRY (1UL << 6) struct rpc_clnt *rpc_create(struct rpc_create_args *args); struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 393e70aee18..c21aa0a7f77 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -249,6 +249,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) clnt->cl_autobind = 1; if (args->flags & RPC_CLNT_CREATE_ONESHOT) clnt->cl_oneshot = 1; + if (args->flags & RPC_CLNT_CREATE_DISCRTRY) + clnt->cl_discrtry = 1; return clnt; } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index cf59f7d315d..1975139b26e 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -735,6 +735,16 @@ void xprt_transmit(struct rpc_task *task) xprt_reset_majortimeo(req); /* Turn off autodisconnect */ del_singleshot_timer_sync(&xprt->timer); + } else { + /* If all request bytes have been sent, + * then we must be retransmitting this one */ + if (!req->rq_bytes_sent) { + if (task->tk_client->cl_discrtry) { + xprt_disconnect(xprt); + task->tk_status = -ENOTCONN; + return; + } + } } } else if (!req->rq_bytes_sent) return; |