Blame SOURCES/autofs-5.1.7-add-mount-and-umount-offsets-functions.patch

9a499a
autofs-5.1.7 - add mount and umount offsets functions
9a499a
9a499a
From: Ian Kent <raven@themaw.net>
9a499a
9a499a
Add tree_mapent_mount_offsets() and tree_mapent_umount_offsets() to
9a499a
the mapent tree handling implementation.
9a499a
9a499a
Signed-off-by: Ian Kent <raven@themaw.net>
9a499a
---
9a499a
 CHANGELOG        |    1 
9a499a
 include/mounts.h |    2 
9a499a
 lib/mounts.c     |  260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
9a499a
 3 files changed, 263 insertions(+)
9a499a
9a499a
--- autofs-5.1.4.orig/CHANGELOG
9a499a
+++ autofs-5.1.4/CHANGELOG
9a499a
@@ -39,6 +39,7 @@
9a499a
 - fix mount_fullpath().
9a499a
 - add tree_mapent_cleanup_offsets().
9a499a
 - add set_offset_tree_catatonic().
9a499a
+- add mount and umount offsets functions.
9a499a
 
9a499a
 xx/xx/2018 autofs-5.1.5
9a499a
 - fix flag file permission.
9a499a
--- autofs-5.1.4.orig/include/mounts.h
9a499a
+++ autofs-5.1.4/include/mounts.h
9a499a
@@ -172,6 +172,8 @@ struct tree_node *tree_mapent_root(struc
9a499a
 int tree_mapent_add_node(struct mapent_cache *mc, const char *base, const char *key);
9a499a
 int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key);
9a499a
 void tree_mapent_cleanup_offsets(struct mapent *oe);
9a499a
+int tree_mapent_mount_offsets(struct mapent *oe, int nonstrict);
9a499a
+int tree_mapent_umount_offsets(struct mapent *oe, int nonstrict);
9a499a
 int unlink_mount_tree(struct autofs_point *ap, const char *mp);
9a499a
 void free_mnt_list(struct mnt_list *list);
9a499a
 int is_mounted(const char *mp, unsigned int type);
9a499a
--- autofs-5.1.4.orig/lib/mounts.c
9a499a
+++ autofs-5.1.4/lib/mounts.c
9a499a
@@ -1692,6 +1692,266 @@ void tree_mapent_cleanup_offsets(struct
9a499a
 	}
9a499a
 }
9a499a
 
9a499a
+static int tree_mapent_rmdir_path_offset(struct autofs_point *ap, struct mapent *oe)
9a499a
+{
9a499a
+	struct mapent *mm_root = MAPENT(MAPENT_ROOT(oe));
9a499a
+	char *dir, *path;
9a499a
+	unsigned int split;
9a499a
+	int ret;
9a499a
+
9a499a
+	if (ap->type == LKP_DIRECT)
9a499a
+		return rmdir_path(ap, oe->key, mm_root->dev);
9a499a
+
9a499a
+	dir = strdup(oe->key);
9a499a
+
9a499a
+	if (ap->flags & MOUNT_FLAG_GHOST)
9a499a
+		split = ap->len + mm_root->len + 1;
9a499a
+	else
9a499a
+		split = ap->len;
9a499a
+
9a499a
+	dir[split] = '\0';
9a499a
+	path = &dir[split + 1];
9a499a
+
9a499a
+	if (chdir(dir) == -1) {
9a499a
+		error(ap->logopt, "failed to chdir to %s", dir);
9a499a
+		free(dir);
9a499a
+		return -1;
9a499a
+	}
9a499a
+
9a499a
+	ret = rmdir_path(ap, path, ap->dev);
9a499a
+
9a499a
+	free(dir);
9a499a
+
9a499a
+	if (chdir("/") == -1)
9a499a
+		error(ap->logopt, "failed to chdir to /");
9a499a
+
9a499a
+	return ret;
9a499a
+}
9a499a
+
9a499a
+static int tree_mapent_mount_offset(struct mapent *oe, void *ptr)
9a499a
+{
9a499a
+	struct traverse_subtree_context *ctxt = ptr;
9a499a
+	struct autofs_point *ap = ctxt->ap;
9a499a
+	int ret;
9a499a
+
9a499a
+	debug(ap->logopt, "mount offset %s", oe->key);
9a499a
+
9a499a
+	ret = mount_autofs_offset(ap, oe);
9a499a
+	if (ret < MOUNT_OFFSET_OK) {
9a499a
+		if (ret != MOUNT_OFFSET_IGNORE) {
9a499a
+			warn(ap->logopt, "failed to mount offset");
9a499a
+			return 0;
9a499a
+		} else {
9a499a
+			debug(ap->logopt,
9a499a
+			      "ignoring \"nohide\" trigger %s", oe->key);
9a499a
+			/*
9a499a
+			 * Ok, so we shouldn't modify the mapent but
9a499a
+			 * mount requests are blocked at a point above
9a499a
+			 * this and expire only uses the mapent key or
9a499a
+			 * holds the cache write lock.
9a499a
+			 */
9a499a
+			free(oe->mapent);
9a499a
+			oe->mapent = NULL;
9a499a
+		}
9a499a
+	}
9a499a
+
9a499a
+	return 1;
9a499a
+}
9a499a
+
9a499a
+static int tree_mapent_umount_offset(struct mapent *oe, void *ptr)
9a499a
+{
9a499a
+	struct traverse_subtree_context *ctxt = ptr;
9a499a
+	struct autofs_point *ap = ctxt->ap;
9a499a
+	int ret = 1;
9a499a
+
9a499a
+	/*
9a499a
+	 * Check for and umount subtree offsets resulting from
9a499a
+	 * nonstrict mount fail.
9a499a
+	 */
9a499a
+	ret = tree_mapent_umount_offsets(oe, ctxt->strict);
9a499a
+	if (!ret)
9a499a
+		return 0;
9a499a
+
9a499a
+	/*
9a499a
+	 * If an offset that has an active mount has been removed
9a499a
+	 * from the multi-mount we don't want to attempt to trigger
9a499a
+	 * mounts for it. Obviously this is because it has been
9a499a
+	 * removed, but less obvious is the potential strange
9a499a
+	 * behaviour that can result if we do try and mount it
9a499a
+	 * again after it's been expired. For example, if an NFS
9a499a
+	 * file system is no longer exported and is later umounted
9a499a
+	 * it can be mounted again without any error message but
9a499a
+	 * shows as an empty directory. That's going to confuse
9a499a
+	 * people for sure.
9a499a
+	 *
9a499a
+	 * If the mount cannot be umounted (the process is now
9a499a
+	 * using a stale mount) the offset needs to be invalidated
9a499a
+	 * so no further mounts will be attempted but the offset
9a499a
+	 * cache entry must remain so expires can continue to
9a499a
+	 * attempt to umount it. If the mount can be umounted and
9a499a
+	 * the offset is removed, at least for NFS we will get
9a499a
+	 * ESTALE errors when attempting list the directory.
9a499a
+	 */
9a499a
+	if (oe->ioctlfd != -1 ||
9a499a
+	    is_mounted(oe->key, MNTS_REAL)) {
9a499a
+		if (umount_ent(ap, oe->key) &&
9a499a
+		    is_mounted(oe->key, MNTS_REAL)) {
9a499a
+			debug(ap->logopt,
9a499a
+			      "offset %s has active mount, invalidate",
9a499a
+			      oe->key);
9a499a
+			/*
9a499a
+			 * Ok, so we shouldn't modify the mapent but
9a499a
+			 * mount requests are blocked at a point above
9a499a
+			 * this and expire only uses the mapent key or
9a499a
+			 * holds the cache write lock.
9a499a
+			 */
9a499a
+			if (oe->mapent) {
9a499a
+				free(oe->mapent);
9a499a
+				oe->mapent = NULL;
9a499a
+			}
9a499a
+			return 0;
9a499a
+		}
9a499a
+	}
9a499a
+
9a499a
+	/* Don't bother if there's noting to umount. */
9a499a
+	if (!is_mounted(oe->key, MNTS_AUTOFS))
9a499a
+		goto done;
9a499a
+
9a499a
+	debug(ap->logopt, "umount offset %s", oe->key);
9a499a
+
9a499a
+	if (umount_autofs_offset(ap, oe)) {
9a499a
+		warn(ap->logopt, "failed to umount offset");
9a499a
+		ret = 0;
9a499a
+	} else {
9a499a
+		struct stat st;
9a499a
+		int ret;
9a499a
+
9a499a
+		if (!(oe->flags & MOUNT_FLAG_DIR_CREATED))
9a499a
+			goto done;
9a499a
+
9a499a
+		/*
9a499a
+		 * An error due to partial directory removal is
9a499a
+		 * ok so only try and remount the offset if the
9a499a
+		 * actual mount point still exists.
9a499a
+		 */
9a499a
+		ret = tree_mapent_rmdir_path_offset(ap, oe);
9a499a
+		if (ret == -1 && !stat(oe->key, &st)) {
9a499a
+			ret = tree_mapent_mount_offset(oe, ctxt);
9a499a
+			/* But we did origianlly create this */
9a499a
+			oe->flags |= MOUNT_FLAG_DIR_CREATED;
9a499a
+		}
9a499a
+	}
9a499a
+done:
9a499a
+	return ret;
9a499a
+}
9a499a
+
9a499a
+static int tree_mapent_mount_offsets_work(struct tree_node *n, void *ptr)
9a499a
+{
9a499a
+	struct traverse_subtree_context *ctxt = ptr;
9a499a
+	struct mapent *oe = MAPENT(n);
9a499a
+	struct mapent *mm_root = MAPENT(MAPENT_ROOT(oe));
9a499a
+	struct autofs_point *ap = ctxt->ap;
9a499a
+	int ret;
9a499a
+
9a499a
+	if (!oe->mapent)
9a499a
+		return 1;
9a499a
+
9a499a
+	/* Stale offset, no longer present in the mapent */
9a499a
+	if (oe->age != mm_root->age) {
9a499a
+		/* Best effort */
9a499a
+		tree_mapent_umount_offset(oe, ctxt);
9a499a
+		return 1;
9a499a
+	}
9a499a
+
9a499a
+	ret = tree_mapent_mount_offset(oe, ctxt);
9a499a
+
9a499a
+	/*
9a499a
+	 * If re-constructing a multi-mount it's necessary to walk
9a499a
+	 * into nested mounts, unlike the usual "mount only what's
9a499a
+	 * needed as you go" behavior.
9a499a
+	 */
9a499a
+	if (ap->state == ST_READMAP && ap->flags & MOUNT_FLAG_REMOUNT) {
9a499a
+		if (oe->ioctlfd != -1 ||
9a499a
+		    is_mounted(oe->key, MNTS_REAL))
9a499a
+			/* Best effort */
9a499a
+			tree_mapent_mount_offsets(oe, !ctxt->strict);
9a499a
+	}
9a499a
+
9a499a
+	return ret;
9a499a
+}
9a499a
+
9a499a
+int tree_mapent_mount_offsets(struct mapent *oe, int nonstrict)
9a499a
+{
9a499a
+	struct tree_node *base = MAPENT_NODE(oe);
9a499a
+	struct traverse_subtree_context ctxt = {
9a499a
+		.ap = oe->mc->ap,
9a499a
+		.base = base,
9a499a
+		.strict = !nonstrict,
9a499a
+	};
9a499a
+
9a499a
+	return tree_mapent_traverse_subtree(base,
9a499a
+				tree_mapent_mount_offsets_work, &ctxt);
9a499a
+}
9a499a
+
9a499a
+static int tree_mapent_umount_offsets_work(struct tree_node *n, void *ptr)
9a499a
+{
9a499a
+	struct mapent *oe = MAPENT(n);
9a499a
+
9a499a
+	return tree_mapent_umount_offset(oe, ptr);
9a499a
+}
9a499a
+
9a499a
+int tree_mapent_umount_offsets(struct mapent *oe, int nonstrict)
9a499a
+{
9a499a
+	struct tree_node *base = MAPENT_NODE(oe);
9a499a
+	struct autofs_point *ap = oe->mc->ap;
9a499a
+	struct traverse_subtree_context ctxt = {
9a499a
+		.ap = ap,
9a499a
+		.base = base,
9a499a
+		.strict = !nonstrict,
9a499a
+	};
9a499a
+	int ret;
9a499a
+
9a499a
+	ret = tree_mapent_traverse_subtree(base,
9a499a
+				tree_mapent_umount_offsets_work, &ctxt);
9a499a
+	if (ret && tree_mapent_is_root(oe)) {
9a499a
+		char mp[PATH_MAX + 1];
9a499a
+
9a499a
+		/*
9a499a
+		 * The map entry cache stores mapent keys. For indirect
9a499a
+		 * mount maps they are single direcory components so when
9a499a
+		 * one of these keys is the root of a multi-mount the mount
9a499a
+		 * path must be constructed.
9a499a
+		 */
9a499a
+		if (!mount_fullpath(mp, PATH_MAX, ap->path, oe->key)) {
9a499a
+			error(ap->logopt, "mount path is too long");
9a499a
+			return 0;
9a499a
+		}
9a499a
+
9a499a
+		/*
9a499a
+		 * Special case.
9a499a
+		 * If we can't umount the root container then we can't
9a499a
+		 * delete the offsets from the cache and we need to put
9a499a
+		 * the offset triggers back.
9a499a
+		 */
9a499a
+		if (is_mounted(mp, MNTS_REAL)) {
9a499a
+			info(ap->logopt, "unmounting dir = %s", mp);
9a499a
+			if (umount_ent(ap, mp) &&
9a499a
+			    is_mounted(mp, MNTS_REAL)) {
9a499a
+				if (!tree_mapent_mount_offsets(oe, 1))
9a499a
+					warn(ap->logopt,
9a499a
+					     "failed to remount offset triggers");
9a499a
+				return 0;
9a499a
+			}
9a499a
+		}
9a499a
+
9a499a
+		/* check for mounted mount entry and remove it if found */
9a499a
+		mnts_remove_mount(mp, MNTS_MOUNTED);
9a499a
+
9a499a
+	}
9a499a
+
9a499a
+	return ret;
9a499a
+}
9a499a
+
9a499a
 /* From glibc decode_name() */
9a499a
 /* Since the values in a line are separated by spaces, a name cannot
9a499a
  * contain a space.  Therefore some programs encode spaces in names