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>
This commit is contained in:
committed by
Trond Myklebust
parent
a301b77771
commit
43d78ef2ba
@@ -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,
|
static int nfs_create_rpc_client(struct nfs_client *clp, int proto,
|
||||||
unsigned int timeo,
|
unsigned int timeo,
|
||||||
unsigned int retrans,
|
unsigned int retrans,
|
||||||
rpc_authflavor_t flavor)
|
rpc_authflavor_t flavor,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
struct rpc_timeout timeparms;
|
struct rpc_timeout timeparms;
|
||||||
struct rpc_clnt *clnt = NULL;
|
struct rpc_clnt *clnt = NULL;
|
||||||
@@ -407,6 +408,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto,
|
|||||||
.program = &nfs_program,
|
.program = &nfs_program,
|
||||||
.version = clp->rpc_ops->version,
|
.version = clp->rpc_ops->version,
|
||||||
.authflavor = flavor,
|
.authflavor = flavor,
|
||||||
|
.flags = flags,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!IS_ERR(clp->cl_rpcclient))
|
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
|
* - RFC 2623, sec 2.3.2
|
||||||
*/
|
*/
|
||||||
error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans,
|
error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans,
|
||||||
RPC_AUTH_UNIX);
|
RPC_AUTH_UNIX, 0);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto error;
|
goto error;
|
||||||
nfs_mark_client_ready(clp, NFS_CS_READY);
|
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 */
|
/* Check NFS protocol revision and initialize RPC op vector */
|
||||||
clp->rpc_ops = &nfs_v4_clientops;
|
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)
|
if (error < 0)
|
||||||
goto error;
|
goto error;
|
||||||
memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
|
memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
|
||||||
|
@@ -40,6 +40,7 @@ struct rpc_clnt {
|
|||||||
|
|
||||||
unsigned int cl_softrtry : 1,/* soft timeouts */
|
unsigned int cl_softrtry : 1,/* soft timeouts */
|
||||||
cl_intr : 1,/* interruptible */
|
cl_intr : 1,/* interruptible */
|
||||||
|
cl_discrtry : 1,/* disconnect before retry */
|
||||||
cl_autobind : 1,/* use getport() */
|
cl_autobind : 1,/* use getport() */
|
||||||
cl_oneshot : 1,/* dispose after use */
|
cl_oneshot : 1,/* dispose after use */
|
||||||
cl_dead : 1;/* abandoned */
|
cl_dead : 1;/* abandoned */
|
||||||
@@ -111,6 +112,7 @@ struct rpc_create_args {
|
|||||||
#define RPC_CLNT_CREATE_ONESHOT (1UL << 3)
|
#define RPC_CLNT_CREATE_ONESHOT (1UL << 3)
|
||||||
#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4)
|
#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4)
|
||||||
#define RPC_CLNT_CREATE_NOPING (1UL << 5)
|
#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_create(struct rpc_create_args *args);
|
||||||
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
|
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
|
||||||
|
@@ -249,6 +249,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
|
|||||||
clnt->cl_autobind = 1;
|
clnt->cl_autobind = 1;
|
||||||
if (args->flags & RPC_CLNT_CREATE_ONESHOT)
|
if (args->flags & RPC_CLNT_CREATE_ONESHOT)
|
||||||
clnt->cl_oneshot = 1;
|
clnt->cl_oneshot = 1;
|
||||||
|
if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
|
||||||
|
clnt->cl_discrtry = 1;
|
||||||
|
|
||||||
return clnt;
|
return clnt;
|
||||||
}
|
}
|
||||||
|
@@ -735,6 +735,16 @@ void xprt_transmit(struct rpc_task *task)
|
|||||||
xprt_reset_majortimeo(req);
|
xprt_reset_majortimeo(req);
|
||||||
/* Turn off autodisconnect */
|
/* Turn off autodisconnect */
|
||||||
del_singleshot_timer_sync(&xprt->timer);
|
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)
|
} else if (!req->rq_bytes_sent)
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user