forced-unmount flag.
* conf/umount/umount_default.c (umount_fs): if regular umount got
EBUSY, EIO, or ESTALE, then try forced unmount, if supported. Try
umount2 (Solaris) or uvmount (AIX).
* conf/umount/umount_{bsd44,osf}.c (umount_fs): if default
umount() failed with EIO or ESTALE, also try forced unmount.
* amd/autil.c (amfs_mount), amd/amfs_toplvl.c
(amfs_toplvl_umount): enable forced/lazy unmounts only if user
asked for it (and dlog it).
* scripts/amd.conf.5: document new force_unmount global parameter.
* doc/am-utils.texi (forced_unmounts Parameter): document new
global parameter.
* amd/conf.c (gopt_forced_unmounts): process forced_unmounts
option (default "no"). Exit with an error if user specified the
option as "yes" but configure couldn't find support for either the
MNT_FORCE or MNT_DETACH flags.
* scripts/amd.conf-sample (forced_unmounts): example usage of new
option.
* amd/amd.h (CFM_FORCED_UNMOUNTS): new flag for forced_unmounts
option.
* m4/macros/header_templates.m4: templates for _DETACH and _FORCE.
* configure.in: check for generic u/mount options "detach" and
"force".
* include/am_utils.h (UMOUNT_FS, umount_fs): new prototypes.
Define AMU_UMOUNT flags for force, detach, and autofs.
* amd/amfs_toplvl.c (amfs_toplvl_umount): pass _FORCE and _DETACH
unmount flags unconditionally. Pass them to UMOUNT_FS().
* conf/nfs_prot/nfs_prot_linux.h: define MNT_FORCE and MNT_DETACH
if needed, because some Linux systems don't define them
(presumably because it would be too dangerous to expose these
flags to users).
* amd/autil.c (amfs_mount): if mount(2) failed with ESTALE or EIO,
then assume that we're in trouble, possibly because a previous
mount is hung. So, first try to force a lazy unmount of the old
mount. If the forced unmount worked, then try again to mount the
desired file system. If the forced unmount failed, then don't
retry: just return an error.
* amd/amfs_generic.c (amfs_generic_umount), amd/amfs_host.c
(amfs_host_umount), amd/ops_cachefs.c (cachefs_umount),
amd/ops_cdfs.c (cdfs_umount), amd/ops_efs.c (efs_umount),
amd/ops_lofs.c (lofs_umount), amd/ops_nfs.c (nfs_umount),
amd/ops_pcfs.c (pcfs_umount), amd/ops_ufs.c (ufs_umount),
amd/ops_xfs.c (xfs_umount), conf/umount/umount_bsd44.c
(umount_fs), conf/umount/umount_default.c (umount_fs),
conf/umount/umount_linux.c (umount_fs), conf/umount/umount_osf.c
(umount_fs): compute and use unmount specific flags.
+2005-07-19 Erez Zadok <ezk@cs.sunysb.edu>
+
+ * conf/nfs_prot/nfs_prot_aix5_2.h: define compatible
+ forced-unmount flag.
+
+ * conf/umount/umount_default.c (umount_fs): if regular umount got
+ EBUSY, EIO, or ESTALE, then try forced unmount, if supported. Try
+ umount2 (Solaris) or uvmount (AIX).
+
+ * conf/umount/umount_{bsd44,osf}.c (umount_fs): if default
+ umount() failed with EIO or ESTALE, also try forced unmount.
+
+2005-07-18 Erez Zadok <ezk@cs.sunysb.edu>
+
+ * amd/autil.c (amfs_mount), amd/amfs_toplvl.c
+ (amfs_toplvl_umount): enable forced/lazy unmounts only if user
+ asked for it (and dlog it).
+
+ * scripts/amd.conf.5: document new force_unmount global parameter.
+
+ * doc/am-utils.texi (forced_unmounts Parameter): document new
+ global parameter.
+
+ * amd/conf.c (gopt_forced_unmounts): process forced_unmounts
+ option (default "no"). Exit with an error if user specified the
+ option as "yes" but configure couldn't find support for either the
+ MNT_FORCE or MNT_DETACH flags.
+
+ * scripts/amd.conf-sample (forced_unmounts): example usage of new
+ option.
+
+ * amd/amd.h (CFM_FORCED_UNMOUNTS): new flag for forced_unmounts
+ option.
+
+ * m4/macros/header_templates.m4: templates for _DETACH and _FORCE.
+
+ * configure.in: check for generic u/mount options "detach" and
+ "force".
+
+ * include/am_utils.h (UMOUNT_FS, umount_fs): new prototypes.
+ Define AMU_UMOUNT flags for force, detach, and autofs.
+
+ * amd/amfs_toplvl.c (amfs_toplvl_umount): pass _FORCE and _DETACH
+ unmount flags unconditionally. Pass them to UMOUNT_FS().
+
+ * conf/nfs_prot/nfs_prot_linux.h: define MNT_FORCE and MNT_DETACH
+ if needed, because some Linux systems don't define them
+ (presumably because it would be too dangerous to expose these
+ flags to users).
+
+ * amd/autil.c (amfs_mount): if mount(2) failed with ESTALE or EIO,
+ then assume that we're in trouble, possibly because a previous
+ mount is hung. So, first try to force a lazy unmount of the old
+ mount. If the forced unmount worked, then try again to mount the
+ desired file system. If the forced unmount failed, then don't
+ retry: just return an error.
+
+ * amd/amfs_generic.c (amfs_generic_umount), amd/amfs_host.c
+ (amfs_host_umount), amd/ops_cachefs.c (cachefs_umount),
+ amd/ops_cdfs.c (cdfs_umount), amd/ops_efs.c (efs_umount),
+ amd/ops_lofs.c (lofs_umount), amd/ops_nfs.c (nfs_umount),
+ amd/ops_pcfs.c (pcfs_umount), amd/ops_ufs.c (ufs_umount),
+ amd/ops_xfs.c (xfs_umount), conf/umount/umount_bsd44.c
+ (umount_fs), conf/umount/umount_default.c (umount_fs),
+ conf/umount/umount_linux.c (umount_fs), conf/umount/umount_osf.c
+ (umount_fs): compute and use unmount specific flags.
+
2005-07-16 Erez Zadok <ezk@cs.sunysb.edu>
* configure.in: better help for users, if nfs_args can't be found.
*** Notes specific to am-utils version 6.1.1-rc1
+New amd.conf global parameter: forced_unmounts (default to "no"). If set to
+"yes," and the client OS supports forced or lazy unmounts, then Amd will
+attempt to use them if it gets any of three serious error conditions when
+trying to unmount an existing mount point or mount on top of one: EIO,
+ESTALE, or EBUSY. This could be useful to recover from serious conditions
+such as hardware failure of mounted disks, or NFS servers which are down
+permanently, were migrated, or changed their IP address. Only
+"type:=toplvl" mounts hung with EBUSY are forcibly unmounted using this
+option, which is useful to recover from a hung Amd).
+
- minor new ports:
i386-pc-linux-fc4
i386-pc-linux-suse9.3
* SUCH DAMAGE.
*
*
- * $Id: amd.h,v 1.66 2005/06/04 16:34:33 ezk Exp $
+ * $Id: amd.h,v 1.67 2005/07/20 03:32:30 ezk Exp $
*
*/
#endif /* MOUNT_TABLE_ON_FILE */
/* options for amd.conf */
-#define CFM_BROWSABLE_DIRS 0x0001
-#define CFM_MOUNT_TYPE_AUTOFS 0x0002 /* use kernel autofs support */
-#define CFM_SELECTORS_IN_DEFAULTS 0x0004
-#define CFM_NORMALIZE_HOSTNAMES 0x0008
-#define CFM_PROCESS_LOCK 0x0010
-#define CFM_PRINT_PID 0x0020
-#define CFM_RESTART_EXISTING_MOUNTS 0x0040
-#define CFM_SHOW_STATFS_ENTRIES 0x0080
-#define CFM_FULLY_QUALIFIED_HOSTS 0x0100
-#define CFM_BROWSABLE_DIRS_FULL 0x0200 /* allow '/' in readdir() */
-#define CFM_UNMOUNT_ON_EXIT 0x0400 /* when amd finishing */
-#define CFM_USE_TCPWRAPPERS 0x0800
-#define CFM_AUTOFS_USE_LOFS 0x1000
-#define CFM_NFS_INSECURE_PORT 0x2000
-#define CFM_DOMAIN_STRIP 0x4000
-#define CFM_NORMALIZE_SLASHES 0x8000 /* normalize slashes? */
+#define CFM_BROWSABLE_DIRS 0x00000001
+#define CFM_MOUNT_TYPE_AUTOFS 0x00000002 /* use kernel autofs support */
+#define CFM_SELECTORS_IN_DEFAULTS 0x00000004
+#define CFM_NORMALIZE_HOSTNAMES 0x00000008
+#define CFM_PROCESS_LOCK 0x00000010
+#define CFM_PRINT_PID 0x00000020
+#define CFM_RESTART_EXISTING_MOUNTS 0x00000040
+#define CFM_SHOW_STATFS_ENTRIES 0x00000080
+#define CFM_FULLY_QUALIFIED_HOSTS 0x00000100
+#define CFM_BROWSABLE_DIRS_FULL 0x00000200 /* allow '/' in readdir() */
+#define CFM_UNMOUNT_ON_EXIT 0x00000400 /* when amd finishing */
+#define CFM_USE_TCPWRAPPERS 0x00000800
+#define CFM_AUTOFS_USE_LOFS 0x00001000
+#define CFM_NFS_INSECURE_PORT 0x00002000
+#define CFM_DOMAIN_STRIP 0x00004000
+#define CFM_NORMALIZE_SLASHES 0x00008000 /* normalize slashes? */
+#define CFM_FORCED_UNMOUNTS 0x00010000 /* normalize slashes? */
/* defaults global flags: plock, tcpwrappers, and autofs/lofs */
#define CFM_DEFAULT_FLAGS (CFM_PROCESS_LOCK|CFM_USE_TCPWRAPPERS|CFM_AUTOFS_USE_LOFS|CFM_DOMAIN_STRIP|CFM_NORMALIZE_SLASHES)
* SUCH DAMAGE.
*
*
- * $Id: amfs_generic.c,v 1.30 2005/05/16 18:08:53 ezk Exp $
+ * $Id: amfs_generic.c,v 1.31 2005/07/20 03:32:30 ezk Exp $
*
*/
int error = 0;
#ifdef HAVE_FS_AUTOFS
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
if (mf->mf_flags & MFF_IS_AUTOFS)
- error = UMOUNT_FS(mp->am_path, mnttab_file_name, on_autofs);
+ error = UMOUNT_FS(mp->am_path, mnttab_file_name, unmount_flags);
#endif /* HAVE_FS_AUTOFS */
return error;
* SUCH DAMAGE.
*
*
- * $Id: amfs_host.c,v 1.31 2005/05/02 00:27:47 ottavio Exp $
+ * $Id: amfs_host.c,v 1.32 2005/07/20 03:32:30 ezk Exp $
*
*/
amfs_host_umount(am_node *am, mntfs *mf)
{
mntlist *ml, *mprev;
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
int xerror = 0;
/*
/*
* Unmount "dir"
*/
- error = UMOUNT_FS(dir, mnttab_file_name, on_autofs);
+ error = UMOUNT_FS(dir, mnttab_file_name, unmount_flags);
/*
* Keep track of errors
*/
* 'xerror' is the return value for this function.
*
* We do not want to pass ENOENT as an error because if the
- * directory does not exists our work is done anyway.
+ * directory does not exists our work is done anyway.
*/
- if (!xerror && error != ENOENT)
+ if (!xerror && error != ENOENT)
xerror = error;
if (error != EBUSY) {
errno = error;
* SUCH DAMAGE.
*
*
- * $Id: amfs_toplvl.c,v 1.38 2005/04/17 03:05:54 ezk Exp $
+ * $Id: amfs_toplvl.c,v 1.39 2005/07/20 03:32:30 ezk Exp $
*
*/
amfs_toplvl_umount(am_node *mp, mntfs *mf)
{
struct stat stb;
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
int error;
+ /* if user wants forced/lazy unmount semantics, set those flags */
+ if (gopt.flags & CFM_FORCED_UNMOUNTS) {
+ dlog("enabling forced/lazy unmounts for toplvl node %s", mp->am_path);
+ unmount_flags |= (AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH);
+ }
+
again:
/*
* The lstat is needed if this mount is type=direct.
goto out;
}
- error = UMOUNT_FS(mp->am_path, mnttab_file_name, on_autofs);
+ error = UMOUNT_FS(mp->am_path, mnttab_file_name, unmount_flags);
if (error == EBUSY) {
#ifdef HAVE_FS_AUTOFS
/*
* SUCH DAMAGE.
*
*
- * $Id: autil.c,v 1.51 2005/04/17 03:05:54 ezk Exp $
+ * $Id: autil.c,v 1.52 2005/07/20 03:32:30 ezk Exp $
*
*/
char *dir = mf->mf_mount;
mntent_t mnt;
MTYPE_TYPE type;
+ int forced_unmount = 0; /* are we using forced unmounts? */
memset((voidp) &mnt, 0, sizeof(mnt));
mnt.mnt_dir = dir;
#endif /* HAVE_FS_AUTOFS */
genflags |= compute_automounter_mount_flags(&mnt);
+again:
if (!(mf->mf_flags & MFF_IS_AUTOFS)) {
nfs_args_t nfs_args;
am_nfs_fh *fhp;
retry, type, 0, NULL, mnttab_file_name, on_autofs);
#endif /* HAVE_FS_AUTOFS */
}
+ if (error == 0 || forced_unmount)
+ return error;
+
+ /*
+ * If user wants forced/lazy unmount semantics, then try it iff the
+ * current mount failed with EIO or ESTALE.
+ */
+ if (gopt.flags & CFM_FORCED_UNMOUNTS) {
+ switch (errno) {
+ case ESTALE:
+ case EIO:
+ forced_unmount = errno;
+ plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path);
+ if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name,
+ AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) {
+ plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path);
+ errno = forced_unmount;
+ } else
+ goto again;
+ default:
+ break;
+ }
+ }
return error;
}
* SUCH DAMAGE.
*
*
- * $Id: conf.c,v 1.32 2005/04/17 03:05:54 ezk Exp $
+ * $Id: conf.c,v 1.33 2005/07/20 03:32:30 ezk Exp $
*
*/
static int gopt_dismount_interval(const char *val);
static int gopt_domain_strip(const char *val);
static int gopt_exec_map_timeout(const char *val);
+static int gopt_forced_unmounts(const char *val);
static int gopt_full_os(const char *val);
static int gopt_fully_qualified_hosts(const char *val);
static int gopt_hesiod_base(const char *val);
{"dismount_interval", gopt_dismount_interval},
{"domain_strip", gopt_domain_strip},
{"exec_map_timeout", gopt_exec_map_timeout},
+ {"forced_unmounts", gopt_forced_unmounts},
{"fully_qualified_hosts", gopt_fully_qualified_hosts},
{"full_os", gopt_full_os},
{"hesiod_base", gopt_hesiod_base},
}
+static int
+gopt_forced_unmounts(const char *val)
+{
+ if (STREQ(val, "yes")) {
+#if !defined(MNT2_GEN_OPT_DETACH) && !defined(MNT2_GEN_OPT_FORCE)
+ fprintf(stderr, "conf: forced_unmounts unsupported on this system.\n");
+ return 1;
+#else /* defined(MNT2_GEN_OPT_DETACH) || defined(MNT2_GEN_OPT_FORCE) */
+ gopt.flags |= CFM_FORCED_UNMOUNTS;
+ return 0;
+#endif /* defined(MNT2_GEN_OPT_DETACH) || defined(MNT2_GEN_OPT_FORCE) */
+ } else if (STREQ(val, "no")) {
+ gopt.flags &= ~CFM_FORCED_UNMOUNTS;
+ return 0;
+ }
+
+ fprintf(stderr, "conf: unknown value to unmount_on_exit \"%s\"\n", val);
+ return 1; /* unknown value */
+}
+
+
static int
gopt_full_os(const char *val)
{
* SUCH DAMAGE.
*
*
- * $Id: ops_cachefs.c,v 1.18 2005/03/06 03:19:01 ezk Exp $
+ * $Id: ops_cachefs.c,v 1.19 2005/07/20 03:32:30 ezk Exp $
*
*/
static int
cachefs_umount(am_node *am, mntfs *mf)
{
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
int error;
- error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, on_autofs);
+ error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
/*
* In the case of cachefs, we must fsck the cache directory. Otherwise,
* SUCH DAMAGE.
*
*
- * $Id: ops_cdfs.c,v 1.24 2005/01/03 20:56:45 ezk Exp $
+ * $Id: ops_cdfs.c,v 1.25 2005/07/20 03:32:30 ezk Exp $
*
*/
static int
cdfs_umount(am_node *am, mntfs *mf)
{
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name, on_autofs);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
* SUCH DAMAGE.
*
*
- * $Id: ops_efs.c,v 1.19 2005/01/03 20:56:45 ezk Exp $
+ * $Id: ops_efs.c,v 1.20 2005/07/20 03:32:30 ezk Exp $
*
*/
static int
efs_umount(am_node *am, mntfs *mf)
{
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name, on_autofs);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
* SUCH DAMAGE.
*
*
- * $Id: ops_lofs.c,v 1.18 2005/01/03 20:56:45 ezk Exp $
+ * $Id: ops_lofs.c,v 1.19 2005/07/20 03:32:30 ezk Exp $
*
*/
static int
lofs_umount(am_node *am, mntfs *mf)
{
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name, on_autofs);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
* SUCH DAMAGE.
*
*
- * $Id: ops_nfs.c,v 1.43 2005/06/04 16:34:33 ezk Exp $
+ * $Id: ops_nfs.c,v 1.44 2005/07/20 03:32:30 ezk Exp $
*
*/
static int
nfs_umount(am_node *am, mntfs *mf)
{
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
- int error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, on_autofs);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+ int error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
/*
* Here is some code to unmount 'restarted' file systems.
if (NSTREQ(mf->mf_mount, new_mf->mf_mount, len) &&
new_mf->mf_mount[len] == '/') {
- UMOUNT_FS(new_mf->mf_mount, mnttab_file_name, 0);
+ int new_unmount_flags =
+ (new_mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+ UMOUNT_FS(new_mf->mf_mount, mnttab_file_name, new_unmount_flags);
didsome = 1;
}
}
if (didsome)
- error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, on_autofs);
+ error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
if (error)
return error;
* SUCH DAMAGE.
*
*
- * $Id: ops_pcfs.c,v 1.19 2005/01/03 20:56:45 ezk Exp $
+ * $Id: ops_pcfs.c,v 1.20 2005/07/20 03:32:30 ezk Exp $
*
*/
static int
pcfs_umount(am_node *am, mntfs *mf)
{
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name, on_autofs);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
* SUCH DAMAGE.
*
*
- * $Id: ops_ufs.c,v 1.18 2005/01/03 20:56:45 ezk Exp $
+ * $Id: ops_ufs.c,v 1.19 2005/07/20 03:32:30 ezk Exp $
*
*/
static int
ufs_umount(am_node *am, mntfs *mf)
{
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name, on_autofs);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
* SUCH DAMAGE.
*
*
- * $Id: ops_xfs.c,v 1.20 2005/01/03 20:56:45 ezk Exp $
+ * $Id: ops_xfs.c,v 1.21 2005/07/20 03:32:30 ezk Exp $
*
*/
static int
xfs_umount(am_node *am, mntfs *mf)
{
- int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
- return UMOUNT_FS(mf->mf_mount, mnttab_file_name, on_autofs);
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+
+ return UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
* SUCH DAMAGE.
*
*
- * $Id: nfs_prot_aix5_2.h,v 1.10 2005/05/26 13:36:35 ezk Exp $
+ * $Id: nfs_prot_aix5_2.h,v 1.11 2005/07/20 03:32:30 ezk Exp $
*
*/
# define MNTNAMLEN 255
#endif /* not MNTNAMLEN */
+/* compatible macro name with other OSs */
+#ifdef UVMNT_FORCE
+# define MS_FORCE UVMNT_FORCE
+#endif /* UVMNT_FORCE */
+
/********************************************************************************/
/*
* NFS mount option flags (out of mount.h)
* SUCH DAMAGE.
*
*
- * $Id: nfs_prot_linux.h,v 1.21 2005/01/03 20:56:45 ezk Exp $
+ * $Id: nfs_prot_linux.h,v 1.22 2005/07/20 03:32:30 ezk Exp $
*
*/
#ifndef MNTTYPE_NFS3
# define MNTTYPE_NFS3 "nfs"
#endif /* not MNTTYPE_NFS3 */
-
#endif /* HAVE_FS_NFS3 */
+/*
+ * These two force/lazy unmount flags are sometimes missing from some linux
+ * systems' headers.
+ */
+#ifdef HAVE_UMOUNT2
+# ifndef MNT_FORCE
+# define MNT_FORCE 0x1 /* from <sys/mount.h> */
+# endif /* not MNT_FORCE */
+# ifndef MNT_DETACH
+# define MNT_DETACH 0x2 /* from kernel <linux/fs.h> */
+# endif /* not MNT_DETACH */
+#endif /* HAVE_UMOUNT2 */
+
/* XXX: hack until we have a better way to detect /dev/loop devices */
#ifdef HAVE_LINUX_LOOP_H
# define HAVE_LOOP_DEVICE
* SUCH DAMAGE.
*
*
- * $Id: umount_bsd44.c,v 1.12 2005/01/03 20:56:45 ezk Exp $
+ * $Id: umount_bsd44.c,v 1.13 2005/07/20 03:32:30 ezk Exp $
*
*/
int
-umount_fs(char *mntdir, const char *mnttabname, int on_autofs)
+umount_fs(char *mntdir, const char *mnttabname, int unmount_flags)
{
int error;
dlog("%s: unmount: %m", mntdir);
goto eintr;
+#ifdef MNT2_GEN_OPT_FORCE
+ case EBUSY:
+ case EIO:
+ case ESTALE:
+ /* caller determines if forced unmounts should be used */
+ if (unmount_flags & AMU_UMOUNT_FORCE) {
+ if ((error = unmount(mntdir, MNT2_GEN_OPT_FORCE)) < 0)
+ error = errno;
+ else
+ return error;
+ }
+ /* fallthrough */
+#endif /* MNT2_GEN_OPT_FORCE */
+
default:
dlog("%s: unmount: %m", mntdir);
break;
* SUCH DAMAGE.
*
*
- * $Id: umount_default.c,v 1.14 2005/01/17 19:31:54 ib42 Exp $
+ * $Id: umount_default.c,v 1.15 2005/07/20 03:32:30 ezk Exp $
*
*/
int
-umount_fs(char *mntdir, const char *mnttabname, int on_autofs)
+umount_fs(char *mntdir, const char *mnttabname, int unmount_flags)
{
mntlist *mlist, *mp, *mp_save = 0;
int error = 0;
#endif /* MOUNT_TABLE_ON_FILE */
#ifdef NEED_AUTOFS_SPACE_HACK
- if (on_autofs) {
+ if (unmount_flags & AMU_UMOUNT_AUTOFS) {
char *mnt_dir_save = mp_save->mnt->mnt_dir;
mp_save->mnt->mnt_dir = autofs_strdup_space_hack(mnt_dir_save);
error = UNMOUNT_TRAP(mp_save->mnt);
#endif /* NEED_AUTOFS_SPACE_HACK */
error = UNMOUNT_TRAP(mp_save->mnt);
if (error < 0) {
- switch (error = errno) {
+ switch ((error = errno)) {
case EINVAL:
case ENOTBLK:
plog(XLOG_WARNING, "unmount: %s is not mounted", mp_save->mnt->mnt_dir);
plog(XLOG_ERROR, "mount point %s: %m", mp_save->mnt->mnt_dir);
break;
+#if defined(MNT2_GEN_OPT_FORCE) && (defined(HAVE_UMOUNT2) || defined(HAVE_UVMOUNT))
+ case EBUSY:
+ case EIO:
+ case ESTALE:
+ /* caller determines if forced unmounts should be used */
+ if (unmount_flags & AMU_UMOUNT_FORCE) {
+# ifdef HAVE_UMOUNT2
+ error = umount2(mntdir, MNT2_GEN_OPT_FORCE); /* Solaris */
+# else /* not HAVE_UMOUNT2 */
+# ifdef HAVE_UVMOUNT
+ error = uvmount(mp_save->mnt->mnt_passno, MNT2_GEN_OPT_FORCE); /* AIX */
+# endif /* HAVE_UVMOUNT */
+# endif /* not HAVE_UMOUNT2 */
+ if (error < 0)
+ error = errno;
+ else
+ break; /* all is OK */
+ }
+ /* fallthrough */
+#endif /* MNT2_GEN_OPT_FORCE && (HAVE_UMOUNT2 || HAVE_UVMOUNT) */
default:
dlog("%s: unmount: %m", mp_save->mnt->mnt_dir);
break;
* SUCH DAMAGE.
*
*
- * $Id: umount_linux.c,v 1.5 2005/07/10 21:41:49 ezk Exp $
+ * $Id: umount_linux.c,v 1.6 2005/07/20 03:32:30 ezk Exp $
*
*/
int
-umount_fs(char *mntdir, const char *mnttabname, int on_autofs)
+umount_fs(char *mntdir, const char *mnttabname, int unmount_flags)
{
+ struct stat dummy;
mntlist *mlist, *mp, *mp_save = 0;
int error = 0;
unlock_mntlist();
#endif /* MOUNT_TABLE_ON_FILE */
- error = UNMOUNT_TRAP(mp_save->mnt);
+#if defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_DETACH)
+ /*
+ * If user asked to try forced unmounts, then do a quick check to see if
+ * the mount point is hung badly. If so, then try to detach it by
+ * force; if the latter works, we're done.
+ *
+ * XXX: the stat() below may hang this unmount attempt of a toplvl
+ * mount. In that case, you may have to kill -9 the Amd process. A
+ * better way to handle this would be to check mtab for an old amd
+ * process, send a kill -0 to it to see if the Amd process is alive, and
+ * only do the forced unmount if the older Amd process died.
+ */
+ if ((unmount_flags & AMU_UMOUNT_DETACH) &&
+ (stat(mp_save->mnt->mnt_dir, &dummy) < 0 &&
+ (errno == ESTALE || errno == EIO))) {
+ plog(XLOG_INFO, "Forcibly unmounting stale/bad %s (%m)",
+ mp_save->mnt->mnt_dir);
+ error = umount2(mp_save->mnt->mnt_dir, MNT2_GEN_OPT_DETACH);
+ } else
+#endif /* defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_DETACH) */
+ error = UNMOUNT_TRAP(mp_save->mnt);
if (error < 0) {
plog(XLOG_WARNING, "unmount(%s) failed: %m", mp_save->mnt->mnt_dir);
switch ((error = errno)) {
plog(XLOG_ERROR, "mount point %s: %m", mp_save->mnt->mnt_dir);
break;
-#ifdef HAVE_UMOUNT2
-# ifndef MNT_DETACH
-# define MNT_DETACH 0x2 /* from kernel <linux/fs.h> */
-# endif /* not MNT_DETACH */
- case EIO:
- case ESTALE:
- plog(XLOG_ERROR, "umount %s failed (retrying): %m", mp_save->mnt->mnt_dir);
- error = umount2(mp_save->mnt->mnt_dir, MNT_DETACH | MNT_FORCE);
- if (error < 0) {
- dlog("%s: unmount2(detach+force): %m", mp_save->mnt->mnt_dir);
+#if defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_DETACH)
+ case EBUSY:
+ /*
+ * Caller determines if forced unmounts should be used now (for
+ * EBUSY). If caller asked to force an unmount, *and* the above
+ * "trivial" unmount attempt failed with EBUSY, then try to force
+ * the unmount.
+ */
+ if (unmount_flags & AMU_UMOUNT_FORCE) {
+ error = umount2(mp_save->mnt->mnt_dir, MNT2_GEN_OPT_FORCE);
+ if (error < 0) {
+ plog(XLOG_WARNING, "%s: unmount/detach: %m",
+ mp_save->mnt->mnt_dir);
error = errno;
+ }
}
break;
-#endif /* HAVE_UMOUNT2 */
+#endif /* defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_DETACH) */
default:
dlog("%s: unmount: %m", mp_save->mnt->mnt_dir);
* SUCH DAMAGE.
*
*
- * $Id: umount_osf.c,v 1.11 2005/01/03 20:56:45 ezk Exp $
+ * $Id: umount_osf.c,v 1.12 2005/07/20 03:32:30 ezk Exp $
*
*/
int
-umount_fs(char *fs_name, const char *mnttabname, int on_autofs)
+umount_fs(char *fs_name, const char *mnttabname, int unmount_flags)
{
int error;
dlog("%s: unmount: %m", fs_name);
goto eintr;
+#ifdef MNT2_GEN_OPT_FORCE
+ case EBUSY:
+ case EIO:
+ case ESTALE:
+ /* caller determines if forced unmounts should be used */
+ if (unmount_flags & AMU_UMOUNT_FORCE) {
+ if ((error = umount(mntdir, MNT2_GEN_OPT_FORCE)) < 0)
+ error = errno;
+ else
+ return error;
+ }
+ /* fallthrough */
+#endif /* MNT2_GEN_OPT_FORCE */
+
default:
dlog("%s: unmount: %m", fs_name);
break;
dnl
dnl AC_CONFIG_AUX_DIR(m4)
AC_PREREQ(2.52)
-AC_REVISION($Revision: 1.103 $)
+AC_REVISION($Revision: 1.104 $)
AC_COPYRIGHT([Copyright (c) 1997-2005 Erez Zadok])
dnl find out system type
AC_MSG_NOTICE(*** SYSTEM TYPES ***)
bind \
cache \
data \
+ detach \
+ force \
fss \
grpid \
ignore \
@c
@c %W% (Berkeley) %G%
@c
-@c $Id: am-utils.texi,v 1.102 2005/05/03 03:14:31 ezk Exp $
+@c $Id: am-utils.texi,v 1.103 2005/07/20 03:32:30 ezk Exp $
@c
@setfilename am-utils.info
* dismount_interval Parameter::
* domain_strip Parameter::
* exec_map_timeout Parameter::
+* forced_unmounts Parameter::
* full_os Parameter::
* fully_qualified_hosts Parameter::
* hesiod_base Parameter::
identical).
@c ----------------------------------------------------------------
-@node exec_map_timeout Parameter, full_os Parameter, domain_strip Parameter, Global Parameters
+@node exec_map_timeout Parameter, forced_unmounts Parameter, domain_strip Parameter, Global Parameters
@comment node-name, next, previous, up
@subsection @t{exec_map_timeout} Parameter
@cindex exec_map_timeout Parameter
to any other queries. @xref{Executable maps}.
@c ----------------------------------------------------------------
-@node full_os Parameter, fully_qualified_hosts Parameter, exec_map_timeout Parameter, Global Parameters
+@node forced_unmounts Parameter, full_os Parameter, exec_map_timeout Parameter, Global Parameters
+@comment node-name, next, previous, up
+@subsection @t{forced_unmounts} Parameter
+@cindex forced_unmounts Parameter
+
+(type=boolean, default=@samp{no}).
+Sometimes, mount points are hung due to unrecoverable conditions, such
+as when NFS servers migrate, change their IP address, are down
+permanently, or due to hardware failures, and more. In this case,
+attempting to unmount an existing mount point, or even just to
+@b{stat}(2) it, results in one of three fatal errors: EIO, ESTALE, or
+EBUSY. At that point, @i{Amd} can do little to recover that hung
+point (in fact, the OS cannot automatically recover either). For that
+reason, some OSs support special kinds of forced unmounts, which must
+be used very carefully: they will force an ummount immediately (or
+lazily on Linux), which could result in application data loss.
+However, that may be the only way to recover the entire host (without
+rebooting). Once a hung mount point is forced out, @i{Amd} can then
+re-mount a replacement one (if available), bringing a mostly-hung
+system back to operation and avoiding a potentially costly reboot.
+
+If the @samp{forced_unmounts} option is set to @samp{yes}, and the
+client OS supports forced or lazy unmounts, then @i{Amd} will attempt
+to use them if it gets any of the three serious error conditions
+listed above. Note that @i{Amd} will force the unmount of mount
+points that returned EBUSY only for @samp{type:=toplvl} mounts
+(@xref{Top-level Filesystem}): that is, @i{Amd}'s own mount points.
+This is useful to recover from a hung @i{Amd}.
+
+If this option is set to @samp{no} (the default), then @i{Amd} will
+not attempt this special recovery procedure.
+
+@c ----------------------------------------------------------------
+@node full_os Parameter, fully_qualified_hosts Parameter, forced_unmounts Parameter, Global Parameters
@comment node-name, next, previous, up
@subsection @t{full_os} Parameter
@cindex full_os Parameter
@subsection @t{unmount_on_exit} Parameter
@cindex unmount_on_exit Parameter
-(type=boolean), default=@samp{no}). If @samp{yes}, then @i{Amd} will attempt
+(type=boolean, default=@samp{no}). If @samp{yes}, then @i{Amd} will attempt
to unmount all file systems which it knows about. Normally it leaves
all (esp. NFS) mounted file systems intact. Note that @i{Amd} does not
know about file systems mounted before it starts up, unless the
* SUCH DAMAGE.
*
*
- * $Id: am_utils.h,v 1.66 2005/07/07 23:34:23 ezk Exp $
+ * $Id: am_utils.h,v 1.67 2005/07/20 03:32:31 ezk Exp $
*
*/
* Systems which have the mount table in a file need to read it before
* they can perform an unmount() system call.
*/
-#define UMOUNT_FS(dir, mtb_name, on_autofs) umount_fs(dir, mtb_name, on_autofs)
-
+#define UMOUNT_FS(dir, mtb_name, unmount_flags) umount_fs(dir, mtb_name, unmount_flags)
/* imported via $srcdir/conf/umount/umount_*.c */
-extern int umount_fs(char *mntdir, const char *mnttabname, int on_autofs);
+extern int umount_fs(char *mntdir, const char *mnttabname, int unmount_flags);
+/* unmount-related flags (special handling of autofs, forced/lazy, etc.) */
+#define AMU_UMOUNT_FORCE 0x1
+#define AMU_UMOUNT_DETACH 0x2
+#define AMU_UMOUNT_AUTOFS 0x4
/*
* The following values can be tuned...
AH_TEMPLATE([MNT2_GEN_OPT_DATA],
[6-argument mount])
+AH_TEMPLATE([MNT2_GEN_OPT_DETACH],
+[Use a lazy unmount (detach)])
+
+AH_TEMPLATE([MNT2_GEN_OPT_FORCE],
+[Use a forced unmount])
+
AH_TEMPLATE([MNT2_GEN_OPT_FSS],
[old (4-argument) mount (compatibility)])
# (amd -r)
restart_mounts = no | yes
unmount_on_exit = no | yes
+forced_unmounts = no | yes
# (amd -a)
auto_dir = /a
# duration in seconds that a looked up name remain cached (amd -c)
.\"
.\" %W% (Berkeley) %G%
.\"
-.\" $Id: amd.conf.5,v 1.37 2005/04/17 03:05:54 ezk Exp $
+.\" $Id: amd.conf.5,v 1.38 2005/07/20 03:32:31 ezk Exp $
.\"
.TH AMD.CONF 5 "7 August 1997"
.SH NAME
.I Amd
is essentially waiting and is thus not responding to any other queries.
+.TP
+.BR forced_unmounts " (boolean, default=no)"
+If set to "yes," and the client OS supports forced or lazy unmounts, then
+.I Amd
+will attempt to use them if it gets any of three serious error conditions
+when trying to unmount an existing mount point or mount on top of one: EIO,
+ESTALE, or EBUSY.
+
+This could be useful to recover from serious conditions such as hardware
+failure of mounted disks, or NFS servers which are down permanently, were
+migrated, or changed their IP address. Only "type:=toplvl" mounts hung with
+EBUSY are forcibly unmounted using this option, which is useful to recover
+from a hung
+.IR Amd ).
+
.TP
.BR full_os " (string, default to compiled in value)"
The full name of the operating system, along with its version. Allows you