|
@@ -1137,13 +1137,30 @@ static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
|
|
|
nfs4_state_set_mode_locked(state, state->state | fmode);
|
|
|
}
|
|
|
|
|
|
+static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state)
|
|
|
+{
|
|
|
+ struct nfs_client *clp = state->owner->so_server->nfs_client;
|
|
|
+ bool need_recover = false;
|
|
|
+
|
|
|
+ if (test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags) && state->n_rdonly)
|
|
|
+ need_recover = true;
|
|
|
+ if (test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags) && state->n_wronly)
|
|
|
+ need_recover = true;
|
|
|
+ if (test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags) && state->n_rdwr)
|
|
|
+ need_recover = true;
|
|
|
+ if (need_recover)
|
|
|
+ nfs4_state_mark_reclaim_nograce(clp, state);
|
|
|
+}
|
|
|
+
|
|
|
static bool nfs_need_update_open_stateid(struct nfs4_state *state,
|
|
|
nfs4_stateid *stateid)
|
|
|
{
|
|
|
if (test_and_set_bit(NFS_OPEN_STATE, &state->flags) == 0)
|
|
|
return true;
|
|
|
- if (!nfs4_stateid_match_other(stateid, &state->open_stateid))
|
|
|
+ if (!nfs4_stateid_match_other(stateid, &state->open_stateid)) {
|
|
|
+ nfs_test_and_clear_all_open_stateid(state);
|
|
|
return true;
|
|
|
+ }
|
|
|
if (nfs4_stateid_is_newer(stateid, &state->open_stateid))
|
|
|
return true;
|
|
|
return false;
|
|
@@ -1179,6 +1196,8 @@ static void nfs_clear_open_stateid(struct nfs4_state *state, nfs4_stateid *state
|
|
|
write_seqlock(&state->seqlock);
|
|
|
nfs_clear_open_stateid_locked(state, stateid, fmode);
|
|
|
write_sequnlock(&state->seqlock);
|
|
|
+ if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
|
|
|
+ nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
|
|
|
}
|
|
|
|
|
|
static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
|
|
@@ -1255,6 +1274,8 @@ no_delegation:
|
|
|
__update_open_stateid(state, open_stateid, NULL, fmode);
|
|
|
ret = 1;
|
|
|
}
|
|
|
+ if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
|
|
|
+ nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -1488,12 +1509,15 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
|
|
|
struct nfs4_state *newstate;
|
|
|
int ret;
|
|
|
|
|
|
+ /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */
|
|
|
+ clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
|
+ clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
|
+ clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
|
/* memory barrier prior to reading state->n_* */
|
|
|
clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
|
clear_bit(NFS_OPEN_STATE, &state->flags);
|
|
|
smp_rmb();
|
|
|
if (state->n_rdwr != 0) {
|
|
|
- clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
|
ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
|
|
|
if (ret != 0)
|
|
|
return ret;
|
|
@@ -1501,7 +1525,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
|
|
|
return -ESTALE;
|
|
|
}
|
|
|
if (state->n_wronly != 0) {
|
|
|
- clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
|
ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
|
|
|
if (ret != 0)
|
|
|
return ret;
|
|
@@ -1509,7 +1532,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
|
|
|
return -ESTALE;
|
|
|
}
|
|
|
if (state->n_rdonly != 0) {
|
|
|
- clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
|
ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
|
|
|
if (ret != 0)
|
|
|
return ret;
|