mount: Support negotiation between v4, v3, and v2 nfs-utils-1-2-1-rc6
authorChuck Lever <chuck.lever@oracle.com>
Tue, 29 Sep 2009 14:38:52 +0000 (10:38 -0400)
committerSteve Dickson <steved@redhat.com>
Tue, 29 Sep 2009 14:38:52 +0000 (10:38 -0400)
When negotiating between v3 and v2, mount.nfs first tries v3, then v2.
Take the same approach for v4: try v4 first, then v3, then v2, in
order to get the highest NFS version both the client and server
support.

No MNT request is needed for v4.  Since we want to avoid an rpcbind
query for the v4 attempt, just go straight for mount(2) without a MNT
request or rpcbind negotiation first.  If the server reports that v4
is not supported, try lower versions.

The decisions made by the fg/bg retry loop have nothing to do with
version negotation.  To avoid a layering violation, mount.nfs's
multi-version negotiation strategy is wholly encapsulated within
nfs_try_mount().  Thus, code duplication between nfsmount_fg(),
nfsmount_parent(), and nfsmount_child() is avoided.

For now, negotiating version 4 is supported only on kernels that can
handle the vers=4 option on type "nfs" file systems.  At some point
we could also allow mount.nfs to switch to an "nfs4" file system in
this case.

Since mi->version == 0 can now mean v2, v3, or v4, limit the versions
tried for RDMA mounts.  Today, only version 3 supports RDMA.

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

index 25b206f..069bdc1 100644 (file)
@@ -278,6 +278,11 @@ static int nfs_validate_options(struct nfsmount_info *mi)
                return 0;
        if (strncmp(mi->type, "nfs4", 4) == 0)
                mi->version = 4;
+       else {
+               char *option = po_get(mi->options, "proto");
+               if (option && strcmp(option, "rdma") == 0)
+                       mi->version = 3;
+       }
 
        if (!nfs_append_sloppy_option(mi->options))
                return 0;
@@ -558,11 +563,17 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi)
                return result;
        }
 
+       if (mi->version == 0) {
+               if (po_append(options, "vers=4") == PO_FAILED) {
+                       errno = EINVAL;
+                       goto out_fail;
+               }
+       }
+
        if (!nfs_append_clientaddr_option(sap, mi->salen, options)) {
                errno = EINVAL;
                goto out_fail;
        }
-
        /*
         * Update option string to be recorded in /etc/mtab.
         */
@@ -590,6 +601,12 @@ static int nfs_try_mount(struct nfsmount_info *mi)
 
        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)
+                               break;
+               }
        case 2:
        case 3:
                result = nfs_try_mount_v3v2(mi);