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>
Sun, 12 Jan 2020 10:24:15 +0000 (11:24 +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 032fcae3a94fe6309a601d89357a847bcc3eeb23..db4bd70b62d008c509bd996de77d35d8b77154a7 100644 (file)
@@ -3067,12 +3067,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))