From 0de3189d32a183f5e91a6d27a9e8f159216d9473 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 29 Sep 2009 10:38:05 -0400 Subject: [PATCH] The user's mount options and the set of versions to try should not change over the course of mount retries. With this patch, each version-specific mount attempt is compartment- alized, and starts from the user's original mount options each time. Thus these attempts can now be safely performed in any order, depending on what the user has requested, what the server advertises, and what is up and running at any given point. Don't regress the fix in commit 23c1a452. For v2/v3 negotation, only the user's mount options are written to /etc/mtab, and not any options that were negotiated by mount.nfs. There's no way to guarantee that the server configuration will be the same at umount time as it was at mount time. Signed-off-by: Chuck Lever Signed-off-by: Steve Dickson --- utils/mount/stropts.c | 130 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 24 deletions(-) diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index 76bbefd..25b206f 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -259,7 +259,7 @@ static int nfs_append_sloppy_option(struct mount_options *options) } /* - * Set up mandatory NFS mount options. + * Set up mandatory non-version specific NFS mount options. * * Returns 1 if successful; otherwise zero. */ @@ -279,28 +279,12 @@ static int nfs_validate_options(struct nfsmount_info *mi) if (strncmp(mi->type, "nfs4", 4) == 0) mi->version = 4; - if (mi->version == 4) { - if (!nfs_append_clientaddr_option(sap, mi->salen, mi->options)) - return 0; - } else { - if (!nfs_fix_mounthost_option(mi->options)) - return 0; - if (!mi->fake && !nfs_verify_lock_option(mi->options)) - return 0; - } - if (!nfs_append_sloppy_option(mi->options)) return 0; if (!nfs_append_addr_option(sap, mi->salen, mi->options)) return 0; - /* - * Update option string to be recorded in /etc/mnttab - */ - if (po_join(mi->options, mi->extra_opts) == PO_FAILED) - return 0; - return 1; } @@ -490,17 +474,12 @@ out: * Returns TRUE if successful, otherwise FALSE. * "errno" is set to reflect the individual error. */ -static int nfs_try_mount(struct nfsmount_info *mi) +static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts) { char *options = NULL; int result; - if (mi->version != 4) { - if (!nfs_rewrite_pmap_mount_options(mi->options)) - return 0; - } - - if (po_join(mi->options, &options) == PO_FAILED) { + if (po_join(opts, &options) == PO_FAILED) { errno = EIO; return 0; } @@ -522,6 +501,109 @@ static int nfs_try_mount(struct nfsmount_info *mi) return !result; } +/* + * For "-t nfs vers=2" or "-t nfs vers=3" mounts. + */ +static int nfs_try_mount_v3v2(struct nfsmount_info *mi) +{ + struct mount_options *options = po_dup(mi->options); + int result = 0; + + if (!options) { + errno = ENOMEM; + return result; + } + + if (!nfs_fix_mounthost_option(options)) { + errno = EINVAL; + goto out_fail; + } + if (!mi->fake && !nfs_verify_lock_option(options)) { + errno = EINVAL; + goto out_fail; + } + + /* + * Options we negotiate below may be stale by the time this + * file system is unmounted. In order to force umount.nfs + * to renegotiate with the server, only write the user- + * specified options, and not negotiated options, to /etc/mtab. + */ + if (po_join(options, mi->extra_opts) == PO_FAILED) { + errno = ENOMEM; + goto out_fail; + } + + if (!nfs_rewrite_pmap_mount_options(options)) + goto out_fail; + + result = nfs_sys_mount(mi, options); + +out_fail: + po_destroy(options); + return result; +} + +/* + * For "-t nfs -o vers=4" or "-t nfs4" mounts. + */ +static int nfs_try_mount_v4(struct nfsmount_info *mi) +{ + struct sockaddr *sap = (struct sockaddr *)&mi->address; + struct mount_options *options = po_dup(mi->options); + int result = 0; + + if (!options) { + errno = ENOMEM; + return result; + } + + if (!nfs_append_clientaddr_option(sap, mi->salen, options)) { + errno = EINVAL; + goto out_fail; + } + + /* + * Update option string to be recorded in /etc/mtab. + */ + if (po_join(options, mi->extra_opts) == PO_FAILED) { + errno = ENOMEM; + return 0; + } + + result = nfs_sys_mount(mi, options); + +out_fail: + po_destroy(options); + return result; +} + +/* + * This is a single pass through the fg/bg loop. + * + * Returns TRUE if successful, otherwise FALSE. + * "errno" is set to reflect the individual error. + */ +static int nfs_try_mount(struct nfsmount_info *mi) +{ + int result = 0; + + switch (mi->version) { + case 0: + case 2: + case 3: + result = nfs_try_mount_v3v2(mi); + break; + case 4: + result = nfs_try_mount_v4(mi); + break; + default: + errno = EIO; + } + + return result; +} + /* * Distinguish between permanent and temporary errors. * -- 2.39.2