summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--utils/mount/stropts.c138
1 files changed, 95 insertions, 43 deletions
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index faa77cf..76ecb32 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -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;