]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
pnfs/flexfiles: retry getting layout segment for reads
authorMike Snitzer <snitzer@kernel.org>
Fri, 17 Jan 2025 01:05:39 +0000 (20:05 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 13 Mar 2025 11:47:12 +0000 (12:47 +0100)
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

index a263bfec4244dddfce1cb9989a793dbd0accd803..1af0b8ad83f2d0069970efb196ae6c80ec672e01 100644 (file)
@@ -840,6 +840,9 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
        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 */
@@ -853,6 +856,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) {
@@ -869,14 +874,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,