Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFS: Treat ENETUNREACH errors as fatal in containers

Propagate the NFS_MOUNT_NETUNREACH_FATAL flag to work with the generic
NFS client. If the flag is set, the client will receive ENETDOWN and
ENETUNREACH errors from the RPC layer, and is expected to treat them as
being fatal.

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>

+39 -9
+5
fs/nfs/client.c
··· 546 546 args.flags |= RPC_CLNT_CREATE_NOPING; 547 547 if (test_bit(NFS_CS_REUSEPORT, &clp->cl_flags)) 548 548 args.flags |= RPC_CLNT_CREATE_REUSEPORT; 549 + if (test_bit(NFS_CS_NETUNREACH_FATAL, &clp->cl_flags)) 550 + args.flags |= RPC_CLNT_CREATE_NETUNREACH_FATAL; 549 551 550 552 if (!IS_ERR(clp->cl_rpcclient)) 551 553 return 0; ··· 710 708 ctx->timeo, ctx->retrans); 711 709 if (ctx->flags & NFS_MOUNT_NORESVPORT) 712 710 set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); 711 + 712 + if (ctx->flags & NFS_MOUNT_NETUNREACH_FATAL) 713 + __set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags); 713 714 714 715 /* Allocate or find a client reference we can use */ 715 716 clp = nfs_get_client(&cl_init);
+2
fs/nfs/nfs4client.c
··· 233 233 __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags); 234 234 if (test_bit(NFS_CS_PNFS, &cl_init->init_flags)) 235 235 __set_bit(NFS_CS_PNFS, &clp->cl_flags); 236 + if (test_bit(NFS_CS_NETUNREACH_FATAL, &cl_init->init_flags)) 237 + __set_bit(NFS_CS_NETUNREACH_FATAL, &clp->cl_flags); 236 238 /* 237 239 * Set up the connection to the server before we add add to the 238 240 * global list.
+3
fs/nfs/nfs4proc.c
··· 195 195 return -EBUSY; 196 196 case -NFS4ERR_NOT_SAME: 197 197 return -ENOTSYNC; 198 + case -ENETDOWN: 199 + case -ENETUNREACH: 200 + break; 198 201 default: 199 202 dprintk("%s could not handle NFSv4 error %d\n", 200 203 __func__, -err);
+1
include/linux/nfs_fs_sb.h
··· 50 50 #define NFS_CS_DS 7 /* - Server is a DS */ 51 51 #define NFS_CS_REUSEPORT 8 /* - reuse src port on reconnect */ 52 52 #define NFS_CS_PNFS 9 /* - Server used for pnfs */ 53 + #define NFS_CS_NETUNREACH_FATAL 10 /* - ENETUNREACH errors are fatal */ 53 54 struct sockaddr_storage cl_addr; /* server identifier */ 54 55 size_t cl_addrlen; 55 56 char * cl_hostname; /* hostname of server */
+4 -1
include/linux/sunrpc/clnt.h
··· 64 64 cl_noretranstimeo: 1,/* No retransmit timeouts */ 65 65 cl_autobind : 1,/* use getport() */ 66 66 cl_chatty : 1,/* be verbose */ 67 - cl_shutdown : 1;/* rpc immediate -EIO */ 67 + cl_shutdown : 1,/* rpc immediate -EIO */ 68 + cl_netunreach_fatal : 1; 69 + /* Treat ENETUNREACH errors as fatal */ 68 70 struct xprtsec_parms cl_xprtsec; /* transport security policy */ 69 71 70 72 struct rpc_rtt * cl_rtt; /* RTO estimator data */ ··· 177 175 #define RPC_CLNT_CREATE_SOFTERR (1UL << 10) 178 176 #define RPC_CLNT_CREATE_REUSEPORT (1UL << 11) 179 177 #define RPC_CLNT_CREATE_CONNECTED (1UL << 12) 178 + #define RPC_CLNT_CREATE_NETUNREACH_FATAL (1UL << 13) 180 179 181 180 struct rpc_clnt *rpc_create(struct rpc_create_args *args); 182 181 struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
+1
include/linux/sunrpc/sched.h
··· 134 134 #define RPC_TASK_MOVEABLE 0x0004 /* nfs4.1+ rpc tasks */ 135 135 #define RPC_TASK_NULLCREDS 0x0010 /* Use AUTH_NULL credential */ 136 136 #define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ 137 + #define RPC_TASK_NETUNREACH_FATAL 0x0040 /* ENETUNREACH is fatal */ 137 138 #define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ 138 139 #define RPC_TASK_NO_ROUND_ROBIN 0x0100 /* send requests on "main" xprt */ 139 140 #define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
+1
include/trace/events/sunrpc.h
··· 343 343 { RPC_TASK_MOVEABLE, "MOVEABLE" }, \ 344 344 { RPC_TASK_NULLCREDS, "NULLCREDS" }, \ 345 345 { RPC_CALL_MAJORSEEN, "MAJORSEEN" }, \ 346 + { RPC_TASK_NETUNREACH_FATAL, "NETUNREACH_FATAL"}, \ 346 347 { RPC_TASK_DYNAMIC, "DYNAMIC" }, \ 347 348 { RPC_TASK_NO_ROUND_ROBIN, "NO_ROUND_ROBIN" }, \ 348 349 { RPC_TASK_SOFT, "SOFT" }, \
+22 -8
net/sunrpc/clnt.c
··· 512 512 clnt->cl_discrtry = 1; 513 513 if (!(args->flags & RPC_CLNT_CREATE_QUIET)) 514 514 clnt->cl_chatty = 1; 515 + if (args->flags & RPC_CLNT_CREATE_NETUNREACH_FATAL) 516 + clnt->cl_netunreach_fatal = 1; 515 517 516 518 return clnt; 517 519 } ··· 664 662 new->cl_noretranstimeo = clnt->cl_noretranstimeo; 665 663 new->cl_discrtry = clnt->cl_discrtry; 666 664 new->cl_chatty = clnt->cl_chatty; 665 + new->cl_netunreach_fatal = clnt->cl_netunreach_fatal; 667 666 new->cl_principal = clnt->cl_principal; 668 667 new->cl_max_connect = clnt->cl_max_connect; 669 668 return new; ··· 1198 1195 task->tk_flags |= RPC_TASK_TIMEOUT; 1199 1196 if (clnt->cl_noretranstimeo) 1200 1197 task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT; 1198 + if (clnt->cl_netunreach_fatal) 1199 + task->tk_flags |= RPC_TASK_NETUNREACH_FATAL; 1201 1200 atomic_inc(&clnt->cl_task_count); 1202 1201 } 1203 1202 ··· 2107 2102 case -EPROTONOSUPPORT: 2108 2103 trace_rpcb_bind_version_err(task); 2109 2104 goto retry_timeout; 2105 + case -ENETDOWN: 2106 + case -ENETUNREACH: 2107 + if (task->tk_flags & RPC_TASK_NETUNREACH_FATAL) 2108 + break; 2109 + fallthrough; 2110 2110 case -ECONNREFUSED: /* connection problems */ 2111 2111 case -ECONNRESET: 2112 2112 case -ECONNABORTED: 2113 2113 case -ENOTCONN: 2114 2114 case -EHOSTDOWN: 2115 - case -ENETDOWN: 2116 2115 case -EHOSTUNREACH: 2117 - case -ENETUNREACH: 2118 2116 case -EPIPE: 2119 2117 trace_rpcb_unreachable_err(task); 2120 2118 if (!RPC_IS_SOFTCONN(task)) { ··· 2199 2191 2200 2192 task->tk_status = 0; 2201 2193 switch (status) { 2194 + case -ENETDOWN: 2195 + case -ENETUNREACH: 2196 + if (task->tk_flags & RPC_TASK_NETUNREACH_FATAL) 2197 + break; 2198 + fallthrough; 2202 2199 case -ECONNREFUSED: 2203 2200 case -ECONNRESET: 2204 2201 /* A positive refusal suggests a rebind is needed. */ 2205 - if (RPC_IS_SOFTCONN(task)) 2206 - break; 2207 2202 if (clnt->cl_autobind) { 2208 2203 rpc_force_rebind(clnt); 2204 + if (RPC_IS_SOFTCONN(task)) 2205 + break; 2209 2206 goto out_retry; 2210 2207 } 2211 2208 fallthrough; 2212 2209 case -ECONNABORTED: 2213 - case -ENETDOWN: 2214 - case -ENETUNREACH: 2215 2210 case -EHOSTUNREACH: 2216 2211 case -EPIPE: 2217 2212 case -EPROTO: ··· 2466 2455 trace_rpc_call_status(task); 2467 2456 task->tk_status = 0; 2468 2457 switch(status) { 2469 - case -EHOSTDOWN: 2470 2458 case -ENETDOWN: 2471 - case -EHOSTUNREACH: 2472 2459 case -ENETUNREACH: 2460 + if (task->tk_flags & RPC_TASK_NETUNREACH_FATAL) 2461 + goto out_exit; 2462 + fallthrough; 2463 + case -EHOSTDOWN: 2464 + case -EHOSTUNREACH: 2473 2465 case -EPERM: 2474 2466 if (RPC_IS_SOFTCONN(task)) 2475 2467 goto out_exit;