| From eb3fabde15bccdf34f1c9b35a83aa4c0dacbb4ca Mon Sep 17 00:00:00 2001 |
| From: Mike Snitzer <snitzer@kernel.org> |
| Date: Thu, 16 Jan 2025 20:05:39 -0500 |
| Subject: pnfs/flexfiles: retry getting layout segment for reads |
| |
| From: Mike Snitzer <snitzer@kernel.org> |
| |
| commit eb3fabde15bccdf34f1c9b35a83aa4c0dacbb4ca upstream. |
| |
| If ff_layout_pg_get_read()'s attempt to get a layout segment results |
| in -EAGAIN have ff_layout_pg_init_read() retry it after sleeping. |
| |
| If "softerr" mount is used, use 'io_maxretrans' to limit the number of |
| attempts to get a layout segment. |
| |
| This fixes a long-standing issue of O_DIRECT reads failing with |
| -EAGAIN (11) when using flexfiles Client Side Mirroring (CSM). |
| |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Mike Snitzer <snitzer@kernel.org> |
| Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/nfs/flexfilelayout/flexfilelayout.c | 27 +++++++++++++++++++++------ |
| 1 file changed, 21 insertions(+), 6 deletions(-) |
| |
| --- a/fs/nfs/flexfilelayout/flexfilelayout.c |
| +++ b/fs/nfs/flexfilelayout/flexfilelayout.c |
| @@ -839,6 +839,9 @@ ff_layout_pg_init_read(struct nfs_pageio |
| struct nfs4_pnfs_ds *ds; |
| u32 ds_idx; |
| |
| + if (NFS_SERVER(pgio->pg_inode)->flags & |
| + (NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR)) |
| + pgio->pg_maxretrans = io_maxretrans; |
| retry: |
| ff_layout_pg_check_layout(pgio, req); |
| /* Use full layout for now */ |
| @@ -852,6 +855,8 @@ retry: |
| if (!pgio->pg_lseg) |
| goto out_nolseg; |
| } |
| + /* Reset wb_nio, since getting layout segment was successful */ |
| + req->wb_nio = 0; |
| |
| ds = ff_layout_get_ds_for_read(pgio, &ds_idx); |
| if (!ds) { |
| @@ -868,14 +873,24 @@ retry: |
| pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize; |
| |
| pgio->pg_mirror_idx = ds_idx; |
| - |
| - if (NFS_SERVER(pgio->pg_inode)->flags & |
| - (NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR)) |
| - pgio->pg_maxretrans = io_maxretrans; |
| return; |
| out_nolseg: |
| - if (pgio->pg_error < 0) |
| - return; |
| + 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; |
| + } |
| out_mds: |
| trace_pnfs_mds_fallback_pg_init_read(pgio->pg_inode, |
| 0, NFS4_MAX_UINT64, IOMODE_READ, |