From f6d5c04b79dea7313fc80a2604a9542c2bd7bff4 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Wed, 18 May 2022 09:52:43 +0800 Subject: [PATCH] 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 --- ...-TCP_REQUESTED-when-setting-NFS-port.patch | 34 +++ ...e-NFS-version-check-flags-consistent.patch | 65 ++++++ autofs-5.1.7-refactor-get_nfs_info.patch | 202 ++++++++++++++++++ autofs-5.1.8-bailout-on-rpc-systemerror.patch | 34 +++ ...4-only-mounts-should-not-use-rpcbind.patch | 94 ++++++++ autofs.spec | 21 +- 6 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 autofs-5.1.7-also-require-TCP_REQUESTED-when-setting-NFS-port.patch create mode 100644 autofs-5.1.7-make-NFS-version-check-flags-consistent.patch create mode 100644 autofs-5.1.7-refactor-get_nfs_info.patch create mode 100644 autofs-5.1.8-bailout-on-rpc-systemerror.patch create mode 100644 autofs-5.1.8-fix-nfsv4-only-mounts-should-not-use-rpcbind.patch diff --git a/autofs-5.1.7-also-require-TCP_REQUESTED-when-setting-NFS-port.patch b/autofs-5.1.7-also-require-TCP_REQUESTED-when-setting-NFS-port.patch new file mode 100644 index 0000000..0db26c4 --- /dev/null +++ b/autofs-5.1.7-also-require-TCP_REQUESTED-when-setting-NFS-port.patch @@ -0,0 +1,34 @@ +autofs-5.1.7 - also require TCP_REQUESTED when setting NFS port + +From: Ian Kent + +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 +--- + 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; diff --git a/autofs-5.1.7-make-NFS-version-check-flags-consistent.patch b/autofs-5.1.7-make-NFS-version-check-flags-consistent.patch new file mode 100644 index 0000000..5c2c25e --- /dev/null +++ b/autofs-5.1.7-make-NFS-version-check-flags-consistent.patch @@ -0,0 +1,65 @@ +autofs-5.1.7 - make NFS version check flags consistent + +From: Ian Kent + +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 +--- + 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, diff --git a/autofs-5.1.7-refactor-get_nfs_info.patch b/autofs-5.1.7-refactor-get_nfs_info.patch new file mode 100644 index 0000000..3418180 --- /dev/null +++ b/autofs-5.1.7-refactor-get_nfs_info.patch @@ -0,0 +1,202 @@ +autofs-5.1.7 - refactor get_nfs_info() + +From: Ian Kent + +Make getting a portmap client and getting a service port from portmap +helper functions and simplify the return handling. + +Signed-off-by: Ian Kent +--- + 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) diff --git a/autofs-5.1.8-bailout-on-rpc-systemerror.patch b/autofs-5.1.8-bailout-on-rpc-systemerror.patch new file mode 100644 index 0000000..24e9f1d --- /dev/null +++ b/autofs-5.1.8-bailout-on-rpc-systemerror.patch @@ -0,0 +1,34 @@ +autofs-5.1.8 - bailout on rpc systemerror + +From: Ian Kent + +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 +--- + 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, diff --git a/autofs-5.1.8-fix-nfsv4-only-mounts-should-not-use-rpcbind.patch b/autofs-5.1.8-fix-nfsv4-only-mounts-should-not-use-rpcbind.patch new file mode 100644 index 0000000..64d1d91 --- /dev/null +++ b/autofs-5.1.8-fix-nfsv4-only-mounts-should-not-use-rpcbind.patch @@ -0,0 +1,94 @@ +autofs-5.1.8 - fix nfsv4 only mounts should not use rpcbind + +From: Ian Kent + +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 +--- + 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)) diff --git a/autofs.spec b/autofs.spec index 17cc176..f1f6dcd 100644 --- a/autofs.spec +++ b/autofs.spec @@ -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 - 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 - 1:5.1.7-29 - bz2056321 - autofs attempts unmount on directory in use - remove nonstrict parameter from tree_mapent_umount_offsets().