]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS in pg_get_mirror_count_write
authorMike Snitzer <snitzer@kernel.org>
Thu, 4 Jun 2026 20:24:03 +0000 (16:24 -0400)
committerAnna Schumaker <anna.schumaker@hammerspace.com>
Mon, 8 Jun 2026 16:06:41 +0000 (12:06 -0400)
The FF_FLAGS_NO_IO_THRU_MDS flag lives on each lseg, so any fallback
decision made when there is no current lseg (e.g. between LAYOUTRETURN
and the next LAYOUTGET) cannot run the per-lseg check.

Introduce a sticky hdr-level ditto for FF_FLAGS_NO_IO_THRU_MDS in
struct nfs4_flexfile_layout::flags (NFS4_FF_HDR_NO_IO_THRU_MDS bit),
set whenever ff_layout_alloc_lseg() parses an lseg with the flag.  The
bit is never cleared for the lifetime of the layout hdr; the server is
assumed to be consistent in its no-fallback policy per file.
kzalloc() in ff_layout_alloc_layout_hdr() zero-initializes the field.

Use the new ff_layout_hdr_no_fallback_to_mds() helper to gate
ff_layout_pg_get_mirror_count_write(): when pnfs_update_layout() returns
NULL (e.g. NFS_LAYOUT_BULK_RECALL, pnfs_layout_io_test_failed,
pnfs_layoutgets_blocked) the existing code unconditionally calls
nfs_pageio_reset_write_mds().  This is a source of unwanted WRITE to
MDS.  Fix it by checking NFS4_FF_HDR_NO_IO_THRU_MDS bit, and if set
surface -EAGAIN instead; the writepage-side caller (nfs_do_writepage()
for buffered, nfs_direct_write_reschedule() for O_DIRECT) then
redirties the request so writeback retries via pNFS.

Fixes: 260074cd8413 ("pNFS/flexfiles: Add support for FF_FLAGS_NO_IO_THRU_MDS")
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/flexfilelayout/flexfilelayout.h

index 0a4a06d93e6a45ae16b1d32231d795f3885b0618..c4aa995026f67130eb903916ab1deb6b40cf9434 100644 (file)
@@ -636,6 +636,9 @@ 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)
+               set_bit(NFS4_FF_HDR_NO_IO_THRU_MDS,
+                       &FF_LAYOUT_FROM_HDR(lh)->flags);
 
        p = xdr_inline_decode(&stream, 4);
        if (!p)
@@ -1185,6 +1188,16 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,
                        0, NFS4_MAX_UINT64, IOMODE_RW,
                        NFS_I(pgio->pg_inode)->layout,
                        pgio->pg_lseg);
+       if (NFS_I(pgio->pg_inode)->layout &&
+           ff_layout_hdr_no_fallback_to_mds(NFS_I(pgio->pg_inode)->layout)) {
+               /*
+                * FF_FLAGS_NO_IO_THRU_MDS: no current lseg but the server's
+                * policy forbids MDS fallback.  Surface -EAGAIN so writeback
+                * retries rather than silently issuing the WRITE via MDS.
+                */
+               pgio->pg_error = -EAGAIN;
+               goto out;
+       }
        /* no lseg means that pnfs is not in use, so no mirroring here */
        nfs_pageio_reset_write_mds(pgio);
 out:
index 17a008c8e97ce97df3e9c06d6562efc3d18691db..a5bd00f69e824288e120b6256c6c90916cb37e91 100644 (file)
@@ -112,12 +112,16 @@ struct nfs4_ff_layout_segment {
        struct nfs4_ff_layout_mirror    *mirror_array[] __counted_by(mirror_array_cnt);
 };
 
+/* nfs4_flexfile_layout::flags bit indices */
+#define NFS4_FF_HDR_NO_IO_THRU_MDS  0   /* any lseg has had FF_FLAGS_NO_IO_THRU_MDS */
+
 struct nfs4_flexfile_layout {
        struct pnfs_layout_hdr generic_hdr;
        struct pnfs_ds_commit_info commit_info;
        struct list_head        mirrors;
        struct list_head        error_list; /* nfs4_ff_layout_ds_err */
        ktime_t                 last_report_time; /* Layoutstat report times */
+       unsigned long           flags;
 };
 
 struct nfs4_flexfile_layoutreturn_args {
@@ -184,6 +188,18 @@ ff_layout_no_fallback_to_mds(struct pnfs_layout_segment *lseg)
        return FF_LAYOUT_LSEG(lseg)->flags & FF_FLAGS_NO_IO_THRU_MDS;
 }
 
+/*
+ * Sticky hdr-level mirror of FF_FLAGS_NO_IO_THRU_MDS so callers that have
+ * no current lseg (e.g. between LAYOUTRETURN and the next LAYOUTGET) can
+ * still honor the no-MDS-fallback policy.
+ */
+static inline bool
+ff_layout_hdr_no_fallback_to_mds(struct pnfs_layout_hdr *lo)
+{
+       return test_bit(NFS4_FF_HDR_NO_IO_THRU_MDS,
+                       &FF_LAYOUT_FROM_HDR(lo)->flags);
+}
+
 static inline bool
 ff_layout_no_read_on_rw(struct pnfs_layout_segment *lseg)
 {