[CRIU] [RFC PATCH 2/5] autofs: dump stage introduced

Stanislav Kinsburskiy skinsbursky at virtuozzo.com
Mon Nov 23 09:22:38 PST 2015


Autofs doesn't need any special dump tricks.
However, we don't want to dump it, if controlling pipe is not empty, because
it means, that kernel has some state, which we don't want to carry with us.

We also need to update mount options, because "pgrp=" option content is pid
namespace dependant. There are two ways how to do so:
1) Clone a process in desired pid namespace and collect mounts within it or
2) Replace AutoFS real prgp with container's one on dump.

This patch implements the second.

Signed-off-by: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>
---
 mount.c |  144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 144 insertions(+)

diff --git a/mount.c b/mount.c
index 562d6ca..c07d2d1 100644
--- a/mount.c
+++ b/mount.c
@@ -1383,6 +1383,145 @@ static int always_fail(struct mount_info *pm)
 	return -1;
 }
 
+/*
+ * AutoFS options have to be fixed:
+ * - "timeout" have to be removed
+ * - "pgrp" have to be updated to virtual pid value
+ */
+static int autofs_fixup_options(struct mount_info *new)
+{
+	char **options;
+	int nr_opts, i, err = -1;
+
+	split(new->options, ',', &options, &nr_opts);
+	if (!options)
+		return -1;
+
+	xfree(new->options);
+	new->options = xzalloc(1);
+	if (!new->options)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_opts; i++) {
+		char *opt = options[i];
+
+		if (!strncmp(opt, "timeout=", strlen("timeout=")))
+			continue;
+		if (!strncmp(opt, "pgrp=", strlen("pgrp="))) {
+			int real_pid, virt_pid = -1;
+			struct pstree_item *item;
+
+			if (sscanf(opt, "pgrp=%d", &real_pid) != 1) {
+				pr_err("Failed to get pgrp: %s\n", opt);
+				goto out;
+			}
+
+			for_each_pstree_item(item) {
+				if (item->pid.real == real_pid) {
+					virt_pid = item->pid.virt;
+					break;
+				}
+			}
+
+			pr_info("real pid: %d, virt pid: %d\n", real_pid, virt_pid);
+
+			if (virt_pid == -1) {
+				pr_err("Failed to find process entry %d\n",
+						real_pid);
+				goto out;
+			}
+
+			/* This should be enough: "pgrp=" + pid */
+			opt = xrealloc(opt, 32);
+			if (!opt)
+				goto out;
+
+			if (snprintf(opt, 32, "pgrp=%d", virt_pid) == 32)
+				return -1;
+
+			options[i] = opt;
+		}
+
+		if (attach_option(new, opt))
+			goto out;
+	}
+
+	err = 0;
+out:
+	for (i = 0; i < nr_opts; i++)
+		xfree(options[i]);
+	xfree(options);
+	return err;
+}
+
+static int autofs_dump(struct mount_info *pm)
+{
+	unsigned pgrp, fd;
+	int pipe_fd, pipe_size, steal_pipe[2];
+	ssize_t bytes;
+	int err;
+
+	/* TODO: we are called wthin proper pid namespace. We can't use blobal
+	 * proc and have to mount proc somewhere */
+
+	pr_info("autofs mount options: %s\n", pm->options);
+	if (sscanf(pm->options, "fd=%d,pgrp=%d%*s", &fd, &pgrp) != 2) {
+		pr_err("Unsupported autofs mount options: %s\n", pm->options);
+		return -EINVAL;
+	}
+
+	pr_info("automount: pgrp: %d, fd: %d\n", pgrp, fd);
+
+	pipe_fd = open_proc(pgrp, "fd/%d", fd);
+	if (pipe_fd < 0) {
+		pr_perror("Can't open automount pipe\n");
+		return pipe_fd;
+	}
+
+	pipe_size = fcntl(pipe_fd, F_GETPIPE_SZ);
+	if (pipe_size < 0) {
+		err = -errno;
+		pr_perror("Can't obtain piped data size\n");
+		goto close_pipe;
+	}
+
+	if (pipe(steal_pipe) < 0) {
+		err = -errno;
+		pr_perror("Can't create pipe for stealing data");
+		goto close_pipe;
+	}
+
+	bytes = tee(pipe_fd, steal_pipe[1], pipe_size, SPLICE_F_NONBLOCK);
+	if (bytes < 0) {
+		if (errno != EAGAIN) {
+			err = -errno;
+			pr_perror("Can't pick pipe data");
+			goto close_steal;
+		}
+
+		bytes = 0;
+	}
+
+	if (bytes) {
+		err = -ENOTSUP;
+		pr_perror("Can't dump autofs mount, when autmount pipe is not empty\n");
+		goto close_steal;
+	}
+
+	err = autofs_fixup_options(pm);
+	if (err)
+		goto close_steal;
+
+	err = 0;
+
+close_steal:
+	close(steal_pipe[0]);
+	close(steal_pipe[1]);
+close_pipe:
+	close(pipe_fd);
+	return err;
+}
+
 static struct fstype fstypes[32] = {
 	{
 		.name = "unsupported",
@@ -1451,6 +1590,11 @@ static struct fstype fstypes[32] = {
 		.name = "overlay",
 		.code = FSTYPE__OVERLAYFS,
 		.parse = overlayfs_parse,
+	}, {
+		.name = "autofs",
+		.code = FSTYPE__AUTOFS,
+		.dump = autofs_dump,
+		.restore = always_fail,
 	},
 };
 



More information about the CRIU mailing list