- if (strncmp(type, "nfs4", 4) == 0)
- return try_nfs4mount(spec, node, flags,
- options, fake, extra_opts);
- else
- return try_nfs23mount(spec, node, flags,
- options, fake, extra_opts);
+ struct addrinfo *ai;
+ int ret;
+
+ for (ai = mi->address; ai != NULL; ai = ai->ai_next) {
+ ret = nfs_do_mount_v4(mi, ai->ai_addr, ai->ai_addrlen);
+ if (ret != 0)
+ return ret;
+
+ switch (errno) {
+ case ECONNREFUSED:
+ case EHOSTUNREACH:
+ continue;
+ default:
+ break;
+ }
+ }
+ return ret;
+}
+
+/*
+ * This is a single pass through the fg/bg loop.
+ *
+ * Returns TRUE if successful, otherwise FALSE.
+ * "errno" is set to reflect the individual error.
+ */
+static int nfs_try_mount(struct nfsmount_info *mi)
+{
+ int result = 0;
+
+ switch (mi->version) {
+ case 0:
+ if (linux_version_code() > MAKE_VERSION(2, 6, 31)) {
+ errno = 0;
+ result = nfs_try_mount_v4(mi);
+ if (errno != EPROTONOSUPPORT) {
+ /*
+ * To deal with legacy Linux servers that don't
+ * automatically export a pseudo root, retry
+ * ENOENT errors using version 3. And for
+ * Linux servers prior to 2.6.25, retry EPERM
+ */
+ if (errno != ENOENT && errno != EPERM)
+ break;
+ }
+ }
+ case 2:
+ case 3:
+ result = nfs_try_mount_v3v2(mi);
+ break;
+ case 4:
+ result = nfs_try_mount_v4(mi);
+ break;
+ default:
+ errno = EIO;
+ }
+
+ return result;
+}
+
+/*
+ * Distinguish between permanent and temporary errors.
+ *
+ * Basically, we retry if communication with the server has
+ * 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.
+ *
+ * Returns 1 if we should fail immediately, or 0 if we
+ * should retry.
+ */
+static int nfs_is_permanent_error(int error)
+{
+ switch (error) {
+ case ESTALE:
+ case ETIMEDOUT:
+ case ECONNREFUSED:
+ case EHOSTUNREACH:
+ return 0; /* temporary */
+ default:
+ return 1; /* permanent */
+ }