autofs is slow to mount when doing lookups returns multiple entries

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2084108

autofs can take 5 seconds or more to automount file systems in some
cases. This is caused by the server probe logic attempting to connect
to a server when it isn't available.

Attempting to fix this problem introduced a regression where rpcbind
was being consulted in a case where it shouldn't have been.

This MR resolves these problems.

Note that for NFSv4 mounts, if rpcbind is to be avoided then fallback
to NFSv3 must be disabled. This has historically been done by using
the "fstype=nfs4" automount option to requiest a specific nfs version.

Resolves: rhbz#2084108

Signed-off-by: Ian Kent ikent@redhat.com
This commit is contained in:
Ian Kent 2022-05-18 09:52:43 +08:00
parent 1350def07e
commit f6d5c04b79
6 changed files with 449 additions and 1 deletions

View File

@ -0,0 +1,34 @@
autofs-5.1.7 - also require TCP_REQUESTED when setting NFS port
From: Ian Kent <raven@themaw.net>
Set the NFS service port to the default (2049) only if tcp protocol is
being used and not alternate port has been given.
Signed-off-by: Ian Kent <raven@themaw.net>
---
CHANGELOG | 1 +
modules/replicated.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
--- autofs-5.1.7.orig/CHANGELOG
+++ autofs-5.1.7/CHANGELOG
@@ -98,6 +98,7 @@
- fix handling of incorrect return from umount_ent().
- make NFS version check flags consistent.
- refactor get_nfs_info().
+- also require TCP_REQUESTED when setting NFS port.
25/01/2021 autofs-5.1.7
- make bind mounts propagation slave by default.
--- autofs-5.1.7.orig/modules/replicated.c
+++ autofs-5.1.7/modules/replicated.c
@@ -291,7 +291,7 @@ static unsigned int get_nfs_info(unsigne
rpc_info->proto = proto;
if (port < 0) {
- if (version & NFS4_REQUESTED)
+ if ((version & NFS4_REQUESTED) && (version & TCP_REQUESTED))
rpc_info->port = NFS_PORT;
else
port = 0;

View File

@ -0,0 +1,65 @@
autofs-5.1.7 - make NFS version check flags consistent
From: Ian Kent <raven@themaw.net>
Several of the NFS connection macros have the same value so that they
can be used as internal code documentation of what is being done.
Adjust the protocol macro naming to be consistent in a few places.
Also make sure the correct flags are set for the function they indicate.
Signed-off-by: Ian Kent <raven@themaw.net>
---
CHANGELOG | 1 +
modules/mount_nfs.c | 16 +++++++++-------
2 files changed, 10 insertions(+), 7 deletions(-)
--- autofs-5.1.7.orig/CHANGELOG
+++ autofs-5.1.7/CHANGELOG
@@ -96,6 +96,7 @@
- fix sysconf(3) return handling.
- remove nonstrict parameter from tree_mapent_umount_offsets().
- fix handling of incorrect return from umount_ent().
+- make NFS version check flags consistent.
25/01/2021 autofs-5.1.7
- make bind mounts propagation slave by default.
--- autofs-5.1.7.orig/modules/mount_nfs.c
+++ autofs-5.1.7/modules/mount_nfs.c
@@ -178,18 +178,20 @@ int mount_mount(struct autofs_point *ap,
port = 0;
} else if (_strncmp("proto=udp", cp, o_len) == 0 ||
_strncmp("udp", cp, o_len) == 0) {
- vers &= ~TCP_SUPPORTED;
+ vers &= ~TCP_REQUESTED;
+ vers |= UDP_REQUESTED;
} else if (_strncmp("proto=udp6", cp, o_len) == 0 ||
_strncmp("udp6", cp, o_len) == 0) {
- vers &= ~TCP_SUPPORTED;
- vers |= UDP6_REQUESTED;
+ vers &= ~(TCP_REQUESTED|TCP6_REQUESTED);
+ vers |= (UDP_REQUESTED|UDP6_REQUESTED);
} else if (_strncmp("proto=tcp", cp, o_len) == 0 ||
_strncmp("tcp", cp, o_len) == 0) {
- vers &= ~UDP_SUPPORTED;
+ vers &= ~UDP_REQUESTED;
+ vers |= TCP_REQUESTED;
} else if (_strncmp("proto=tcp6", cp, o_len) == 0 ||
_strncmp("tcp6", cp, o_len) == 0) {
- vers &= ~UDP_SUPPORTED;
- vers |= TCP6_REQUESTED;
+ vers &= ~(UDP_REQUESTED|UDP6_REQUESTED);
+ vers |= TCP_REQUESTED|TCP6_REQUESTED;
}
/* Check for options that also make sense
with bind mounts */
@@ -246,7 +248,7 @@ int mount_mount(struct autofs_point *ap,
mount_default_proto == 4 &&
(vers & NFS_VERS_MASK) != 0 &&
(vers & NFS4_VERS_MASK) != 0 &&
- !(vers & UDP6_REQUESTED)) {
+ !(vers & (UDP_REQUESTED|UDP6_REQUESTED))) {
unsigned int v4_probe_ok = 0;
struct host *tmp = new_host(hosts->name, 0,
hosts->addr, hosts->addr_len,

View File

@ -0,0 +1,202 @@
autofs-5.1.7 - refactor get_nfs_info()
From: Ian Kent <raven@themaw.net>
Make getting a portmap client and getting a service port from portmap
helper functions and simplify the return handling.
Signed-off-by: Ian Kent <raven@themaw.net>
---
CHANGELOG | 1
modules/replicated.c | 135 ++++++++++++++++++++++++++++-----------------------
2 files changed, 76 insertions(+), 60 deletions(-)
--- autofs-5.1.7.orig/CHANGELOG
+++ autofs-5.1.7/CHANGELOG
@@ -97,6 +97,7 @@
- remove nonstrict parameter from tree_mapent_umount_offsets().
- fix handling of incorrect return from umount_ent().
- make NFS version check flags consistent.
+- refactor get_nfs_info().
25/01/2021 autofs-5.1.7
- make bind mounts propagation slave by default.
--- autofs-5.1.7.orig/modules/replicated.c
+++ autofs-5.1.7/modules/replicated.c
@@ -223,6 +223,49 @@ void free_host_list(struct host **list)
*list = NULL;
}
+static unsigned int get_portmap_client(unsigned logopt,
+ struct conn_info *pm_info, struct host *host,
+ int proto)
+{
+ unsigned int status;
+
+ /* On success client is stored in pm_info->client */
+ status = rpc_portmap_getclient(pm_info,
+ host->name, host->addr, host->addr_len,
+ proto, RPC_CLOSE_DEFAULT);
+ if (status == -EHOSTUNREACH)
+ debug(logopt,
+ "host not reachable getting portmap client");
+ else if (status)
+ debug(logopt, "error 0x%d getting portmap client");
+
+ return status;
+}
+
+static unsigned int get_portmap_port(unsigned logopt,
+ struct conn_info *pm_info, struct pmap *parms,
+ unsigned long vers, unsigned int version,
+ short unsigned int *port)
+{
+ unsigned int status;
+ short unsigned int nfs_port;
+
+ parms->pm_vers = vers;
+ status = rpc_portmap_getport(pm_info, parms, &nfs_port);
+ if (status == -EHOSTUNREACH || status == -ETIMEDOUT) {
+ debug(logopt,
+ "host not reachable or timed out getting service port");
+ } else if (status < 0) {
+ if (!(version & NFS_VERS_MASK))
+ debug(logopt, "error 0x%d getting service port");
+ }
+
+ if (!status)
+ *port = nfs_port;
+
+ return status;
+}
+
static unsigned int get_nfs_info(unsigned logopt, struct host *host,
struct conn_info *pm_info, struct conn_info *rpc_info,
int proto, unsigned int version, int port)
@@ -263,33 +306,20 @@ static unsigned int get_nfs_info(unsigne
goto v3_ver;
if (!port) {
- status = rpc_portmap_getclient(pm_info,
- host->name, host->addr, host->addr_len,
- proto, RPC_CLOSE_DEFAULT);
- if (status == -EHOSTUNREACH) {
- debug(logopt,
- "host not reachable getting portmap client");
- supported = status;
- goto done_ver;
- } else if (status) {
- debug(logopt, "error 0x%d getting portmap client");
+ status = get_portmap_client(logopt, pm_info, host, proto);
+ if (status) {
+ if (status == -EHOSTUNREACH)
+ supported = status;
goto done_ver;
}
- parms.pm_vers = NFS4_VERSION;
- status = rpc_portmap_getport(pm_info, &parms, &rpc_info->port);
- if (status == -EHOSTUNREACH || status == -ETIMEDOUT) {
- debug(logopt,
- "host not reachable or timed out getting service port");
- supported = status;
- goto done_ver;
- } else if (status < 0) {
- if (version & NFS_VERS_MASK)
+ status = get_portmap_port(logopt, pm_info, &parms,
+ NFS4_VERSION, version, &rpc_info->port);
+ if (status) {
+ if (status == -EHOSTUNREACH || status == -ETIMEDOUT)
+ supported = status;
+ if (status < 0 && version & NFS_VERS_MASK)
goto v3_ver; /* MOUNT_NFS_DEFAULT_PROTOCOL=4 */
- else {
- debug(logopt,
- "error 0x%d getting service port");
- goto done_ver;
- }
+ goto done_ver;
}
}
@@ -334,31 +364,22 @@ v3_ver:
goto v2_ver;
if (!port && !pm_info->client) {
- status = rpc_portmap_getclient(pm_info,
- host->name, host->addr, host->addr_len,
- proto, RPC_CLOSE_DEFAULT);
- if (status == -EHOSTUNREACH) {
- debug(logopt,
- "host not reachable getting portmap client");
- supported = status;
- goto done_ver;
- } else if (status) {
- debug(logopt,
- "error 0x%d getting getting portmap client");
+ status = get_portmap_client(logopt, pm_info, host, proto);
+ if (status) {
+ if (status == -EHOSTUNREACH)
+ supported = status;
goto done_ver;
}
}
if (!port) {
- parms.pm_vers = NFS3_VERSION;
- status = rpc_portmap_getport(pm_info, &parms, &rpc_info->port);
- if (status == -EHOSTUNREACH || status == -ETIMEDOUT) {
- debug(logopt,
- "host not reachable or timed out getting service port");
- supported = status;
+ status = get_portmap_port(logopt, pm_info, &parms,
+ NFS3_VERSION, version, &rpc_info->port);
+ if (status) {
+ if (status == -EHOSTUNREACH || status == -ETIMEDOUT)
+ supported = status;
goto done_ver;
- } else if (status < 0)
- goto v2_ver;
+ }
}
if (rpc_info->proto == IPPROTO_UDP)
@@ -399,28 +420,22 @@ v2_ver:
goto done_ver;
if (!port && !pm_info->client) {
- status = rpc_portmap_getclient(pm_info,
- host->name, host->addr, host->addr_len,
- proto, RPC_CLOSE_DEFAULT);
- if (status == -EHOSTUNREACH) {
- debug(logopt,
- "host not reachable getting portmap client");
- supported = status;
- goto done_ver;
- } else if (status)
+ status = get_portmap_client(logopt, pm_info, host, proto);
+ if (status) {
+ if (status == -EHOSTUNREACH)
+ supported = status;
goto done_ver;
+ }
}
if (!port) {
- parms.pm_vers = NFS2_VERSION;
- status = rpc_portmap_getport(pm_info, &parms, &rpc_info->port);
- if (status == -EHOSTUNREACH || status == -ETIMEDOUT) {
- debug(logopt,
- "host not reachable or timed out getting service port");
- supported = status;
- goto done_ver;
- } else if (status < 0)
+ status = get_portmap_port(logopt, pm_info, &parms,
+ NFS2_VERSION, version, &rpc_info->port);
+ if (status) {
+ if (status == -EHOSTUNREACH || status == -ETIMEDOUT)
+ supported = status;
goto done_ver;
+ }
}
if (rpc_info->proto == IPPROTO_UDP)

View File

@ -0,0 +1,34 @@
autofs-5.1.8 - bailout on rpc systemerror
From: Ian Kent <raven@themaw.net>
If there's a system error (eg. oversize packet received) just give up
since redoing the call would likely end up with the same error.
Signed-off-by: Ian Kent <raven@themaw.net>
---
CHANGELOG | 1 +
lib/rpc_subs.c | 2 ++
2 files changed, 3 insertions(+)
--- autofs-5.1.7.orig/CHANGELOG
+++ autofs-5.1.7/CHANGELOG
@@ -99,6 +99,7 @@
- make NFS version check flags consistent.
- refactor get_nfs_info().
- also require TCP_REQUESTED when setting NFS port.
+- bailout on rpc systemerror.
25/01/2021 autofs-5.1.7
- make bind mounts propagation slave by default.
--- autofs-5.1.7.orig/lib/rpc_subs.c
+++ autofs-5.1.7/lib/rpc_subs.c
@@ -1200,6 +1200,8 @@ static int rpc_get_exports_proto(struct
info->timeout);
if (status == RPC_SUCCESS)
break;
+ if (status == RPC_SYSTEMERROR)
+ break;
if (++vers_entry > 2)
break;
CLNT_CONTROL(client, CLSET_VERS,

View File

@ -0,0 +1,94 @@
autofs-5.1.8 - fix nfsv4 only mounts should not use rpcbind
From: Ian Kent <raven@themaw.net>
Commit 606795ecfaa1 ("autofs-5.1.7 - also require TCP_REQUESTED when
setting NFS port" together with commit 26fb6b5408be) caused NFSv4 only
mounts to also use rpcbind to probe availability which breaks the
requirememt that this type of mount not use rpcbind at all.
Fix this by treating fstype=nfs4 mounts as a special case which doesn't
use rpcbind.
Signed-off-by: Ian Kent <raven@themaw.net>
---
CHANGELOG | 1 +
include/replicated.h | 2 ++
modules/mount_nfs.c | 13 +++++++------
modules/replicated.c | 4 ++--
4 files changed, 12 insertions(+), 8 deletions(-)
--- autofs-5.1.7.orig/CHANGELOG
+++ autofs-5.1.7/CHANGELOG
@@ -100,6 +100,7 @@
- refactor get_nfs_info().
- also require TCP_REQUESTED when setting NFS port.
- bailout on rpc systemerror.
+- fix nfsv4 only mounts should not use rpcbind.
25/01/2021 autofs-5.1.7
- make bind mounts propagation slave by default.
--- autofs-5.1.7.orig/include/replicated.h
+++ autofs-5.1.7/include/replicated.h
@@ -35,6 +35,8 @@
#define NFS3_REQUESTED NFS3_SUPPORTED
#define NFS4_REQUESTED NFS4_SUPPORTED
+#define NFS4_ONLY_REQUESTED 0x0800
+
#define TCP_SUPPORTED 0x0001
#define UDP_SUPPORTED 0x0002
#define TCP_REQUESTED TCP_SUPPORTED
--- autofs-5.1.7.orig/modules/mount_nfs.c
+++ autofs-5.1.7/modules/mount_nfs.c
@@ -92,7 +92,7 @@ int mount_mount(struct autofs_point *ap,
mount_default_proto = defaults_get_mount_nfs_default_proto();
vers = NFS_VERS_DEFAULT | NFS_PROTO_DEFAULT;
if (strcmp(fstype, "nfs4") == 0)
- vers = NFS4_VERS_DEFAULT | TCP_SUPPORTED;
+ vers = NFS4_VERS_DEFAULT | TCP_SUPPORTED | NFS4_ONLY_REQUESTED;
else if (mount_default_proto == 4)
vers = vers | NFS4_VERS_DEFAULT;
@@ -157,15 +157,16 @@ int mount_mount(struct autofs_point *ap,
} else {
/* Is any version of NFSv4 in the options */
if (_strncmp("vers=4", cp, 6) == 0 ||
- _strncmp("nfsvers=4", cp, 9) == 0)
- vers = NFS4_VERS_MASK | TCP_SUPPORTED;
- else if (_strncmp("vers=3", cp, o_len) == 0 ||
+ _strncmp("nfsvers=4", cp, 9) == 0) {
+ vers &= ~(NFS_VERS_MASK);
+ vers |= NFS4_VERS_MASK | TCP_SUPPORTED | NFS4_ONLY_REQUESTED;
+ } else if (_strncmp("vers=3", cp, o_len) == 0 ||
_strncmp("nfsvers=3", cp, o_len) == 0) {
- vers &= ~(NFS4_VERS_MASK | NFS_VERS_MASK);
+ vers &= ~(NFS4_VERS_MASK | NFS_VERS_MASK | NFS4_ONLY_REQUESTED);
vers |= NFS3_REQUESTED;
} else if (_strncmp("vers=2", cp, o_len) == 0 ||
_strncmp("nfsvers=2", cp, o_len) == 0) {
- vers &= ~(NFS4_VERS_MASK | NFS_VERS_MASK);
+ vers &= ~(NFS4_VERS_MASK | NFS_VERS_MASK | NFS4_ONLY_REQUESTED);
vers |= NFS2_REQUESTED;
} else if (strstr(cp, "port=") == cp &&
o_len - 5 < 25) {
--- autofs-5.1.7.orig/modules/replicated.c
+++ autofs-5.1.7/modules/replicated.c
@@ -291,7 +291,7 @@ static unsigned int get_nfs_info(unsigne
rpc_info->proto = proto;
if (port < 0) {
- if ((version & NFS4_REQUESTED) && (version & TCP_REQUESTED))
+ if (version & NFS4_REQUESTED && (version & NFS4_ONLY_REQUESTED))
rpc_info->port = NFS_PORT;
else
port = 0;
@@ -525,7 +525,7 @@ static int get_vers_and_cost(unsigned lo
{
struct conn_info pm_info, rpc_info;
time_t timeout = RPC_TIMEOUT;
- unsigned int supported, vers = (NFS_VERS_MASK | NFS4_VERS_MASK);
+ unsigned int supported, vers = (NFS_VERS_MASK | NFS4_VERS_MASK | NFS4_ONLY_REQUESTED);
int ret = 0;
if (!check_address_proto(logopt, host, version))

View File

@ -12,7 +12,7 @@
Summary: A tool for automatically mounting and unmounting filesystems
Name: autofs
Version: 5.1.7
Release: 29%{?dist}
Release: 30%{?dist}
Epoch: 1
License: GPLv2+
Source: https://www.kernel.org/pub/linux/daemons/autofs/v5/autofs-%{version}-2.tar.gz
@ -121,6 +121,12 @@ Patch95: autofs-5.1.8-fix-sysconf-return-handling.patch
Patch96: autofs-5.1.8-remove-nonstrict-parameter-from-tree_mapent_umount_offsets.patch
Patch97: autofs-5.1.8-fix-handling-of-incorrect-return-from-umount_ent.patch
Patch98: autofs-5.1.7-make-NFS-version-check-flags-consistent.patch
Patch99: autofs-5.1.7-refactor-get_nfs_info.patch
Patch100: autofs-5.1.7-also-require-TCP_REQUESTED-when-setting-NFS-port.patch
Patch101: autofs-5.1.8-bailout-on-rpc-systemerror.patch
Patch102: autofs-5.1.8-fix-nfsv4-only-mounts-should-not-use-rpcbind.patch
%if %{with_systemd}
BuildRequires: systemd-units
BuildRequires: systemd-devel
@ -285,6 +291,11 @@ echo %{version}-%{release} > .version
%patch95 -p1
%patch96 -p1
%patch97 -p1
%patch98 -p1
%patch99 -p1
%patch100 -p1
%patch101 -p1
%patch102 -p1
%build
LDFLAGS=-Wl,-z,now
@ -393,6 +404,14 @@ fi
%dir /etc/auto.master.d
%changelog
* Mon May 16 2022 Ian Kent <ikent@redhat.com> - 1:5.1.7-30
- bz2084108 - autofs is slow to mount when doing lookups returns multiple entries
- make NFS version check flags consistent.
- refactor get_nfs_info().
- also require TCP_REQUESTED when setting NFS port.
- bailout on rpc systemerror.
- fix nfsv4 only mounts should not use rpcbind.
* Fri May 13 2022 Ian Kent <ikent@redhat.com> - 1:5.1.7-29
- bz2056321 - autofs attempts unmount on directory in use
- remove nonstrict parameter from tree_mapent_umount_offsets().