Skip to contentSkip to conversation

mount.nfs default version

PATCH In review Benjamin Coddington 2 participants 8 messages Nov 18, 2014 – Jan 28, 2015

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v2 cover mount.nfs default version

Here's the work posted yesterday broken out a bit with an addition of enabling nfsmount.conf by default, and the change to autonegotiate starting with version 4.2 (instead of 4.0) when no version is specified in either config or mount option.

Benjamin Coddington (6):
mount.nfs: default enable mount config file (nfsmount.conf) mount.nfs: fix a comment typo in parse options mount.nfs: parse options - add helper po_contains_prefix mount.nfs: Add struct nfs_version and generalize version parsing nfsmount.conf: Always parse versions
mount.nfs: configurable minor version defaults

 configure.ac             |    8 +-
 utils/mount/configfile.c |   36 +-----------
 utils/mount/network.c    |  122 ++++++++++++++++++-------------------
 utils/mount/network.h    |   15 ++++-
 utils/mount/nfsumount.c  |    4 +-
 utils/mount/parse_opt.c  |   26 ++++++++-
 utils/mount/parse_opt.h  |    2 +
 utils/mount/stropts.c    |  150 +++++++++++++++++++++++++++++++---------------
 8 files changed, 209 insertions(+), 154 deletions(-)
#1 lore raw

PATCH v2 1/6 mount.nfs: default enable mount config file (nfsmount.conf)

---
 configure.ac |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
configure.ac +4 -4
index e3af723..c13e7ee 100644
@@ -178,8 +178,10 @@ if test "$enable_mount" = yes; then
 	[AC_HELP_STRING([--enable-mountconfig],
                         [enable mount to use a configuration file])],
 	mountconfig=$enableval,
-	mountconfig=no)
-	if test "$enable_mountconfig" = yes; then
+	mountconfig=yes)
+	if test "$enable_mountconfig" = no; then
+		enable_mountconfig=
+	else
 		AC_DEFINE(MOUNT_CONFIG, 1, 
 			[Define this if you want mount to read a configuration file])
 		AC_ARG_WITH(mountfile,
@@ -191,8 +193,6 @@ if test "$enable_mount" = yes; then
 		AC_SUBST(mountfile)
 		AC_DEFINE_UNQUOTED(MOUNTOPTS_CONFFILE, "$mountfile", 
 			[This defines the location of the NFS mount configuration file])
-	else
-		enable_mountconfig=
 	fi
 	AC_SUBST(enable_mountconfig)
 	AM_CONDITIONAL(MOUNT_CONFIG, [test "$enable_mountconfig" = "yes"])
Signature · 1 line
1.7.1
#2 lore raw

PATCH v2 2/6 mount.nfs: fix a comment typo in parse options

In reply to Benjamin Coddington
---
 utils/mount/parse_opt.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
utils/mount/parse_opt.c +1 -1
index 75a0daa..342e210 100644
@@ -391,7 +391,7 @@ po_return_t po_append(struct mount_options *options, char *str)
 }
 
 /**
- * po_contains - check for presense of an option in a group
+ * po_contains - check for presence of an option in a group
  * @options: pointer to mount options
  * @keyword: pointer to a C string containing option keyword for which to search
  *
Signature · 1 line
1.7.1
#3 lore raw

PATCH v2 3/6 mount.nfs: parse options - add helper po_contains_prefix

In reply to Benjamin Coddington

The version options (v2,v4,v4.2) may increase in the future, but they have a predictable prefix. Add a parse option helper to locate and return these options by prefix so that a future increment of version does not require the addition of strings to a search table.

---
 utils/mount/parse_opt.c |   24 ++++++++++++++++++++++++
 utils/mount/parse_opt.h |    2 ++
 2 files changed, 26 insertions(+), 0 deletions(-)
utils/mount/parse_opt.c +24 -0
index 342e210..7ba61c4 100644
@@ -410,6 +410,30 @@ po_found_t po_contains(struct mount_options *options, char *keyword)
 }
 
 /**
+ * po_contains_prefix - check for presence of an option matching a prefix
+ * @options: pointer to mount options
+ * @prefix: pointer to prefix to match against a keyword
+ * @keyword: pointer to a C string containing the option keyword if found
+ *
+ * On success, *keyword contains the pointer of the matching option's keyword.
+ */
+po_found_t po_contains_prefix(struct mount_options *options,
+								const char *prefix, char **keyword)
+{
+	struct mount_option *option;
+
+	if (options && prefix) {
+		for (option = options->head; option; option = option->next)
+			if (strncmp(option->keyword, prefix, strlen(prefix)) == 0) {
+				*keyword = option->keyword;
+				return PO_FOUND;
+			}
+	}
+
+	return PO_NOT_FOUND;
+}
+
+/**
  * po_get - return the value of the rightmost instance of an option
  * @options: pointer to mount options
  * @keyword: pointer to a C string containing option keyword for which to search
utils/mount/parse_opt.h +2 -0
index 5037207..0745e0f 100644
@@ -45,6 +45,8 @@ po_return_t		po_join(struct mount_options *, char **);
 
 po_return_t		po_append(struct mount_options *, char *);
 po_found_t		po_contains(struct mount_options *, char *);
+po_found_t		po_contains_prefix(struct mount_options *options,
+						const char *prefix, char **keyword);
 char *			po_get(struct mount_options *, char *);
 po_found_t		po_get_numeric(struct mount_options *,
 					char *, long *);
Signature · 1 line
1.7.1
#4 lore raw

PATCH v2 4/6 mount.nfs: Add struct nfs_version and generalize version parsing

In reply to Benjamin Coddington

The nfs_version needs to carry major, minor, and basic mode information to allow decisions to be made to override, discard, or negotiate various versions. Update nfs_nfs_version() to work against this struct and set the various modes. This change also makes nfs_nfs_version() parse properly for future version number additions.

The general rules for version.v_mode are

 - not set             V_DEFAULT
 - single digit => 4   V_GENERAL
 - single digit < 4    V_SPECIFIC
 - decimal included    V_SPECIFIC
 - miss all others     V_PARSE_ERR
---
 utils/mount/configfile.c |    2 +-
 utils/mount/network.c    |  122 ++++++++++++++++++++++-----------------------
 utils/mount/network.h    |   15 +++++-
 utils/mount/nfsumount.c  |    4 +-
 utils/mount/stropts.c    |   22 ++++----
 5 files changed, 88 insertions(+), 77 deletions(-)
utils/mount/configfile.c +1 -1
index 39d3741..a0072f1 100644
@@ -258,7 +258,7 @@ check_vers(char *mopt, char *field)
 	return 0;
 }
 
-unsigned long config_default_vers;
+struct nfs_version config_default_vers;
 unsigned long config_default_proto;
 extern sa_family_t config_default_family;
 
utils/mount/network.c +60 -62

150 lines not on this page · raw message

utils/mount/network.h +14 -1
index d7636d7..9cc5dec 100644
@@ -57,9 +57,22 @@ int clnt_ping(struct sockaddr_in *, const unsigned long,
 
 struct mount_options;
 
+enum {
+	V_DEFAULT = 0,
+	V_GENERAL,
+	V_SPECIFIC,
+	V_PARSE_ERR,
+};
+
+struct nfs_version {
+	unsigned long major;
+	unsigned long minor;
+	int v_mode;
+};
+
 int nfs_nfs_proto_family(struct mount_options *options, sa_family_t *family);
 int nfs_mount_proto_family(struct mount_options *options, sa_family_t *family);
-int nfs_nfs_version(struct mount_options *options, unsigned long *version);
+int nfs_nfs_version(struct mount_options *options, struct nfs_version *version);
 int  nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol);
 
 int nfs_options2pmap(struct mount_options *,
utils/mount/nfsumount.c +2 -2
index 3538d88..de284f2 100644
@@ -179,10 +179,10 @@ static int nfs_umount_is_vers4(const struct mntentchn *mc)
 
 		options = po_split(pmc->m.mnt_opts);
 		if (options != NULL) {
-			unsigned long version;
+			struct nfs_version version;
 			int rc = nfs_nfs_version(options, &version);
 			po_destroy(options);
-			if (rc && version == 4)
+			if (rc && version.major == 4)
 				goto out_nfs4;
 		}
 
utils/mount/stropts.c +11 -11
index 2d72d5b..faa77cf 100644
@@ -88,7 +88,7 @@ struct nfsmount_info {
 	struct mount_options	*options;	/* parsed mount options */
 	char			**extra_opts;	/* string for /etc/mtab */
 
-	unsigned long		version;	/* NFS version */
+	struct nfs_version	version;	/* NFS version */
 	int			flags,		/* MS_ flags */
 				fake,		/* actually do the mount? */
 				child;		/* forked bg child? */
@@ -99,13 +99,13 @@ static void nfs_default_version(struct nfsmount_info *mi);
 
 static void nfs_default_version(struct nfsmount_info *mi)
 {
-	extern unsigned long config_default_vers;
+	extern struct nfs_version config_default_vers;
 	/*
 	 * Use the default value set in the config file when
 	 * the version has not been explicitly set.
 	 */
-	if (mi->version == 0 && config_default_vers) {
-		if (config_default_vers < 4)
+	if (mi->version.major == 0 && config_default_vers.major) {
+		if (config_default_vers.major < 4)
 			mi->version = config_default_vers;
 	}
 }
@@ -300,7 +300,7 @@ static int nfs_set_version(struct nfsmount_info *mi)
 		return 0;
 
 	if (strncmp(mi->type, "nfs4", 4) == 0)
-		mi->version = 4;
+		mi->version.major = 4;
 
 	/*
 	 * Before 2.6.32, the kernel NFS client didn't
@@ -308,20 +308,20 @@ static int nfs_set_version(struct nfsmount_info *mi)
 	 * 4 cannot be included when autonegotiating
 	 * while running on those kernels.
 	 */
-	if (mi->version == 0 &&
+	if (mi->version.major == 0 &&
 	    linux_version_code() <= MAKE_VERSION(2, 6, 31))
-		mi->version = 3;
+		mi->version.major = 3;
 
 	/*
 	 * If we still don't know, check for version-specific
 	 * mount options.
 	 */
-	if (mi->version == 0) {
+	if (mi->version.major == 0) {
 		if (po_contains(mi->options, "mounthost") ||
 		    po_contains(mi->options, "mountaddr") ||
 		    po_contains(mi->options, "mountvers") ||
 		    po_contains(mi->options, "mountproto"))
-			mi->version = 3;
+			mi->version.major = 3;
 	}
 
 	/*
@@ -691,7 +691,7 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi,
 		return result;
 	}
 
-	if (mi->version == 0) {
+	if (mi->version.major == 0) {
 		if (po_contains(options, "mounthost") ||
 			po_contains(options, "mountaddr") ||
 			po_contains(options, "mountvers") ||
@@ -839,7 +839,7 @@ static int nfs_try_mount(struct nfsmount_info *mi)
 {
 	int result = 0;
 
-	switch (mi->version) {
+	switch (mi->version.major) {
 	case 0:
 		result = nfs_autonegotiate(mi);
 		break;
Signature · 1 line
1.7.1
#5 lore raw

PATCH v2 5/6 nfsmount.conf: Always parse versions

In reply to Benjamin Coddington

In order to make decisions about which default version to use when only the major version is specified, the nfsmount.conf Defaultvers options should always be parsed, even when a version has already been specified. Remove the check and bypass for parsing the Defaultvers options from nfsmount.conf.

---
 utils/mount/configfile.c |   34 ----------------------------------
 1 files changed, 0 insertions(+), 34 deletions(-)
utils/mount/configfile.c +0 -34
index a0072f1..0a4cc04 100644
@@ -228,35 +228,6 @@ void free_all(void)
 		free(entry);
 	}
 }
-static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL};
-static int 
-check_vers(char *mopt, char *field)
-{
-	int i, found=0;
-
-	/*
-	 * First check to see if the config setting is one 
-	 * of the many version settings
-	 */
-	for (i=0; versions[i]; i++) { 
-		if (strcasestr(field, versions[i]) != NULL) {
-			found++;
-			break;
-		}
-	}
-	if (!found)
-		return 0;
-	/*
-	 * It appears the version is being set, now see
-	 * if the version appears on the command 
-	 */
-	for (i=0; versions[i]; i++)  {
-		if (strcasestr(mopt, versions[i]) != NULL)
-			return 1;
-	}
-
-	return 0;
-}
 
 struct nfs_version config_default_vers;
 unsigned long config_default_proto;
@@ -331,11 +302,6 @@ conf_parse_mntopts(char *section, char *arg, char *opts)
 		snprintf(buf, BUFSIZ, "%s=", node->field);
 		if (opts && strcasestr(opts, buf) != NULL)
 			continue;
-		/* 
-		 * Protocol verions can be set in a number of ways
-		 */
-		if (opts && check_vers(opts, node->field))
-			continue;
 
 		if (lookup_entry(node->field) != NULL)
 			continue;
Signature · 1 line
1.7.1
#6 lore raw

PATCH v2 6/6 mount.nfs: configurable minor version defaults

In reply to Benjamin Coddington

Update nfsmount.conf to allow minor version specification, and rearrange the autonegotiation logic to agreed upon best behavior. Depending upon the combination of values specified within nfsmount.conf and given to mount.nfs, the retry behavior of mount.nfs varies according to the general rule of defaulting to the most specific setting, with some exceptions. A general guide to the expected behavior follows:

┌────────────────┐
│ nfsmount.conf  ├──────────────┬───────────────────┐
│ Defaultvers=   │  arg option  │     attempts:     │
├────────────────┼──────────────┼───────────────────┤
│     4.2        │  not set     │ v4.2 v4.1 v4.0 v3 │
│     4.2        │   v4         │ v4.2 v4.1 v4.0    │
│     4.1        │  not set     │      v4.1 v4.0 v3 │
│     4.1        │   v4         │      v4.1 v4.0    │
│     4          │  not set     │           v4.0 v3 │
│     4          │   v4         │           v4.0    │
│     3          │  not set     │                v3 │
│    any set     │   v4.2       │ v4.2              │
│    any set     │   v4.1       │      v4.1         │
│    any set     │   v4         │           v4.0    │
│    any set     │   v3         │                v3 │
│    not set     │  not set     │ v4.2 v4.1 v4.0 v3 │
└────────────────┴──────────────┴───────────────────┘

If built with --enable-mountconfig=no, then the behavior is the same as if nfsmount.conf did not set Defaultvers.

---
 utils/mount/stropts.c |  138 +++++++++++++++++++++++++++++++++---------------
 1 files changed, 95 insertions(+), 43 deletions(-)
utils/mount/stropts.c +95 -43
index faa77cf..76ecb32 100644
@@ -94,24 +94,44 @@ struct nfsmount_info {
 				child;		/* forked bg child? */
 };
 
-#ifdef MOUNT_CONFIG
-static void nfs_default_version(struct nfsmount_info *mi);
 
 static void nfs_default_version(struct nfsmount_info *mi)
 {
+#ifdef MOUNT_CONFIG
 	extern struct nfs_version config_default_vers;
 	/*
 	 * Use the default value set in the config file when
 	 * the version has not been explicitly set.
 	 */
-	if (mi->version.major == 0 && config_default_vers.major) {
-		if (config_default_vers.major < 4)
-			mi->version = config_default_vers;
+	if (config_default_vers.v_mode == V_PARSE_ERR) {
+		mi->version.v_mode = V_PARSE_ERR;
+		return;
 	}
-}
-#else
-inline void nfs_default_version(__attribute__ ((unused)) struct nfsmount_info *mi) {}
+
+	if (mi->version.v_mode == V_GENERAL &&
+		config_default_vers.v_mode == V_DEFAULT) {
+		mi->version.v_mode = V_SPECIFIC;
+		return;
+	}
+
+	if (mi->version.v_mode == V_DEFAULT &&
+		config_default_vers.v_mode != V_DEFAULT) {
+		mi->version.major = config_default_vers.major;
+		mi->version.minor = config_default_vers.minor;
+		return;
+	}
+
+	if (mi->version.v_mode == V_GENERAL &&
+		config_default_vers.v_mode != V_DEFAULT) {
+		if (mi->version.major == config_default_vers.major)
+			mi->version.minor = config_default_vers.minor;
+		return;
+	}
+
 #endif /* MOUNT_CONFIG */
+	mi->version.major = 4;
+	mi->version.minor = 2;
+}
 
 /*
  * Obtain a retry timeout value based on the value of the "retry=" option.
@@ -308,28 +328,44 @@ static int nfs_set_version(struct nfsmount_info *mi)
 	 * 4 cannot be included when autonegotiating
 	 * while running on those kernels.
 	 */
-	if (mi->version.major == 0 &&
-	    linux_version_code() <= MAKE_VERSION(2, 6, 31))
+	if (mi->version.v_mode == V_DEFAULT &&
+	    linux_version_code() <= MAKE_VERSION(2, 6, 31)) {
 		mi->version.major = 3;
+		mi->version.v_mode = V_SPECIFIC;
+	}
 
 	/*
 	 * If we still don't know, check for version-specific
 	 * mount options.
 	 */
-	if (mi->version.major == 0) {
+	if (mi->version.v_mode == V_DEFAULT) {
 		if (po_contains(mi->options, "mounthost") ||
 		    po_contains(mi->options, "mountaddr") ||
 		    po_contains(mi->options, "mountvers") ||
-		    po_contains(mi->options, "mountproto"))
+		    po_contains(mi->options, "mountproto")) {
 			mi->version.major = 3;
+			mi->version.v_mode = V_SPECIFIC;
+		}
 	}
 
 	/*
 	 * If enabled, see if the default version was
 	 * set in the config file
 	 */
-	nfs_default_version(mi);
-	
+	if (mi->version.v_mode != V_SPECIFIC) {
+		nfs_default_version(mi);
+		/*
+		 * If the version was not specifically set, it will
+		 * be set by autonegotiation later, so remove it now:
+		 */
+		po_remove_all(mi->options, "v4");
+		po_remove_all(mi->options, "vers");
+		po_remove_all(mi->options, "nfsvers");
+	}
+
+	if (mi->version.v_mode == V_PARSE_ERR)
+		return 0;
+
 	return 1;
 }
 
@@ -684,6 +720,7 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi,
 {
 	struct mount_options *options = po_dup(mi->options);
 	int result = 0;
+	char version_opt[16];
 	char *extra_opts = NULL;
 
 	if (!options) {
@@ -691,20 +728,24 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi,
 		return result;
 	}
 
-	if (mi->version.major == 0) {
-		if (po_contains(options, "mounthost") ||
-			po_contains(options, "mountaddr") ||
-			po_contains(options, "mountvers") ||
-			po_contains(options, "mountproto")) {
-		/*
-		 * Since these mountd options are set assume version 3
-		 * is wanted so error out with EPROTONOSUPPORT so the
-		 * protocol negation starts with v3.
-		 */
-			errno = EPROTONOSUPPORT;
-			goto out_fail;
-		}
-		if (po_append(options, "vers=4") == PO_FAILED) {
+	if (po_contains(options, "mounthost") ||
+		po_contains(options, "mountaddr") ||
+		po_contains(options, "mountvers") ||
+		po_contains(options, "mountproto")) {
+	/*
+	 * Since these mountd options are set assume version 3
+	 * is wanted so error out with EPROTONOSUPPORT so the
+	 * protocol negation starts with v3.
+	 */
+		errno = EPROTONOSUPPORT;
+		goto out_fail;
+	}
+
+	if (mi->version.v_mode != V_SPECIFIC) {
+		snprintf(version_opt, sizeof(version_opt) - 1,
+			"vers=%lu.%lu", mi->version.major, mi->version.minor);
+
+		if (po_append(options, version_opt) == PO_FAILED) {
 			errno = EINVAL;
 			goto out_fail;
 		}
@@ -792,14 +833,25 @@ static int nfs_autonegotiate(struct nfsmount_info *mi)
 	int result;
 
 	result = nfs_try_mount_v4(mi);
+check_result:
 	if (result)
 		return result;
 
-check_errno:
 	switch (errno) {
 	case EPROTONOSUPPORT:
 		/* A clear indication that the server or our
-		 * client does not support NFS version 4. */
+		 * client does not support NFS version 4 and minor */
+		if (mi->version.v_mode == V_GENERAL &&
+			mi->version.minor == 0)
+				return result;
+		if (mi->version.v_mode != V_SPECIFIC) {
+			if (mi->version.minor > 0) {
+				mi->version.minor--;
+				result = nfs_try_mount_v4(mi);
+				goto check_result;
+			}
+		}
+
 		goto fall_back;
 	case ENOENT:
 		/* Legacy Linux servers don't export an NFS
@@ -818,7 +870,7 @@ check_errno:
 			/* v4 server seems to be registered now. */
 			result = nfs_try_mount_v4(mi);
 			if (result == 0 && errno != ECONNREFUSED)
-				goto check_errno;
+				goto check_result;
 		}
 		return result;
 	default:
@@ -840,18 +892,18 @@ static int nfs_try_mount(struct nfsmount_info *mi)
 	int result = 0;
 
 	switch (mi->version.major) {
-	case 0:
-		result = nfs_autonegotiate(mi);
-		break;
-	case 2:
-	case 3:
-		result = nfs_try_mount_v3v2(mi, FALSE);
-		break;
-	case 4:
-		result = nfs_try_mount_v4(mi);
-		break;
-	default:
-		errno = EIO;
+		case 2:
+		case 3:
+			result = nfs_try_mount_v3v2(mi, FALSE);
+			break;
+		case 4:
+			if (mi->version.v_mode != V_SPECIFIC)
+				result = nfs_autonegotiate(mi);
+			else
+				result = nfs_try_mount_v4(mi);
+			break;
+		default:
+			errno = EIO;
 	}
 
 	return result;
Signature · 1 line
1.7.1
#7 lore raw
In reply to Benjamin Coddington
Quoted 23 lines · Benjamin Coddington

Here's the work posted yesterday broken out a bit with an addition of enabling nfsmount.conf by default, and the change to autonegotiate starting with version 4.2 (instead of 4.0) when no version is specified in either config or mount option.

Benjamin Coddington (6):
mount.nfs: default enable mount config file (nfsmount.conf) mount.nfs: fix a comment typo in parse options mount.nfs: parse options - add helper po_contains_prefix mount.nfs: Add struct nfs_version and generalize version parsing nfsmount.conf: Always parse versions
mount.nfs: configurable minor version defaults

 configure.ac             |    8 +-
 utils/mount/configfile.c |   36 +-----------
 utils/mount/network.c    |  122 ++++++++++++++++++-------------------
 utils/mount/network.h    |   15 ++++-
 utils/mount/nfsumount.c  |    4 +-
 utils/mount/parse_opt.c  |   26 ++++++++-
 utils/mount/parse_opt.h  |    2 +
 utils/mount/stropts.c    |  150 +++++++++++++++++++++++++++++++---------------
 8 files changed, 209 insertions(+), 154 deletions(-)
Quoted 5 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Committed... But I did have to fix an issue with the first patch See commit e1a49cf3... No biggie...

steved.