]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
text-based mount: Support protocol family negotiation
authorChuck Lever <chuck.lever@oracle.com>
Fri, 12 Feb 2010 18:38:59 +0000 (13:38 -0500)
committerSteve Dickson <steved@redhat.com>
Fri, 12 Feb 2010 18:41:48 +0000 (13:41 -0500)
Jeff Layton pointed out that the current negotiation logic in
stropts.c simply doesn't handle the case where a server may have an
IPv6 address and an IPv4 address, but only NFS/IPv4 is supported.
This is typical of all currently deployed Linux servers.

Add support for trying all addresses returned from DNS when
"proto=" is not specified on the command line.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
utils/mount/stropts.c

index fc1b0da5da65a723ba6385a4f2bfbc34e339bab1..9b8c38fa9b86bb045be854a63e6b4bff3d13bc84 100644 (file)
@@ -576,12 +576,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;
 
@@ -590,7 +587,7 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
                return result;
        }
 
-       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;
        }
@@ -630,11 +627,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 +684,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 +713,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.
  *