+/*
+ * 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, mi->hostname)) {
+ 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 = &mi->address.sa;
+ struct mount_options *options = po_dup(mi->options);
+ int result = 0;
+
+ if (!options) {
+ errno = ENOMEM;
+ return result;
+ }
+
+ if (mi->version == 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) {
+ 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.
+ */
+ if (po_join(options, mi->extra_opts) == PO_FAILED) {
+ errno = ENOMEM;
+ goto out_fail;
+ }
+
+ 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:
+ if (linux_version_code() > MAKE_VERSION(2, 6, 31)) {
+ errno = 0;
+ result = nfs_try_mount_v4(mi);
+ if (errno != EPROTONOSUPPORT) {
+ /*
+ * To deal with legacy Linux servers that don't
+ * automatically export a pseudo root, retry
+ * ENOENT errors using version 3. And for
+ * Linux servers prior to 2.6.25, retry EPERM
+ */
+ if (errno != ENOENT && errno != EPERM)
+ break;
+ }
+ }
+ 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;
+}
+