From 74b172da4458db11c2c7f1f0b68558d0de2a38ac Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Thu, 20 Mar 2014 15:19:26 +0800 Subject: [PATCH] - make am-utils work with autofs (since NFSv2 client is disabled) and add misc bug fixes (bz1074376). --- ...s-6.1.5-check-fh-on-umount-succeeded.patch | 24 +++ ...-6.1.5-dont-background-autofs-umount.patch | 35 ++++ ....1.5-fix-autofs-proto-version-define.patch | 28 ++++ ...OENT-umount-return-for-autofs-mounts.patch | 33 ++++ ...fb4-fix-handle-failed-umount-on-exit.patch | 13 ++ ....9b652fb4-linux-umount-wait-on-ebusy.patch | 50 ++++++ ....git.e03592f0-fix-debug-log-deadlock.patch | 82 ++++++++++ ...e03592f0-fix-get_nfs_version-message.patch | 22 +++ ...-in-the-proper-order-when-going-down.patch | 152 ++++++++++++++++++ am-utils.spec | 34 +++- 10 files changed, 472 insertions(+), 1 deletion(-) create mode 100644 am-utils-6.1.5-check-fh-on-umount-succeeded.patch create mode 100644 am-utils-6.1.5-dont-background-autofs-umount.patch create mode 100644 am-utils-6.1.5-fix-autofs-proto-version-define.patch create mode 100644 am-utils-6.1.5-handle-ENOENT-umount-return-for-autofs-mounts.patch create mode 100644 am-utils-6.2-0.git.9b652fb4-fix-handle-failed-umount-on-exit.patch create mode 100644 am-utils-6.2-0.git.9b652fb4-linux-umount-wait-on-ebusy.patch create mode 100644 am-utils-6.2-1.git.e03592f0-fix-debug-log-deadlock.patch create mode 100644 am-utils-6.2-1.git.e03592f0-fix-get_nfs_version-message.patch create mode 100644 am-utils-6.2-make-sure-to-remove-nodes-in-the-proper-order-when-going-down.patch diff --git a/am-utils-6.1.5-check-fh-on-umount-succeeded.patch b/am-utils-6.1.5-check-fh-on-umount-succeeded.patch new file mode 100644 index 0000000..5325438 --- /dev/null +++ b/am-utils-6.1.5-check-fh-on-umount-succeeded.patch @@ -0,0 +1,24 @@ + + +From: Ian Kent + + +--- + conf/autofs/autofs_linux.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/conf/autofs/autofs_linux.c b/conf/autofs/autofs_linux.c +index 5e6a171..fd5dbc6 100644 +--- a/conf/autofs/autofs_linux.c ++++ b/conf/autofs/autofs_linux.c +@@ -753,6 +753,10 @@ autofs_umount_succeeded(am_node *mp) + autofs_fh_t *fh = mp->am_parent->am_autofs_fh; + struct autofs_pending_umount **pp, *p; + ++ /* Already gone? */ ++ if (fh == NULL) ++ return 0; ++ + pp = &fh->pending_umounts; + while (*pp && !STREQ((*pp)->name, mp->am_name)) + pp = &(*pp)->next; diff --git a/am-utils-6.1.5-dont-background-autofs-umount.patch b/am-utils-6.1.5-dont-background-autofs-umount.patch new file mode 100644 index 0000000..7f8cde7 --- /dev/null +++ b/am-utils-6.1.5-dont-background-autofs-umount.patch @@ -0,0 +1,35 @@ +am-utils-6.1.5 - dont background autofs umount + +From: Ian Kent + +When using an autofs multi-level mount map amd can fail to umount +NFS leaf mounts causing shutdown to fail. It also can cause amd to +SEGV because, even though umounts fail, the autofs mount control +structure is freed and a later umount attempt doesn't check if this +struct is valid before using it. + +The cause of the umount failure appears to be the background umount +of NFS mounts at the leaf of the tree not finishing before the autofs +file system mounts above are attempted. + +It isn't worth adding a patch to check if the autofs mount control +structure is valid because if it isn't, in this case, amd doesn't +crash but still becomes unresponsive. +--- + amd/map.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/amd/map.c b/amd/map.c +index 2fad4b7..8e86b39 100644 +--- a/amd/map.c ++++ b/amd/map.c +@@ -946,7 +946,8 @@ unmount_mp(am_node *mp) + #endif /* HAVE_FS_AUTOFS */ + + if ((mf->mf_fsflags & FS_UBACKGROUND) && +- (mf->mf_flags & MFF_MOUNTED)) { ++ (mf->mf_flags & MFF_MOUNTED) && ++ !(mf->mf_flags & MFF_ON_AUTOFS)) { + dlog("Trying unmount in background"); + run_task(unmount_node, (opaque_t) mp, + free_map_if_success, (opaque_t) mp); diff --git a/am-utils-6.1.5-fix-autofs-proto-version-define.patch b/am-utils-6.1.5-fix-autofs-proto-version-define.patch new file mode 100644 index 0000000..8b04bcc --- /dev/null +++ b/am-utils-6.1.5-fix-autofs-proto-version-define.patch @@ -0,0 +1,28 @@ +am-utils-6.1.5 - fix autofs proto version define + +From: Ian Kent + +I don't think am-utils works with autofs protocol version 5. +--- + + conf/autofs/autofs_linux.c | 5 ++++- + 1 files changed, 4 insertions(+), 1 deletions(-) + + +diff --git a/conf/autofs/autofs_linux.c b/conf/autofs/autofs_linux.c +index f56befa..eeb211f 100644 +--- a/conf/autofs/autofs_linux.c ++++ b/conf/autofs/autofs_linux.c +@@ -59,8 +59,11 @@ + */ + + #define AUTOFS_MIN_VERSION 3 ++#if AUTOFS_MAX_PROTO_VERSION >= 5 ++#define AUTOFS_MAX_VERSION 4 ++#else + #define AUTOFS_MAX_VERSION AUTOFS_MAX_PROTO_VERSION +- ++#endif + + /* + * STRUCTURES: diff --git a/am-utils-6.1.5-handle-ENOENT-umount-return-for-autofs-mounts.patch b/am-utils-6.1.5-handle-ENOENT-umount-return-for-autofs-mounts.patch new file mode 100644 index 0000000..5785898 --- /dev/null +++ b/am-utils-6.1.5-handle-ENOENT-umount-return-for-autofs-mounts.patch @@ -0,0 +1,33 @@ +am-utils-6.1.5 - handle ENOENT umount return for autofs mounts + +From: Ian Kent + +An ENOENT return from umount(2) means the kernel path walk couldn't +resolve the path of the mount to a dentry. In that case there can't +be an autofs waitq entry waiting for notification, since there's no +dentry, so don't even try to notify the kernel. +--- + amd/map.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/amd/map.c b/amd/map.c +index 8e86b39..e6d14b8 100644 +--- a/amd/map.c ++++ b/amd/map.c +@@ -873,10 +873,12 @@ free_map_if_success(int rc, int term, opaque_t arg) + else + plog(XLOG_ERROR, "%s: unmount: %s", mp->am_path, strerror(rc)); + #ifdef HAVE_FS_AUTOFS +- if (mf->mf_flags & MFF_IS_AUTOFS) +- autofs_get_mp(mp); +- if (mp->am_flags & AMF_AUTOFS) +- autofs_umount_failed(mp); ++ if (rc != ENOENT) { ++ if (mf->mf_flags & MFF_IS_AUTOFS) ++ autofs_get_mp(mp); ++ if (mp->am_flags & AMF_AUTOFS) ++ autofs_umount_failed(mp); ++ } + #endif /* HAVE_FS_AUTOFS */ + amd_stats.d_uerr++; + } else { diff --git a/am-utils-6.2-0.git.9b652fb4-fix-handle-failed-umount-on-exit.patch b/am-utils-6.2-0.git.9b652fb4-fix-handle-failed-umount-on-exit.patch new file mode 100644 index 0000000..7ece413 --- /dev/null +++ b/am-utils-6.2-0.git.9b652fb4-fix-handle-failed-umount-on-exit.patch @@ -0,0 +1,13 @@ +diff -up am-utils-6.1.5/amd/map.c.orig am-utils-6.1.5/amd/map.c +--- am-utils-6.1.5/amd/map.c.orig 2014-03-19 19:45:45.000000000 +0800 ++++ am-utils-6.1.5/amd/map.c 2014-03-19 19:47:42.741848068 +0800 +@@ -748,7 +748,8 @@ umount_exported(void) + } else { + am_unmounted(mp); + } +- exported_ap[i] = NULL; ++ if (!(mf->mf_flags && (MFF_UNMOUNTING|MFF_MOUNTED))) ++ exported_ap[i] = NULL; + } else { + /* + * Any other node gets forcibly timed out. diff --git a/am-utils-6.2-0.git.9b652fb4-linux-umount-wait-on-ebusy.patch b/am-utils-6.2-0.git.9b652fb4-linux-umount-wait-on-ebusy.patch new file mode 100644 index 0000000..3896c68 --- /dev/null +++ b/am-utils-6.2-0.git.9b652fb4-linux-umount-wait-on-ebusy.patch @@ -0,0 +1,50 @@ +am-utils-6.2-0.git.9b652fb4 - linux umount wait on ebusy + +From: Ian Kent + +For some reason, when umounting autofs mounts after closing the ioctl +file handle, the kernel can return EBUSY for some small amount of time. + +This can cause umounts to incorrectly fail when in fact they should +succeed. + +Retrying for about a second and a half seems to work quite well. +--- + conf/umount/umount_linux.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/conf/umount/umount_linux.c b/conf/umount/umount_linux.c +index 782c2cd..81b0527 100644 +--- a/conf/umount/umount_linux.c ++++ b/conf/umount/umount_linux.c +@@ -63,6 +63,7 @@ umount_fs(char *mntdir, const char *mnttabname, u_int unmount_flags) + char loopstr[] = "loop="; + char *loopdev; + #endif /* HAVE_LOOP_DEVICE */ ++ unsigned int retries = 8; + + mp = mlist = read_mtab(mntdir, mnttabname); + +@@ -94,6 +95,7 @@ umount_fs(char *mntdir, const char *mnttabname, u_int unmount_flags) + unlock_mntlist(); + #endif /* MOUNT_TABLE_ON_FILE */ + ++again: + #if defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_DETACH) + /* + * If user asked to try forced unmounts, then do a quick check to see if +@@ -111,6 +113,14 @@ umount_fs(char *mntdir, const char *mnttabname, u_int unmount_flags) + } else + #endif /* defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_DETACH) */ + error = UNMOUNT_TRAP(mp_save->mnt); ++ ++ /* Linux kernel can be sluggish for some reason */ ++ if (error == EBUSY && retries--) { ++ struct timespec tm = {0, 200000000}; ++ nanosleep(&tm, NULL); ++ goto again; ++ } ++ + if (error < 0) { + plog(XLOG_WARNING, "unmount(%s) failed: %m", mp_save->mnt->mnt_dir); + switch ((error = errno)) { diff --git a/am-utils-6.2-1.git.e03592f0-fix-debug-log-deadlock.patch b/am-utils-6.2-1.git.e03592f0-fix-debug-log-deadlock.patch new file mode 100644 index 0000000..442442d --- /dev/null +++ b/am-utils-6.2-1.git.e03592f0-fix-debug-log-deadlock.patch @@ -0,0 +1,82 @@ +am-utils-6.2-1.git.e03592f0 - fix debug log deadlock + +From: Ian Kent + +It's possible (and likely) a SIGCHLD signal can arrive while in syslog(2) +and also attempt log log a message leading to deadlock. +--- + libamu/xutil.c | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/libamu/xutil.c b/libamu/xutil.c +index b3e3a0f..0d9d2ec 100644 +--- a/libamu/xutil.c ++++ b/libamu/xutil.c +@@ -420,14 +420,33 @@ debug_option(char *opt) + void + dplog(const char *fmt, ...) + { ++#ifdef HAVE_SIGACTION ++ sigset_t old, chld; ++#else /* not HAVE_SIGACTION */ ++ int mask; ++#endif /* not HAVE_SIGACTION */ + va_list ap; + ++#ifdef HAVE_SIGACTION ++ sigemptyset(&chld); ++ sigaddset(&chld, SIGCHLD); ++#else /* not HAVE_SIGACTION */ ++ mask = sigblock(sigmask(SIGCHLD)); ++#endif /* not HAVE_SIGACTION */ ++ ++ sigprocmask(SIG_BLOCK, &chld, &old); + if (!logfp) + logfp = stderr; /* initialize before possible first use */ + + va_start(ap, fmt); + real_plog(XLOG_DEBUG, fmt, ap); + va_end(ap); ++ ++#ifdef HAVE_SIGACTION ++ sigprocmask(SIG_SETMASK, &old, NULL); ++#else /* not HAVE_SIGACTION */ ++ mask = sigblock(sigmask(SIGCHLD)); ++#endif /* not HAVE_SIGACTION */ + } + #endif /* DEBUG */ + +@@ -435,14 +454,33 @@ dplog(const char *fmt, ...) + void + plog(int lvl, const char *fmt, ...) + { ++#ifdef HAVE_SIGACTION ++ sigset_t old, chld; ++#else /* not HAVE_SIGACTION */ ++ int mask; ++#endif /* not HAVE_SIGACTION */ + va_list ap; + ++#ifdef HAVE_SIGACTION ++ sigemptyset(&chld); ++ sigaddset(&chld, SIGCHLD); ++ sigprocmask(SIG_BLOCK, &chld, &old); ++#else /* not HAVE_SIGACTION */ ++ mask = sigblock(sigmask(SIGCHLD)); ++#endif /* not HAVE_SIGACTION */ ++ + if (!logfp) + logfp = stderr; /* initialize before possible first use */ + + va_start(ap, fmt); + real_plog(lvl, fmt, ap); + va_end(ap); ++ ++#ifdef HAVE_SIGACTION ++ sigprocmask(SIG_SETMASK, &old, NULL); ++#else /* not HAVE_SIGACTION */ ++ sigsetmask(mask); ++#endif /* not HAVE_SIGACTION */ + } + + diff --git a/am-utils-6.2-1.git.e03592f0-fix-get_nfs_version-message.patch b/am-utils-6.2-1.git.e03592f0-fix-get_nfs_version-message.patch new file mode 100644 index 0000000..76e438f --- /dev/null +++ b/am-utils-6.2-1.git.e03592f0-fix-get_nfs_version-message.patch @@ -0,0 +1,22 @@ +am-utils-6.2-1.git.e03592f0 - fix get_nfs_version() message + +From: Ian Kent + +Fix a error message formating mistake in get_nfs_version(). +--- + conf/transp/transp_sockets.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/conf/transp/transp_sockets.c b/conf/transp/transp_sockets.c +index d5e729f..5036b26 100644 +--- a/conf/transp/transp_sockets.c ++++ b/conf/transp/transp_sockets.c +@@ -478,7 +478,7 @@ try_again: + } + + if (errstr) { +- plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s%s", ++ plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s: %s", + (int) nfs_version, proto, host, errstr); + if (again) { + #ifdef HAVE_FS_NFS3 diff --git a/am-utils-6.2-make-sure-to-remove-nodes-in-the-proper-order-when-going-down.patch b/am-utils-6.2-make-sure-to-remove-nodes-in-the-proper-order-when-going-down.patch new file mode 100644 index 0000000..c5878bf --- /dev/null +++ b/am-utils-6.2-make-sure-to-remove-nodes-in-the-proper-order-when-going-down.patch @@ -0,0 +1,152 @@ +diff -up am-utils-6.1.5/amd/map.c.orig am-utils-6.1.5/amd/map.c +--- am-utils-6.1.5/amd/map.c.orig 2014-03-19 19:34:23.000000000 +0800 ++++ am-utils-6.1.5/amd/map.c 2014-03-19 19:44:17.918101095 +0800 +@@ -687,68 +687,80 @@ make_root_node(void) + void + umount_exported(void) + { +- int i; ++ int i, work_done; + +- for (i = last_used_map; i >= 0; --i) { +- am_node *mp = exported_ap[i]; +- mntfs *mf; ++ do { ++ work_done = 0; + +- if (!mp) +- continue; ++ for (i = last_used_map; i >= 0; --i) { ++ am_node *mp = exported_ap[i]; ++ mntfs *mf; + +- mf = mp->am_mnt; +- if (mf->mf_flags & MFF_UNMOUNTING) { +- /* +- * If this node is being unmounted then just ignore it. However, +- * this could prevent amd from finishing if the unmount gets blocked +- * since the am_node will never be free'd. am_unmounted needs +- * telling about this possibility. - XXX +- */ +- continue; +- } ++ if (!mp) ++ continue; + +- if (!(mf->mf_fsflags & FS_DIRECTORY)) + /* +- * When shutting down this had better +- * look like a directory, otherwise it +- * can't be unmounted! ++ * Wait for children to be removed first + */ +- mk_fattr(&mp->am_fattr, NFDIR); ++ if (mp->am_child) ++ continue; + +- if ((--immediate_abort < 0 && +- !(mp->am_flags & AMF_ROOT) && mp->am_parent) || +- (mf->mf_flags & MFF_RESTART)) { ++ mf = mp->am_mnt; ++ if (mf->mf_flags & MFF_UNMOUNTING) { ++ /* ++ * If this node is being unmounted then just ignore it. However, ++ * this could prevent amd from finishing if the unmount gets blocked ++ * since the am_node will never be free'd. am_unmounted needs ++ * telling about this possibility. - XXX ++ */ ++ continue; ++ } + +- /* +- * Just throw this node away without bothering to unmount it. If +- * the server is not known to be up then don't discard the mounted +- * on directory or Amd might hang... +- */ +- if (mf->mf_server && ++ if (!(mf->mf_fsflags & FS_DIRECTORY)) ++ /* ++ * When shutting down this had better ++ * look like a directory, otherwise it ++ * can't be unmounted! ++ */ ++ mk_fattr(&mp->am_fattr, NFDIR); ++ ++ if ((--immediate_abort < 0 && ++ !(mp->am_flags & AMF_ROOT) && mp->am_parent) || ++ (mf->mf_flags & MFF_RESTART)) { ++ ++ work_done++; ++ ++ /* ++ * Just throw this node away without bothering to unmount it. If ++ * the server is not known to be up then don't discard the mounted ++ * on directory or Amd might hang... ++ */ ++ if (mf->mf_server && + (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) != FSF_VALID) + mf->mf_flags &= ~MFF_MKMNT; +- if (gopt.flags & CFM_UNMOUNT_ON_EXIT || mp->am_flags & AMF_AUTOFS) { +- plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount); +- /* +- * use unmount_mp, not unmount_node, so that unmounts be +- * backgrounded as needed. +- */ +- unmount_mp((opaque_t) mp); +- } else { +- am_unmounted(mp); +- } +- exported_ap[i] = 0; +- } else { +- /* +- * Any other node gets forcibly timed out. +- */ +- mp->am_flags &= ~AMF_NOTIMEOUT; +- mp->am_mnt->mf_flags &= ~MFF_RSTKEEP; +- mp->am_ttl = 0; +- mp->am_timeo = 1; +- mp->am_timeo_w = 0; +- } +- } ++ if (gopt.flags & CFM_UNMOUNT_ON_EXIT || mp->am_flags & AMF_AUTOFS) { ++ plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount); ++ /* ++ * use unmount_mp, not unmount_node, so that unmounts be ++ * backgrounded as needed. ++ */ ++ unmount_mp((opaque_t) mp); ++ } else { ++ am_unmounted(mp); ++ } ++ exported_ap[i] = NULL; ++ } else { ++ /* ++ * Any other node gets forcibly timed out. ++ */ ++ mp->am_flags &= ~AMF_NOTIMEOUT; ++ mp->am_mnt->mf_flags &= ~MFF_RSTKEEP; ++ mp->am_ttl = 0; ++ mp->am_timeo = 1; ++ mp->am_timeo_w = 0; ++ } ++ } ++ } while (work_done); + } + + +diff -U0 am-utils-6.1.5/ChangeLog.orig am-utils-6.1.5/ChangeLog +--- am-utils-6.1.5/ChangeLog.orig 2006-05-12 01:25:47.000000000 +0800 ++++ am-utils-6.1.5/ChangeLog 2014-03-19 19:36:27.335598581 +0800 +@@ -0,0 +1,12 @@ ++2009-12-10 Christos Zoulas ++ ++ * Make sure to remove nodes in the proper order when going ++ down. Depending on what order the nodes got created it's ++ possible that the parent of a node has a bigger am_mapno ++ (index in exported_ap[]) so that it gets freed before ++ its child while the child's am_parent pointer is still ++ pointing to the already freed block of memory. ++ This change makes sure that umount_exported() cleans up ++ all children of a node first before freeing the node. ++ From: Krisztian Kovacs ++ diff --git a/am-utils.spec b/am-utils.spec index 05659a4..6b326d8 100644 --- a/am-utils.spec +++ b/am-utils.spec @@ -1,7 +1,7 @@ Summary: Automount utilities including an updated version of Amd Name: am-utils Version: 6.1.5 -Release: 29%{?dist} +Release: 30%{?dist} License: BSD Epoch: 5 Group: System Environment/Daemons @@ -59,6 +59,17 @@ Patch8: am-utils-6.1.5-use-_hardened_build-flag.patch # Fix documentation build fails. Patch9: am-utils-6.1.5-texinfo-documentation-build-fixes.patch +Patch10: am-utils-6.1.5-dont-background-autofs-umount.patch +Patch11: am-utils-6.1.5-check-fh-on-umount-succeeded.patch +Patch12: am-utils-6.1.5-handle-ENOENT-umount-return-for-autofs-mounts.patch +Patch13: am-utils-6.2-1.git.e03592f0-fix-get_nfs_version-message.patch +Patch14: am-utils-6.2-1.git.e03592f0-fix-debug-log-deadlock.patch +Patch15: am-utils-6.2-0.git.9b652fb4-linux-umount-wait-on-ebusy.patch +Patch16: am-utils-6.2-make-sure-to-remove-nodes-in-the-proper-order-when-going-down.patch +Patch17: am-utils-6.2-0.git.9b652fb4-fix-handle-failed-umount-on-exit.patch +# Don't attempt to use v5 protocol +Patch18: am-utils-6.1.5-fix-autofs-proto-version-define.patch + %global _hardened_build 1 # We need to filter out some perl requirements for now. @@ -88,6 +99,15 @@ mounting and unmounting filesystems. %patch7 -p1 %patch8 -p1 %patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 find_requires=%{old_find_requires} echo "$find_requires | grep -v lostaltmail.conf" > find-requires @@ -199,6 +219,18 @@ fi %{_libdir}/libamu.so* %changelog +* Fri Mar 20 2014 Ian Kent - 5:6.1.5-30 +- bz1074376 - am-utils will no longer start due to missing NFSv2 + - dont background autofs umount. + - check fh on umount succeeded. + - handle ENOENT umount return for autofs mounts. + - fix get_nfs_version() message. + - fix debug log deadlock. + - linux umount wait on ebusy. + - make sure to remove nodes in the proper order when going down. + - fix handle failed umount on exit. + - fix autofs proto version define. + * Sat Aug 03 2013 Fedora Release Engineering - 5:6.1.5-29 - Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild