Signed-off-by: Andrey Vagin <ava...@openvz.org>
---
 include/cpt.h      |  13 ++
 include/types.h    |  25 ++--
 src/lib/cpt.c      | 403 +----------------------------------------------------
 src/lib/hooks_vz.c | 385 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 416 insertions(+), 410 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 79e22ca..73cdea9 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.
  */
@@ -101,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);
        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);
@@ -115,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 e4213a2..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,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 afbcd0f..a30722b 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 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,
+               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

Reply via email to