Blob Blame History Raw
autofs-5.0.6 - fix offset mount point directory removal

From: Ian Kent <ikent@redhat.com>

Attempting to remove the last component of a multi-mount offset mount
point is incorrect. The removal and attempted recovery is better
handled in the calling function.
---

 CHANGELOG       |    1 
 daemon/direct.c |    7 ----
 lib/mounts.c    |   82 ++++++++++++++++++++++++++++++++------------------------
 3 files changed, 49 insertions(+), 41 deletions(-)


--- autofs-5.0.6.orig/CHANGELOG
+++ autofs-5.0.6/CHANGELOG
@@ -54,6 +54,7 @@
 - fix sss map age not updated.
 - fix remount deadlock.
 - fix umount recovery of busy direct mount.
+- fix offset mount point directory removal.
 
 28/06/2011 autofs-5.0.6
 -----------------------
--- autofs-5.0.6.orig/daemon/direct.c
+++ autofs-5.0.6/daemon/direct.c
@@ -633,13 +633,6 @@ force_umount:
 	} else
 		info(ap->logopt, "umounted offset mount %s", me->key);
 
-	if (!rv && me->flags & MOUNT_FLAG_DIR_CREATED) {
-		if  (rmdir(me->key) == -1) {
-			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-			warn(ap->logopt, "failed to remove dir %s: %s",
-			     me->key, estr);
-		}
-	}
 	return rv;
 }
 
--- autofs-5.0.6.orig/lib/mounts.c
+++ autofs-5.0.6/lib/mounts.c
@@ -1605,6 +1605,33 @@ int umount_ent(struct autofs_point *ap,
 	return rv;
 }
 
+static int do_mount_autofs_offset(struct autofs_point *ap,
+				  struct mapent *oe, const char *root,
+				  char *offset)
+
+{
+	int mounted = 0;
+	int ret;
+
+	debug(ap->logopt, "mount offset %s at %s", oe->key, root);
+
+	ret = mount_autofs_offset(ap, oe, root, offset);
+	if (ret >= MOUNT_OFFSET_OK)
+		mounted++;
+	else {
+		if (ret != MOUNT_OFFSET_IGNORE)
+			warn(ap->logopt, "failed to mount offset");
+		else {
+			debug(ap->logopt, "ignoring \"nohide\" trigger %s",
+			      oe->key);
+			free(oe->mapent);
+			oe->mapent = NULL;
+		}
+	}
+
+	return mounted;
+}
+
 int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
 			 const char *root, unsigned int start, const char *base)
 {
@@ -1613,8 +1640,7 @@ int mount_multi_triggers(struct autofs_p
 	struct mapent *oe;
 	struct list_head *pos = NULL;
 	unsigned int fs_path_len;
-	unsigned int mounted;
-	int ret;
+	int mounted;
 
 	fs_path_len = start + strlen(base);
 	if (fs_path_len > PATH_MAX)
@@ -1634,22 +1660,7 @@ int mount_multi_triggers(struct autofs_p
 		if (!oe || !oe->mapent)
 			goto cont;
 
-		debug(ap->logopt, "mount offset %s at %s", oe->key, root);
-
-		ret = mount_autofs_offset(ap, oe, root, offset);
-		if (ret >= MOUNT_OFFSET_OK)
-			mounted++;
-		else {
-			if (ret != MOUNT_OFFSET_IGNORE)
-				warn(ap->logopt, "failed to mount offset");
-			else {
-				debug(ap->logopt,
-				      "ignoring \"nohide\" trigger %s",
-				      oe->key);
-				free(oe->mapent);
-				oe->mapent = NULL;
-			}
-		}
+		mounted += do_mount_autofs_offset(ap, oe, root, offset);
 cont:
 		offset = cache_get_offset(base,
 				offset, start, &me->multi_list, &pos);
@@ -1681,7 +1692,6 @@ int umount_multi_triggers(struct autofs_
 	pos = NULL;
 	offset = path;
 
-	/* Make sure "none" of the offsets have an active mount. */
 	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
 		char *oe_base;
 
@@ -1700,28 +1710,32 @@ int umount_multi_triggers(struct autofs_
 		if (oe->ioctlfd != -1 ||
 		    is_mounted(_PROC_MOUNTS, oe->key, MNTS_REAL)) {
 			left++;
-			break;
-		}
-	}
-
-	if (left)
-		return left;
-
-	pos = NULL;
-	offset = path;
-
-	/* Make sure "none" of the offsets have an active mount. */
-	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
-		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
-		/* root offset is a special case */
-		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
 			continue;
+		}
 
 		debug(ap->logopt, "umount offset %s", oe->key);
 
 		if (umount_autofs_offset(ap, oe)) {
 			warn(ap->logopt, "failed to umount offset");
 			left++;
+		} else {
+			struct stat st;
+			int ret;
+
+			if (!(oe->flags & MOUNT_FLAG_DIR_CREATED))
+				continue;
+
+			/*
+			 * An error due to partial directory removal is
+			 * ok so only try and remount the offset if the
+			 * actual mount point still exists.
+			 */
+			ret = rmdir_path(ap, oe->key, ap->dev);
+			if (ret == -1 && !stat(oe->key, &st)) {
+				ret = do_mount_autofs_offset(ap, oe, root, offset);
+				if (ret)
+					left++;
+			}
 		}
 	}