blob: 6fea773955d4cb81387bbee2390ab98554efe5ac [file] [log] [blame]
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)