[lxc-devel] [PATCH] Add remove_snapshots_entry() (rebased - v2)

Serge Hallyn serge.hallyn at ubuntu.com
Mon Sep 14 15:03:58 UTC 2015


Quoting Christian Brauner (christianvanbrauner at gmail.com):
> When creating ephemeral containers that have the option lxc.ephemeral = 1 set
> in their config, they will be destroyed on shutdown. As they are simple overlay
> clones of an existing container they should be registered in the lxc_snapshots
> file of the original container to stay consistent and adhere to the
> expectancies of the users. Most of all, it ensure that we cannot remove a
> container that has clones, even if they are just ephemeral snapshot-clones. The
> function adds further consistency because remove_snapshots_entry() ensures that
> ephemeral clone-snapshots deregister themselves from the lxc_snapshots file
> when they are destroyed.
> 
> Signed-off-by: Christian Brauner <christianvanbrauner at gmail.com>
> ---
>  src/lxc/start.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 123 insertions(+)
> 
> diff --git a/src/lxc/start.c b/src/lxc/start.c
> index 8fe08a1..f58d9a4 100644
> --- a/src/lxc/start.c
> +++ b/src/lxc/start.c
> @@ -33,6 +33,7 @@
>  #include <fcntl.h>
>  #include <grp.h>
>  #include <poll.h>
> +#include <sys/mman.h>
>  #include <sys/param.h>
>  #include <sys/file.h>
>  #include <sys/mount.h>
> @@ -83,6 +84,7 @@ const struct ns_info ns_info[LXC_NS_MAX] = {
>  	[LXC_NS_NET] = {"net", CLONE_NEWNET}
>  };
>  
> +static void remove_snapshot_entry(struct lxc_handler *handler, const char *name);
>  static bool do_destroy_container(struct lxc_conf *conf);
>  static int lxc_rmdir_onedev_wrapper(void *data);
>  static void lxc_destroy_container_on_signal(struct lxc_handler *handler,
> @@ -1322,6 +1324,8 @@ static void lxc_destroy_container_on_signal(struct lxc_handler *handler,
>  		return;
>  	}
>  
> +	remove_snapshot_entry(handler, name);

There's probably a reason I haven't considered - but shouldn't this
really be using mod_all_rdeps(c, false)?

Well, technically mod_all_rdeps takes a lxc_container which you don't have
here.  So mod_all_rdeps() and remove_snapshot_entry() should be sharing a
common fn which takes lxcpath and lxcname and does the bulk of the work.

> +
>  	if (am_unpriv())
>  		ret = userns_exec_1(handler->conf, lxc_rmdir_onedev_wrapper, destroy);
>  	else
> @@ -1349,3 +1353,122 @@ static bool do_destroy_container(struct lxc_conf *conf) {
>          return bdev_destroy(conf);
>  }
>  
> +static void remove_snapshot_entry(struct lxc_handler *handler, const char *name)
> +{
> +	char rdepfile[MAXPATHLEN];
> +	char path[MAXPATHLEN];
> +	char newpath[MAXPATHLEN];
> +	char *base = NULL;
> +	char *buf = NULL;
> +	char *del = NULL;
> +	char *scratch = NULL;
> +	char *origpath = NULL;
> +	char *origname = NULL;
> +	int ret = 0;
> +	int bytes = 0;
> +	int fd = -1;
> +	size_t len = 0;
> +	struct stat fbuf;
> +
> +	ret = snprintf(rdepfile, MAXPATHLEN, "%s/%s/lxc_rdepends", handler->lxcpath, name);
> +	if (ret < 0 || ret >= MAXPATHLEN)
> +		return;
> +
> +	fd = open(rdepfile, O_RDONLY | O_CLOEXEC);
> +	if (fd < 0)
> +		return;
> +
> +	ret = fstat(fd, &fbuf);
> +	if (ret < 0) {
> +		close(fd);
> +		return;
> +	}
> +
> +	base = calloc(fbuf.st_size + 1, sizeof(char));
> +	if (!base) {
> +		close(fd);
> +		return;
> +	}
> +
> +	ret = read(fd, (void *)base, fbuf.st_size);
> +	if (ret <= 0) {
> +		free(base);
> +		close(fd);
> +		return;
> +	}
> +
> +	origpath = strtok_r(base, "\n", &scratch);
> +	if (!origpath) {
> +		free(base);
> +		close(fd);
> +		return;
> +	}
> +
> +	origname = strtok_r(NULL, "\n", &scratch);
> +	if (!origname) {
> +		free(base);
> +		close(fd);
> +		return;
> +	}
> +
> +	close(fd);
> +
> +	ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", origpath, origname);
> +	if (ret < 0 || ret >= MAXPATHLEN) {
> +		free(base);
> +		return;
> +	}
> +	free(base);
> +
> +	ret = snprintf(newpath, MAXPATHLEN, "%s\n%s\n", handler->lxcpath, name);
> +	if (ret < 0 || ret >= MAXPATHLEN)
> +		return;
> +
> +	fd = open(path, O_RDWR | O_CLOEXEC);
> +	if (fd < 0)
> +		return;
> +
> +	ret = fstat(fd, &fbuf);
> +	if (ret < 0) {
> +		close(fd);
> +		return;
> +	}
> +
> +	if (fbuf.st_size != 0) {
> +		/* write terminating \0-byte to file */
> +		if (pwrite(fd, "", 1, fbuf.st_size) <= 0) {
> +			close(fd);
> +			return;
> +		}
> +
> +		buf = mmap(NULL, fbuf.st_size + 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
> +		if (buf == MAP_FAILED) {
> +			SYSERROR("Failed to create mapping %s", path);
> +			close(fd);
> +			return;
> +		}
> +
> +		len = strlen(newpath);
> +		while ((del = strstr((char *)buf, newpath))) {
> +			memmove(del, del + len, strlen(del) - len + 1);
> +			bytes += len;
> +		}
> +
> +		munmap(buf, fbuf.st_size + 1);
> +		if (ftruncate(fd, fbuf.st_size - bytes) < 0) {
> +			SYSERROR("Failed to truncate file %s", path);
> +			close(fd);
> +			return;
> +		}
> +	}
> +
> +	close(fd);
> +
> +	/* If the lxc-snapshot file is empty, remove it. */
> +	if (stat(path, &fbuf) < 0)
> +		return;
> +	if (!fbuf.st_size) {
> +		remove(path);
> +	}
> +}
> +
> -- 
> 2.5.1
> 


More information about the lxc-devel mailing list