[lxc-devel] [lxc/master] lxc-copy: allow snapshots to be placed on tmpfs

brauner on Github lxc-bot at linuxcontainers.org
Sat Jul 16 14:21:52 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 2082 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160716/1cb130dd/attachment.bin>
-------------- next part --------------
From 0ebd67cd49d130646d046ef53731259960f2223b Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at mailbox.org>
Date: Sat, 16 Jul 2016 11:00:17 +0200
Subject: [PATCH] lxc-copy: allow snapshots to be placed on tmpfs

Place an ephemeral container started with -e flag on a tmpfs. Restrictions are
that you cannot request the data to be kept while placing the container on a
tmpfs, that either overlay or aufs backing storage must be used, and that the
storage backend of the original container must be a directory.

For ephemeral snapshots backed by overlay or aufs filesystems, a fresh tmpfs
is mounted over the containers directory if the user requests it. This should
be the easiest options. Anything else would require us to change the current
mount-layout of overlay and aufs snapshots. (A standard overlay or aufs
snapshot clone currently has the layout:

	/var/lib/lxc/CLONE_SNAPSHOT/delta0      <-- upperdir
	/var/lib/lxc/CLONE_SNAPSHOT/rootfs
	/var/lib/lxc/CLONE_SNAPSHOT/olwork
	/var/lib/lxc/CLONE_SNAPSHOT/olwork/work <-- workdir

with the lowerdir being

	/var/lib/lxc/CLONE_PARENT/rootfs

The fact that upperdir and workdir are not placed in a common subfolder under
the container directory has the consequence that we cannot simply mount a fresh
tmpfs under upperdir and workdir because overlay expects them to be on the same
filesystem.)

Because we mount a fresh tmpfs over the directory of the container the updated
/etc/hostname file created during the clone residing in the upperdir (currently
named "delta0" by default) will be hidden. Hence, if the user requests that the
old name is not to be kept for the clone, we recreate this file on the tmpfs.
This should be all that is required to restore the exact behaviour we would get
with a normal clone.
NOTE: If the container is rebooted all changes made to it are lost. This is not
easy to prevent since each reboot remounts the rootfs again.

Signed-off-by: Christian Brauner <cbrauner at suse.de>
---
 src/lxc/arguments.h |   3 ++
 src/lxc/lxc_copy.c  | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h
index 6bc6fcd..f68f8ab 100644
--- a/src/lxc/arguments.h
+++ b/src/lxc/arguments.h
@@ -131,6 +131,9 @@ struct lxc_arguments {
 	bool ls_running;
 	bool ls_stopped;
 
+	/* lxc-copy */
+	bool tmpfs;
+
 	/* remaining arguments */
 	char *const *argv;
 	int argc;
diff --git a/src/lxc/lxc_copy.c b/src/lxc/lxc_copy.c
index e424e65..a78bfd7 100644
--- a/src/lxc/lxc_copy.c
+++ b/src/lxc/lxc_copy.c
@@ -87,6 +87,7 @@ static const struct option my_longopts[] = {
 	{ "keepdata", no_argument, 0, 'D'},
 	{ "keepname", no_argument, 0, 'K'},
 	{ "keepmac", no_argument, 0, 'M'},
+	{ "tmpfs", no_argument, 0, 't'},
 	LXC_COMMON_OPTIONS
 };
 
@@ -119,6 +120,7 @@ Options :\n\
   -m, --mount	            directory to mount into container, either \n\
 			    {bind,aufs,overlay}=/src-path or {bind,aufs,overlay}=/src-path:/dst-path\n\
   -B, --backingstorage=TYPE backingstorage type for the container\n\
+  -t, --tmpfs		    place ephemeral container on a tmpfs\n\
   -L, --fssize		    size of the new block device for block device containers\n\
   -D, --keedata	            pass together with -e start a persistent snapshot \n\
   -K, --keepname	    keep the hostname of the original container\n\
@@ -129,6 +131,7 @@ Options :\n\
 	.task = CLONE,
 	.daemonize = 1,
 	.quiet = false,
+	.tmpfs = false,
 };
 
 static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num,
@@ -148,6 +151,13 @@ static int do_clone_task(struct lxc_container *c, enum task task, int flags,
 			 char **args);
 static void free_mnts(void);
 static uint64_t get_fssize(char *s);
+
+/* Place an ephemeral container started with -e flag on a tmpfs. Restrictions
+ * are that you cannot request the data to be kept while placing the container
+ * on a tmpfs and that either overlay or aufs backing storage must be used.
+ */
+static char *mount_tmpfs(const char *oldname, const char *newname,
+			 const char *path, struct lxc_arguments *arg);
 static int parse_mntsubopts(char *subopts, char *const *keys,
 			    char *mntparameters);
 static int parse_aufs_mnt(char *mntstring, enum mnttype type);
@@ -369,12 +379,13 @@ static int do_clone(struct lxc_container *c, char *newname, char *newpath,
 static int do_clone_ephemeral(struct lxc_container *c,
 		struct lxc_arguments *arg, char **args, int flags)
 {
+	char *bdev;
+	char *premount;
 	char randname[MAXPATHLEN];
 	unsigned int i;
 	int ret = 0;
 	bool bret = true, started = false;
 	struct lxc_container *clone;
-
 	lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
 	attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
 
@@ -396,6 +407,23 @@ static int do_clone_ephemeral(struct lxc_container *c,
 	if (!clone)
 		return -1;
 
+	if (arg->tmpfs) {
+		bdev = c->lxc_conf->rootfs.bdev_type;
+		if (bdev && strcmp(bdev, "dir")) {
+			fprintf(stderr, "Cannot currently use tmpfs with %s storage backend.\n", bdev);
+			goto destroy_and_put;
+		}
+
+		premount = mount_tmpfs(arg->name, arg->newname, arg->newpath, arg);
+		if (!premount)
+			goto destroy_and_put;
+
+		bret = clone->set_config_item(clone, "lxc.hook.pre-mount", premount);
+		free(premount);
+		if (!bret)
+			goto destroy_and_put;
+	}
+
 	if (!arg->keepdata)
 		if (!clone->set_config_item(clone, "lxc.ephemeral", "1"))
 			goto destroy_and_put;
@@ -575,6 +603,9 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
 	case 'B':
 		args->bdevtype = arg;
 		break;
+	case 't':
+		args->tmpfs = true;
+		break;
 	case 'L':
 		args->fssize = get_fssize(optarg);
 		break;
@@ -753,3 +784,75 @@ static int parse_ovl_mnt(char *mntstring, enum mnttype type)
 	lxc_free_array((void **)mntarray, free);
 	return -1;
 }
+
+/* For ephemeral snapshots backed by overlay or aufs filesystems, this function
+ * mounts a fresh tmpfs over the containers directory if the user requests it.
+ * Because we mount a fresh tmpfs over the directory of the container the
+ * updated /etc/hostname file created during the clone residing in the upperdir
+ * (currently named "delta0" by default) will be hidden. Hence, if the user
+ * requests that the old name is not to be kept for the clone, we recreate this
+ * file on the tmpfs. This should be all that is required to restore the exact
+ * behaviour we would get with a normal clone.
+ */
+static char *mount_tmpfs(const char *oldname, const char *newname,
+			 const char *path, struct lxc_arguments *arg)
+{
+	int ret, fd;
+	size_t len;
+	char *premount = NULL;
+
+	if (arg->tmpfs && arg->keepdata) {
+		fprintf(stderr, "%s\n", "A container can only be placed on a "
+					"tmpfs when storage backend is overlay "
+					"or aufs.");
+		goto err_free;
+	}
+
+	if (arg->tmpfs && !arg->bdevtype) {
+		arg->bdevtype = "overlayfs";
+	} else if (arg->tmpfs && arg->bdevtype && strcmp(arg->bdevtype, "overlayfs") && strcmp(arg->bdevtype, "aufs")) {
+		fprintf(stderr, "%s\n", "A container can only be placed on a "
+					"tmpfs when storage backend is overlay "
+					"or aufs.");
+		goto err_free;
+	}
+
+	len = strlen(path) + strlen(newname) + strlen("pre-start-XXXXXX") + /* //\0 */ 3;
+	premount = malloc(len);
+	if (!premount)
+		goto err_free;
+
+	ret = snprintf(premount, len, "%s/%s/pre-start-XXXXXX", path, newname);
+	if (ret < 0 || (size_t)ret >= len)
+		goto err_free;
+
+	fd = mkostemp(premount, O_CLOEXEC);
+	if (fd < 0)
+		goto err_free;
+
+	if (chmod(premount, 0755) < 0)
+		goto err_close;
+
+	ret = dprintf(fd, "#! /bin/sh\n"
+			  "mount -n -t tmpfs -o mode=0755 none %s/%s\n",
+		      path, newname);
+	if (ret < 0)
+		goto err_close;
+
+	if (!arg->keepname) {
+		ret = dprintf(fd, "mkdir -p %s/%s/delta0/etc\n"
+				  "echo %s > %s/%s/delta0/etc/hostname\n",
+			      path, newname, newname, path, newname);
+		if (ret < 0)
+			goto err_close;
+	}
+
+	close(fd);
+	return premount;
+
+err_close:
+	close(fd);
+err_free:
+	free(premount);
+	return NULL;
+}


More information about the lxc-devel mailing list