[CRIU] [PATCH 4/6] vzctl: move cpt/rst code in hook_vz

Andrey Vagin avagin at openvz.org
Tue May 21 12:13:31 EDT 2013


Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/cpt.h      |  13 ++
 include/types.h    |  25 ++--
 src/lib/cpt.c      | 404 +----------------------------------------------------
 src/lib/hooks_vz.c | 386 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 417 insertions(+), 411 deletions(-)

diff --git a/include/cpt.h b/include/cpt.h
index 013dbbd..7932952 100644
--- a/include/cpt.h
+++ b/include/cpt.h
@@ -15,6 +15,19 @@
 #define CMD_KILL		10
 #define CMD_RESUME		11
 
+#define GET_DUMP_FILE(req_cmd)							\
+do {										\
+	dumpfile = param->dumpfile;						\
+	if (dumpfile == NULL) {							\
+		if (cmd == req_cmd) {						\
+			logger(-1,  0, "Error: dumpfile is not specified");	\
+			goto err;						\
+		}								\
+		get_dump_file(veid, param->dumpdir, buf, sizeof(buf));		\
+		dumpfile = buf;							\
+	}									\
+} while (0)
+
 int cpt_cmd(vps_handler *h, envid_t veid, const char *root,
 		int action, int cmd, unsigned int ctx);
 int vps_chkpnt(vps_handler *h, envid_t veid, const fs_param *fs,
diff --git a/include/types.h b/include/types.h
index 583dc36..518ffed 100644
--- a/include/types.h
+++ b/include/types.h
@@ -90,6 +90,18 @@ struct dev_res;
 struct cpu_param;
 struct veth_dev;
 struct meminfo_param;
+struct cpt_param;
+struct vps_param;
+struct fs_param;
+
+typedef enum {
+	SKIP_NONE =		0,
+	SKIP_SETUP =		(1<<0),
+	SKIP_CONFIGURE =	(1<<1),
+	SKIP_ACTION_SCRIPT =	(1<<2),
+	SKIP_UMOUNT =		(1<<3),
+	SKIP_REMOUNT =		(1<<4),
+} skipFlags;
 
 /** CT handler.
  */
@@ -102,6 +114,10 @@ typedef struct vps_handler {
 	int (*enter)(struct vps_handler *h, envid_t veid, const char *root, int flags);
 	int (*destroy)(struct vps_handler *h, envid_t veid);
 	int (*env_create)(struct arg_start *arg);
+	int (*env_chkpnt)(struct vps_handler *h, envid_t veid,
+			  const struct fs_param *fs, int cmd, struct cpt_param *param);
+	int (*env_restore)(struct vps_handler *h, envid_t veid, struct vps_param *vps_p,
+			   int cmd, struct cpt_param *param, skipFlags skip);
 	int (*setlimits)(struct vps_handler *h, envid_t, struct ub_struct *ub);
 	int (*setcpus)(struct vps_handler *h, envid_t, struct cpu_param *cpu);
 	int (*setcontext)(envid_t veid);
@@ -116,15 +132,6 @@ static inline int is_vz_kernel(vps_handler *h)
 	return h && h->vzfd != -1;
 }
 
-typedef enum {
-	SKIP_NONE =		0,
-	SKIP_SETUP =		(1<<0),
-	SKIP_CONFIGURE =	(1<<1),
-	SKIP_ACTION_SCRIPT =	(1<<2),
-	SKIP_UMOUNT =		(1<<3),
-	SKIP_REMOUNT =		(1<<4),
-} skipFlags;
-
 typedef int (* execFn)(void *data);
 
 /* Some kernels use a few IDs close to INT_MAX (2147483647) */
diff --git a/src/lib/cpt.c b/src/lib/cpt.c
index cca15b6..bf1c7f6 100644
--- a/src/lib/cpt.c
+++ b/src/lib/cpt.c
@@ -44,8 +44,6 @@
 #include "logger.h"
 #include "util.h"
 
-static int setup_hardlink_dir(const char *mntdir, int cpt_fd);
-
 int cpt_cmd(vps_handler *h, envid_t veid, const char *root,
 		int action, int cmd, unsigned int ctx)
 {
@@ -108,98 +106,6 @@ err:
 	return ret ? err : 0;
 }
 
-static int real_chkpnt(int cpt_fd, envid_t veid, const char *root,
-		cpt_param *param, int cmd)
-{
-	int ret, len, len1;
-	char buf[PIPE_BUF];
-	int err_p[2];
-
-	if ((ret = vz_chroot(root)))
-		return VZ_CHKPNT_ERROR;
-	if (pipe(err_p) < 0) {
-		logger(-1, errno, "Can't create pipe");
-		return VZ_CHKPNT_ERROR;
-	}
-	fcntl(err_p[0], F_SETFL, O_NONBLOCK);
-	fcntl(err_p[1], F_SETFL, O_NONBLOCK);
-	if (ioctl(cpt_fd, CPT_SET_ERRORFD, err_p[1]) < 0) {
-		logger(-1, errno, "Can't set errorfd");
-		return VZ_CHKPNT_ERROR;
-	}
-	close(err_p[1]);
-	if (cmd == CMD_CHKPNT || cmd == CMD_SUSPEND) {
-		logger(0, 0, "\tsuspend...");
-		if (ioctl(cpt_fd, CPT_SUSPEND, 0) < 0) {
-			logger(-1, errno, "Can not suspend container");
-			goto err_out;
-		}
-	}
-	if (cmd == CMD_CHKPNT || cmd == CMD_DUMP) {
-		logger(0, 0, "\tdump...");
-		clean_hardlink_dir("/");
-		if (setup_hardlink_dir("/", cpt_fd))
-			goto err_out;
-		if (ioctl(cpt_fd, CPT_DUMP, 0) < 0) {
-			logger(-1, errno, "Can not dump container");
-			if (cmd == CMD_CHKPNT) {
-				clean_hardlink_dir("/");
-				if (ioctl(cpt_fd, CPT_RESUME, 0) < 0)
-					logger(-1, errno, "Can not "
-							"resume container");
-			}
-			goto err_out;
-		}
-	}
-	if (cmd == CMD_CHKPNT) {
-		logger(0, 0, "\tkill...");
-		if (ioctl(cpt_fd, CPT_KILL, 0) < 0) {
-			logger(-1, errno, "Can not kill container");
-			goto err_out;
-		}
-	}
-	if (cmd == CMD_SUSPEND && !param->ctx) {
-		logger(0, 0, "\tget context...");
-		if (ioctl(cpt_fd, CPT_GET_CONTEXT, veid) < 0) {
-			logger(-1, errno, "Can not get context");
-			goto err_out;
-		}
-	}
-	close(err_p[0]);
-	return 0;
-err_out:
-	while ((len = read(err_p[0], buf, PIPE_BUF)) > 0) {
-		do {
-			len1 = write(STDERR_FILENO, buf, len);
-			len -= len1;
-		} while (len > 0 && len1 > 0);
-		if (cmd == CMD_SUSPEND && param->ctx) {
-			/* destroy context */
-			if (ioctl(cpt_fd, CPT_PUT_CONTEXT, veid) < 0)
-				logger(-1, errno, "Can't put context");
-		}
-	}
-	fflush(stderr);
-	close(err_p[0]);
-	return VZ_CHKPNT_ERROR;
-}
-
-#define GET_DUMP_FILE(req_cmd)							\
-do {										\
-	dumpfile = param->dumpfile;						\
-	if (dumpfile == NULL) {							\
-		if (cmd == req_cmd) {						\
-			logger(-1,  0, "Error: dumpfile is not specified");	\
-			goto err;						\
-		}								\
-		get_dump_file(veid, param->dumpdir, buf, sizeof(buf));		\
-		dumpfile = buf;							\
-	}									\
-} while (0)
-
-static int vz_chkpnt(vps_handler *h, envid_t veid,
-		     const fs_param *fs, int cmd, cpt_param *param);
-
 int vps_chkpnt(vps_handler *h, envid_t veid, const fs_param *fs,
 		int cmd, cpt_param *param)
 {
@@ -215,202 +121,9 @@ int vps_chkpnt(vps_handler *h, envid_t veid, const fs_param *fs,
 		return VZ_VE_NOT_RUNNING;
 	}
 
-	return vz_chkpnt(h, veid, fs, cmd, param);
-}
-
-static int vz_chkpnt(vps_handler *h, envid_t veid,
-		     const fs_param *fs, int cmd, cpt_param *param)
-{
-	int dump_fd = -1;
-	char buf[PATH_LEN];
-	const char *dumpfile = NULL;
-	int cpt_fd, pid, ret;
-	const char *root = fs->root;
-
-	ret = VZ_CHKPNT_ERROR;
-
-	logger(0, 0, "Setting up checkpoint...");
-	if ((cpt_fd = open(PROC_CPT, O_RDWR)) < 0) {
-		if (errno == ENOENT)
-			logger(-1, errno, "Error: No checkpointing"
-				" support, unable to open " PROC_CPT);
-		else
-			logger(-1, errno, "Unable to open " PROC_CPT);
-		return VZ_CHKPNT_ERROR;
-	}
-	if ((cmd == CMD_CHKPNT || cmd == CMD_DUMP)) {
-		GET_DUMP_FILE(CMD_DUMP);
-		make_dir(dumpfile, 0);
-		dump_fd = open(dumpfile, O_CREAT|O_TRUNC|O_RDWR, 0600);
-		if (dump_fd < 0) {
-			logger(-1, errno, "Can not create dump file %s",
-					dumpfile);
-			goto err;
-		}
-	}
-	if (param->ctx || cmd > CMD_SUSPEND) {
-		logger(0, 0, "\tjoin context..");
-		if (ioctl(cpt_fd, CPT_JOIN_CONTEXT, param->ctx ? : veid) < 0) {
-			logger(-1, errno, "Can not join cpt context");
-			goto err;
-		}
-	} else {
-		if (ioctl(cpt_fd, CPT_SET_VEID, veid) < 0) {
-			logger(-1, errno, "Can not set CT ID");
-			goto err;
-		}
-	}
-	if (dump_fd != -1) {
-		if (ioctl(cpt_fd, CPT_SET_DUMPFD, dump_fd) < 0) {
-			logger(-1, errno, "Can not set dump file");
-			goto err;
-		}
-	}
-	if (param->cpu_flags) {
-		logger(0, 0, "\tset CPU flags..");
-		if (ioctl(cpt_fd, CPT_SET_CPU_FLAGS, param->cpu_flags) < 0) {
-			logger(-1, errno, "Can not set CPU flags");
-			goto err;
-		}
-	}
-	if ((pid = fork()) < 0) {
-		logger(-1, errno, "Can't fork");
-		ret = VZ_RESOURCE_ERROR;
-		goto err;
-	} else if (pid == 0) {
-		if ((ret = h->setcontext(veid)))
-			exit(ret);
-		if ((pid = fork()) < 0) {
-			logger(-1, errno, "Can't fork");
-			exit(VZ_RESOURCE_ERROR);
-		} else if (pid == 0) {
-			ret = real_chkpnt(cpt_fd, veid, root, param, cmd);
-			exit(ret);
-		}
-		ret = env_wait(pid);
-		exit(ret);
-	}
-	close(cpt_fd);
-	cpt_fd = -1;
-	ret = env_wait(pid);
-	if (ret)
-		goto err;
-	ret = 0;
-	logger(0, 0, "Checkpointing completed successfully");
-err:
-	if (ret) {
-		ret = VZ_CHKPNT_ERROR;
-		logger(-1, 0, "Checkpointing failed");
-		if (cmd == CMD_CHKPNT || cmd == CMD_DUMP)
-			if (dumpfile)
-				unlink(dumpfile);
-	}
-	if (dump_fd != -1) {
-		if (ret == 0)
-			fsync(dump_fd);
-		close(dump_fd);
-	}
-	if (cpt_fd != -1)
-		close(cpt_fd);
-
-	return ret;
-}
-
-static int restore_fn(vps_handler *h, envid_t veid, int wait_p,
-		int old_wait_p, int err_p, void *data)
-{
-	int status, len, len1, ret;
-	cpt_param *param = (cpt_param *) data;
-	char buf[PIPE_BUF];
-	int error_pipe[2];
-
-	status = VZ_RESTORE_ERROR;
-	if (param == NULL)
-		goto err_pipe;
-	/* Close all fds */
-	close_fds(0, wait_p, old_wait_p, err_p, param->rst_fd, h->vzfd, -1);
-	if (ioctl(param->rst_fd, CPT_SET_VEID, veid) < 0) {
-		logger(-1, errno, "Can't set CT ID %d", param->rst_fd);
-		goto err_pipe;
-	}
-	if (pipe(error_pipe) < 0 ) {
-		logger(-1, errno, "Can't create pipe");
-		goto err_pipe;
-	}
-	fcntl(error_pipe[0], F_SETFL, O_NONBLOCK);
-	fcntl(error_pipe[1], F_SETFL, O_NONBLOCK);
-	if (ioctl(param->rst_fd, CPT_SET_ERRORFD, error_pipe[1]) < 0) {
-		logger(-1, errno, "Can't set errorfd");
-		goto err;
-	}
-	close(error_pipe[1]);
-
-	ret = ioctl(param->rst_fd, CPT_SET_LOCKFD2, wait_p);
-	if (ret < 0 && errno == EINVAL)
-		ret = ioctl(param->rst_fd, CPT_SET_LOCKFD, old_wait_p);
-	if (ret < 0) {
-		logger(-1, errno, "Can't set lockfd");
-		goto err;
-	}
-
-	if (ioctl(param->rst_fd, CPT_SET_STATUSFD, STDIN_FILENO) < 0) {
-		logger(-1, errno, "Can't set statusfd");
-		goto err;
-	}
-	/* Close status descriptor to report that
-	* environment is created.
-	*/
-	close(STDIN_FILENO);
-
-	ioctl(param->rst_fd, CPT_HARDLNK_ON);
-
-	logger(0, 0, "\tundump...");
-	if (ioctl(param->rst_fd, CPT_UNDUMP, 0) != 0) {
-		logger(-1, errno, "Error: undump failed");
-		goto err_undump;
-	}
-	/* Now we wait until CT setup will be done */
-	read(wait_p, &len, sizeof(len));
-	if (param->cmd == CMD_RESTORE) {
-		clean_hardlink_dir("/");
-		logger(0, 0, "\tresume...");
-		if (ioctl(param->rst_fd, CPT_RESUME, 0)) {
-			logger(-1, errno, "Error: resume failed");
-			goto err_undump;
-		}
-	} else if (param->cmd == CMD_UNDUMP && !param->ctx) {
-		logger(0, 0, "\tget context...");
-		if (ioctl(param->rst_fd, CPT_GET_CONTEXT, veid) < 0) {
-			logger(-1, errno, "Can not get context");
-			goto err_undump;
-		}
-	}
-	status = 0;
-
-err:
-	close(error_pipe[0]);
-err_pipe:
-	if (status)
-		write(err_p, &status, sizeof(status));
-	return status;
-
-err_undump:
-	logger(-1, 0, "Restoring failed:");
-	while ((len = read(error_pipe[0], buf, PIPE_BUF)) > 0) {
-		do {
-			len1 = write(STDERR_FILENO, buf, len);
-			len -= len1;
-		} while (len > 0 && len1 > 0);
-	}
-	fflush(stderr);
-	close(error_pipe[0]);
-	write(err_p, &status, sizeof(status));
-	return status;
+	return h->env_chkpnt(h, veid, fs, cmd, param);
 }
 
-static int vz_restore(vps_handler *h, envid_t veid, vps_param *vps_p,
-			int cmd, cpt_param *param, skipFlags skip);
-
 int vps_restore(vps_handler *h, envid_t veid, vps_param *vps_p, int cmd,
 	cpt_param *param, skipFlags skip)
 {
@@ -420,118 +133,5 @@ int vps_restore(vps_handler *h, envid_t veid, vps_param *vps_p, int cmd,
 		return VZ_VE_RUNNING;
 	}
 
-	return vz_restore(h, veid, vps_p, cmd, param, skip);
-}
-
-static int vz_restore(vps_handler *h, envid_t veid, vps_param *vps_p,
-			int cmd, cpt_param *param, skipFlags skip)
-{
-	int ret, rst_fd;
-	int dump_fd = -1;
-	char buf[PATH_LEN];
-	const char *dumpfile = NULL;
-
-	logger(0, 0, "Restoring container ...");
-	ret = VZ_RESTORE_ERROR;
-	if ((rst_fd = open(PROC_RST, O_RDWR)) < 0) {
-		if (errno == ENOENT)
-			logger(-1, errno, "Error: No checkpointing"
-				" support, unable to open " PROC_RST);
-		else
-			logger(-1, errno, "Unable to open " PROC_RST);
-		return VZ_RESTORE_ERROR;
-	}
-	if (param->ctx) {
-		if (ioctl(rst_fd, CPT_JOIN_CONTEXT, param->ctx) < 0) {
-			logger(-1, errno, "Can not join cpt context");
-			goto err;
-		}
-	}
-	GET_DUMP_FILE(CMD_UNDUMP);
-	if (cmd == CMD_RESTORE || cmd == CMD_UNDUMP) {
-		dump_fd = open(dumpfile, O_RDONLY);
-		if (dump_fd < 0) {
-			logger(-1, errno, "Unable to open %s", dumpfile);
-			goto err;
-		}
-	}
-	if (dump_fd != -1) {
-		if (ioctl(rst_fd, CPT_SET_DUMPFD, dump_fd)) {
-			logger(-1, errno, "Can't set dumpfile");
-			goto err;
-		}
-	}
-	param->rst_fd = rst_fd;
-	param->cmd = cmd;
-	ret = vps_start_custom(h, veid, vps_p,
-			SKIP_CONFIGURE | SKIP_ACTION_SCRIPT | skip,
-			NULL, restore_fn, param);
-	if (ret)
-		goto err;
-err:
-	close(rst_fd);
-	if (dump_fd != -1)
-		close(dump_fd);
-	if (!ret) {
-		logger(0, 0, "Restoring completed successfully");
-		if (cmd == CMD_RESTORE)
-			if (dumpfile)
-				unlink(dumpfile);
-	}
-	return ret;
-}
-
-/* with mix of md5sum: try generate unique name */
-#define CPT_HARDLINK_DIR ".cpt_hardlink_dir_a920e4ddc233afddc9fb53d26c392319"
-
-void clean_hardlink_dir(const char *mntdir)
-{
-	char buf[STR_SIZE];
-	struct dirent *ep;
-	DIR *dp;
-
-	snprintf(buf, sizeof(buf), "%s/%s", mntdir, CPT_HARDLINK_DIR);
-
-	unlink(buf);		/* if file was created by someone */
-	if (!(dp = opendir(buf)))
-		return;
-	while ((ep = readdir(dp))) {
-		if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
-			continue;
-
-		snprintf(buf, sizeof(buf), "%s/%s/%s",
-				mntdir, CPT_HARDLINK_DIR, ep->d_name);
-		unlink(buf);
-	}
-	closedir(dp);
-
-	snprintf(buf, sizeof(buf), "%s/%s", mntdir, CPT_HARDLINK_DIR);
-	rmdir(buf);
-}
-
-static int setup_hardlink_dir(const char *mntdir, int cpt_fd)
-{
-	char buf[STR_SIZE];
-	int fd, res = 0;
-
-	snprintf(buf, sizeof(buf), "%s/%s", mntdir, CPT_HARDLINK_DIR);
-	mkdir(buf, 0711);
-
-	fd = open(buf, O_RDONLY | O_NOFOLLOW | O_DIRECTORY);
-	if (fd < 0) {
-		logger(-1, errno, "Error: Unable to open "
-				"hardlink directory %s", buf);
-		return 1;
-	}
-
-	if (ioctl(cpt_fd, CPT_LINKDIR_ADD, fd) < 0) {
-		if (errno != EINVAL) {
-			res = 1;
-			logger(-1, errno, "Cannot set linkdir in kernel");
-		}
-		rmdir(buf);
-	}
-
-	close(fd);
-	return res;
+	return h->env_restore(h, veid, vps_p, cmd, param, skip);
 }
diff --git a/src/lib/hooks_vz.c b/src/lib/hooks_vz.c
index 50770c0..94b6c18 100644
--- a/src/lib/hooks_vz.c
+++ b/src/lib/hooks_vz.c
@@ -24,13 +24,18 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <dirent.h>
 #include <sys/ioctl.h>
 #include <netinet/in.h>
 #include <linux/vzcalluser.h>
 #include <linux/vzctl_veth.h>
 #include <linux/vzctl_venet.h>
+#include <linux/cpt_ioctl.h>
 
 #include "env.h"
+#include "exec.h"
+#include "cpt.h"
 #include "util.h"
 #include "types.h"
 #include "logger.h"
@@ -466,6 +471,385 @@ static int vz_veth_ctl(vps_handler *h, envid_t veid, int op, veth_dev *dev)
 	return ret;
 }
 
+/* with mix of md5sum: try generate unique name */
+#define CPT_HARDLINK_DIR ".cpt_hardlink_dir_a920e4ddc233afddc9fb53d26c392319"
+
+void clean_hardlink_dir(const char *mntdir)
+{
+	char buf[STR_SIZE];
+	struct dirent *ep;
+	DIR *dp;
+
+	snprintf(buf, sizeof(buf), "%s/%s", mntdir, CPT_HARDLINK_DIR);
+
+	unlink(buf);		/* if file was created by someone */
+	if (!(dp = opendir(buf)))
+		return;
+	while ((ep = readdir(dp))) {
+		if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
+			continue;
+
+		snprintf(buf, sizeof(buf), "%s/%s/%s",
+				mntdir, CPT_HARDLINK_DIR, ep->d_name);
+		unlink(buf);
+	}
+	closedir(dp);
+
+	snprintf(buf, sizeof(buf), "%s/%s", mntdir, CPT_HARDLINK_DIR);
+	rmdir(buf);
+}
+
+static int setup_hardlink_dir(const char *mntdir, int cpt_fd)
+{
+	char buf[STR_SIZE];
+	int fd, res = 0;
+
+	snprintf(buf, sizeof(buf), "%s/%s", mntdir, CPT_HARDLINK_DIR);
+	mkdir(buf, 0711);
+
+	fd = open(buf, O_RDONLY | O_NOFOLLOW | O_DIRECTORY);
+	if (fd < 0) {
+		logger(-1, errno, "Error: Unable to open "
+				"hardlink directory %s", buf);
+		return 1;
+	}
+
+	if (ioctl(cpt_fd, CPT_LINKDIR_ADD, fd) < 0) {
+		if (errno != EINVAL) {
+			res = 1;
+			logger(-1, errno, "Cannot set linkdir in kernel");
+		}
+		rmdir(buf);
+	}
+
+	close(fd);
+	return res;
+}
+
+static int real_chkpnt(int cpt_fd, envid_t veid, const char *root,
+		cpt_param *param, int cmd)
+{
+	int ret, len, len1;
+	char buf[PIPE_BUF];
+	int err_p[2];
+
+	if ((ret = vz_chroot(root)))
+		return VZ_CHKPNT_ERROR;
+	if (pipe(err_p) < 0) {
+		logger(-1, errno, "Can't create pipe");
+		return VZ_CHKPNT_ERROR;
+	}
+	fcntl(err_p[0], F_SETFL, O_NONBLOCK);
+	fcntl(err_p[1], F_SETFL, O_NONBLOCK);
+	if (ioctl(cpt_fd, CPT_SET_ERRORFD, err_p[1]) < 0) {
+		logger(-1, errno, "Can't set errorfd");
+		return VZ_CHKPNT_ERROR;
+	}
+	close(err_p[1]);
+	if (cmd == CMD_CHKPNT || cmd == CMD_SUSPEND) {
+		logger(0, 0, "\tsuspend...");
+		if (ioctl(cpt_fd, CPT_SUSPEND, 0) < 0) {
+			logger(-1, errno, "Can not suspend container");
+			goto err_out;
+		}
+	}
+	if (cmd == CMD_CHKPNT || cmd == CMD_DUMP) {
+		logger(0, 0, "\tdump...");
+		clean_hardlink_dir("/");
+		if (setup_hardlink_dir("/", cpt_fd))
+			goto err_out;
+		if (ioctl(cpt_fd, CPT_DUMP, 0) < 0) {
+			logger(-1, errno, "Can not dump container");
+			if (cmd == CMD_CHKPNT) {
+				clean_hardlink_dir("/");
+				if (ioctl(cpt_fd, CPT_RESUME, 0) < 0)
+					logger(-1, errno, "Can not "
+							"resume container");
+			}
+			goto err_out;
+		}
+	}
+	if (cmd == CMD_CHKPNT) {
+		logger(0, 0, "\tkill...");
+		if (ioctl(cpt_fd, CPT_KILL, 0) < 0) {
+			logger(-1, errno, "Can not kill container");
+			goto err_out;
+		}
+	}
+	if (cmd == CMD_SUSPEND && !param->ctx) {
+		logger(0, 0, "\tget context...");
+		if (ioctl(cpt_fd, CPT_GET_CONTEXT, veid) < 0) {
+			logger(-1, errno, "Can not get context");
+			goto err_out;
+		}
+	}
+	close(err_p[0]);
+	return 0;
+err_out:
+	while ((len = read(err_p[0], buf, PIPE_BUF)) > 0) {
+		do {
+			len1 = write(STDERR_FILENO, buf, len);
+			len -= len1;
+		} while (len > 0 && len1 > 0);
+		if (cmd == CMD_SUSPEND && param->ctx) {
+			/* destroy context */
+			if (ioctl(cpt_fd, CPT_PUT_CONTEXT, veid) < 0)
+				logger(-1, errno, "Can't put context");
+		}
+	}
+	fflush(stderr);
+	close(err_p[0]);
+	return VZ_CHKPNT_ERROR;
+}
+
+static int vz_chkpnt(vps_handler *h, envid_t veid,
+		     const fs_param *fs, int cmd, cpt_param *param)
+{
+	int dump_fd = -1;
+	char buf[PATH_LEN];
+	const char *dumpfile = NULL;
+	int cpt_fd, pid, ret;
+	const char *root = fs->root;
+
+	ret = VZ_CHKPNT_ERROR;
+
+	logger(0, 0, "Setting up checkpoint...");
+	if ((cpt_fd = open(PROC_CPT, O_RDWR)) < 0) {
+		if (errno == ENOENT)
+			logger(-1, errno, "Error: No checkpointing"
+				" support, unable to open " PROC_CPT);
+		else
+			logger(-1, errno, "Unable to open " PROC_CPT);
+		return VZ_CHKPNT_ERROR;
+	}
+	if ((cmd == CMD_CHKPNT || cmd == CMD_DUMP)) {
+		GET_DUMP_FILE(CMD_DUMP);
+		make_dir(dumpfile, 0);
+		dump_fd = open(dumpfile, O_CREAT|O_TRUNC|O_RDWR, 0600);
+		if (dump_fd < 0) {
+			logger(-1, errno, "Can not create dump file %s",
+					dumpfile);
+			goto err;
+		}
+	}
+	if (param->ctx || cmd > CMD_SUSPEND) {
+		logger(0, 0, "\tjoin context..");
+		if (ioctl(cpt_fd, CPT_JOIN_CONTEXT, param->ctx ? : veid) < 0) {
+			logger(-1, errno, "Can not join cpt context");
+			goto err;
+		}
+	} else {
+		if (ioctl(cpt_fd, CPT_SET_VEID, veid) < 0) {
+			logger(-1, errno, "Can not set CT ID");
+			goto err;
+		}
+	}
+	if (dump_fd != -1) {
+		if (ioctl(cpt_fd, CPT_SET_DUMPFD, dump_fd) < 0) {
+			logger(-1, errno, "Can not set dump file");
+			goto err;
+		}
+	}
+	if (param->cpu_flags) {
+		logger(0, 0, "\tset CPU flags..");
+		if (ioctl(cpt_fd, CPT_SET_CPU_FLAGS, param->cpu_flags) < 0) {
+			logger(-1, errno, "Can not set CPU flags");
+			goto err;
+		}
+	}
+	if ((pid = fork()) < 0) {
+		logger(-1, errno, "Can't fork");
+		ret = VZ_RESOURCE_ERROR;
+		goto err;
+	} else if (pid == 0) {
+		if ((ret = h->setcontext(veid)))
+			exit(ret);
+		if ((pid = fork()) < 0) {
+			logger(-1, errno, "Can't fork");
+			exit(VZ_RESOURCE_ERROR);
+		} else if (pid == 0) {
+			ret = real_chkpnt(cpt_fd, veid, root, param, cmd);
+			exit(ret);
+		}
+		ret = env_wait(pid);
+		exit(ret);
+	}
+	close(cpt_fd);
+	cpt_fd = -1;
+	ret = env_wait(pid);
+	if (ret)
+		goto err;
+	ret = 0;
+	logger(0, 0, "Checkpointing completed successfully");
+err:
+	if (ret) {
+		ret = VZ_CHKPNT_ERROR;
+		logger(-1, 0, "Checkpointing failed");
+		if (cmd == CMD_CHKPNT || cmd == CMD_DUMP)
+			if (dumpfile)
+				unlink(dumpfile);
+	}
+	if (dump_fd != -1) {
+		if (ret == 0)
+			fsync(dump_fd);
+		close(dump_fd);
+	}
+	if (cpt_fd != -1)
+		close(cpt_fd);
+
+	return ret;
+}
+
+static int restore_fn(vps_handler *h, envid_t veid, int wait_p,
+		int old_wait_p, int err_p, void *data)
+{
+	int status, len, len1, ret;
+	cpt_param *param = (cpt_param *) data;
+	char buf[PIPE_BUF];
+	int error_pipe[2];
+
+	status = VZ_RESTORE_ERROR;
+	if (param == NULL)
+		goto err_pipe;
+	/* Close all fds */
+	close_fds(0, wait_p, old_wait_p, err_p, param->rst_fd, h->vzfd, -1);
+	if (ioctl(param->rst_fd, CPT_SET_VEID, veid) < 0) {
+		logger(-1, errno, "Can't set CT ID %d", param->rst_fd);
+		goto err_pipe;
+	}
+	if (pipe(error_pipe) < 0 ) {
+		logger(-1, errno, "Can't create pipe");
+		goto err_pipe;
+	}
+	fcntl(error_pipe[0], F_SETFL, O_NONBLOCK);
+	fcntl(error_pipe[1], F_SETFL, O_NONBLOCK);
+	if (ioctl(param->rst_fd, CPT_SET_ERRORFD, error_pipe[1]) < 0) {
+		logger(-1, errno, "Can't set errorfd");
+		goto err;
+	}
+	close(error_pipe[1]);
+
+	ret = ioctl(param->rst_fd, CPT_SET_LOCKFD2, wait_p);
+	if (ret < 0 && errno == EINVAL)
+		ret = ioctl(param->rst_fd, CPT_SET_LOCKFD, old_wait_p);
+	if (ret < 0) {
+		logger(-1, errno, "Can't set lockfd");
+		goto err;
+	}
+
+	if (ioctl(param->rst_fd, CPT_SET_STATUSFD, STDIN_FILENO) < 0) {
+		logger(-1, errno, "Can't set statusfd");
+		goto err;
+	}
+	/* Close status descriptor to report that
+	* environment is created.
+	*/
+	close(STDIN_FILENO);
+
+	ioctl(param->rst_fd, CPT_HARDLNK_ON);
+
+	logger(0, 0, "\tundump...");
+	if (ioctl(param->rst_fd, CPT_UNDUMP, 0) != 0) {
+		logger(-1, errno, "Error: undump failed");
+		goto err_undump;
+	}
+	/* Now we wait until CT setup will be done */
+	read(wait_p, &len, sizeof(len));
+	if (param->cmd == CMD_RESTORE) {
+		clean_hardlink_dir("/");
+		logger(0, 0, "\tresume...");
+		if (ioctl(param->rst_fd, CPT_RESUME, 0)) {
+			logger(-1, errno, "Error: resume failed");
+			goto err_undump;
+		}
+	} else if (param->cmd == CMD_UNDUMP && !param->ctx) {
+		logger(0, 0, "\tget context...");
+		if (ioctl(param->rst_fd, CPT_GET_CONTEXT, veid) < 0) {
+			logger(-1, errno, "Can not get context");
+			goto err_undump;
+		}
+	}
+	status = 0;
+
+err:
+	close(error_pipe[0]);
+err_pipe:
+	if (status)
+		write(err_p, &status, sizeof(status));
+	return status;
+
+err_undump:
+	logger(-1, 0, "Restoring failed:");
+	while ((len = read(error_pipe[0], buf, PIPE_BUF)) > 0) {
+		do {
+			len1 = write(STDERR_FILENO, buf, len);
+			len -= len1;
+		} while (len > 0 && len1 > 0);
+	}
+	fflush(stderr);
+	close(error_pipe[0]);
+	write(err_p, &status, sizeof(status));
+	return status;
+}
+
+static int vz_restore(vps_handler *h, envid_t veid, vps_param *vps_p,
+			int cmd, cpt_param *param, skipFlags skip)
+{
+	int ret, rst_fd;
+	int dump_fd = -1;
+	char buf[PATH_LEN];
+	const char *dumpfile = NULL;
+
+	logger(0, 0, "Restoring container ...");
+	ret = VZ_RESTORE_ERROR;
+	if ((rst_fd = open(PROC_RST, O_RDWR)) < 0) {
+		if (errno == ENOENT)
+			logger(-1, errno, "Error: No checkpointing"
+				" support, unable to open " PROC_RST);
+		else
+			logger(-1, errno, "Unable to open " PROC_RST);
+		return VZ_RESTORE_ERROR;
+	}
+	if (param->ctx) {
+		if (ioctl(rst_fd, CPT_JOIN_CONTEXT, param->ctx) < 0) {
+			logger(-1, errno, "Can not join cpt context");
+			goto err;
+		}
+	}
+	GET_DUMP_FILE(CMD_UNDUMP);
+	if (cmd == CMD_RESTORE || cmd == CMD_UNDUMP) {
+		dump_fd = open(dumpfile, O_RDONLY);
+		if (dump_fd < 0) {
+			logger(-1, errno, "Unable to open %s", dumpfile);
+			goto err;
+		}
+	}
+	if (dump_fd != -1) {
+		if (ioctl(rst_fd, CPT_SET_DUMPFD, dump_fd)) {
+			logger(-1, errno, "Can't set dumpfile");
+			goto err;
+		}
+	}
+	param->rst_fd = rst_fd;
+	param->cmd = cmd;
+	ret = vps_start_custom(h, veid, vps_p,
+			SKIP_CONFIGURE | SKIP_ACTION_SCRIPT | skip,
+			NULL, restore_fn, param);
+	if (ret)
+		goto err;
+err:
+	close(rst_fd);
+	if (dump_fd != -1)
+		close(dump_fd);
+	if (!ret) {
+		logger(0, 0, "Restoring completed successfully");
+		if (cmd == CMD_RESTORE)
+			if (dumpfile)
+				unlink(dumpfile);
+	}
+	return ret;
+}
+
 int vz_do_open(vps_handler *h, vps_param *param)
 {
 	if ((h->vzfd = open(VZCTLDEV, O_RDWR)) < 0) {
@@ -488,6 +872,8 @@ int vz_do_open(vps_handler *h, vps_param *param)
 	h->enter = vz_enter;
 	h->destroy = vz_destroy;
 	h->env_create = vz_do_env_create;
+	h->env_chkpnt = vz_chkpnt;
+	h->env_restore = vz_restore;
 	h->setlimits = set_ublimit;
 	h->setcpus = vz_setcpu;
 	h->setcontext = vz_setluid;
-- 
1.8.2



More information about the CRIU mailing list