aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-03-14 16:57:48 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-03-25 12:04:10 -0400
commit5d422301f97b821301efcdb6fc9d1a83a5c102d6 (patch)
treeed7117feb89a0a804669f9f017d2ce3ef7fee10c /fs
parent3ed5e2a2c394df4e03a680842c2d07a8680f133b (diff)
NFSv4: Fail I/O if the state recovery fails irrevocably
If state recovery fails with an ESTALE or a ENOENT, then we shouldn't keep retrying. Instead, mark the stateid as being invalid and fail the I/O with an EIO error. For other operations such as POSIX and BSD file locking, truncate etc, fail with an EBADF to indicate that this file descriptor is no longer valid. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs4_fs.h8
-rw-r--r--fs/nfs/nfs4filelayout.c12
-rw-r--r--fs/nfs/nfs4proc.c37
-rw-r--r--fs/nfs/nfs4state.c19
-rw-r--r--fs/nfs/pnfs.c2
5 files changed, 61 insertions, 17 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 944c9a5c1039..9ce90135bf22 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -149,6 +149,7 @@ enum {
149 NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */ 149 NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */
150 NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */ 150 NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */
151 NFS_STATE_POSIX_LOCKS, /* Posix locks are supported */ 151 NFS_STATE_POSIX_LOCKS, /* Posix locks are supported */
152 NFS_STATE_RECOVERY_FAILED, /* OPEN stateid state recovery failed */
152}; 153};
153 154
154struct nfs4_state { 155struct nfs4_state {
@@ -347,7 +348,7 @@ extern int nfs4_wait_clnt_recover(struct nfs_client *clp);
347extern int nfs4_client_recover_expired_lease(struct nfs_client *clp); 348extern int nfs4_client_recover_expired_lease(struct nfs_client *clp);
348extern void nfs4_schedule_state_manager(struct nfs_client *); 349extern void nfs4_schedule_state_manager(struct nfs_client *);
349extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); 350extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
350extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); 351extern int nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
351extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); 352extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
352extern void nfs41_handle_server_scope(struct nfs_client *, 353extern void nfs41_handle_server_scope(struct nfs_client *,
353 struct nfs41_server_scope **); 354 struct nfs41_server_scope **);
@@ -412,6 +413,11 @@ static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_statei
412 return memcmp(dst, src, sizeof(*dst)) == 0; 413 return memcmp(dst, src, sizeof(*dst)) == 0;
413} 414}
414 415
416static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)
417{
418 return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0;
419}
420
415#else 421#else
416 422
417#define nfs4_close_state(a, b) do { } while (0) 423#define nfs4_close_state(a, b) do { } while (0)
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 4fb234d3aefb..1ee5737211d7 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -158,11 +158,14 @@ static int filelayout_async_handle_error(struct rpc_task *task,
158 case -NFS4ERR_OPENMODE: 158 case -NFS4ERR_OPENMODE:
159 if (state == NULL) 159 if (state == NULL)
160 break; 160 break;
161 nfs4_schedule_stateid_recovery(mds_server, state); 161 if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
162 goto out_bad_stateid;
162 goto wait_on_recovery; 163 goto wait_on_recovery;
163 case -NFS4ERR_EXPIRED: 164 case -NFS4ERR_EXPIRED:
164 if (state != NULL) 165 if (state != NULL) {
165 nfs4_schedule_stateid_recovery(mds_server, state); 166 if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
167 goto out_bad_stateid;
168 }
166 nfs4_schedule_lease_recovery(mds_client); 169 nfs4_schedule_lease_recovery(mds_client);
167 goto wait_on_recovery; 170 goto wait_on_recovery;
168 /* DS session errors */ 171 /* DS session errors */
@@ -226,6 +229,9 @@ reset:
226out: 229out:
227 task->tk_status = 0; 230 task->tk_status = 0;
228 return -EAGAIN; 231 return -EAGAIN;
232out_bad_stateid:
233 task->tk_status = -EIO;
234 return 0;
229wait_on_recovery: 235wait_on_recovery:
230 rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL); 236 rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL);
231 if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0) 237 if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 26431cf62ddb..c3bbb6c53d61 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -295,7 +295,9 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
295 } 295 }
296 if (state == NULL) 296 if (state == NULL)
297 break; 297 break;
298 nfs4_schedule_stateid_recovery(server, state); 298 ret = nfs4_schedule_stateid_recovery(server, state);
299 if (ret < 0)
300 break;
299 goto wait_on_recovery; 301 goto wait_on_recovery;
300 case -NFS4ERR_DELEG_REVOKED: 302 case -NFS4ERR_DELEG_REVOKED:
301 case -NFS4ERR_ADMIN_REVOKED: 303 case -NFS4ERR_ADMIN_REVOKED:
@@ -303,11 +305,16 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
303 if (state == NULL) 305 if (state == NULL)
304 break; 306 break;
305 nfs_remove_bad_delegation(state->inode); 307 nfs_remove_bad_delegation(state->inode);
306 nfs4_schedule_stateid_recovery(server, state); 308 ret = nfs4_schedule_stateid_recovery(server, state);
309 if (ret < 0)
310 break;
307 goto wait_on_recovery; 311 goto wait_on_recovery;
308 case -NFS4ERR_EXPIRED: 312 case -NFS4ERR_EXPIRED:
309 if (state != NULL) 313 if (state != NULL) {
310 nfs4_schedule_stateid_recovery(server, state); 314 ret = nfs4_schedule_stateid_recovery(server, state);
315 if (ret < 0)
316 break;
317 }
311 case -NFS4ERR_STALE_STATEID: 318 case -NFS4ERR_STALE_STATEID:
312 case -NFS4ERR_STALE_CLIENTID: 319 case -NFS4ERR_STALE_CLIENTID:
313 nfs4_schedule_lease_recovery(clp); 320 nfs4_schedule_lease_recovery(clp);
@@ -2053,7 +2060,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
2053 2060
2054 nfs_fattr_init(fattr); 2061 nfs_fattr_init(fattr);
2055 2062
2056 if (state != NULL) { 2063 if (state != NULL && nfs4_valid_open_stateid(state)) {
2057 struct nfs_lockowner lockowner = { 2064 struct nfs_lockowner lockowner = {
2058 .l_owner = current->files, 2065 .l_owner = current->files,
2059 .l_pid = current->tgid, 2066 .l_pid = current->tgid,
@@ -2201,6 +2208,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
2201 calldata->arg.fmode &= ~FMODE_WRITE; 2208 calldata->arg.fmode &= ~FMODE_WRITE;
2202 } 2209 }
2203 } 2210 }
2211 if (!nfs4_valid_open_stateid(state))
2212 call_close = 0;
2204 spin_unlock(&state->owner->so_lock); 2213 spin_unlock(&state->owner->so_lock);
2205 2214
2206 if (!call_close) { 2215 if (!call_close) {
@@ -3980,11 +3989,14 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
3980 case -NFS4ERR_OPENMODE: 3989 case -NFS4ERR_OPENMODE:
3981 if (state == NULL) 3990 if (state == NULL)
3982 break; 3991 break;
3983 nfs4_schedule_stateid_recovery(server, state); 3992 if (nfs4_schedule_stateid_recovery(server, state) < 0)
3993 goto stateid_invalid;
3984 goto wait_on_recovery; 3994 goto wait_on_recovery;
3985 case -NFS4ERR_EXPIRED: 3995 case -NFS4ERR_EXPIRED:
3986 if (state != NULL) 3996 if (state != NULL) {
3987 nfs4_schedule_stateid_recovery(server, state); 3997 if (nfs4_schedule_stateid_recovery(server, state) < 0)
3998 goto stateid_invalid;
3999 }
3988 case -NFS4ERR_STALE_STATEID: 4000 case -NFS4ERR_STALE_STATEID:
3989 case -NFS4ERR_STALE_CLIENTID: 4001 case -NFS4ERR_STALE_CLIENTID:
3990 nfs4_schedule_lease_recovery(clp); 4002 nfs4_schedule_lease_recovery(clp);
@@ -4016,6 +4028,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
4016 } 4028 }
4017 task->tk_status = nfs4_map_errors(task->tk_status); 4029 task->tk_status = nfs4_map_errors(task->tk_status);
4018 return 0; 4030 return 0;
4031stateid_invalid:
4032 task->tk_status = -EIO;
4033 return 0;
4019wait_on_recovery: 4034wait_on_recovery:
4020 rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); 4035 rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
4021 if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) 4036 if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
@@ -4632,12 +4647,18 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
4632 data->res.open_seqid = data->arg.open_seqid; 4647 data->res.open_seqid = data->arg.open_seqid;
4633 } else 4648 } else
4634 data->arg.new_lock_owner = 0; 4649 data->arg.new_lock_owner = 0;
4650 if (!nfs4_valid_open_stateid(state)) {
4651 data->rpc_status = -EBADF;
4652 task->tk_action = NULL;
4653 goto out_release_open_seqid;
4654 }
4635 data->timestamp = jiffies; 4655 data->timestamp = jiffies;
4636 if (nfs4_setup_sequence(data->server, 4656 if (nfs4_setup_sequence(data->server,
4637 &data->arg.seq_args, 4657 &data->arg.seq_args,
4638 &data->res.seq_res, 4658 &data->res.seq_res,
4639 task) == 0) 4659 task) == 0)
4640 return; 4660 return;
4661out_release_open_seqid:
4641 nfs_release_seqid(data->arg.open_seqid); 4662 nfs_release_seqid(data->arg.open_seqid);
4642out_release_lock_seqid: 4663out_release_lock_seqid:
4643 nfs_release_seqid(data->arg.lock_seqid); 4664 nfs_release_seqid(data->arg.lock_seqid);
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 6ace365c6334..fec1c5bb4863 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -699,6 +699,8 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
699 list_for_each_entry(state, &nfsi->open_states, inode_states) { 699 list_for_each_entry(state, &nfsi->open_states, inode_states) {
700 if (state->owner != owner) 700 if (state->owner != owner)
701 continue; 701 continue;
702 if (!nfs4_valid_open_stateid(state))
703 continue;
702 if (atomic_inc_not_zero(&state->count)) 704 if (atomic_inc_not_zero(&state->count))
703 return state; 705 return state;
704 } 706 }
@@ -1286,14 +1288,17 @@ static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_s
1286 return 1; 1288 return 1;
1287} 1289}
1288 1290
1289void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state) 1291int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state)
1290{ 1292{
1291 struct nfs_client *clp = server->nfs_client; 1293 struct nfs_client *clp = server->nfs_client;
1292 1294
1295 if (!nfs4_valid_open_stateid(state))
1296 return -EBADF;
1293 nfs4_state_mark_reclaim_nograce(clp, state); 1297 nfs4_state_mark_reclaim_nograce(clp, state);
1294 dprintk("%s: scheduling stateid recovery for server %s\n", __func__, 1298 dprintk("%s: scheduling stateid recovery for server %s\n", __func__,
1295 clp->cl_hostname); 1299 clp->cl_hostname);
1296 nfs4_schedule_state_manager(clp); 1300 nfs4_schedule_state_manager(clp);
1301 return 0;
1297} 1302}
1298EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery); 1303EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
1299 1304
@@ -1323,6 +1328,11 @@ void nfs_inode_find_state_and_recover(struct inode *inode,
1323 nfs4_schedule_state_manager(clp); 1328 nfs4_schedule_state_manager(clp);
1324} 1329}
1325 1330
1331static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error)
1332{
1333 set_bit(NFS_STATE_RECOVERY_FAILED, &state->flags);
1334}
1335
1326 1336
1327static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) 1337static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
1328{ 1338{
@@ -1398,6 +1408,8 @@ restart:
1398 list_for_each_entry(state, &sp->so_states, open_states) { 1408 list_for_each_entry(state, &sp->so_states, open_states) {
1399 if (!test_and_clear_bit(ops->state_flag_bit, &state->flags)) 1409 if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
1400 continue; 1410 continue;
1411 if (!nfs4_valid_open_stateid(state))
1412 continue;
1401 if (state->state == 0) 1413 if (state->state == 0)
1402 continue; 1414 continue;
1403 atomic_inc(&state->count); 1415 atomic_inc(&state->count);
@@ -1430,10 +1442,7 @@ restart:
1430 * Open state on this file cannot be recovered 1442 * Open state on this file cannot be recovered
1431 * All we can do is revert to using the zero stateid. 1443 * All we can do is revert to using the zero stateid.
1432 */ 1444 */
1433 memset(&state->stateid, 0, 1445 nfs4_state_mark_recovery_failed(state, status);
1434 sizeof(state->stateid));
1435 /* Mark the file as being 'closed' */
1436 state->state = 0;
1437 break; 1446 break;
1438 case -NFS4ERR_ADMIN_REVOKED: 1447 case -NFS4ERR_ADMIN_REVOKED:
1439 case -NFS4ERR_STALE_STATEID: 1448 case -NFS4ERR_STALE_STATEID:
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 4bdffe0ba025..c5bd758e5637 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -718,6 +718,8 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
718 spin_lock(&lo->plh_inode->i_lock); 718 spin_lock(&lo->plh_inode->i_lock);
719 if (pnfs_layoutgets_blocked(lo, 1)) { 719 if (pnfs_layoutgets_blocked(lo, 1)) {
720 status = -EAGAIN; 720 status = -EAGAIN;
721 } else if (!nfs4_valid_open_stateid(open_state)) {
722 status = -EBADF;
721 } else if (list_empty(&lo->plh_segs)) { 723 } else if (list_empty(&lo->plh_segs)) {
722 int seq; 724 int seq;
723 725