Skip to content

Commit 8478eaa

Browse files
neilbrowntrondmypd
authored andcommitted
NFSv4: use exponential retry on NFS4ERR_DELAY for async requests.
Currently asynchronous NFSv4 request will be retried with exponential timeout (from 1/10 to 15 seconds), but async requests will always use a 15second retry. Some "async" requests are really synchronous though. The async mechanism is used to allow the request to continue if the requesting process is killed. In those cases, an exponential retry is appropriate. For example, if two different clients both open a file and get a READ delegation, and one client then unlinks the file (while still holding an open file descriptor), that unlink will used the "silly-rename" handling which is async. The first rename will result in NFS4ERR_DELAY while the delegation is reclaimed from the other client. The rename will not be retried for 15 seconds, causing an unlink to take 15 seconds rather than 100msec. This patch only added exponential timeout for async unlink and async rename. Other async calls, such as 'close' are sometimes waited for so they might benefit from exponential timeout too. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
1 parent 3dedbb5 commit 8478eaa

File tree

2 files changed

+44
-23
lines changed

2 files changed

+44
-23
lines changed

fs/nfs/nfs4proc.c

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ struct nfs4_opendata;
7777
static int _nfs4_proc_open(struct nfs4_opendata *data);
7878
static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
7979
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
80-
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
80+
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *, long *);
8181
static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
8282
static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label);
8383
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label);
@@ -314,20 +314,30 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
314314
kunmap_atomic(start);
315315
}
316316

317+
static long nfs4_update_delay(long *timeout)
318+
{
319+
long ret;
320+
if (!timeout)
321+
return NFS4_POLL_RETRY_MAX;
322+
if (*timeout <= 0)
323+
*timeout = NFS4_POLL_RETRY_MIN;
324+
if (*timeout > NFS4_POLL_RETRY_MAX)
325+
*timeout = NFS4_POLL_RETRY_MAX;
326+
ret = *timeout;
327+
*timeout <<= 1;
328+
return ret;
329+
}
330+
317331
static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
318332
{
319333
int res = 0;
320334

321335
might_sleep();
322336

323-
if (*timeout <= 0)
324-
*timeout = NFS4_POLL_RETRY_MIN;
325-
if (*timeout > NFS4_POLL_RETRY_MAX)
326-
*timeout = NFS4_POLL_RETRY_MAX;
327-
freezable_schedule_timeout_killable_unsafe(*timeout);
337+
freezable_schedule_timeout_killable_unsafe(
338+
nfs4_update_delay(timeout));
328339
if (fatal_signal_pending(current))
329340
res = -ERESTARTSYS;
330-
*timeout <<= 1;
331341
return res;
332342
}
333343

@@ -2583,7 +2593,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
25832593
if (calldata->arg.fmode == 0)
25842594
break;
25852595
default:
2586-
if (nfs4_async_handle_error(task, server, state) == -EAGAIN) {
2596+
if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) {
25872597
rpc_restart_call_prepare(task);
25882598
goto out_release;
25892599
}
@@ -3572,7 +3582,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
35723582

35733583
if (!nfs4_sequence_done(task, &res->seq_res))
35743584
return 0;
3575-
if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
3585+
if (nfs4_async_handle_error(task, res->server, NULL,
3586+
&data->timeout) == -EAGAIN)
35763587
return 0;
35773588
update_changeattr(dir, &res->cinfo);
35783589
return 1;
@@ -3605,7 +3616,7 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
36053616

36063617
if (!nfs4_sequence_done(task, &res->seq_res))
36073618
return 0;
3608-
if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
3619+
if (nfs4_async_handle_error(task, res->server, NULL, &data->timeout) == -EAGAIN)
36093620
return 0;
36103621

36113622
update_changeattr(old_dir, &res->old_cinfo);
@@ -4109,7 +4120,8 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr)
41094120

41104121
trace_nfs4_read(hdr, task->tk_status);
41114122
if (nfs4_async_handle_error(task, server,
4112-
hdr->args.context->state) == -EAGAIN) {
4123+
hdr->args.context->state,
4124+
NULL) == -EAGAIN) {
41134125
rpc_restart_call_prepare(task);
41144126
return -EAGAIN;
41154127
}
@@ -4177,10 +4189,11 @@ static int nfs4_write_done_cb(struct rpc_task *task,
41774189
struct nfs_pgio_header *hdr)
41784190
{
41794191
struct inode *inode = hdr->inode;
4180-
4192+
41814193
trace_nfs4_write(hdr, task->tk_status);
41824194
if (nfs4_async_handle_error(task, NFS_SERVER(inode),
4183-
hdr->args.context->state) == -EAGAIN) {
4195+
hdr->args.context->state,
4196+
NULL) == -EAGAIN) {
41844197
rpc_restart_call_prepare(task);
41854198
return -EAGAIN;
41864199
}
@@ -4260,7 +4273,8 @@ static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *da
42604273
struct inode *inode = data->inode;
42614274

42624275
trace_nfs4_commit(data, task->tk_status);
4263-
if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
4276+
if (nfs4_async_handle_error(task, NFS_SERVER(inode),
4277+
NULL, NULL) == -EAGAIN) {
42644278
rpc_restart_call_prepare(task);
42654279
return -EAGAIN;
42664280
}
@@ -4813,7 +4827,8 @@ nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen)
48134827

48144828

48154829
static int
4816-
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
4830+
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
4831+
struct nfs4_state *state, long *timeout)
48174832
{
48184833
struct nfs_client *clp = server->nfs_client;
48194834

@@ -4863,6 +4878,8 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
48634878
#endif /* CONFIG_NFS_V4_1 */
48644879
case -NFS4ERR_DELAY:
48654880
nfs_inc_server_stats(server, NFSIOS_DELAY);
4881+
rpc_delay(task, nfs4_update_delay(timeout));
4882+
goto restart_call;
48664883
case -NFS4ERR_GRACE:
48674884
rpc_delay(task, NFS4_POLL_RETRY_MAX);
48684885
case -NFS4ERR_RETRY_UNCACHED_REP:
@@ -5103,8 +5120,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
51035120
pnfs_roc_set_barrier(data->inode, data->roc_barrier);
51045121
break;
51055122
default:
5106-
if (nfs4_async_handle_error(task, data->res.server, NULL) ==
5107-
-EAGAIN) {
5123+
if (nfs4_async_handle_error(task, data->res.server,
5124+
NULL, NULL) == -EAGAIN) {
51085125
rpc_restart_call_prepare(task);
51095126
return;
51105127
}
@@ -5368,7 +5385,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
53685385
case -NFS4ERR_EXPIRED:
53695386
break;
53705387
default:
5371-
if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
5388+
if (nfs4_async_handle_error(task, calldata->server,
5389+
NULL, NULL) == -EAGAIN)
53725390
rpc_restart_call_prepare(task);
53735391
}
53745392
nfs_release_seqid(calldata->arg.seqid);
@@ -5974,7 +5992,8 @@ static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
59745992
break;
59755993
case -NFS4ERR_LEASE_MOVED:
59765994
case -NFS4ERR_DELAY:
5977-
if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN)
5995+
if (nfs4_async_handle_error(task, server,
5996+
NULL, NULL) == -EAGAIN)
59785997
rpc_restart_call_prepare(task);
59795998
}
59805999
}
@@ -7591,7 +7610,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
75917610
rpc_restart_call_prepare(task);
75927611
}
75937612
}
7594-
if (nfs4_async_handle_error(task, server, state) == -EAGAIN)
7613+
if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN)
75957614
rpc_restart_call_prepare(task);
75967615
out:
75977616
dprintk("<-- %s\n", __func__);
@@ -7751,7 +7770,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
77517770
case 0:
77527771
break;
77537772
case -NFS4ERR_DELAY:
7754-
if (nfs4_async_handle_error(task, server, NULL) != -EAGAIN)
7773+
if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN)
77557774
break;
77567775
rpc_restart_call_prepare(task);
77577776
return;
@@ -7882,7 +7901,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
78827901
case 0:
78837902
break;
78847903
default:
7885-
if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
7904+
if (nfs4_async_handle_error(task, server, NULL, NULL) == -EAGAIN) {
78867905
rpc_restart_call_prepare(task);
78877906
return;
78887907
}
@@ -8178,7 +8197,7 @@ static void nfs41_free_stateid_done(struct rpc_task *task, void *calldata)
81788197

81798198
switch (task->tk_status) {
81808199
case -NFS4ERR_DELAY:
8181-
if (nfs4_async_handle_error(task, data->server, NULL) == -EAGAIN)
8200+
if (nfs4_async_handle_error(task, data->server, NULL, NULL) == -EAGAIN)
81828201
rpc_restart_call_prepare(task);
81838202
}
81848203
}

include/linux/nfs_xdr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,7 @@ struct nfs_unlinkdata {
13391339
struct inode *dir;
13401340
struct rpc_cred *cred;
13411341
struct nfs_fattr dir_attr;
1342+
long timeout;
13421343
};
13431344

13441345
struct nfs_renamedata {
@@ -1352,6 +1353,7 @@ struct nfs_renamedata {
13521353
struct dentry *new_dentry;
13531354
struct nfs_fattr new_fattr;
13541355
void (*complete)(struct rpc_task *, struct nfs_renamedata *);
1356+
long timeout;
13551357
};
13561358

13571359
struct nfs_access_entry;

0 commit comments

Comments
 (0)