pNFS/NFSv4: Improve rejection of out-of-order layouts

If a layoutget ends up being reordered w.r.t. a layoutreturn, e.g. due
to a layoutget-on-open not knowing a priori which file to lock, then we
must assume the layout is no longer being considered valid state by the
server.
Incrementally improve our ability to reject such states by using the
cached old stateid in conjunction with the plh_barrier to try to
identify them.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>

+16 -6
+16 -6
fs/nfs/pnfs.c
··· 1000 { 1001 u32 seqid = be32_to_cpu(stateid->seqid); 1002 1003 - return !pnfs_seqid_is_newer(seqid, lo->plh_barrier); 1004 } 1005 1006 /* lget is set to 1 if called from inside send_layoutget call chain */ ··· 1912 wake_up_var(&lo->plh_outstanding); 1913 } 1914 1915 static void pnfs_clear_first_layoutget(struct pnfs_layout_hdr *lo) 1916 { 1917 unsigned long *bitlock = &lo->plh_flags; ··· 2391 goto out_forget; 2392 } 2393 2394 - if (!pnfs_layout_is_valid(lo)) { 2395 - /* We have a completely new layout */ 2396 - pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, true); 2397 - } else if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) { 2398 /* existing state ID, make sure the sequence number matches. */ 2399 if (pnfs_layout_stateid_blocked(lo, &res->stateid)) { 2400 dprintk("%s forget reply due to sequence\n", __func__); 2401 goto out_forget; 2402 } 2403 pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, false); 2404 - } else { 2405 /* 2406 * We got an entirely new state ID. Mark all segments for the 2407 * inode invalid, and retry the layoutget ··· 2414 pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, 2415 &range, 0); 2416 goto out_forget; 2417 } 2418 2419 pnfs_get_lseg(lseg);
··· 1000 { 1001 u32 seqid = be32_to_cpu(stateid->seqid); 1002 1003 + return !pnfs_seqid_is_newer(seqid, lo->plh_barrier) && lo->plh_barrier; 1004 } 1005 1006 /* lget is set to 1 if called from inside send_layoutget call chain */ ··· 1912 wake_up_var(&lo->plh_outstanding); 1913 } 1914 1915 + static bool pnfs_is_first_layoutget(struct pnfs_layout_hdr *lo) 1916 + { 1917 + return test_bit(NFS_LAYOUT_FIRST_LAYOUTGET, &lo->plh_flags); 1918 + } 1919 + 1920 static void pnfs_clear_first_layoutget(struct pnfs_layout_hdr *lo) 1921 { 1922 unsigned long *bitlock = &lo->plh_flags; ··· 2386 goto out_forget; 2387 } 2388 2389 + if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) { 2390 /* existing state ID, make sure the sequence number matches. */ 2391 if (pnfs_layout_stateid_blocked(lo, &res->stateid)) { 2392 + if (!pnfs_layout_is_valid(lo) && 2393 + pnfs_is_first_layoutget(lo)) 2394 + lo->plh_barrier = 0; 2395 dprintk("%s forget reply due to sequence\n", __func__); 2396 goto out_forget; 2397 } 2398 pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, false); 2399 + } else if (pnfs_layout_is_valid(lo)) { 2400 /* 2401 * We got an entirely new state ID. Mark all segments for the 2402 * inode invalid, and retry the layoutget ··· 2409 pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, 2410 &range, 0); 2411 goto out_forget; 2412 + } else { 2413 + /* We have a completely new layout */ 2414 + if (!pnfs_is_first_layoutget(lo)) 2415 + goto out_forget; 2416 + pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, true); 2417 } 2418 2419 pnfs_get_lseg(lseg);