NFSv4.1/pNFS: Ensure we enforce RFC5661 Section 12.5.5.2.1
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 28 Dec 2015 17:57:53 +0000 (12:57 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 28 Dec 2015 19:33:04 +0000 (14:33 -0500)
The RFC requires us to check if the server is recalling a stateid that we
haven't yet received. If so, tell it to wait.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/callback_proc.c

index 34852ece4057f90cdab96ae0e07dd42978cccfdc..1b24ad07d4f535b5dd5d0cc90d75325e25cb536d 100644 (file)
@@ -160,6 +160,22 @@ static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
        return lo;
 }
 
+/*
+ * Enforce RFC5661 section 12.5.5.2.1. (Layout Recall and Return Sequencing)
+ */
+static bool pnfs_check_stateid_sequence(struct pnfs_layout_hdr *lo,
+                                       const nfs4_stateid *new)
+{
+       u32 oldseq, newseq;
+
+       oldseq = be32_to_cpu(lo->plh_stateid.seqid);
+       newseq = be32_to_cpu(new->seqid);
+
+       if (newseq > oldseq + 1)
+               return false;
+       return true;
+}
+
 static u32 initiate_file_draining(struct nfs_client *clp,
                                  struct cb_layoutrecallargs *args)
 {
@@ -175,6 +191,10 @@ static u32 initiate_file_draining(struct nfs_client *clp,
        ino = lo->plh_inode;
 
        spin_lock(&ino->i_lock);
+       if (!pnfs_check_stateid_sequence(lo, &args->cbl_stateid)) {
+               rv = NFS4ERR_DELAY;
+               goto unlock;
+       }
        pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
        spin_unlock(&ino->i_lock);