From 3a612faba5c40a59257db50e3a2da30c02a8c969 Mon Sep 17 00:00:00 2001 From: Benjamin Coddington Date: Wed, 9 Sep 2026 13:11:47 -0400 Subject: [PATCH] NFSv4/flexfiles: report the intended opnum when DS connection setup fails When nfs4_ff_layout_prepare_ds() cannot establish a connection to a data server, it records a device error with opnum OP_ILLEGAL, since no operation ever made it to the wire. But servers can use the ff_ioerr4 opnum to distinguish failed read-class operations from write-class operations when deciding how to recover the affected mirror -- a mirror that may have missed writes needs to be brought back in sync, while one that merely failed to serve a read does not. OP_ILLEGAL gives the server nothing to act on. Every caller of nfs4_ff_layout_prepare_ds() knows which operation it was preparing to send, and the existing fail_return argument already divides the callers along the same boundary (false for READ, true for WRITE and COMMIT). Replace the boolean with the intended opnum, derive the layout return decision from it, and report it in the tracked device error instead of OP_ILLEGAL. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington Reviewed-by: Tigran Mkrtchyan Signed-off-by: Anna Schumaker --- fs/nfs/flexfilelayout/flexfilelayout.c | 13 ++++++++----- fs/nfs/flexfilelayout/flexfilelayout.h | 2 +- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 14 ++++++++------ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 2ea63fda0035..6fa6aa82d509 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -883,7 +883,7 @@ ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg, mirror_ds = ff_layout_get_mirror_ds(lseg->pls_layout, mirror, *dss_id); ds = nfs4_ff_layout_prepare_ds(lseg, mirror, mirror_ds, - *dss_id, false); + *dss_id, OP_READ); if (IS_ERR(ds)) { nfs4_ff_layout_put_deviceid(mirror_ds); ret = ERR_CAST(ds); @@ -1132,7 +1132,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, mirror_ds = ff_layout_get_mirror_ds(pgio->pg_lseg->pls_layout, mirror, dss_id); ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, mirror, - mirror_ds, dss_id, true); + mirror_ds, dss_id, OP_WRITE); if (IS_ERR(ds)) { nfs4_ff_layout_put_deviceid(mirror_ds); if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg)) @@ -2188,7 +2188,8 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr) mirror->dss_count, offset); mirror_ds = ff_layout_get_mirror_ds(lseg->pls_layout, mirror, dss_id); - ds = nfs4_ff_layout_prepare_ds(lseg, mirror, mirror_ds, dss_id, false); + ds = nfs4_ff_layout_prepare_ds(lseg, mirror, mirror_ds, dss_id, + OP_READ); if (IS_ERR(ds)) { ds_fatal_error = nfs_error_is_fatal(PTR_ERR(ds)); goto out_failed; @@ -2288,7 +2289,8 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync) mirror->dss_count, offset); mirror_ds = ff_layout_get_mirror_ds(lseg->pls_layout, mirror, dss_id); - ds = nfs4_ff_layout_prepare_ds(lseg, mirror, mirror_ds, dss_id, true); + ds = nfs4_ff_layout_prepare_ds(lseg, mirror, mirror_ds, dss_id, + OP_WRITE); if (IS_ERR(ds)) { ds_fatal_error = nfs_error_is_fatal(PTR_ERR(ds)); goto out_failed; @@ -2398,7 +2400,8 @@ static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how) mirror = FF_LAYOUT_COMP(lseg, idx); dss_id = calc_dss_id_from_commit(lseg, data->ds_commit_index); mirror_ds = ff_layout_get_mirror_ds(lseg->pls_layout, mirror, dss_id); - ds = nfs4_ff_layout_prepare_ds(lseg, mirror, mirror_ds, dss_id, true); + ds = nfs4_ff_layout_prepare_ds(lseg, mirror, mirror_ds, dss_id, + OP_COMMIT); if (IS_ERR(ds)) goto out_err; diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h index 72b11034851a..09c3cd6964fd 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.h +++ b/fs/nfs/flexfilelayout/flexfilelayout.h @@ -256,7 +256,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, struct nfs4_ff_layout_mirror *mirror, struct nfs4_ff_layout_ds *mirror_ds, u32 dss_id, - bool fail_return); + enum nfs_opnum4 opnum); struct rpc_clnt * nfs4_ff_find_or_create_ds_client(const struct nfs4_ff_layout_ds *mirror_ds, diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index d52f485d0650..bc95628a811f 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -379,7 +379,7 @@ ff_layout_get_mirror_ds(struct pnfs_layout_hdr *lo, * @mirror_ds: referenced device node for the stripe, from * ff_layout_get_mirror_ds() (may be an ERR_PTR) * @dss_id: DS stripe id to select stripe to use - * @fail_return: return layout on connect failure? + * @opnum: operation this connection is being prepared for * * Try to prepare a DS connection to accept an RPC call. This involves * selecting a mirror to use and connecting the client to it if it's not @@ -387,8 +387,10 @@ ff_layout_get_mirror_ds(struct pnfs_layout_hdr *lo, * * Since we only need a single functioning mirror to satisfy a read, we don't * want to return the layout if there is one. For writes though, any down - * mirror should result in a LAYOUTRETURN. @fail_return is how we distinguish - * between the two cases. + * mirror should result in a LAYOUTRETURN. @opnum is how we distinguish + * between the two cases. On failure, @opnum is also reported in the tracked + * device error so that the server can tell which class of I/O the client + * was unable to send to the mirror. * * Returns a pointer to a connected DS object on success or NULL on failure. */ @@ -397,7 +399,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, struct nfs4_ff_layout_mirror *mirror, struct nfs4_ff_layout_ds *mirror_ds, u32 dss_id, - bool fail_return) + enum nfs_opnum4 opnum) { struct nfs4_pnfs_ds *ds; struct inode *ino = lseg->pls_layout->plh_inode; @@ -448,9 +450,9 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, NULL : &mirror_ds->id_node, dss_id, lseg->pls_range.offset, lseg->pls_range.length, NFS4ERR_NXIO, - OP_ILLEGAL, GFP_NOIO); + opnum, GFP_NOIO); ff_layout_send_layouterror(lseg); - if (fail_return || !ff_layout_has_available_ds(lseg)) + if (opnum != OP_READ || !ff_layout_has_available_ds(lseg)) pnfs_error_mark_layout_for_return(ino, lseg); ds = ERR_PTR(status); out: