Hi,

Currently, mount_nfs will attempt to use NFSv3 and fallback to NFSv2. The manual page says:

     nfsv2   Use the NFS Version 2 protocol (the default is to try
             version 3 first then version 2).  Note that NFS version 2
             has a file size limit of 2 gigabytes.

And the code agrees, too:

%%%%%%%%
        if (trymntmode == V4) {
                nfsvers = 4;
                mntvers = 3; /* Workaround for GCC. */
        } else if (trymntmode == V2) {
                nfsvers = 2;
                mntvers = 1;
        } else {
                nfsvers = 3;
                mntvers = 3;
        }
%%%%%%%%

When trymntmode == ANY, which is the default, mount_nfs would attempt NFSv3, and if rpcb_getaddr() returned RPC_PROGVERSMISMATCH, it would try again with trymntmode = V2.

Nowadays, it seems that NFSv4 is becoming more and more popular. If a server is providing only NFSv4 service, when mounting without -o nfsv4, the user would receive message like:

        RPCPROG_MNT: RPC:Timed out

A friend of mine who is using TrueNAS core hit this yesterday and his Linux client worked just fine. It took me some time to figure out that the root cause. It seems that modern Linux distributions have been using NFSv4 by default for some time.

So I think it makes sense to teach mount_nfs to attempt NFSv4, then NFSv3 and NFSv2. However, this might be a POLA violation and we would like to know if there is any objections.

(I've attached a patch but I haven't actually tested it yet).

Cheers,
From eb6e60233d840d072d0280325ca2cb37455dc2f1 Mon Sep 17 00:00:00 2001
From: Xin LI <delp...@freebsd.org>
Date: Mon, 3 Jan 2022 10:48:17 -0800
Subject: [PATCH] mount_nfs: Attempt NFSv4 before NFSv3 and NFSv2.

---
 sbin/mount_nfs/mount_nfs.8 |  6 +++---
 sbin/mount_nfs/mount_nfs.c | 29 ++++++++++++++++++++---------
 2 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/sbin/mount_nfs/mount_nfs.8 b/sbin/mount_nfs/mount_nfs.8
index 648cb2128e90..741b5c24a080 100644
--- a/sbin/mount_nfs/mount_nfs.8
+++ b/sbin/mount_nfs/mount_nfs.8
@@ -28,7 +28,7 @@
 .\"	@(#)mount_nfs.8	8.3 (Berkeley) 3/29/95
 .\" $FreeBSD$
 .\"
-.Dd July 10, 2021
+.Dd January 10, 2022
 .Dt MOUNT_NFS 8
 .Os
 .Sh NAME
@@ -216,8 +216,8 @@ This option requires the
 .Cm nfsv4
 option.
 .It Cm nfsv2
-Use the NFS Version 2 protocol (the default is to try version 3 first
-then version 2).
+Use the NFS Version 2 protocol (the default is to try version 4 first,
+then version 3, then version 2).
 Note that NFS version 2 has a file size limit of 2 gigabytes.
 .It Cm nfsv3
 Use the NFS Version 3 protocol.
diff --git a/sbin/mount_nfs/mount_nfs.c b/sbin/mount_nfs/mount_nfs.c
index e1eaf206e982..e6d7e0afbfb7 100644
--- a/sbin/mount_nfs/mount_nfs.c
+++ b/sbin/mount_nfs/mount_nfs.c
@@ -125,6 +125,7 @@ static enum mountmode {
 	ANY,
 	V2,
 	V3,
+	V3orV2,
 	V4
 } mountmode = ANY;
 
@@ -777,15 +778,21 @@ nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr,
 	}
 
 tryagain:
-	if (trymntmode == V4) {
+	switch (trymntmode) {
+	case V4:
+	case ANY:
 		nfsvers = 4;
 		mntvers = 3; /* Workaround for GCC. */
-	} else if (trymntmode == V2) {
-		nfsvers = 2;
-		mntvers = 1;
-	} else {
+		break;
+	case V3orV2:
+	case V3:
 		nfsvers = 3;
 		mntvers = 3;
+		break;
+	case V2:
+		nfsvers = 2;
+		mntvers = 1;
+		break;
 	}
 
 	if (portspec != NULL) {
@@ -799,10 +806,14 @@ nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr,
 
 		if (!rpcb_getaddr(NFS_PROGRAM, nfsvers, nconf, &nfs_nb,
 		    hostp)) {
-			if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH &&
-			    trymntmode == ANY) {
-				trymntmode = V2;
-				goto tryagain;
+			if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) {
+				if (trymntmode == ANY) {
+					trymntmode = V3orV2;
+					goto tryagain;
+				} else if (trymntmode == V3orV2) {
+					trymntmode = V2;
+					goto tryagain;
+				}
 			}
 			snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s",
 			    netid, hostp, spec,
-- 
2.34.1

Reply via email to