diff options
-rw-r--r-- | fs/nfs/nfs4proc.c | 92 |
1 files changed, 62 insertions, 30 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d6413b48b057..cab0eb915145 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -389,11 +389,12 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | |||
389 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 389 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
390 | } | 390 | } |
391 | 391 | ||
392 | static void nfs41_sequence_done(struct nfs4_sequence_res *res) | 392 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) |
393 | { | 393 | { |
394 | unsigned long timestamp; | 394 | unsigned long timestamp; |
395 | struct nfs4_slot_table *tbl; | 395 | struct nfs4_slot_table *tbl; |
396 | struct nfs4_slot *slot; | 396 | struct nfs4_slot *slot; |
397 | struct nfs_client *clp; | ||
397 | 398 | ||
398 | /* | 399 | /* |
399 | * sr_status remains 1 if an RPC level error occurred. The server | 400 | * sr_status remains 1 if an RPC level error occurred. The server |
@@ -408,14 +409,16 @@ static void nfs41_sequence_done(struct nfs4_sequence_res *res) | |||
408 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | 409 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) |
409 | goto out; | 410 | goto out; |
410 | 411 | ||
412 | tbl = &res->sr_session->fc_slot_table; | ||
413 | slot = tbl->slots + res->sr_slotid; | ||
414 | |||
411 | /* Check the SEQUENCE operation status */ | 415 | /* Check the SEQUENCE operation status */ |
412 | if (res->sr_status == 0) { | 416 | switch (res->sr_status) { |
413 | struct nfs_client *clp = res->sr_session->clp; | 417 | case 0: |
414 | tbl = &res->sr_session->fc_slot_table; | ||
415 | slot = tbl->slots + res->sr_slotid; | ||
416 | /* Update the slot's sequence and clientid lease timer */ | 418 | /* Update the slot's sequence and clientid lease timer */ |
417 | ++slot->seq_nr; | 419 | ++slot->seq_nr; |
418 | timestamp = res->sr_renewal_time; | 420 | timestamp = res->sr_renewal_time; |
421 | clp = res->sr_session->clp; | ||
419 | spin_lock(&clp->cl_lock); | 422 | spin_lock(&clp->cl_lock); |
420 | if (time_before(clp->cl_last_renewal, timestamp)) | 423 | if (time_before(clp->cl_last_renewal, timestamp)) |
421 | clp->cl_last_renewal = timestamp; | 424 | clp->cl_last_renewal = timestamp; |
@@ -423,18 +426,39 @@ static void nfs41_sequence_done(struct nfs4_sequence_res *res) | |||
423 | /* Check sequence flags */ | 426 | /* Check sequence flags */ |
424 | if (atomic_read(&clp->cl_count) > 1) | 427 | if (atomic_read(&clp->cl_count) > 1) |
425 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | 428 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); |
429 | break; | ||
430 | case -NFS4ERR_DELAY: | ||
431 | /* The server detected a resend of the RPC call and | ||
432 | * returned NFS4ERR_DELAY as per Section 2.10.6.2 | ||
433 | * of RFC5661. | ||
434 | */ | ||
435 | dprintk("%s: slot=%d seq=%d: Operation in progress\n", | ||
436 | __func__, res->sr_slotid, slot->seq_nr); | ||
437 | goto out_retry; | ||
438 | default: | ||
439 | /* Just update the slot sequence no. */ | ||
440 | ++slot->seq_nr; | ||
426 | } | 441 | } |
427 | out: | 442 | out: |
428 | /* The session may be reset by one of the error handlers. */ | 443 | /* The session may be reset by one of the error handlers. */ |
429 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | 444 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); |
430 | nfs41_sequence_free_slot(res); | 445 | nfs41_sequence_free_slot(res); |
446 | return 1; | ||
447 | out_retry: | ||
448 | rpc_restart_call(task); | ||
449 | /* FIXME: rpc_restart_call() should be made to return success/fail */ | ||
450 | if (task->tk_action == NULL) | ||
451 | goto out; | ||
452 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
453 | return 0; | ||
431 | } | 454 | } |
432 | 455 | ||
433 | static void nfs4_sequence_done(const struct nfs_server *server, | 456 | static int nfs4_sequence_done(struct rpc_task *task, |
434 | struct nfs4_sequence_res *res, int rpc_status) | 457 | struct nfs4_sequence_res *res) |
435 | { | 458 | { |
436 | if (res->sr_session != NULL) | 459 | if (res->sr_session == NULL) |
437 | nfs41_sequence_done(res); | 460 | return 1; |
461 | return nfs41_sequence_done(task, res); | ||
438 | } | 462 | } |
439 | 463 | ||
440 | /* | 464 | /* |
@@ -592,7 +616,7 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | |||
592 | { | 616 | { |
593 | struct nfs41_call_sync_data *data = calldata; | 617 | struct nfs41_call_sync_data *data = calldata; |
594 | 618 | ||
595 | nfs41_sequence_done(data->seq_res); | 619 | nfs41_sequence_done(task, data->seq_res); |
596 | } | 620 | } |
597 | 621 | ||
598 | struct rpc_call_ops nfs41_call_sync_ops = { | 622 | struct rpc_call_ops nfs41_call_sync_ops = { |
@@ -650,9 +674,10 @@ int _nfs4_call_sync_session(struct nfs_server *server, | |||
650 | } | 674 | } |
651 | 675 | ||
652 | #else | 676 | #else |
653 | static void nfs4_sequence_done(const struct nfs_server *server, | 677 | static int nfs4_sequence_done(struct rpc_task *task, |
654 | struct nfs4_sequence_res *res, int rpc_status) | 678 | struct nfs4_sequence_res *res) |
655 | { | 679 | { |
680 | return 1; | ||
656 | } | 681 | } |
657 | #endif /* CONFIG_NFS_V4_1 */ | 682 | #endif /* CONFIG_NFS_V4_1 */ |
658 | 683 | ||
@@ -1379,8 +1404,8 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
1379 | 1404 | ||
1380 | data->rpc_status = task->tk_status; | 1405 | data->rpc_status = task->tk_status; |
1381 | 1406 | ||
1382 | nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res, | 1407 | if (!nfs4_sequence_done(task, &data->o_res.seq_res)) |
1383 | task->tk_status); | 1408 | return; |
1384 | 1409 | ||
1385 | if (RPC_ASSASSINATED(task)) | 1410 | if (RPC_ASSASSINATED(task)) |
1386 | return; | 1411 | return; |
@@ -1832,7 +1857,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1832 | struct nfs4_state *state = calldata->state; | 1857 | struct nfs4_state *state = calldata->state; |
1833 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1858 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
1834 | 1859 | ||
1835 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | 1860 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
1861 | return; | ||
1836 | if (RPC_ASSASSINATED(task)) | 1862 | if (RPC_ASSASSINATED(task)) |
1837 | return; | 1863 | return; |
1838 | /* hmm. we are done with the inode, and in the process of freeing | 1864 | /* hmm. we are done with the inode, and in the process of freeing |
@@ -2642,7 +2668,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2642 | { | 2668 | { |
2643 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2669 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
2644 | 2670 | ||
2645 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | 2671 | if (!nfs4_sequence_done(task, &res->seq_res)) |
2672 | return 0; | ||
2646 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2673 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2647 | return 0; | 2674 | return 0; |
2648 | update_changeattr(dir, &res->cinfo); | 2675 | update_changeattr(dir, &res->cinfo); |
@@ -3087,7 +3114,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
3087 | 3114 | ||
3088 | dprintk("--> %s\n", __func__); | 3115 | dprintk("--> %s\n", __func__); |
3089 | 3116 | ||
3090 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | 3117 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3118 | return -EAGAIN; | ||
3091 | 3119 | ||
3092 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 3120 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
3093 | nfs_restart_rpc(task, server->nfs_client); | 3121 | nfs_restart_rpc(task, server->nfs_client); |
@@ -3110,8 +3138,8 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3110 | { | 3138 | { |
3111 | struct inode *inode = data->inode; | 3139 | struct inode *inode = data->inode; |
3112 | 3140 | ||
3113 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3141 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3114 | task->tk_status); | 3142 | return -EAGAIN; |
3115 | 3143 | ||
3116 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 3144 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
3117 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3145 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
@@ -3139,8 +3167,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3139 | { | 3167 | { |
3140 | struct inode *inode = data->inode; | 3168 | struct inode *inode = data->inode; |
3141 | 3169 | ||
3142 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3170 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3143 | task->tk_status); | 3171 | return -EAGAIN; |
3172 | |||
3144 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3173 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
3145 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3174 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
3146 | return -EAGAIN; | 3175 | return -EAGAIN; |
@@ -3630,8 +3659,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
3630 | { | 3659 | { |
3631 | struct nfs4_delegreturndata *data = calldata; | 3660 | struct nfs4_delegreturndata *data = calldata; |
3632 | 3661 | ||
3633 | nfs4_sequence_done(data->res.server, &data->res.seq_res, | 3662 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3634 | task->tk_status); | 3663 | return; |
3635 | 3664 | ||
3636 | switch (task->tk_status) { | 3665 | switch (task->tk_status) { |
3637 | case -NFS4ERR_STALE_STATEID: | 3666 | case -NFS4ERR_STALE_STATEID: |
@@ -3881,8 +3910,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3881 | { | 3910 | { |
3882 | struct nfs4_unlockdata *calldata = data; | 3911 | struct nfs4_unlockdata *calldata = data; |
3883 | 3912 | ||
3884 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | 3913 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
3885 | task->tk_status); | 3914 | return; |
3886 | if (RPC_ASSASSINATED(task)) | 3915 | if (RPC_ASSASSINATED(task)) |
3887 | return; | 3916 | return; |
3888 | switch (task->tk_status) { | 3917 | switch (task->tk_status) { |
@@ -4091,8 +4120,8 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
4091 | 4120 | ||
4092 | dprintk("%s: begin!\n", __func__); | 4121 | dprintk("%s: begin!\n", __func__); |
4093 | 4122 | ||
4094 | nfs4_sequence_done(data->server, &data->res.seq_res, | 4123 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
4095 | task->tk_status); | 4124 | return; |
4096 | 4125 | ||
4097 | data->rpc_status = task->tk_status; | 4126 | data->rpc_status = task->tk_status; |
4098 | if (RPC_ASSASSINATED(task)) | 4127 | if (RPC_ASSASSINATED(task)) |
@@ -4629,7 +4658,8 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
4629 | (struct nfs4_get_lease_time_data *)calldata; | 4658 | (struct nfs4_get_lease_time_data *)calldata; |
4630 | 4659 | ||
4631 | dprintk("--> %s\n", __func__); | 4660 | dprintk("--> %s\n", __func__); |
4632 | nfs41_sequence_done(&data->res->lr_seq_res); | 4661 | if (!nfs41_sequence_done(task, &data->res->lr_seq_res)) |
4662 | return; | ||
4633 | switch (task->tk_status) { | 4663 | switch (task->tk_status) { |
4634 | case -NFS4ERR_DELAY: | 4664 | case -NFS4ERR_DELAY: |
4635 | case -NFS4ERR_GRACE: | 4665 | case -NFS4ERR_GRACE: |
@@ -5111,7 +5141,8 @@ static void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
5111 | struct nfs4_sequence_data *calldata = data; | 5141 | struct nfs4_sequence_data *calldata = data; |
5112 | struct nfs_client *clp = calldata->clp; | 5142 | struct nfs_client *clp = calldata->clp; |
5113 | 5143 | ||
5114 | nfs41_sequence_done(task->tk_msg.rpc_resp); | 5144 | if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp)) |
5145 | return; | ||
5115 | 5146 | ||
5116 | if (task->tk_status < 0) { | 5147 | if (task->tk_status < 0) { |
5117 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | 5148 | dprintk("%s ERROR %d\n", __func__, task->tk_status); |
@@ -5255,7 +5286,8 @@ static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | |||
5255 | struct nfs4_sequence_res *res = &calldata->res.seq_res; | 5286 | struct nfs4_sequence_res *res = &calldata->res.seq_res; |
5256 | 5287 | ||
5257 | dprintk("--> %s\n", __func__); | 5288 | dprintk("--> %s\n", __func__); |
5258 | nfs41_sequence_done(res); | 5289 | if (!nfs41_sequence_done(task, res)) |
5290 | return; | ||
5259 | 5291 | ||
5260 | if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) { | 5292 | if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) { |
5261 | rpc_restart_call_prepare(task); | 5293 | rpc_restart_call_prepare(task); |