aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-02-12 19:15:06 -0500
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-02-19 21:21:07 -0500
commit4f14c194a996e75c01e44a8832f1d983ccaeefc0 (patch)
tree31182d2e8707bccf3cc650844785f2953ee32ac1 /fs/nfs
parent226056c5c312b3dac16ff6d4f40208f95c070b6a (diff)
NFSv4: Clear the open state flags if the new stateid does not match
RFC3530 and RFC5661 both prescribe that the 'opaque' field of the open stateid returned by new OPEN/OPEN_DOWNGRADE/CLOSE calls for the same file and open owner should match. If this is not the case, assume that the open state has been lost, and that we need to recover it. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4proc.c30
-rw-r--r--fs/nfs/nfs4state.c2
3 files changed, 28 insertions, 5 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index df81fcc138a7..e1d1badbe53c 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -427,6 +427,7 @@ extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
427extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); 427extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
428extern void nfs_inode_find_state_and_recover(struct inode *inode, 428extern void nfs_inode_find_state_and_recover(struct inode *inode,
429 const nfs4_stateid *stateid); 429 const nfs4_stateid *stateid);
430extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *, struct nfs4_state *);
430extern void nfs4_schedule_lease_recovery(struct nfs_client *); 431extern void nfs4_schedule_lease_recovery(struct nfs_client *);
431extern int nfs4_wait_clnt_recover(struct nfs_client *clp); 432extern int nfs4_wait_clnt_recover(struct nfs_client *clp);
432extern int nfs4_client_recover_expired_lease(struct nfs_client *clp); 433extern int nfs4_client_recover_expired_lease(struct nfs_client *clp);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1f593a0bd938..2427ef4c4d63 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1137,13 +1137,30 @@ static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
1137 nfs4_state_set_mode_locked(state, state->state | fmode); 1137 nfs4_state_set_mode_locked(state, state->state | fmode);
1138} 1138}
1139 1139
1140static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state)
1141{
1142 struct nfs_client *clp = state->owner->so_server->nfs_client;
1143 bool need_recover = false;
1144
1145 if (test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags) && state->n_rdonly)
1146 need_recover = true;
1147 if (test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags) && state->n_wronly)
1148 need_recover = true;
1149 if (test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags) && state->n_rdwr)
1150 need_recover = true;
1151 if (need_recover)
1152 nfs4_state_mark_reclaim_nograce(clp, state);
1153}
1154
1140static bool nfs_need_update_open_stateid(struct nfs4_state *state, 1155static bool nfs_need_update_open_stateid(struct nfs4_state *state,
1141 nfs4_stateid *stateid) 1156 nfs4_stateid *stateid)
1142{ 1157{
1143 if (test_and_set_bit(NFS_OPEN_STATE, &state->flags) == 0) 1158 if (test_and_set_bit(NFS_OPEN_STATE, &state->flags) == 0)
1144 return true; 1159 return true;
1145 if (!nfs4_stateid_match_other(stateid, &state->open_stateid)) 1160 if (!nfs4_stateid_match_other(stateid, &state->open_stateid)) {
1161 nfs_test_and_clear_all_open_stateid(state);
1146 return true; 1162 return true;
1163 }
1147 if (nfs4_stateid_is_newer(stateid, &state->open_stateid)) 1164 if (nfs4_stateid_is_newer(stateid, &state->open_stateid))
1148 return true; 1165 return true;
1149 return false; 1166 return false;
@@ -1179,6 +1196,8 @@ static void nfs_clear_open_stateid(struct nfs4_state *state, nfs4_stateid *state
1179 write_seqlock(&state->seqlock); 1196 write_seqlock(&state->seqlock);
1180 nfs_clear_open_stateid_locked(state, stateid, fmode); 1197 nfs_clear_open_stateid_locked(state, stateid, fmode);
1181 write_sequnlock(&state->seqlock); 1198 write_sequnlock(&state->seqlock);
1199 if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
1200 nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
1182} 1201}
1183 1202
1184static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) 1203static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
@@ -1255,6 +1274,8 @@ no_delegation:
1255 __update_open_stateid(state, open_stateid, NULL, fmode); 1274 __update_open_stateid(state, open_stateid, NULL, fmode);
1256 ret = 1; 1275 ret = 1;
1257 } 1276 }
1277 if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
1278 nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
1258 1279
1259 return ret; 1280 return ret;
1260} 1281}
@@ -1488,12 +1509,15 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
1488 struct nfs4_state *newstate; 1509 struct nfs4_state *newstate;
1489 int ret; 1510 int ret;
1490 1511
1512 /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */
1513 clear_bit(NFS_O_RDWR_STATE, &state->flags);
1514 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1515 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1491 /* memory barrier prior to reading state->n_* */ 1516 /* memory barrier prior to reading state->n_* */
1492 clear_bit(NFS_DELEGATED_STATE, &state->flags); 1517 clear_bit(NFS_DELEGATED_STATE, &state->flags);
1493 clear_bit(NFS_OPEN_STATE, &state->flags); 1518 clear_bit(NFS_OPEN_STATE, &state->flags);
1494 smp_rmb(); 1519 smp_rmb();
1495 if (state->n_rdwr != 0) { 1520 if (state->n_rdwr != 0) {
1496 clear_bit(NFS_O_RDWR_STATE, &state->flags);
1497 ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); 1521 ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
1498 if (ret != 0) 1522 if (ret != 0)
1499 return ret; 1523 return ret;
@@ -1501,7 +1525,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
1501 return -ESTALE; 1525 return -ESTALE;
1502 } 1526 }
1503 if (state->n_wronly != 0) { 1527 if (state->n_wronly != 0) {
1504 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1505 ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); 1528 ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
1506 if (ret != 0) 1529 if (ret != 0)
1507 return ret; 1530 return ret;
@@ -1509,7 +1532,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
1509 return -ESTALE; 1532 return -ESTALE;
1510 } 1533 }
1511 if (state->n_rdonly != 0) { 1534 if (state->n_rdonly != 0) {
1512 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1513 ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); 1535 ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
1514 if (ret != 0) 1536 if (ret != 0)
1515 return ret; 1537 return ret;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index e5be72518bd7..b524df9f6a74 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1321,7 +1321,7 @@ static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_st
1321 return 1; 1321 return 1;
1322} 1322}
1323 1323
1324static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) 1324int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
1325{ 1325{
1326 set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); 1326 set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
1327 clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); 1327 clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);