Merge tag 'nfs-for-4.9-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
[cascardo/linux.git] / fs / nfs / nfs4state.c
index 9801b5b..5f4281e 100644 (file)
@@ -991,6 +991,8 @@ int nfs4_select_rw_stateid(struct nfs4_state *state,
 {
        int ret;
 
+       if (!nfs4_valid_open_stateid(state))
+               return -EIO;
        if (cred != NULL)
                *cred = NULL;
        ret = nfs4_copy_lock_stateid(dst, state, lockowner);
@@ -1303,6 +1305,8 @@ void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
 static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
 {
 
+       if (!nfs4_valid_open_stateid(state))
+               return 0;
        set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
        /* Don't recover state that expired before the reboot */
        if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) {
@@ -1316,6 +1320,8 @@ static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_st
 
 int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
 {
+       if (!nfs4_valid_open_stateid(state))
+               return 0;
        set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
        clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
        set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
@@ -1327,9 +1333,8 @@ int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_
 {
        struct nfs_client *clp = server->nfs_client;
 
-       if (!nfs4_valid_open_stateid(state))
+       if (!nfs4_state_mark_reclaim_nograce(clp, state))
                return -EBADF;
-       nfs4_state_mark_reclaim_nograce(clp, state);
        dprintk("%s: scheduling stateid recovery for server %s\n", __func__,
                        clp->cl_hostname);
        nfs4_schedule_state_manager(clp);
@@ -1337,6 +1342,35 @@ int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_
 }
 EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
 
+static struct nfs4_lock_state *
+nfs_state_find_lock_state_by_stateid(struct nfs4_state *state,
+               const nfs4_stateid *stateid)
+{
+       struct nfs4_lock_state *pos;
+
+       list_for_each_entry(pos, &state->lock_states, ls_locks) {
+               if (!test_bit(NFS_LOCK_INITIALIZED, &pos->ls_flags))
+                       continue;
+               if (nfs4_stateid_match_other(&pos->ls_stateid, stateid))
+                       return pos;
+       }
+       return NULL;
+}
+
+static bool nfs_state_lock_state_matches_stateid(struct nfs4_state *state,
+               const nfs4_stateid *stateid)
+{
+       bool found = false;
+
+       if (test_bit(LK_STATE_IN_USE, &state->flags)) {
+               spin_lock(&state->state_lock);
+               if (nfs_state_find_lock_state_by_stateid(state, stateid))
+                       found = true;
+               spin_unlock(&state->state_lock);
+       }
+       return found;
+}
+
 void nfs_inode_find_state_and_recover(struct inode *inode,
                const nfs4_stateid *stateid)
 {
@@ -1351,14 +1385,18 @@ void nfs_inode_find_state_and_recover(struct inode *inode,
                state = ctx->state;
                if (state == NULL)
                        continue;
-               if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
-                       continue;
-               if (!nfs4_stateid_match(&state->stateid, stateid))
+               if (nfs4_stateid_match_other(&state->stateid, stateid) &&
+                   nfs4_state_mark_reclaim_nograce(clp, state)) {
+                       found = true;
                        continue;
-               nfs4_state_mark_reclaim_nograce(clp, state);
-               found = true;
+               }
+               if (nfs_state_lock_state_matches_stateid(state, stateid) &&
+                   nfs4_state_mark_reclaim_nograce(clp, state))
+                       found = true;
        }
        spin_unlock(&inode->i_lock);
+
+       nfs_inode_find_delegation_state_and_recover(inode, stateid);
        if (found)
                nfs4_schedule_state_manager(clp);
 }
@@ -1498,6 +1536,9 @@ restart:
                                        __func__, status);
                        case -ENOENT:
                        case -ENOMEM:
+                       case -EACCES:
+                       case -EROFS:
+                       case -EIO:
                        case -ESTALE:
                                /* Open state on this file cannot be recovered */
                                nfs4_state_mark_recovery_failed(state, status);
@@ -1656,15 +1697,9 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
        put_rpccred(cred);
 }
 
-static void nfs_delegation_clear_all(struct nfs_client *clp)
-{
-       nfs_delegation_mark_reclaim(clp);
-       nfs_delegation_reap_unclaimed(clp);
-}
-
 static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
 {
-       nfs_delegation_clear_all(clp);
+       nfs_mark_test_expired_all_delegations(clp);
        nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
 }
 
@@ -2195,7 +2230,7 @@ static void nfs41_handle_all_state_revoked(struct nfs_client *clp)
 
 static void nfs41_handle_some_state_revoked(struct nfs_client *clp)
 {
-       nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
+       nfs4_state_start_reclaim_nograce(clp);
        nfs4_schedule_state_manager(clp);
 
        dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname);
@@ -2420,6 +2455,13 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        nfs4_state_end_reclaim_reboot(clp);
                }
 
+               /* Detect expired delegations... */
+               if (test_and_clear_bit(NFS4CLNT_DELEGATION_EXPIRED, &clp->cl_state)) {
+                       section = "detect expired delegations";
+                       nfs_reap_expired_delegations(clp);
+                       continue;
+               }
+
                /* Now recover expired state... */
                if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
                        section = "reclaim nograce";