diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 94cc324b591f..7d45401ee5b1 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -639,9 +639,12 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, if (!p) goto out_sort_mirrors; fls->flags = be32_to_cpup(p); - if (fls->flags & FF_FLAGS_NO_IO_THRU_MDS) + if (fls->flags & FF_FLAGS_NO_IO_THRU_MDS) { set_bit(NFS4_FF_HDR_NO_IO_THRU_MDS, &FF_LAYOUT_FROM_HDR(lh)->flags); + /* Outlives this layout hdr; see NFS_INO_NO_IO_THRU_MDS */ + nfs_set_no_io_thru_mds(lh->plh_inode); + } p = xdr_inline_decode(&stream, 4); if (!p) diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 48f7c0e25da1..959edbc9add2 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -546,6 +546,35 @@ static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi) return test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0; } +/* + * Module-private nfs_inode->flags bit (not in , so no + * exported layout changes): set, and never cleared for the life of the + * in-core inode, once a layout driver has seen the server forbid I/O + * through the MDS for this file (flexfiles sets it from + * FF_FLAGS_NO_IO_THRU_MDS in ff_layout_alloc_lseg()). The RFC 5661 + * mdsthreshold hint must not be acted on for such a file, since the only + * thing pnfs_within_mdsthreshold() can ask for is the one thing the + * layout forbids. Servers are assumed to be consistent in their + * no-fallback policy per file, the same assumption + * ff_layout_hdr_no_fallback_to_mds() already makes; if one were not, the + * only effect is that its mdsthreshold hint - a SHOULD - stops being + * honored for an inode that is already in core. + */ +#define NFS_INO_NO_IO_THRU_MDS (30) + +static inline void nfs_set_no_io_thru_mds(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + if (!test_bit(NFS_INO_NO_IO_THRU_MDS, &nfsi->flags)) + set_bit(NFS_INO_NO_IO_THRU_MDS, &nfsi->flags); +} + +static inline bool nfs_no_io_thru_mds(struct inode *inode) +{ + return test_bit(NFS_INO_NO_IO_THRU_MDS, &NFS_I(inode)->flags); +} + /* Must be called with exclusively locked inode->i_rwsem */ static inline void nfs_file_block_o_direct(struct nfs_inode *nfsi) { diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 93a0852e1e8a..a057a06318c7 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -2019,7 +2019,9 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, * is set to IOMODE_READ for a READ request, and set to IOMODE_RW for a * WRITE request. * - * A return of true means use MDS I/O. + * A return of true means use MDS I/O, so for a file whose layout forbids + * that (see NFS_INO_NO_IO_THRU_MDS) the hint is not evaluated at all: + * there is no answer it could give that this client may act on. * * From rfc 5661: * If a file's size is smaller than the file size threshold, data accesses @@ -2040,6 +2042,14 @@ static bool pnfs_within_mdsthreshold(struct nfs_open_context *ctx, if (t == NULL) return ret; + /* + * The server has told a layout driver that this file's I/O may not + * go through the MDS (flexfiles FF_FLAGS_NO_IO_THRU_MDS). Honor + * that over its own mdsthreshold hint. + */ + if (nfs_no_io_thru_mds(ino)) + return ret; + dprintk("%s bm=0x%x rd_sz=%llu wr_sz=%llu rd_io=%llu wr_io=%llu\n", __func__, t->bm, t->rd_sz, t->wr_sz, t->rd_io_sz, t->wr_io_sz);