diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-12-23 15:21:46 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-12-23 15:21:46 -0500 |
commit | 9e33bed55239bdcee1746c31a11177d239bac1b5 (patch) | |
tree | b6ff90aa50b1d71722ce8eb3f2cecc28dafc3e4d /fs/nfs | |
parent | 95d35cb4c473c754824967c0b069bbeb7efa4847 (diff) |
NFSv4: Add recovery for individual stateids
NFSv4 defines a number of state errors which the client does not currently
handle. Among those we should worry about are:
NFS4ERR_ADMIN_REVOKED - the server's administrator revoked our locks
and/or delegations.
NFS4ERR_BAD_STATEID - the client and server are out of sync, possibly
due to a delegation return racing with an OPEN
request.
NFS4ERR_OPENMODE - the client attempted to do something not sanctioned
by the open mode of the stateid. Should normally just
occur as a result of a delegation return race.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 37 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 2 |
3 files changed, 31 insertions, 10 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index a4e7b3feef8f..46cbc0cdf885 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -169,6 +169,7 @@ struct nfs4_state { | |||
169 | struct nfs4_exception { | 169 | struct nfs4_exception { |
170 | long timeout; | 170 | long timeout; |
171 | int retry; | 171 | int retry; |
172 | struct nfs4_state *state; | ||
172 | }; | 173 | }; |
173 | 174 | ||
174 | struct nfs4_state_recovery_ops { | 175 | struct nfs4_state_recovery_ops { |
@@ -226,6 +227,7 @@ extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t); | |||
226 | extern void nfs4_close_sync(struct path *, struct nfs4_state *, mode_t); | 227 | extern void nfs4_close_sync(struct path *, struct nfs4_state *, mode_t); |
227 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); | 228 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); |
228 | extern void nfs4_schedule_state_recovery(struct nfs_client *); | 229 | extern void nfs4_schedule_state_recovery(struct nfs_client *); |
230 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); | ||
229 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 231 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
230 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 232 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
231 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 233 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 26dcd77abb07..8a2dee9caa6e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -62,7 +62,7 @@ | |||
62 | struct nfs4_opendata; | 62 | struct nfs4_opendata; |
63 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 63 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
64 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 64 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
65 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 65 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
66 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 66 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
67 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 67 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
68 | 68 | ||
@@ -235,12 +235,19 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
235 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | 235 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) |
236 | { | 236 | { |
237 | struct nfs_client *clp = server->nfs_client; | 237 | struct nfs_client *clp = server->nfs_client; |
238 | struct nfs4_state *state = exception->state; | ||
238 | int ret = errorcode; | 239 | int ret = errorcode; |
239 | 240 | ||
240 | exception->retry = 0; | 241 | exception->retry = 0; |
241 | switch(errorcode) { | 242 | switch(errorcode) { |
242 | case 0: | 243 | case 0: |
243 | return 0; | 244 | return 0; |
245 | case -NFS4ERR_ADMIN_REVOKED: | ||
246 | case -NFS4ERR_BAD_STATEID: | ||
247 | case -NFS4ERR_OPENMODE: | ||
248 | if (state == NULL) | ||
249 | break; | ||
250 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
244 | case -NFS4ERR_STALE_CLIENTID: | 251 | case -NFS4ERR_STALE_CLIENTID: |
245 | case -NFS4ERR_STALE_STATEID: | 252 | case -NFS4ERR_STALE_STATEID: |
246 | case -NFS4ERR_EXPIRED: | 253 | case -NFS4ERR_EXPIRED: |
@@ -1320,10 +1327,13 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1320 | renew_lease(server, calldata->timestamp); | 1327 | renew_lease(server, calldata->timestamp); |
1321 | break; | 1328 | break; |
1322 | case -NFS4ERR_STALE_STATEID: | 1329 | case -NFS4ERR_STALE_STATEID: |
1330 | case -NFS4ERR_OLD_STATEID: | ||
1331 | case -NFS4ERR_BAD_STATEID: | ||
1323 | case -NFS4ERR_EXPIRED: | 1332 | case -NFS4ERR_EXPIRED: |
1324 | break; | 1333 | if (calldata->arg.open_flags == 0) |
1334 | break; | ||
1325 | default: | 1335 | default: |
1326 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 1336 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
1327 | rpc_restart_call(task); | 1337 | rpc_restart_call(task); |
1328 | return; | 1338 | return; |
1329 | } | 1339 | } |
@@ -1418,6 +1428,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1418 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1428 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1419 | if (calldata->arg.seqid == NULL) | 1429 | if (calldata->arg.seqid == NULL) |
1420 | goto out_free_calldata; | 1430 | goto out_free_calldata; |
1431 | calldata->arg.open_flags = 0; | ||
1421 | calldata->arg.bitmask = server->attr_bitmask; | 1432 | calldata->arg.bitmask = server->attr_bitmask; |
1422 | calldata->res.fattr = &calldata->fattr; | 1433 | calldata->res.fattr = &calldata->fattr; |
1423 | calldata->res.seqid = calldata->arg.seqid; | 1434 | calldata->res.seqid = calldata->arg.seqid; |
@@ -2064,7 +2075,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2064 | { | 2075 | { |
2065 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2076 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
2066 | 2077 | ||
2067 | if (nfs4_async_handle_error(task, res->server) == -EAGAIN) | 2078 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2068 | return 0; | 2079 | return 0; |
2069 | update_changeattr(dir, &res->cinfo); | 2080 | update_changeattr(dir, &res->cinfo); |
2070 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2081 | nfs_post_op_update_inode(dir, &res->dir_attr); |
@@ -2492,7 +2503,7 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2492 | { | 2503 | { |
2493 | struct nfs_server *server = NFS_SERVER(data->inode); | 2504 | struct nfs_server *server = NFS_SERVER(data->inode); |
2494 | 2505 | ||
2495 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 2506 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2496 | rpc_restart_call(task); | 2507 | rpc_restart_call(task); |
2497 | return -EAGAIN; | 2508 | return -EAGAIN; |
2498 | } | 2509 | } |
@@ -2513,7 +2524,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2513 | { | 2524 | { |
2514 | struct inode *inode = data->inode; | 2525 | struct inode *inode = data->inode; |
2515 | 2526 | ||
2516 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2527 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
2517 | rpc_restart_call(task); | 2528 | rpc_restart_call(task); |
2518 | return -EAGAIN; | 2529 | return -EAGAIN; |
2519 | } | 2530 | } |
@@ -2539,7 +2550,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2539 | { | 2550 | { |
2540 | struct inode *inode = data->inode; | 2551 | struct inode *inode = data->inode; |
2541 | 2552 | ||
2542 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2553 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
2543 | rpc_restart_call(task); | 2554 | rpc_restart_call(task); |
2544 | return -EAGAIN; | 2555 | return -EAGAIN; |
2545 | } | 2556 | } |
@@ -2832,13 +2843,19 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2832 | } | 2843 | } |
2833 | 2844 | ||
2834 | static int | 2845 | static int |
2835 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | 2846 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) |
2836 | { | 2847 | { |
2837 | struct nfs_client *clp = server->nfs_client; | 2848 | struct nfs_client *clp = server->nfs_client; |
2838 | 2849 | ||
2839 | if (!clp || task->tk_status >= 0) | 2850 | if (!clp || task->tk_status >= 0) |
2840 | return 0; | 2851 | return 0; |
2841 | switch(task->tk_status) { | 2852 | switch(task->tk_status) { |
2853 | case -NFS4ERR_ADMIN_REVOKED: | ||
2854 | case -NFS4ERR_BAD_STATEID: | ||
2855 | case -NFS4ERR_OPENMODE: | ||
2856 | if (state == NULL) | ||
2857 | break; | ||
2858 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
2842 | case -NFS4ERR_STALE_CLIENTID: | 2859 | case -NFS4ERR_STALE_CLIENTID: |
2843 | case -NFS4ERR_STALE_STATEID: | 2860 | case -NFS4ERR_STALE_STATEID: |
2844 | case -NFS4ERR_EXPIRED: | 2861 | case -NFS4ERR_EXPIRED: |
@@ -3195,11 +3212,13 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3195 | sizeof(calldata->lsp->ls_stateid.data)); | 3212 | sizeof(calldata->lsp->ls_stateid.data)); |
3196 | renew_lease(calldata->server, calldata->timestamp); | 3213 | renew_lease(calldata->server, calldata->timestamp); |
3197 | break; | 3214 | break; |
3215 | case -NFS4ERR_BAD_STATEID: | ||
3216 | case -NFS4ERR_OLD_STATEID: | ||
3198 | case -NFS4ERR_STALE_STATEID: | 3217 | case -NFS4ERR_STALE_STATEID: |
3199 | case -NFS4ERR_EXPIRED: | 3218 | case -NFS4ERR_EXPIRED: |
3200 | break; | 3219 | break; |
3201 | default: | 3220 | default: |
3202 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) | 3221 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3203 | rpc_restart_call(task); | 3222 | rpc_restart_call(task); |
3204 | } | 3223 | } |
3205 | } | 3224 | } |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index ec0cbe00a804..3d78706b3efb 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -824,7 +824,7 @@ static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_st | |||
824 | return 1; | 824 | return 1; |
825 | } | 825 | } |
826 | 826 | ||
827 | static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) | 827 | int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) |
828 | { | 828 | { |
829 | set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); | 829 | set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); |
830 | clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); | 830 | clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); |