Commit 5b9d31ae authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Add a parameter to limit the number of retries after NFS4ERR_DELAY

When using a 'softerr' mount, the NFSv4 client can get stuck waiting
forever while the server just returns NFS4ERR_DELAY. Among other things,
this causes the knfsd server threads to busy wait.
Add a parameter that tells the NFSv4 client how many times to retry
before giving up.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent 05d3ef8b
...@@ -3533,6 +3533,13 @@ ...@@ -3533,6 +3533,13 @@
[NFS] set the TCP port on which the NFSv4 callback [NFS] set the TCP port on which the NFSv4 callback
channel should listen. channel should listen.
nfs.delay_retrans=
[NFS] specifies the number of times the NFSv4 client
retries the request before returning an EAGAIN error,
after a reply of NFS4ERR_DELAY from the server.
Only applies if the softerr mount option is enabled,
and the specified value is >= 0.
nfs.enable_ino64= nfs.enable_ino64=
[NFS] enable 64-bit inode numbers. [NFS] enable 64-bit inode numbers.
If zero, the NFS client will fake up a 32-bit inode If zero, the NFS client will fake up a 32-bit inode
......
...@@ -209,6 +209,7 @@ struct nfs4_exception { ...@@ -209,6 +209,7 @@ struct nfs4_exception {
struct inode *inode; struct inode *inode;
nfs4_stateid *stateid; nfs4_stateid *stateid;
long timeout; long timeout;
unsigned short retrans;
unsigned char task_is_privileged : 1; unsigned char task_is_privileged : 1;
unsigned char delay : 1, unsigned char delay : 1,
recovering : 1, recovering : 1,
...@@ -546,6 +547,7 @@ extern unsigned short max_session_slots; ...@@ -546,6 +547,7 @@ extern unsigned short max_session_slots;
extern unsigned short max_session_cb_slots; extern unsigned short max_session_cb_slots;
extern unsigned short send_implementation_id; extern unsigned short send_implementation_id;
extern bool recover_lost_locks; extern bool recover_lost_locks;
extern short nfs_delay_retrans;
#define NFS4_CLIENT_ID_UNIQ_LEN (64) #define NFS4_CLIENT_ID_UNIQ_LEN (64)
extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN]; extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN];
......
...@@ -585,6 +585,21 @@ static int nfs4_do_handle_exception(struct nfs_server *server, ...@@ -585,6 +585,21 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
return 0; return 0;
} }
/*
* Track the number of NFS4ERR_DELAY related retransmissions and return
* EAGAIN if the 'softerr' mount option is set, and we've exceeded the limit
* set by 'nfs_delay_retrans'.
*/
static int nfs4_exception_should_retrans(const struct nfs_server *server,
struct nfs4_exception *exception)
{
if (server->flags & NFS_MOUNT_SOFTERR && nfs_delay_retrans >= 0) {
if (exception->retrans++ >= (unsigned short)nfs_delay_retrans)
return -EAGAIN;
}
return 0;
}
/* This is the error handling routine for processes that are allowed /* This is the error handling routine for processes that are allowed
* to sleep. * to sleep.
*/ */
...@@ -595,6 +610,11 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_ ...@@ -595,6 +610,11 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
ret = nfs4_do_handle_exception(server, errorcode, exception); ret = nfs4_do_handle_exception(server, errorcode, exception);
if (exception->delay) { if (exception->delay) {
int ret2 = nfs4_exception_should_retrans(server, exception);
if (ret2 < 0) {
exception->retry = 0;
return ret2;
}
ret = nfs4_delay(&exception->timeout, ret = nfs4_delay(&exception->timeout,
exception->interruptible); exception->interruptible);
goto out_retry; goto out_retry;
...@@ -623,6 +643,11 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server, ...@@ -623,6 +643,11 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
ret = nfs4_do_handle_exception(server, errorcode, exception); ret = nfs4_do_handle_exception(server, errorcode, exception);
if (exception->delay) { if (exception->delay) {
int ret2 = nfs4_exception_should_retrans(server, exception);
if (ret2 < 0) {
exception->retry = 0;
return ret2;
}
rpc_delay(task, nfs4_update_delay(&exception->timeout)); rpc_delay(task, nfs4_update_delay(&exception->timeout));
goto out_retry; goto out_retry;
} }
......
...@@ -1366,6 +1366,7 @@ unsigned short max_session_cb_slots = NFS4_DEF_CB_SLOT_TABLE_SIZE; ...@@ -1366,6 +1366,7 @@ unsigned short max_session_cb_slots = NFS4_DEF_CB_SLOT_TABLE_SIZE;
unsigned short send_implementation_id = 1; unsigned short send_implementation_id = 1;
char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN] = ""; char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN] = "";
bool recover_lost_locks = false; bool recover_lost_locks = false;
short nfs_delay_retrans = -1;
EXPORT_SYMBOL_GPL(nfs_callback_nr_threads); EXPORT_SYMBOL_GPL(nfs_callback_nr_threads);
EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport); EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport);
...@@ -1376,6 +1377,7 @@ EXPORT_SYMBOL_GPL(max_session_cb_slots); ...@@ -1376,6 +1377,7 @@ EXPORT_SYMBOL_GPL(max_session_cb_slots);
EXPORT_SYMBOL_GPL(send_implementation_id); EXPORT_SYMBOL_GPL(send_implementation_id);
EXPORT_SYMBOL_GPL(nfs4_client_id_uniquifier); EXPORT_SYMBOL_GPL(nfs4_client_id_uniquifier);
EXPORT_SYMBOL_GPL(recover_lost_locks); EXPORT_SYMBOL_GPL(recover_lost_locks);
EXPORT_SYMBOL_GPL(nfs_delay_retrans);
#define NFS_CALLBACK_MAXPORTNR (65535U) #define NFS_CALLBACK_MAXPORTNR (65535U)
...@@ -1424,5 +1426,9 @@ MODULE_PARM_DESC(recover_lost_locks, ...@@ -1424,5 +1426,9 @@ MODULE_PARM_DESC(recover_lost_locks,
"If the server reports that a lock might be lost, " "If the server reports that a lock might be lost, "
"try to recover it risking data corruption."); "try to recover it risking data corruption.");
module_param_named(delay_retrans, nfs_delay_retrans, short, 0644);
MODULE_PARM_DESC(delay_retrans,
"Unless negative, specifies the number of times the NFSv4 "
"client retries a request before returning an EAGAIN error, "
"after a reply of NFS4ERR_DELAY from the server.");
#endif /* CONFIG_NFS_V4 */ #endif /* CONFIG_NFS_V4 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment