diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 7d45401ee5b1..84d22f715653 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -1073,19 +1073,33 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, if (pgio->pg_error < 0) { if (pgio->pg_error != -EAGAIN) return; - /* Retry getting layout segment if lower layer returned -EAGAIN */ - if (pgio->pg_maxretrans && req->wb_nio++ > pgio->pg_maxretrans) { - if (NFS_SERVER(pgio->pg_inode)->flags & NFS_MOUNT_SOFTERR) - pgio->pg_error = -ETIMEDOUT; - else - pgio->pg_error = -EIO; - return; - } - pgio->pg_error = 0; - /* Sleep for 1 second before retrying */ - ssleep(1); - goto retry; + goto retry_nolseg; } + /* + * No segment, and no error to report either: pnfs_update_layout() + * simply has nothing to give (NFS_LAYOUT_BULK_RECALL, a failed + * pnfs_layout_io_test, blocked LAYOUTGETs, a layout being + * returned). If the server forbids reading this file through the + * MDS there is no fallback to take, so wait for a layout on the + * same terms as the -EAGAIN above. The layout hdr that carried + * FF_FLAGS_NO_IO_THRU_MDS may itself be gone by now, which is why + * this asks the inode and not the hdr. + */ + if (!nfs_no_io_thru_mds(pgio->pg_inode)) + goto out_mds; +retry_nolseg: + /* Retry getting layout segment if lower layer returned -EAGAIN */ + if (pgio->pg_maxretrans && req->wb_nio++ > pgio->pg_maxretrans) { + if (NFS_SERVER(pgio->pg_inode)->flags & NFS_MOUNT_SOFTERR) + pgio->pg_error = -ETIMEDOUT; + else + pgio->pg_error = -EIO; + return; + } + pgio->pg_error = 0; + /* Sleep for 1 second before retrying */ + ssleep(1); + goto retry; out_mds: trace_pnfs_mds_fallback_pg_init_read(pgio->pg_inode, 0, NFS4_MAX_UINT64, IOMODE_READ,