]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mount/stropts.c
mount.nfs: Use nfs_nfs_protocol() for checking for proto=rdma
[nfs-utils.git] / utils / mount / stropts.c
index fc1b0da5da65a723ba6385a4f2bfbc34e339bab1..9695c739c4f53844a65119b3dd049faca2b304ee 100644 (file)
@@ -303,8 +303,10 @@ static int nfs_set_version(struct nfsmount_info *mi)
        if (strncmp(mi->type, "nfs4", 4) == 0)
                mi->version = 4;
        else {
-               char *option = po_get(mi->options, "proto");
-               if (option && strcmp(option, "rdma") == 0)
+               unsigned long protocol;
+               if (!nfs_nfs_protocol(mi->options, &protocol))
+                       return 0;
+               if (protocol == NFSPROTO_RDMA)
                        mi->version = 3;
        }
 
@@ -490,14 +492,19 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options)
        union nfs_sockaddr mnt_address;
        struct sockaddr *mnt_saddr = &mnt_address.sa;
        socklen_t mnt_salen = sizeof(mnt_address);
+       unsigned long protocol;
        struct pmap mnt_pmap;
        char *option;
 
        /*
-        * Skip option negotiation for proto=rdma mounts.
+        * Version and transport negotiation is not required
+        * and does not work for RDMA mounts.
         */
-       option = po_get(options, "proto");
-       if (option && strcmp(option, "rdma") == 0)
+       if (!nfs_nfs_protocol(options, &protocol)) {
+               errno = EINVAL;
+               return 0;
+       }
+       if (protocol == NFSPROTO_RDMA)
                goto out;
 
        /*
@@ -538,7 +545,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options)
 
        if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap,
                                        mnt_saddr, &mnt_pmap)) {
-               errno = EINVAL;
+               if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO)
+                       errno = EPROTONOSUPPORT;
+               else
+                       errno = EINVAL;
                return 0;
        }
 
@@ -576,12 +586,9 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
        return !result;
 }
 
-/*
- * For "-t nfs vers=2" or "-t nfs vers=3" mounts.
- */
-static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
+static int nfs_do_mount_v3v2(struct nfsmount_info *mi,
+               struct sockaddr *sap, socklen_t salen)
 {
-       struct addrinfo *ai = mi->address;
        struct mount_options *options = po_dup(mi->options);
        int result = 0;
 
@@ -589,18 +596,21 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
                errno = ENOMEM;
                return result;
        }
-
-       if (!nfs_append_addr_option(ai->ai_addr, ai->ai_addrlen, options)) {
-               errno = EINVAL;
+       errno = 0;
+       if (!nfs_append_addr_option(sap, salen, options)) {
+               if (errno == 0)
+                       errno = EINVAL;
                goto out_fail;
        }
 
        if (!nfs_fix_mounthost_option(options, mi->hostname)) {
-               errno = EINVAL;
+               if (errno == 0)
+                       errno = EINVAL;
                goto out_fail;
        }
        if (!mi->fake && !nfs_verify_lock_option(options)) {
-               errno = EINVAL;
+               if (errno == 0)
+                       errno = EINVAL;
                goto out_fail;
        }
 
@@ -630,11 +640,36 @@ out_fail:
 }
 
 /*
- * For "-t nfs -o vers=4" or "-t nfs4" mounts.
+ * Attempt a "-t nfs vers=2" or "-t nfs vers=3" mount.
+ *
+ * Returns TRUE if successful, otherwise FALSE.
+ * "errno" is set to reflect the individual error.
  */
-static int nfs_try_mount_v4(struct nfsmount_info *mi)
+static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
+{
+       struct addrinfo *ai;
+       int ret;
+
+       for (ai = mi->address; ai != NULL; ai = ai->ai_next) {
+               ret = nfs_do_mount_v3v2(mi, ai->ai_addr, ai->ai_addrlen);
+               if (ret != 0)
+                       return ret;
+
+               switch (errno) {
+               case ECONNREFUSED:
+               case EOPNOTSUPP:
+               case EHOSTUNREACH:
+                       continue;
+               default:
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int nfs_do_mount_v4(struct nfsmount_info *mi,
+               struct sockaddr *sap, socklen_t salen)
 {
-       struct addrinfo *ai = mi->address;
        struct mount_options *options = po_dup(mi->options);
        int result = 0;
 
@@ -662,12 +697,12 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi)
                }
        }
 
-       if (!nfs_append_addr_option(ai->ai_addr, ai->ai_addrlen, options)) {
+       if (!nfs_append_addr_option(sap, salen, options)) {
                errno = EINVAL;
                goto out_fail;
        }
 
-       if (!nfs_append_clientaddr_option(ai->ai_addr, ai->ai_addrlen, options)) {
+       if (!nfs_append_clientaddr_option(sap, salen, options)) {
                errno = EINVAL;
                goto out_fail;
        }
@@ -691,6 +726,33 @@ out_fail:
        return result;
 }
 
+/*
+ * Attempt a "-t nfs -o vers=4" or "-t nfs4" mount.
+ *
+ * Returns TRUE if successful, otherwise FALSE.
+ * "errno" is set to reflect the individual error.
+ */
+static int nfs_try_mount_v4(struct nfsmount_info *mi)
+{
+       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.
  *
@@ -750,6 +812,7 @@ static int nfs_is_permanent_error(int error)
        case ESTALE:
        case ETIMEDOUT:
        case ECONNREFUSED:
+       case EHOSTUNREACH:
                return 0;       /* temporary */
        default:
                return 1;       /* permanent */