Skip to content

Commit

Permalink
NFS: disconnect before retrying NFSv4 requests over TCP
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Trond Myklebust <[email protected]>
  • Loading branch information
chucklever authored and Trond Myklebust committed Feb 13, 2007
1 parent a301b77 commit 43d78ef
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 3 deletions.
9 changes: 6 additions & 3 deletions fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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))
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand Down
2 changes: 2 additions & 0 deletions include/linux/sunrpc/clnt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 *,
Expand Down
2 changes: 2 additions & 0 deletions net/sunrpc/clnt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
10 changes: 10 additions & 0 deletions net/sunrpc/xprt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 43d78ef

Please sign in to comment.