aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-12-23 15:21:46 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-12-23 15:21:46 -0500
commit9e33bed55239bdcee1746c31a11177d239bac1b5 (patch)
treeb6ff90aa50b1d71722ce8eb3f2cecc28dafc3e4d /fs/nfs
parent95d35cb4c473c754824967c0b069bbeb7efa4847 (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.h2
-rw-r--r--fs/nfs/nfs4proc.c37
-rw-r--r--fs/nfs/nfs4state.c2
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 {
169struct nfs4_exception { 169struct nfs4_exception {
170 long timeout; 170 long timeout;
171 int retry; 171 int retry;
172 struct nfs4_state *state;
172}; 173};
173 174
174struct nfs4_state_recovery_ops { 175struct nfs4_state_recovery_ops {
@@ -226,6 +227,7 @@ extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t);
226extern void nfs4_close_sync(struct path *, struct nfs4_state *, mode_t); 227extern void nfs4_close_sync(struct path *, struct nfs4_state *, mode_t);
227extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); 228extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
228extern void nfs4_schedule_state_recovery(struct nfs_client *); 229extern void nfs4_schedule_state_recovery(struct nfs_client *);
230extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state);
229extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); 231extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
230extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); 232extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
231extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); 233extern 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 @@
62struct nfs4_opendata; 62struct nfs4_opendata;
63static int _nfs4_proc_open(struct nfs4_opendata *data); 63static int _nfs4_proc_open(struct nfs4_opendata *data);
64static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); 64static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
65static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); 65static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
66static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); 66static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
67static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); 67static 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)
235static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) 235static 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
2834static int 2845static int
2835nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) 2846nfs4_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
827static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) 827int 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);