Signed-off-by: Andrey Vagin <ava...@openvz.org> --- include/cpt.h | 13 ++ include/types.h | 24 ++-- src/lib/cpt.c | 403 +---------------------------------------------------- src/lib/hooks_vz.c | 385 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 415 insertions(+), 410 deletions(-)
diff --git a/include/cpt.h b/include/cpt.h index 191162b..1bb5761 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 vps_res *res, diff --git a/include/types.h b/include/types.h index 150b756..b3f5f0c 100644 --- a/include/types.h +++ b/include/types.h @@ -90,8 +90,19 @@ struct dev_res; struct cpu_param; struct veth_dev; struct meminfo_param; +struct cpt_param; +struct vps_param; struct vps_res; +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. */ typedef struct vps_handler { @@ -102,6 +113,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, const struct vps_res *res); int (*env_create)(struct arg_start *arg); + int (*env_chkpnt)(struct vps_handler *h, envid_t veid, + const struct vps_res *res, 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 +131,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 24ba9a8..b39447e 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 vps_res *res, int cmd, cpt_param *param); - int vps_chkpnt(vps_handler *h, envid_t veid, const vps_res *res, int cmd, cpt_param *param) { @@ -215,202 +121,9 @@ int vps_chkpnt(vps_handler *h, envid_t veid, const vps_res *res, return VZ_VE_NOT_RUNNING; } - return vz_chkpnt(h, veid, res, cmd, param); -} - -static int vz_chkpnt(vps_handler *h, envid_t veid, - const vps_res *res, 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 = res->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, vps_res *res, 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, res, 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,117 +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, - 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 f358f59..7179176 100644 --- a/src/lib/hooks_vz.c +++ b/src/lib/hooks_vz.c @@ -24,13 +24,19 @@ #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/limits.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 +472,383 @@ 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 vps_res *res, 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 = res->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, vps_res *res, 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, + 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) { if ((h->vzfd = open(VZCTLDEV, O_RDWR)) < 0) { @@ -488,6 +871,8 @@ int vz_do_open(vps_handler *h) 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 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel