NFSv4: Fix another reboot recovery race
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 28 Mar 2013 18:01:33 +0000 (14:01 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 28 Mar 2013 20:22:16 +0000 (16:22 -0400)
If the open_context for the file is not yet fully initialised,
then open recovery cannot succeed, and since nfs4_state_find_open_context
returns an ENOENT, we end up treating the file as being irrecoverable.

What we really want to do, is just defer the recovery until later.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c

index 3e7d42fb775cbbc5597d2f499d2af80cd4c7cff0..81343944e09671897d32f3c244782cc9551371c4 100644 (file)
@@ -1373,7 +1373,7 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta
 
        ctx = nfs4_state_find_open_context(state);
        if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
+               return -EAGAIN;
        ret = nfs4_do_open_reclaim(ctx, state);
        put_nfs_open_context(ctx);
        return ret;
@@ -1814,7 +1814,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
 
        ctx = nfs4_state_find_open_context(state);
        if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
+               return -EAGAIN;
        ret = nfs4_do_open_expired(ctx, state);
        put_nfs_open_context(ctx);
        return ret;
@@ -1936,10 +1936,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
        if (ret != 0)
                goto out;
 
-       if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) {
+       if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
                nfs4_schedule_stateid_recovery(server, state);
-               nfs4_wait_clnt_recover(server->nfs_client);
-       }
        *res = state;
 out:
        return ret;
index 685b1e953ed8c3178700ee81c544066062676b63..b924bdd6949483dd510cc38cf3675259962937b2 100644 (file)
@@ -1476,6 +1476,8 @@ restart:
                                 */
                                nfs4_state_mark_recovery_failed(state, status);
                                break;
+                       case -EAGAIN:
+                               ssleep(1);
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_BAD_STATEID: