autofs-5.1.2 - check NFS server availability on local mount fallback

From: Ian Kent <raven@themaw.net>

The availability probe isn't done for anything autofs thinks is a
local mount because it's the local machine.

It first tries a bind mount and if that fails it falls back to trying
a local NFS mount. If the local NFS server is not running mount.nfs(8)
can suffer a lengthy timeout.

So check for the bind mount fallback case and check if an NFS server
is responding before trying the mount.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG           |    1 +
 lib/rpc_subs.c      |   11 +++++++++++
 modules/mount_nfs.c |   15 ++++++++++++++-
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG b/CHANGELOG
index 408edf8..c43ebc9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -32,6 +32,7 @@ xx/xx/2016 autofs-5.1.3
 - set sane default master read wait timeout.
 - don't return until after master map retry read.
 - make lookup_nss_read_master() return nss status.
+- check NFS server availability on local mount fallback.
 
 15/06/2016 autofs-5.1.2
 =======================
diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
index d0d4cf5..386c7ba 100644
--- a/lib/rpc_subs.c
+++ b/lib/rpc_subs.c
@@ -1039,6 +1039,7 @@ static int __rpc_ping(const char *host,
 
 int rpc_ping(const char *host, long seconds, long micros, unsigned int option)
 {
+	unsigned long vers4 = NFS4_VERSION;
 	unsigned long vers3 = NFS3_VERSION;
 	unsigned long vers2 = NFS2_VERSION;
 	int status;
@@ -1051,6 +1052,12 @@ int rpc_ping(const char *host, long seconds, long micros, unsigned int option)
 	if (status > 0)
 		return RPC_PING_V3 | RPC_PING_UDP;
 
+	/* UDP isn't recommended for NFSv4, don't bother checking it.
+	status = __rpc_ping(host, vers4, IPPROTO_UDP, seconds, micros, option);
+	if (status > 0)
+		return RPC_PING_V4 | RPC_PING_UDP;
+	*/
+
 	status = __rpc_ping(host, vers2, IPPROTO_TCP, seconds, micros, option);
 	if (status > 0)
 		return RPC_PING_V2 | RPC_PING_TCP;
@@ -1059,6 +1066,10 @@ int rpc_ping(const char *host, long seconds, long micros, unsigned int option)
 	if (status > 0)
 		return RPC_PING_V3 | RPC_PING_TCP;
 
+	status = __rpc_ping(host, vers4, IPPROTO_TCP, seconds, micros, option);
+	if (status > 0)
+		return RPC_PING_V4 | RPC_PING_TCP;
+
 	return status;
 }
 
diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
index 0af814b..2712140 100644
--- a/modules/mount_nfs.c
+++ b/modules/mount_nfs.c
@@ -348,6 +348,19 @@ dont_probe:
 		strcat(loc, ":");
 		strcat(loc, this->path);
 
+		/* If this is a fallback from a bind mount failure
+		 * check if the local NFS server is available to try
+		 * and prevent lengthy mount failure waits.
+		 */
+		if (this->proximity == PROXIMITY_LOCAL) {
+			char *host = this->name ? this->name : "localhost";
+			int ret;
+
+			ret = rpc_ping(host, 2, 0, RPC_CLOSE_DEFAULT);
+			if (ret <= 0)
+				goto next;
+		}
+
 		if (nfsoptions && *nfsoptions) {
 			debug(ap->logopt,
 			      MODPREFIX "calling mount -t %s " SLOPPY 
@@ -370,7 +383,7 @@ dont_probe:
 			free_host_list(&hosts);
 			return 0;
 		}
-
+next:
 		free(loc);
 		this = this->next;
 	}
