[lxc-devel] [PATCH 1/2] c/r: move criu code to its own file

Tycho Andersen tycho.andersen at canonical.com
Thu Apr 16 18:40:56 UTC 2015


Trying to cage the beast that is lxccontainer.c.

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 src/lxc/Makefile.am    |   4 +-
 src/lxc/criu.c         | 477 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/criu.h         |  70 ++++++++
 src/lxc/lxccontainer.c | 454 +---------------------------------------------
 4 files changed, 551 insertions(+), 454 deletions(-)
 create mode 100644 src/lxc/criu.c
 create mode 100644 src/lxc/criu.h

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index d8e460b..2731843 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -21,7 +21,8 @@ noinst_HEADERS = \
 	namespace.h \
 	start.h \
 	state.h \
-	utils.h
+	utils.h \
+	criu.h
 
 if IS_BIONIC
 noinst_HEADERS += \
@@ -75,6 +76,7 @@ liblxc_so_SOURCES = \
 	state.c state.h \
 	log.c log.h \
 	attach.c attach.h \
+	criu.c criu.h \
 	\
 	network.c network.h \
 	nl.c nl.h \
diff --git a/src/lxc/criu.c b/src/lxc/criu.c
new file mode 100644
index 0000000..043db36
--- /dev/null
+++ b/src/lxc/criu.c
@@ -0,0 +1,477 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2014-2015 Canonical Ltd.
+ *
+ * Authors:
+ * Tycho Andersen <tycho.andersen at canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#define _GNU_SOURCE
+#include <assert.h>
+#include <linux/limits.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "config.h"
+
+#include "bdev.h"
+#include "cgroup.h"
+#include "conf.h"
+#include "criu.h"
+#include "log.h"
+#include "lxc.h"
+#include "lxclock.h"
+#include "network.h"
+#include "utils.h"
+
+lxc_log_define(lxc_criu, lxc);
+
+void exec_criu(struct criu_opts *opts)
+{
+	char **argv, log[PATH_MAX];
+	int static_args = 18, argc = 0, i, ret;
+	int netnr = 0;
+	struct lxc_list *it;
+
+	char buf[4096];
+	FILE *mnts = NULL;
+
+	/* The command line always looks like:
+	 * criu $(action) --tcp-established --file-locks --link-remap --force-irmap \
+	 * --manage-cgroups action-script foo.sh -D $(directory) \
+	 * -o $(directory)/$(action).log --ext-mount-map auto
+	 * --enable-external-sharing --enable-external-masters
+	 * +1 for final NULL */
+
+	if (strcmp(opts->action, "dump") == 0) {
+		/* -t pid */
+		static_args += 2;
+
+		/* --leave-running */
+		if (!opts->stop)
+			static_args++;
+	} else if (strcmp(opts->action, "restore") == 0) {
+		/* --root $(lxc_mount_point) --restore-detached
+		 * --restore-sibling --pidfile $foo --cgroup-root $foo */
+		static_args += 8;
+	} else {
+		return;
+	}
+
+	if (opts->verbose)
+		static_args++;
+
+	ret = snprintf(log, PATH_MAX, "%s/%s.log", opts->directory, opts->action);
+	if (ret < 0 || ret >= PATH_MAX) {
+		ERROR("logfile name too long\n");
+		return;
+	}
+
+	argv = malloc(static_args * sizeof(*argv));
+	if (!argv)
+		return;
+
+	memset(argv, 0, static_args * sizeof(*argv));
+
+#define DECLARE_ARG(arg) 					\
+	do {							\
+		if (arg == NULL) {				\
+			ERROR("Got NULL argument for criu");	\
+			goto err;				\
+		}						\
+		argv[argc++] = strdup(arg);			\
+		if (!argv[argc-1])				\
+			goto err;				\
+	} while (0)
+
+	argv[argc++] = on_path("criu", NULL);
+	if (!argv[argc-1]) {
+		ERROR("Couldn't find criu binary\n");
+		goto err;
+	}
+
+	DECLARE_ARG(opts->action);
+	DECLARE_ARG("--tcp-established");
+	DECLARE_ARG("--file-locks");
+	DECLARE_ARG("--link-remap");
+	DECLARE_ARG("--force-irmap");
+	DECLARE_ARG("--manage-cgroups");
+	DECLARE_ARG("--ext-mount-map");
+	DECLARE_ARG("auto");
+	DECLARE_ARG("--enable-external-sharing");
+	DECLARE_ARG("--enable-external-masters");
+	DECLARE_ARG("-D");
+	DECLARE_ARG(opts->directory);
+	DECLARE_ARG("-o");
+	DECLARE_ARG(log);
+
+	if (opts->verbose)
+		DECLARE_ARG("-vvvvvv");
+
+	if (strcmp(opts->action, "dump") == 0) {
+		char pid[32];
+
+		if (sprintf(pid, "%d", opts->c->init_pid(opts->c)) < 0)
+			goto err;
+
+		DECLARE_ARG("-t");
+		DECLARE_ARG(pid);
+		if (!opts->stop)
+			DECLARE_ARG("--leave-running");
+	} else if (strcmp(opts->action, "restore") == 0) {
+		void *m;
+		int additional;
+
+		DECLARE_ARG("--root");
+		DECLARE_ARG(opts->c->lxc_conf->rootfs.mount);
+		DECLARE_ARG("--restore-detached");
+		DECLARE_ARG("--restore-sibling");
+		DECLARE_ARG("--pidfile");
+		DECLARE_ARG(opts->pidfile);
+		DECLARE_ARG("--cgroup-root");
+		DECLARE_ARG(opts->cgroup_path);
+
+		additional = lxc_list_len(&opts->c->lxc_conf->network) * 2;
+
+		m = realloc(argv, (argc + additional + 1) * sizeof(*argv));	\
+		if (!m)								\
+			goto err;						\
+		argv = m;
+
+		lxc_list_for_each(it, &opts->c->lxc_conf->network) {
+			char eth[128], *veth;
+			struct lxc_netdev *n = it->elem;
+
+			if (n->name) {
+				if (strlen(n->name) >= sizeof(eth))
+					goto err;
+				strncpy(eth, n->name, sizeof(eth));
+			} else
+				sprintf(eth, "eth%d", netnr);
+
+			veth = n->priv.veth_attr.pair;
+
+			ret = snprintf(buf, sizeof(buf), "%s=%s@%s", eth, veth, n->link);
+			if (ret < 0 || ret >= sizeof(buf))
+				goto err;
+
+			DECLARE_ARG("--veth-pair");
+			DECLARE_ARG(buf);
+		}
+
+	}
+
+	argv[argc] = NULL;
+
+#undef DECLARE_ARG
+	execv(argv[0], argv);
+err:
+	if (mnts)
+		fclose(mnts);
+	for (i = 0; argv[i]; i++)
+		free(argv[i]);
+	free(argv);
+}
+
+/* Check and make sure the container has a configuration that we know CRIU can
+ * dump. */
+bool criu_ok(struct lxc_container *c)
+{
+	struct lxc_list *it;
+	bool found_deny_rule = false;
+
+	if (geteuid()) {
+		ERROR("Must be root to checkpoint\n");
+		return false;
+	}
+
+	/* We only know how to restore containers with veth networks. */
+	lxc_list_for_each(it, &c->lxc_conf->network) {
+		struct lxc_netdev *n = it->elem;
+		if (n->type != LXC_NET_VETH && n->type != LXC_NET_NONE) {
+			ERROR("Found network that is not VETH or NONE\n");
+			return false;
+		}
+	}
+
+	// These requirements come from http://criu.org/LXC
+	if (c->lxc_conf->console.path &&
+			strcmp(c->lxc_conf->console.path, "none") != 0) {
+		ERROR("lxc.console must be none\n");
+		return false;
+	}
+
+	if (c->lxc_conf->tty != 0) {
+		ERROR("lxc.tty must be 0\n");
+		return false;
+	}
+
+	lxc_list_for_each(it, &c->lxc_conf->cgroup) {
+		struct lxc_cgroup *cg = it->elem;
+		if (strcmp(cg->subsystem, "devices.deny") == 0 &&
+				strcmp(cg->value, "c 5:1 rwm") == 0) {
+
+			found_deny_rule = true;
+			break;
+		}
+	}
+
+	if (!found_deny_rule) {
+		ERROR("couldn't find devices.deny = c 5:1 rwm");
+		return false;
+	}
+
+	return true;
+}
+
+bool dump_net_info(struct lxc_container *c, char *directory)
+{
+	int netnr;
+	struct lxc_list *it;
+
+	netnr = 0;
+	lxc_list_for_each(it, &c->lxc_conf->network) {
+		char *veth = NULL, *bridge = NULL, veth_path[PATH_MAX], eth[128];
+		struct lxc_netdev *n = it->elem;
+		bool has_error = true;
+		int pret;
+
+		pret = snprintf(veth_path, PATH_MAX, "lxc.network.%d.veth.pair", netnr);
+		if (pret < 0 || pret >= PATH_MAX)
+			goto out;
+
+		veth = c->get_running_config_item(c, veth_path);
+		if (!veth) {
+			/* criu_ok() checks that all interfaces are
+			 * LXC_NET{VETH,NONE}, and VETHs should have this
+			 * config */
+			assert(n->type == LXC_NET_NONE);
+			break;
+		}
+
+		bridge = c->get_running_config_item(c, veth_path);
+		if (!bridge)
+			goto out;
+
+		pret = snprintf(veth_path, PATH_MAX, "%s/veth%d", directory, netnr);
+		if (pret < 0 || pret >= PATH_MAX || print_to_file(veth_path, veth) < 0)
+			goto out;
+
+		if (n->name) {
+			if (strlen(n->name) >= 128)
+				goto out;
+			strncpy(eth, n->name, 128);
+		} else
+			sprintf(eth, "eth%d", netnr);
+
+		has_error = false;
+out:
+		free(veth);
+		free(bridge);
+		if (has_error)
+			return false;
+	}
+
+	return true;
+}
+
+static bool restore_net_info(struct lxc_container *c)
+{
+	struct lxc_list *it;
+	bool has_error = true;
+
+	if (container_mem_lock(c))
+		return false;
+
+	lxc_list_for_each(it, &c->lxc_conf->network) {
+		struct lxc_netdev *netdev = it->elem;
+		char template[IFNAMSIZ];
+		snprintf(template, sizeof(template), "vethXXXXXX");
+
+		if (!netdev->priv.veth_attr.pair)
+			netdev->priv.veth_attr.pair = lxc_mkifname(template);
+
+		if (!netdev->priv.veth_attr.pair)
+			goto out_unlock;
+	}
+
+	has_error = false;
+
+out_unlock:
+	container_mem_unlock(c);
+	return !has_error;
+}
+
+void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose)
+{
+	pid_t pid;
+	char pidfile[L_tmpnam];
+	struct lxc_handler *handler;
+	int status;
+
+	if (!tmpnam(pidfile))
+		goto out;
+
+	handler = lxc_init(c->name, c->lxc_conf, c->config_path);
+	if (!handler)
+		goto out;
+
+	if (!cgroup_init(handler)) {
+		ERROR("failed initing cgroups");
+		goto out_fini_handler;
+	}
+
+	if (!cgroup_create(handler)) {
+		ERROR("failed creating groups");
+		goto out_fini_handler;
+	}
+
+	if (!restore_net_info(c)) {
+		ERROR("failed restoring network info");
+		goto out_fini_handler;
+	}
+
+	resolve_clone_flags(handler);
+
+	pid = fork();
+	if (pid < 0)
+		goto out_fini_handler;
+
+	if (pid == 0) {
+		struct criu_opts os;
+		struct lxc_rootfs *rootfs;
+
+		close(pipe);
+		pipe = -1;
+
+		if (unshare(CLONE_NEWNS))
+			goto out_fini_handler;
+
+		/* CRIU needs the lxc root bind mounted so that it is the root of some
+		 * mount. */
+		rootfs = &c->lxc_conf->rootfs;
+
+		if (rootfs_is_blockdev(c->lxc_conf)) {
+			if (do_rootfs_setup(c->lxc_conf, c->name, c->config_path) < 0)
+				goto out_fini_handler;
+		} else {
+			if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST)
+				goto out_fini_handler;
+
+			if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
+				SYSERROR("remount / to private failed");
+				goto out_fini_handler;
+			}
+
+			if (mount(rootfs->path, rootfs->mount, NULL, MS_BIND, NULL) < 0) {
+				rmdir(rootfs->mount);
+				goto out_fini_handler;
+			}
+		}
+
+		os.action = "restore";
+		os.directory = directory;
+		os.c = c;
+		os.pidfile = pidfile;
+		os.verbose = verbose;
+		os.cgroup_path = cgroup_canonical_path(handler);
+
+		/* exec_criu() returning is an error */
+		exec_criu(&os);
+		umount(rootfs->mount);
+		rmdir(rootfs->mount);
+		goto out_fini_handler;
+	} else {
+		int ret;
+		char title[2048];
+
+		pid_t w = waitpid(pid, &status, 0);
+		if (w == -1) {
+			SYSERROR("waitpid");
+			goto out_fini_handler;
+		}
+
+		ret = write(pipe, &status, sizeof(status));
+		close(pipe);
+		pipe = -1;
+
+		if (sizeof(status) != ret) {
+			SYSERROR("failed to write all of status");
+			goto out_fini_handler;
+		}
+
+		if (WIFEXITED(status)) {
+			if (WEXITSTATUS(status)) {
+				goto out_fini_handler;
+			} else {
+				int ret;
+				FILE *f = fopen(pidfile, "r");
+				if (!f) {
+					SYSERROR("couldn't read restore's init pidfile %s\n", pidfile);
+					goto out_fini_handler;
+				}
+
+				ret = fscanf(f, "%d", (int*) &handler->pid);
+				fclose(f);
+				if (ret != 1) {
+					ERROR("reading restore pid failed");
+					goto out_fini_handler;
+				}
+
+				if (lxc_set_state(c->name, handler, RUNNING))
+					goto out_fini_handler;
+			}
+		} else {
+			ERROR("CRIU was killed with signal %d\n", WTERMSIG(status));
+			goto out_fini_handler;
+		}
+
+		/*
+		 * See comment in lxcapi_start; we don't care if these
+		 * fail because it's just a beauty thing. We just
+		 * assign the return here to silence potential.
+		 */
+		ret = snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
+		ret = setproctitle(title);
+
+		ret = lxc_poll(c->name, handler);
+		if (ret)
+			lxc_abort(c->name, handler);
+		lxc_fini(c->name, handler);
+		exit(ret);
+	}
+
+out_fini_handler:
+	lxc_fini(c->name, handler);
+
+out:
+	if (pipe >= 0) {
+		status = 1;
+		if (write(pipe, &status, sizeof(status)) != sizeof(status)) {
+			SYSERROR("writing status failed");
+		}
+		close(pipe);
+	}
+
+	exit(1);
+}
diff --git a/src/lxc/criu.h b/src/lxc/criu.h
new file mode 100644
index 0000000..1f65e47
--- /dev/null
+++ b/src/lxc/criu.h
@@ -0,0 +1,70 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2014-2015 Canonical Ltd.
+ *
+ * Authors:
+ * Tycho Andersen <tycho.andersen at canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __LXC_CRIU_H
+#define __LXC_CRIU_H
+
+#include <stdbool.h>
+
+#include <lxc/lxccontainer.h>
+
+// We require either the criu major/minor version, or the criu GITID if criu
+// was built from git.
+#define CRIU_VERSION 		"1.6"
+
+#define CRIU_GITID_VERSION	"1.5"
+#define CRIU_GITID_PATCHLEVEL	133
+
+struct criu_opts {
+	/* The type of criu invocation, one of "dump" or "restore" */
+	char *action;
+
+	/* The directory to pass to criu */
+	char *directory;
+
+	/* The container to dump */
+	struct lxc_container *c;
+
+	/* Enable criu verbose mode? */
+	bool verbose;
+
+	/* dump: stop the container or not after dumping? */
+	bool stop;
+
+	/* restore: the file to write the init process' pid into */
+	char *pidfile;
+	const char *cgroup_path;
+};
+
+void exec_criu(struct criu_opts *opts);
+
+/* Check and make sure the container has a configuration that we know CRIU can
+ * dump. */
+bool criu_ok(struct lxc_container *c);
+
+bool dump_net_info(struct lxc_container *c, char *directory);
+
+// do_restore never returns, the calling process is used as the
+// monitor process. do_restore calls exit() if it fails.
+void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose);
+
+#endif
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index d6826ab..0ca5b9f 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -50,6 +50,7 @@
 #include "console.h"
 #include "cgroup.h"
 #include "commands.h"
+#include "criu.h"
 #include "log.h"
 #include "bdev.h"
 #include "utils.h"
@@ -3496,276 +3497,6 @@ static bool lxcapi_detach_interface(struct lxc_container *c, const char *ifname,
 	return true;
 }
 
-struct criu_opts {
-	/* The type of criu invocation, one of "dump" or "restore" */
-	char *action;
-
-	/* The directory to pass to criu */
-	char *directory;
-
-	/* The container to dump */
-	struct lxc_container *c;
-
-	/* Enable criu verbose mode? */
-	bool verbose;
-
-	/* dump: stop the container or not after dumping? */
-	bool stop;
-
-	/* restore: the file to write the init process' pid into */
-	char *pidfile;
-	const char *cgroup_path;
-};
-
-static void exec_criu(struct criu_opts *opts)
-{
-	char **argv, log[PATH_MAX];
-	int static_args = 18, argc = 0, i, ret;
-	int netnr = 0;
-	struct lxc_list *it;
-
-	char buf[4096];
-	FILE *mnts = NULL;
-
-	/* The command line always looks like:
-	 * criu $(action) --tcp-established --file-locks --link-remap --force-irmap \
-	 * --manage-cgroups action-script foo.sh -D $(directory) \
-	 * -o $(directory)/$(action).log --ext-mount-map auto
-	 * --enable-external-sharing --enable-external-masters
-	 * +1 for final NULL */
-
-	if (strcmp(opts->action, "dump") == 0) {
-		/* -t pid */
-		static_args += 2;
-
-		/* --leave-running */
-		if (!opts->stop)
-			static_args++;
-	} else if (strcmp(opts->action, "restore") == 0) {
-		/* --root $(lxc_mount_point) --restore-detached
-		 * --restore-sibling --pidfile $foo --cgroup-root $foo */
-		static_args += 8;
-	} else {
-		return;
-	}
-
-	if (opts->verbose)
-		static_args++;
-
-	ret = snprintf(log, PATH_MAX, "%s/%s.log", opts->directory, opts->action);
-	if (ret < 0 || ret >= PATH_MAX) {
-		ERROR("logfile name too long\n");
-		return;
-	}
-
-	argv = malloc(static_args * sizeof(*argv));
-	if (!argv)
-		return;
-
-	memset(argv, 0, static_args * sizeof(*argv));
-
-#define DECLARE_ARG(arg) 					\
-	do {							\
-		if (arg == NULL) {				\
-			ERROR("Got NULL argument for criu");	\
-			goto err;				\
-		}						\
-		argv[argc++] = strdup(arg);			\
-		if (!argv[argc-1])				\
-			goto err;				\
-	} while (0)
-
-	argv[argc++] = on_path("criu", NULL);
-	if (!argv[argc-1]) {
-		ERROR("Couldn't find criu binary\n");
-		goto err;
-	}
-
-	DECLARE_ARG(opts->action);
-	DECLARE_ARG("--tcp-established");
-	DECLARE_ARG("--file-locks");
-	DECLARE_ARG("--link-remap");
-	DECLARE_ARG("--force-irmap");
-	DECLARE_ARG("--manage-cgroups");
-	DECLARE_ARG("--ext-mount-map");
-	DECLARE_ARG("auto");
-	DECLARE_ARG("--enable-external-sharing");
-	DECLARE_ARG("--enable-external-masters");
-	DECLARE_ARG("-D");
-	DECLARE_ARG(opts->directory);
-	DECLARE_ARG("-o");
-	DECLARE_ARG(log);
-
-	if (opts->verbose)
-		DECLARE_ARG("-vvvvvv");
-
-	if (strcmp(opts->action, "dump") == 0) {
-		char pid[32];
-
-		if (sprintf(pid, "%d", lxcapi_init_pid(opts->c)) < 0)
-			goto err;
-
-		DECLARE_ARG("-t");
-		DECLARE_ARG(pid);
-		if (!opts->stop)
-			DECLARE_ARG("--leave-running");
-	} else if (strcmp(opts->action, "restore") == 0) {
-		void *m;
-		int additional;
-
-		DECLARE_ARG("--root");
-		DECLARE_ARG(opts->c->lxc_conf->rootfs.mount);
-		DECLARE_ARG("--restore-detached");
-		DECLARE_ARG("--restore-sibling");
-		DECLARE_ARG("--pidfile");
-		DECLARE_ARG(opts->pidfile);
-		DECLARE_ARG("--cgroup-root");
-		DECLARE_ARG(opts->cgroup_path);
-
-		additional = lxc_list_len(&opts->c->lxc_conf->network) * 2;
-
-		m = realloc(argv, (argc + additional + 1) * sizeof(*argv));	\
-		if (!m)								\
-			goto err;						\
-		argv = m;
-
-		lxc_list_for_each(it, &opts->c->lxc_conf->network) {
-			char eth[128], *veth;
-			struct lxc_netdev *n = it->elem;
-
-			if (n->name) {
-				if (strlen(n->name) >= sizeof(eth))
-					goto err;
-				strncpy(eth, n->name, sizeof(eth));
-			} else
-				sprintf(eth, "eth%d", netnr);
-
-			veth = n->priv.veth_attr.pair;
-
-			ret = snprintf(buf, sizeof(buf), "%s=%s@%s", eth, veth, n->link);
-			if (ret < 0 || ret >= sizeof(buf))
-				goto err;
-
-			DECLARE_ARG("--veth-pair");
-			DECLARE_ARG(buf);
-		}
-
-	}
-
-	argv[argc] = NULL;
-
-#undef DECLARE_ARG
-	execv(argv[0], argv);
-err:
-	if (mnts)
-		fclose(mnts);
-	for (i = 0; argv[i]; i++)
-		free(argv[i]);
-	free(argv);
-}
-
-/* Check and make sure the container has a configuration that we know CRIU can
- * dump. */
-static bool criu_ok(struct lxc_container *c)
-{
-	struct lxc_list *it;
-	bool found_deny_rule = false;
-
-	if (geteuid()) {
-		ERROR("Must be root to checkpoint\n");
-		return false;
-	}
-
-	/* We only know how to restore containers with veth networks. */
-	lxc_list_for_each(it, &c->lxc_conf->network) {
-		struct lxc_netdev *n = it->elem;
-		if (n->type != LXC_NET_VETH && n->type != LXC_NET_NONE) {
-			ERROR("Found network that is not VETH or NONE\n");
-			return false;
-		}
-	}
-
-	// These requirements come from http://criu.org/LXC
-	if (c->lxc_conf->console.path &&
-			strcmp(c->lxc_conf->console.path, "none") != 0) {
-		ERROR("lxc.console must be none\n");
-		return false;
-	}
-
-	if (c->lxc_conf->tty != 0) {
-		ERROR("lxc.tty must be 0\n");
-		return false;
-	}
-
-	lxc_list_for_each(it, &c->lxc_conf->cgroup) {
-		struct lxc_cgroup *cg = it->elem;
-		if (strcmp(cg->subsystem, "devices.deny") == 0 &&
-				strcmp(cg->value, "c 5:1 rwm") == 0) {
-
-			found_deny_rule = true;
-			break;
-		}
-	}
-
-	if (!found_deny_rule) {
-		ERROR("couldn't find devices.deny = c 5:1 rwm");
-		return false;
-	}
-
-	return true;
-}
-
-static bool dump_net_info(struct lxc_container *c, char *directory)
-{
-	int netnr;
-	struct lxc_list *it;
-
-	netnr = 0;
-	lxc_list_for_each(it, &c->lxc_conf->network) {
-		char *veth = NULL, *bridge = NULL, veth_path[PATH_MAX], eth[128];
-		struct lxc_netdev *n = it->elem;
-		bool has_error = true;
-		int pret;
-
-		pret = snprintf(veth_path, PATH_MAX, "lxc.network.%d.veth.pair", netnr);
-		if (pret < 0 || pret >= PATH_MAX)
-			goto out;
-
-		veth = lxcapi_get_running_config_item(c, veth_path);
-		if (!veth) {
-			/* criu_ok() checks that all interfaces are
-			 * LXC_NET{VETH,NONE}, and VETHs should have this
-			 * config */
-			assert(n->type == LXC_NET_NONE);
-			break;
-		}
-
-		bridge = lxcapi_get_running_config_item(c, veth_path);
-		if (!bridge)
-			goto out;
-
-		pret = snprintf(veth_path, PATH_MAX, "%s/veth%d", directory, netnr);
-		if (pret < 0 || pret >= PATH_MAX || print_to_file(veth_path, veth) < 0)
-			goto out;
-
-		if (n->name) {
-			if (strlen(n->name) >= 128)
-				goto out;
-			strncpy(eth, n->name, 128);
-		} else
-			sprintf(eth, "eth%d", netnr);
-
-		has_error = false;
-out:
-		free(veth);
-		free(bridge);
-		if (has_error)
-			return false;
-	}
-
-	return true;
-}
-
 static bool lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose)
 {
 	pid_t pid;
@@ -3811,189 +3542,6 @@ static bool lxcapi_checkpoint(struct lxc_container *c, char *directory, bool sto
 	}
 }
 
-static bool restore_net_info(struct lxc_container *c)
-{
-	struct lxc_list *it;
-	bool has_error = true;
-
-	if (container_mem_lock(c))
-		return false;
-
-	lxc_list_for_each(it, &c->lxc_conf->network) {
-		struct lxc_netdev *netdev = it->elem;
-		char template[IFNAMSIZ];
-		snprintf(template, sizeof(template), "vethXXXXXX");
-
-		if (!netdev->priv.veth_attr.pair)
-			netdev->priv.veth_attr.pair = lxc_mkifname(template);
-
-		if (!netdev->priv.veth_attr.pair)
-			goto out_unlock;
-	}
-
-	has_error = false;
-
-out_unlock:
-	container_mem_unlock(c);
-	return !has_error;
-}
-
-// do_restore never returns, the calling process is used as the
-// monitor process. do_restore calls exit() if it fails.
-static void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose)
-{
-	pid_t pid;
-	char pidfile[L_tmpnam];
-	struct lxc_handler *handler;
-	int status;
-
-	if (!tmpnam(pidfile))
-		goto out;
-
-	handler = lxc_init(c->name, c->lxc_conf, c->config_path);
-	if (!handler)
-		goto out;
-
-	if (!cgroup_init(handler)) {
-		ERROR("failed initing cgroups");
-		goto out_fini_handler;
-	}
-
-	if (!cgroup_create(handler)) {
-		ERROR("failed creating groups");
-		goto out_fini_handler;
-	}
-
-	if (!restore_net_info(c)) {
-		ERROR("failed restoring network info");
-		goto out_fini_handler;
-	}
-
-	resolve_clone_flags(handler);
-
-	pid = fork();
-	if (pid < 0)
-		goto out_fini_handler;
-
-	if (pid == 0) {
-		struct criu_opts os;
-		struct lxc_rootfs *rootfs;
-
-		close(pipe);
-		pipe = -1;
-
-		if (unshare(CLONE_NEWNS))
-			goto out_fini_handler;
-
-		/* CRIU needs the lxc root bind mounted so that it is the root of some
-		 * mount. */
-		rootfs = &c->lxc_conf->rootfs;
-
-		if (rootfs_is_blockdev(c->lxc_conf)) {
-			if (do_rootfs_setup(c->lxc_conf, c->name, c->config_path) < 0)
-				goto out_fini_handler;
-		} else {
-			if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST)
-				goto out_fini_handler;
-
-			if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
-				SYSERROR("remount / to private failed");
-				goto out_fini_handler;
-			}
-
-			if (mount(rootfs->path, rootfs->mount, NULL, MS_BIND, NULL) < 0) {
-				rmdir(rootfs->mount);
-				goto out_fini_handler;
-			}
-		}
-
-		os.action = "restore";
-		os.directory = directory;
-		os.c = c;
-		os.pidfile = pidfile;
-		os.verbose = verbose;
-		os.cgroup_path = cgroup_canonical_path(handler);
-
-		/* exec_criu() returning is an error */
-		exec_criu(&os);
-		umount(rootfs->mount);
-		rmdir(rootfs->mount);
-		goto out_fini_handler;
-	} else {
-		int ret;
-		char title[2048];
-
-		pid_t w = waitpid(pid, &status, 0);
-		if (w == -1) {
-			SYSERROR("waitpid");
-			goto out_fini_handler;
-		}
-
-		ret = write(pipe, &status, sizeof(status));
-		close(pipe);
-		pipe = -1;
-
-		if (sizeof(status) != ret) {
-			SYSERROR("failed to write all of status");
-			goto out_fini_handler;
-		}
-
-		if (WIFEXITED(status)) {
-			if (WEXITSTATUS(status)) {
-				goto out_fini_handler;
-			} else {
-				int ret;
-				FILE *f = fopen(pidfile, "r");
-				if (!f) {
-					SYSERROR("couldn't read restore's init pidfile %s\n", pidfile);
-					goto out_fini_handler;
-				}
-
-				ret = fscanf(f, "%d", (int*) &handler->pid);
-				fclose(f);
-				if (ret != 1) {
-					ERROR("reading restore pid failed");
-					goto out_fini_handler;
-				}
-
-				if (lxc_set_state(c->name, handler, RUNNING))
-					goto out_fini_handler;
-			}
-		} else {
-			ERROR("CRIU was killed with signal %d\n", WTERMSIG(status));
-			goto out_fini_handler;
-		}
-
-		/*
-		 * See comment in lxcapi_start; we don't care if these
-		 * fail because it's just a beauty thing. We just
-		 * assign the return here to silence potential.
-		 */
-		ret = snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
-		ret = setproctitle(title);
-
-		ret = lxc_poll(c->name, handler);
-		if (ret)
-			lxc_abort(c->name, handler);
-		lxc_fini(c->name, handler);
-		exit(ret);
-	}
-
-out_fini_handler:
-	lxc_fini(c->name, handler);
-
-out:
-	if (pipe >= 0) {
-		status = 1;
-		if (write(pipe, &status, sizeof(status)) != sizeof(status)) {
-			SYSERROR("writing status failed");
-		}
-		close(pipe);
-	}
-
-	exit(1);
-}
-
 static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbose)
 {
 	pid_t pid;
-- 
2.1.4



More information about the lxc-devel mailing list