Blame SOURCES/autofs-5.1.1-always-set-direct-mounts-catatonic-at-exit.patch

304803
autofs-5.1.1 - always set direct mounts catatonic at exit
304803
304803
From: Ian Kent <raven@themaw.net>
304803
304803
Direct mounts are all mounted at application start or when the map
304803
is re-read and entries have been added.
304803
304803
They are only ever umounted at application exit or when the map is
304803
re-read and entries have been removed.
304803
304803
If these mounts are in use (so that they are not umounted) and aren't
304803
set catatonic at exit and an application attempts to access the path
304803
it will lead to a hang as there is no daemon to answer the mount
304803
request.
304803
304803
It's questionable whether to set busy direct mounts catatonic when
304803
attempting to umount them when re-reading the map as the mount may
304803
then expire leaving an unresponsive direct mount trigger that hasn't
304803
yet been cleaned from the map entry cache.
304803
304803
Signed-off-by: Ian Kent <raven@themaw.net>
304803
---
304803
 CHANGELOG       |    1 
304803
 daemon/direct.c |   99 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
304803
 2 files changed, 92 insertions(+), 8 deletions(-)
304803
304803
--- autofs-5.0.7.orig/CHANGELOG
304803
+++ autofs-5.0.7/CHANGELOG
304803
@@ -186,6 +186,7 @@
304803
 - add remote-fs.target systemd dependency.
304803
 - gaurd against incorrect umount return.
304803
 - fix typo in autofs.conf.
304803
+- always set direct mounts catatonic at exit.
304803
 
304803
 25/07/2012 autofs-5.0.7
304803
 =======================
304803
--- autofs-5.0.7.orig/daemon/direct.c
304803
+++ autofs-5.0.7/daemon/direct.c
304803
@@ -82,6 +82,65 @@ static void mnts_cleanup(void *arg)
304803
 	return;
304803
 }
304803
 
304803
+/* When exiting direct mount triggers must be set catatonic, regardless
304803
+ * of whether they are busy on not, to avoid a hang on access once the
304803
+ * daemon has gone away.
304803
+ */
304803
+static int set_direct_mount_catatonic(struct autofs_point *ap, struct mapent *me, int ioctlfd)
304803
+{
304803
+	struct ioctl_ops *ops = get_ioctl_ops();
304803
+	unsigned int opened = 0;
304803
+	char buf[MAX_ERR_BUF];
304803
+	int fd = -1;
304803
+	int error;
304803
+
304803
+	/* In case the miscellaneous device isn't being used try
304803
+	 * and use an existing ioctl control fd. In this case if
304803
+	 * we don't already have an ioctl fd the mount can't be
304803
+	 * set catatonic if it's covered.
304803
+	 */
304803
+	if (ioctlfd >= 0)
304803
+		fd = ioctlfd;
304803
+	else if (me->ioctlfd >= 0)
304803
+		fd = me->ioctlfd;
304803
+	else {
304803
+		error = ops->open(ap->logopt, &fd, me->dev, me->key);
304803
+		if (error == -1) {
304803
+			int err = errno;
304803
+			char *estr;
304803
+
304803
+			estr = strerror_r(errno, buf, MAX_ERR_BUF);
304803
+			error(ap->logopt,
304803
+			      "failed to open ioctlfd for %s, error: %s",
304803
+			      me->key, estr);
304803
+			return err;
304803
+		}
304803
+		opened = 1;
304803
+	}
304803
+
304803
+	if (fd >= 0) {
304803
+		error = ops->catatonic(ap->logopt, fd);
304803
+		if (error == -1) {
304803
+			int err = errno;
304803
+			char *estr;
304803
+
304803
+			estr = strerror_r(errno, buf, MAX_ERR_BUF);
304803
+			error(ap->logopt,
304803
+			      "failed to set %s catatonic, error: %s",
304803
+			      me->key, estr);
304803
+			if (opened)
304803
+				ops->close(ap->logopt, fd);
304803
+			return err;
304803
+		}
304803
+		if (opened)
304803
+			ops->close(ap->logopt, fd);
304803
+	}
304803
+
304803
+	debug(ap->logopt, "set %s catatonic", me->key);
304803
+
304803
+	return 0;
304803
+}
304803
+
304803
 int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
304803
 {
304803
 	struct ioctl_ops *ops = get_ioctl_ops();
304803
@@ -97,7 +156,8 @@ int do_umount_autofs_direct(struct autof
304803
 	}
304803
 
304803
 	if (me->ioctlfd != -1) {
304803
-		if (tree_is_mounted(mnts, me->key, MNTS_REAL)) {
304803
+		if (ap->state == ST_READMAP &&
304803
+		    tree_is_mounted(mnts, me->key, MNTS_REAL)) {
304803
 			error(ap->logopt,
304803
 			      "attempt to umount busy direct mount %s",
304803
 			      me->key);
304803
@@ -116,7 +176,12 @@ int do_umount_autofs_direct(struct autof
304803
 		if (rv) {
304803
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
304803
 			error(ap->logopt, "ioctl failed: %s", estr);
304803
-			if (opened && ioctlfd != -1)
304803
+			/* The ioctl failed so this probably won't
304803
+			 * work either but since we opened it here
304803
+			 * try anyway. We should set these catatonic
304803
+			 * too but ....
304803
+			 */
304803
+			if (opened)
304803
 				ops->close(ap->logopt, ioctlfd);
304803
 			return 1;
304803
 		} else if (!status) {
304803
@@ -124,18 +189,20 @@ int do_umount_autofs_direct(struct autof
304803
 				error(ap->logopt,
304803
 				      "ask umount returned busy for %s",
304803
 				      me->key);
304803
-				if (opened && ioctlfd != -1)
304803
+				if (ap->state != ST_READMAP)
304803
+					set_direct_mount_catatonic(ap, me, ioctlfd);
304803
+				if (opened)
304803
 					ops->close(ap->logopt, ioctlfd);
304803
 				return 1;
304803
 			} else {
304803
 				me->ioctlfd = -1;
304803
-				ops->catatonic(ap->logopt, ioctlfd);
304803
+				set_direct_mount_catatonic(ap, me, ioctlfd);
304803
 				ops->close(ap->logopt, ioctlfd);
304803
 				goto force_umount;
304803
 			}
304803
 		}
304803
 		me->ioctlfd = -1;
304803
-		ops->catatonic(ap->logopt, ioctlfd);
304803
+		set_direct_mount_catatonic(ap, me, ioctlfd);
304803
 		ops->close(ap->logopt, ioctlfd);
304803
 	} else {
304803
 		error(ap->logopt,
304803
@@ -212,15 +279,31 @@ int umount_autofs_direct(struct autofs_p
304803
 		cache_readlock(mc);
304803
 		me = cache_enumerate(mc, NULL);
304803
 		while (me) {
304803
+			int error;
304803
+
304803
 			ne = cache_lookup_distinct(nc, me->key);
304803
 			if (ne && map->master_line > ne->age) {
304803
 				me = cache_enumerate(mc, me);
304803
 				continue;
304803
 			}
304803
 
304803
-			/* TODO: check return, locking me */
304803
-			do_umount_autofs_direct(ap, mnts, me);
304803
-
304803
+			/* The daemon is exiting so ...
304803
+			 * If we get a fail here we must make our
304803
+			 * best effort to set the direct mount trigger
304803
+			 * catatonic regardless of the reason for the
304803
+			 * failed umount.
304803
+			 */
304803
+			error = do_umount_autofs_direct(ap, mnts, me);
304803
+			if (!error)
304803
+				goto done;
304803
+
304803
+			error = set_direct_mount_catatonic(ap, me, me->ioctlfd);
304803
+			if (!error)
304803
+				goto done;
304803
+
304803
+			/* We really need to set this, last ditch attempt */
304803
+			set_direct_mount_catatonic(ap, me, -1);
304803
+done:
304803
 			me = cache_enumerate(mc, me);
304803
 		}
304803
 		pthread_cleanup_pop(1);