diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 84d22f715653..d4f2b57e9d5b 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -1423,6 +1423,23 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task, if (ff_layout_avoid_mds_available_ds(lseg)) return -NFS4ERR_RESET_TO_PNFS; reset: + /* + * FF_FLAGS_NO_IO_THRU_MDS: never resend through the MDS. The + * caller would do so with force_mds set (ff_layout_reset_read(), + * ff_layout_reset_write(hdr, false) -> pnfs_*_done_resend_to_mds()), + * which builds a descriptor out of the plain MDS page ops and so + * consults no layout at all -- this is the last point at which the + * policy can still be applied. Retry through pNFS instead, which + * takes a fresh LAYOUTGET; that is also the right answer for the + * invalid-layout cases that jump here, since they have just called + * pnfs_destroy_layout(). Having done so they can no longer ask the + * layout hdr about the flag, hence the inode. + */ + if (nfs_no_io_thru_mds(inode)) { + dprintk("%s Retry through pNFS, no MDS fallback. Error %d\n", + __func__, task->tk_status); + return -NFS4ERR_RESET_TO_PNFS; + } dprintk("%s Retry through MDS. Error %d\n", __func__, task->tk_status); return -NFS4ERR_RESET_TO_MDS;