File nfs-utils-1.1.2-try-before-mount.patch of Package nfs-utils

From 852424a9a02dbe1a7c3b75a014bc71cad2ab6d5e Mon Sep 17 00:00:00 2001
From: Neil Brown <neilb@suse.de>
Date: Mon, 21 Jul 2008 12:45:50 +1000
References: bnc#404170
Subject: [PATCH] Check nfs options (vers/protocol) before trying mount.

As the kernels nfs-mount client does not have heuristics to pick the
best protocol/version, also check with portmap to find what is
available before requesting a mount.

However don't try to 'ping' the services.  For NFS, this ping would
need to come from a reserved port, and these are a scarce resource.

If the mount found, retry the probe doing any ping that might be
needed in the hope of finding the problem.

Note: this patch also removes the (recently added) setting of
mountport= in the mount arguments. This is because:
  1/ the kernel can find it easily itself
  2/ it could confuse unmount which may be run much later
      when mountd is running on a different port.


Signed-off-by: Neil Brown <neilb@suse.de>
---
 utils/mount/network.c  |   35 +++++++++++++++++++++--------------
 utils/mount/network.h  |    2 +-
 utils/mount/nfsmount.c |    2 +-
 utils/mount/stropts.c  |   18 +++++++-----------
 4 files changed, 30 insertions(+), 27 deletions(-)

--- nfs-utils-1.1.3.orig/utils/mount/network.c
+++ nfs-utils-1.1.3/utils/mount/network.c
@@ -500,9 +500,11 @@ static unsigned short getport(struct soc
  * Use the portmapper to discover whether or not the service we want is
  * available. The lists 'versions' and 'protos' define ordered sequences
  * of service versions and udp/tcp protocols to probe for.
+ * If 'ping' is set, set an RPC NULL request to make sure the service
+ * is there.  Else just assume that it is.
  */
 static int probe_port(clnt_addr_t *server, const unsigned long *versions,
-			const unsigned int *protos)
+			const unsigned int *protos, int ping)
 {
 	struct sockaddr_in *saddr = &server->saddr;
 	struct pmap *pmap = &server->pmap;
@@ -530,7 +532,8 @@ static int probe_port(clnt_addr_t *serve
 							_("UDP") : _("TCP"),
 						p_port);
                                 }
-				if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
+				if (!ping ||
+				    clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
 					goto out_ok;
 			}
 		}
@@ -565,7 +568,7 @@ out_ok:
 	return 1;
 }
 
-static int probe_nfsport(clnt_addr_t *nfs_server)
+static int probe_nfsport(clnt_addr_t *nfs_server, int ping)
 {
 	struct pmap *pmap = &nfs_server->pmap;
 
@@ -573,12 +576,14 @@ static int probe_nfsport(clnt_addr_t *nf
 		return 1;
 
 	if (nfs_mount_data_version >= 4)
-		return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first);
+		return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first,
+				  ping);
 	else
-		return probe_port(nfs_server, probe_nfs2_only, probe_udp_only);
+		return probe_port(nfs_server, probe_nfs2_only, probe_udp_only,
+				  ping);
 }
 
-static int probe_mntport(clnt_addr_t *mnt_server)
+static int probe_mntport(clnt_addr_t *mnt_server, int ping)
 {
 	struct pmap *pmap = &mnt_server->pmap;
 
@@ -586,9 +591,11 @@ static int probe_mntport(clnt_addr_t *mn
 		return 1;
 
 	if (nfs_mount_data_version >= 4)
-		return probe_port(mnt_server, probe_mnt3_first, probe_udp_first);
+		return probe_port(mnt_server, probe_mnt3_first, probe_udp_first,
+				  ping);
 	else
-		return probe_port(mnt_server, probe_mnt1_first, probe_udp_only);
+		return probe_port(mnt_server, probe_mnt1_first, probe_udp_only,
+				  ping);
 }
 
 /**
@@ -601,7 +608,7 @@ static int probe_mntport(clnt_addr_t *mn
  *
  * A side effect of calling this function is that rpccreateerr is set.
  */
-int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
+int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server, int ping)
 {
 	struct pmap *nfs_pmap = &nfs_server->pmap;
 	struct pmap *mnt_pmap = &mnt_server->pmap;
@@ -623,9 +630,9 @@ int probe_bothports(clnt_addr_t *mnt_ser
 
 	for (; *probe_vers; probe_vers++) {
 		nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
-		if ((res = probe_nfsport(nfs_server) != 0)) {
+		if ((res = probe_nfsport(nfs_server, ping) != 0)) {
 			mnt_pmap->pm_vers = *probe_vers;
-			if ((res = probe_mntport(mnt_server)) != 0)
+			if ((res = probe_mntport(mnt_server, ping)) != 0)
 				return 1;
 			memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
 		}
@@ -643,9 +650,9 @@ out_bad:
 	return 0;
 
 version_fixed:
-	if (!probe_nfsport(nfs_server))
+	if (!probe_nfsport(nfs_server, ping))
 		goto out_bad;
-	return probe_mntport(mnt_server);
+	return probe_mntport(mnt_server, ping);
 }
 
 static int probe_statd(void)
@@ -712,7 +719,7 @@ int nfs_call_umount(clnt_addr_t *mnt_ser
 	enum clnt_stat res = 0;
 	int msock;
 
-	if (!probe_mntport(mnt_server))
+	if (!probe_mntport(mnt_server, 0))
 		return 0;
 	clnt = mnt_openclnt(mnt_server, &msock);
 	if (!clnt)
--- nfs-utils-1.1.3.orig/utils/mount/network.h
+++ nfs-utils-1.1.3/utils/mount/network.h
@@ -39,7 +39,7 @@ typedef struct {
 static const struct timeval TIMEOUT = { 20, 0 };
 static const struct timeval RETRY_TIMEOUT = { 3, 0 };
 
-int probe_bothports(clnt_addr_t *, clnt_addr_t *);
+int probe_bothports(clnt_addr_t *, clnt_addr_t *, int);
 int nfs_gethostbyname(const char *, struct sockaddr_in *);
 int nfs_name_to_address(const char *, const sa_family_t,
 		struct sockaddr *, socklen_t *);
--- nfs-utils-1.1.3.orig/utils/mount/nfsmount.c
+++ nfs-utils-1.1.3/utils/mount/nfsmount.c
@@ -129,7 +129,7 @@ nfs_call_mount(clnt_addr_t *mnt_server, 
 	enum clnt_stat stat;
 	int msock;
 
-	if (!probe_bothports(mnt_server, nfs_server))
+	if (!probe_bothports(mnt_server, nfs_server, 1))
 		goto out_bad;
 
 	clnt = mnt_openclnt(mnt_server, &msock);
--- nfs-utils-1.1.3.orig/utils/mount/stropts.c
+++ nfs-utils-1.1.3/utils/mount/stropts.c
@@ -314,7 +314,7 @@ static int nfs_is_permanent_error(int er
  * Returns a new group of mount options if successful; otherwise
  * NULL is returned if some failure occurred.
  */
-static struct mount_options *nfs_rewrite_mount_options(char *str)
+static struct mount_options *nfs_rewrite_mount_options(char *str, int ping)
 {
 	struct mount_options *options;
 	char *option, new_option[64];
@@ -405,7 +405,7 @@ static struct mount_options *nfs_rewrite
 	po_remove_all(options, "tcp");
 	po_remove_all(options, "udp");
 
-	if (!probe_bothports(&mnt_server, &nfs_server)) {
+	if (!probe_bothports(&mnt_server, &nfs_server, ping)) {
 		errno = ESPIPE;
 		goto err;
 	}
@@ -441,11 +441,6 @@ static struct mount_options *nfs_rewrite
 	if (po_append(options, new_option) == PO_FAILED)
 		goto err;
 
-	snprintf(new_option, sizeof(new_option) - 1,
-		 "mountport=%lu", mnt_server.pmap.pm_port);
-	if (po_append(options, new_option) == PO_FAILED)
-		goto err;
-
 	errno = 0;
 	return options;
 
@@ -486,13 +481,13 @@ static int nfs_sys_mount(const struct nf
  * 'extra_opts' are updated to reflect the mount options that worked.
  * If the retry fails, 'options' and 'extra_opts' are left unchanged.
  */
-static int nfs_retry_nfs23mount(struct nfsmount_info *mi)
+static int nfs_try_nfs23mount_probe(struct nfsmount_info *mi, int ping)
 {
 	struct mount_options *retry_options;
 	char *retry_str = NULL;
 	char **extra_opts = mi->extra_opts;
 
-	retry_options = nfs_rewrite_mount_options(*extra_opts);
+	retry_options = nfs_rewrite_mount_options(*extra_opts, ping);
 	if (!retry_options)
 		return 0;
 
@@ -547,7 +542,7 @@ static int nfs_try_nfs23mount(struct nfs
 	if (mi->fake)
 		return 1;
 
-	if (nfs_sys_mount(mi, "nfs", *extra_opts))
+	if (nfs_try_nfs23mount_probe(mi, 0))
 		return 1;
 
 	/*
@@ -557,7 +552,8 @@ static int nfs_try_nfs23mount(struct nfs
 	if (errno != EOPNOTSUPP && errno != EPROTONOSUPPORT)
 		return 0;
 
-	return nfs_retry_nfs23mount(mi);
+	/* Probe harder */
+	return nfs_try_nfs23mount_probe(mi, 1);
 }
 
 /*
openSUSE Build Service is sponsored by