nfsd4: fix up replay_matches_cache()
authorScott Mayhew <smayhew@redhat.com>
Wed, 9 Oct 2019 19:11:37 +0000 (15:11 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Jan 2020 09:17:57 +0000 (10:17 +0100)
commit 6e73e92b155c868ff7fce9d108839668caf1d9be upstream.

When running an nfs stress test, I see quite a few cached replies that
don't match up with the actual request.  The first comment in
replay_matches_cache() makes sense, but the code doesn't seem to
match... fix it.

This isn't exactly a bugfix, as the server isn't required to catch every
case of a false retry.  So, we may as well do this, but if this is
fixing a problem then that suggests there's a client bug.

Fixes: 53da6a53e1d4 ("nfsd4: catch some false session retries")
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfsd/nfs4state.c

index 87ee9cbf7dcbbdc496c400da4536957a5b5dd80d..fc13236d1be1f9c84087e4abbb99a95836605b14 100644 (file)
@@ -3058,12 +3058,17 @@ static bool replay_matches_cache(struct svc_rqst *rqstp,
            (bool)seq->cachethis)
                return false;
        /*
-        * If there's an error than the reply can have fewer ops than
-        * the call.  But if we cached a reply with *more* ops than the
-        * call you're sending us now, then this new call is clearly not
-        * really a replay of the old one:
+        * If there's an error then the reply can have fewer ops than
+        * the call.
         */
-       if (slot->sl_opcnt < argp->opcnt)
+       if (slot->sl_opcnt < argp->opcnt && !slot->sl_status)
+               return false;
+       /*
+        * But if we cached a reply with *more* ops than the call you're
+        * sending us now, then this new call is clearly not really a
+        * replay of the old one:
+        */
+       if (slot->sl_opcnt > argp->opcnt)
                return false;
        /* This is the only check explicitly called by spec: */
        if (!same_creds(&rqstp->rq_cred, &slot->sl_cred))