[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