aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/callback_proc.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 34852ece4057..1b24ad07d4f5 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -160,6 +160,22 @@ static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
160 return lo; 160 return lo;
161} 161}
162 162
163/*
164 * Enforce RFC5661 section 12.5.5.2.1. (Layout Recall and Return Sequencing)
165 */
166static bool pnfs_check_stateid_sequence(struct pnfs_layout_hdr *lo,
167 const nfs4_stateid *new)
168{
169 u32 oldseq, newseq;
170
171 oldseq = be32_to_cpu(lo->plh_stateid.seqid);
172 newseq = be32_to_cpu(new->seqid);
173
174 if (newseq > oldseq + 1)
175 return false;
176 return true;
177}
178
163static u32 initiate_file_draining(struct nfs_client *clp, 179static u32 initiate_file_draining(struct nfs_client *clp,
164 struct cb_layoutrecallargs *args) 180 struct cb_layoutrecallargs *args)
165{ 181{
@@ -175,6 +191,10 @@ static u32 initiate_file_draining(struct nfs_client *clp,
175 ino = lo->plh_inode; 191 ino = lo->plh_inode;
176 192
177 spin_lock(&ino->i_lock); 193 spin_lock(&ino->i_lock);
194 if (!pnfs_check_stateid_sequence(lo, &args->cbl_stateid)) {
195 rv = NFS4ERR_DELAY;
196 goto unlock;
197 }
178 pnfs_set_layout_stateid(lo, &args->cbl_stateid, true); 198 pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
179 spin_unlock(&ino->i_lock); 199 spin_unlock(&ino->i_lock);
180 200