diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index bdd7c24..89b90a1 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -931,19 +931,45 @@ static int nfs_try_mount(struct nfsmount_info *mi) * failed so far, but fail immediately if there is a local * error (like a bad mount option). * - * ESTALE is also a temporary error because some servers - * return ESTALE when a share is temporarily offline. + * If there is a remote error, like ESTALE or RPC_PROGNOTREGISTERED + * then it is probably permanent, but there is a small chance + * the it is temporary can we caught the server at an awkward + * time during start-up. So require that we see three of those + * before treating them as permanent. + * For ECONNREFUSED, wait a bit longer as there is often a longer + * gap between the network being ready and the NFS server starting. * * Returns 1 if we should fail immediately, or 0 if we * should retry. */ static int nfs_is_permanent_error(int error) { + static int prev_error; + static int rpt_cnt; + + if (error == prev_error) + rpt_cnt += 1; + else + rpt_cnt = 1; + prev_error = error; + switch (error) { case ESTALE: - case ETIMEDOUT: + case EOPNOTSUPP: /* aka RPC_PROGNOTREGISTERED */ + /* If two in a row, assume permanent */ + return rpt_cnt >= 3; case ECONNREFUSED: + /* Like the above, this can be temporary during a + * small window. However it is typically a larger + * window than for the others, and we have historically + * treated this as a temporary (i.e. long timeout) + * error with no complaints, so continue to treat + * it as temporary. + */ + return 0; /* temporary */ + case ETIMEDOUT: case EHOSTUNREACH: + case EAGAIN: return 0; /* temporary */ default: return 1; /* permanent */ @@ -987,7 +1013,7 @@ static int nfsmount_fg(struct nfsmount_info *mi) if (secs > 10) secs = 10; } - }; + } mount_error(mi->spec, mi->node, errno); return EX_FAIL; @@ -1005,8 +1031,7 @@ static int nfsmount_parent(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - /* retry background mounts when the server is not up */ - if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) { + if (nfs_is_permanent_error(errno)) { mount_error(mi->spec, mi->node, errno); return EX_FAIL; } @@ -1041,8 +1066,7 @@ static int nfsmount_child(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - /* retry background mounts when the server is not up */ - if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) + if (nfs_is_permanent_error(errno)) break; if (time(NULL) > timeout)