pNFS/flexfiles: Treat ENETUNREACH errors as fatal in containers
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Thu, 20 Mar 2025 12:04:35 +0000 (08:04 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Fri, 21 Mar 2025 16:44:24 +0000 (12:44 -0400)
Propagate the NFS_MOUNT_NETUNREACH_FATAL flag to work with the pNFS
flexfiles client. In these circumstances, the client needs to treat the
ENETDOWN and ENETUNREACH errors as fatal, and should abandon the
attempted I/O.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Tested-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/nfs3client.c
fs/nfs/nfs4client.c
include/linux/nfs4.h

index 98b45b636be33072d0d4bdffe14392058ab19975..f89fdba7289d26b438ca06ade8ab38f86cc817b9 100644 (file)
@@ -1154,10 +1154,14 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
                rpc_wake_up(&tbl->slot_tbl_waitq);
                goto reset;
        /* RPC connection errors */
+       case -ENETDOWN:
+       case -ENETUNREACH:
+               if (test_bit(NFS_CS_NETUNREACH_FATAL, &clp->cl_flags))
+                       return -NFS4ERR_FATAL_IOERROR;
+               fallthrough;
        case -ECONNREFUSED:
        case -EHOSTDOWN:
        case -EHOSTUNREACH:
-       case -ENETUNREACH:
        case -EIO:
        case -ETIMEDOUT:
        case -EPIPE:
@@ -1183,6 +1187,7 @@ reset:
 
 /* Retry all errors through either pNFS or MDS except for -EJUKEBOX */
 static int ff_layout_async_handle_error_v3(struct rpc_task *task,
+                                          struct nfs_client *clp,
                                           struct pnfs_layout_segment *lseg,
                                           u32 idx)
 {
@@ -1200,6 +1205,11 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
        case -EJUKEBOX:
                nfs_inc_stats(lseg->pls_layout->plh_inode, NFSIOS_DELAY);
                goto out_retry;
+       case -ENETDOWN:
+       case -ENETUNREACH:
+               if (test_bit(NFS_CS_NETUNREACH_FATAL, &clp->cl_flags))
+                       return -NFS4ERR_FATAL_IOERROR;
+               fallthrough;
        default:
                dprintk("%s DS connection error %d\n", __func__,
                        task->tk_status);
@@ -1234,7 +1244,7 @@ static int ff_layout_async_handle_error(struct rpc_task *task,
 
        switch (vers) {
        case 3:
-               return ff_layout_async_handle_error_v3(task, lseg, idx);
+               return ff_layout_async_handle_error_v3(task, clp, lseg, idx);
        case 4:
                return ff_layout_async_handle_error_v4(task, state, clp,
                                                       lseg, idx);
@@ -1337,6 +1347,9 @@ static int ff_layout_read_done_cb(struct rpc_task *task,
                return task->tk_status;
        case -EAGAIN:
                goto out_eagain;
+       case -NFS4ERR_FATAL_IOERROR:
+               task->tk_status = -EIO;
+               return 0;
        }
 
        return 0;
@@ -1507,6 +1520,9 @@ static int ff_layout_write_done_cb(struct rpc_task *task,
                return task->tk_status;
        case -EAGAIN:
                return -EAGAIN;
+       case -NFS4ERR_FATAL_IOERROR:
+               task->tk_status = -EIO;
+               return 0;
        }
 
        if (hdr->res.verf->committed == NFS_FILE_SYNC ||
@@ -1551,6 +1567,9 @@ static int ff_layout_commit_done_cb(struct rpc_task *task,
        case -EAGAIN:
                rpc_restart_call_prepare(task);
                return -EAGAIN;
+       case -NFS4ERR_FATAL_IOERROR:
+               task->tk_status = -EIO;
+               return 0;
        }
 
        ff_layout_set_layoutcommit(data->inode, data->lseg, data->lwb);
index b0c8a39c2bbdeab011a468a6b267d20a8d8ce91e..0d7310c1ee0c0c317740588e4910cd7316502ca2 100644 (file)
@@ -120,6 +120,8 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,
 
        if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
                __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
+       if (test_bit(NFS_CS_NETUNREACH_FATAL, &mds_clp->cl_flags))
+               __set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags);
 
        __set_bit(NFS_CS_DS, &cl_init.init_flags);
 
index 8f7d40844cdc5fe416cb500e534612257f3a32de..162c85a83a14aecf101625432cc3b94cd4c6fa42 100644 (file)
@@ -939,6 +939,9 @@ static int nfs4_set_client(struct nfs_server *server,
                __set_bit(NFS_CS_TSM_POSSIBLE, &cl_init.init_flags);
        server->port = rpc_get_port((struct sockaddr *)addr);
 
+       if (server->flags & NFS_MOUNT_NETUNREACH_FATAL)
+               __set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags);
+
        /* Allocate or find a client reference we can use */
        clp = nfs_get_client(&cl_init);
        if (IS_ERR(clp))
@@ -1013,6 +1016,8 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
 
        if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
                __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
+       if (test_bit(NFS_CS_NETUNREACH_FATAL, &mds_clp->cl_flags))
+               __set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags);
 
        __set_bit(NFS_CS_PNFS, &cl_init.init_flags);
        cl_init.max_connect = NFS_MAX_TRANSPORTS;
index 5fa60fe441b5f96e80429b1f3048588a86f78599..d8cad844870aa74ce1e0cc78c499fb001d898c93 100644 (file)
@@ -300,6 +300,7 @@ enum nfsstat4 {
 /* error codes for internal client use */
 #define NFS4ERR_RESET_TO_MDS   12001
 #define NFS4ERR_RESET_TO_PNFS  12002
+#define NFS4ERR_FATAL_IOERROR  12003
 
 static inline bool seqid_mutating_err(u32 err)
 {