Pre-checkpoint does a snapshot of a memory changes since previous 
pre-checkpoint,
allowing to significantly decrease time of an actual checkpoint.

We need it to be able to live-migrate containers faster.

Signed-off-by: Ruslan Kuprieiev <kupru...@gmail.com>
---
 src/lxc/criu.c           | 20 ++++++++++++++
 src/lxc/criu.h           |  1 +
 src/lxc/lxc_checkpoint.c | 41 +++++++++++++++++++++++++++-
 src/lxc/lxccontainer.c   | 70 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/lxc/lxccontainer.h   | 15 ++++++++++-
 5 files changed, 143 insertions(+), 4 deletions(-)

diff --git a/src/lxc/criu.c b/src/lxc/criu.c
index e939b37..a8fcc5f 100644
--- a/src/lxc/criu.c
+++ b/src/lxc/criu.c
@@ -70,6 +70,13 @@ void exec_criu(struct criu_opts *opts)
                /* --leave-running */
                if (!opts->stop)
                        static_args++;
+       } else if (strcmp(opts->action, "pre-dump") == 0) {
+               /* -t pid */
+               static_args += 2;
+
+               /* --prev-images-dir */
+               if (opts->prev_dir)
+                       static_args++;
        } else if (strcmp(opts->action, "restore") == 0) {
                /* --root $(lxc_mount_point) --restore-detached
                 * --restore-sibling --pidfile $foo --cgroup-root $foo */
@@ -127,6 +134,11 @@ void exec_criu(struct criu_opts *opts)
        DECLARE_ARG("-o");
        DECLARE_ARG(log);
 
+       if (opts->prev_dir) {
+               DECLARE_ARG("--prev-images-dir");
+               DECLARE_ARG(opts->prev_dir);
+       }
+
        if (opts->verbose)
                DECLARE_ARG("-vvvvvv");
 
@@ -140,6 +152,14 @@ void exec_criu(struct criu_opts *opts)
                DECLARE_ARG(pid);
                if (!opts->stop)
                        DECLARE_ARG("--leave-running");
+       } else if (strcmp(opts->action, "pre-dump") == 0) {
+               char pid[32];
+
+               if (sprintf(pid, "%d", opts->c->init_pid(opts->c)) < 0)
+                       goto err;
+
+               DECLARE_ARG("-t");
+               DECLARE_ARG(pid);
        } else if (strcmp(opts->action, "restore") == 0) {
                void *m;
                int additional;
diff --git a/src/lxc/criu.h b/src/lxc/criu.h
index 1f65e47..e8ef24b 100644
--- a/src/lxc/criu.h
+++ b/src/lxc/criu.h
@@ -53,6 +53,7 @@ struct criu_opts {
        /* restore: the file to write the init process' pid into */
        char *pidfile;
        const char *cgroup_path;
+       char *prev_dir;
 };
 
 void exec_criu(struct criu_opts *opts);
diff --git a/src/lxc/lxc_checkpoint.c b/src/lxc/lxc_checkpoint.c
index 2e76c2e..d4ff786 100644
--- a/src/lxc/lxc_checkpoint.c
+++ b/src/lxc/lxc_checkpoint.c
@@ -36,6 +36,10 @@ static bool stop = false;
 static bool verbose = false;
 static bool do_restore = false;
 static bool daemonize_set = false;
+static char *prev_checkpoint_dir = NULL;
+static bool do_pre_checkpoint = false;
+
+#define OPT_PREV_DIR OPT_VERSION - 1
 
 static const struct option my_longopts[] = {
        {"checkpoint-dir", required_argument, 0, 'D'},
@@ -44,6 +48,8 @@ static const struct option my_longopts[] = {
        {"restore", no_argument, 0, 'r'},
        {"daemon", no_argument, 0, 'd'},
        {"foreground", no_argument, 0, 'F'},
+       {"pre-checkpoint", no_argument, 0, 'p'},
+       {"prev-checkpoint-dir", required_argument, 0, OPT_PREV_DIR},
        LXC_COMMON_OPTIONS
 };
 
@@ -91,6 +97,14 @@ static int my_parser(struct lxc_arguments *args, int c, char 
*arg)
                args->daemonize = 0;
                daemonize_set = true;
                break;
+       case 'p':
+               do_pre_checkpoint = true;
+               break;
+       case OPT_PREV_DIR:
+               prev_checkpoint_dir = strdup(arg);
+               if (!prev_checkpoint_dir)
+                       return -1;
+               break;
        }
        return 0;
 }
@@ -107,7 +121,9 @@ lxc-checkpoint checkpoints and restores a container\n\
 Options :\n\
   -n, --name=NAME           NAME for name of the container\n\
   -r, --restore             Restore container\n\
+  -p, --pre-checkpoint      Pre-checkpoint container\n\
   -D, --checkpoint-dir=DIR  directory to save the checkpoint in\n\
+  --prev-checkpoint-dir=DIR directory with previous checkpoint(relative to 
-D)\n\
   -v, --verbose             Enable verbose criu logs\n\
   Checkpoint options:\n\
   -s, --stop                Stop the container after checkpointing.\n\
@@ -131,7 +147,7 @@ bool checkpoint(struct lxc_container *c)
                return false;
        }
 
-       ret = c->checkpoint(c, checkpoint_dir, stop, verbose);
+       ret = c->checkpoint(c, checkpoint_dir, prev_checkpoint_dir, stop, 
verbose);
        lxc_container_put(c);
 
        if (!ret) {
@@ -142,6 +158,27 @@ bool checkpoint(struct lxc_container *c)
        return true;
 }
 
+bool pre_checkpoint(struct lxc_container *c)
+{
+       bool ret;
+
+       if (!c->is_running(c)) {
+               fprintf(stderr, "%s not running, not pre-checkpointing.\n", 
my_args.name);
+               lxc_container_put(c);
+               return false;
+       }
+
+       ret = c->pre_checkpoint(c, checkpoint_dir, prev_checkpoint_dir, 
verbose);
+       lxc_container_put(c);
+
+       if (!ret) {
+               fprintf(stderr, "Pre-checkpointing %s failed.\n", my_args.name);
+               return false;
+       }
+
+       return true;
+}
+
 bool restore_finalize(struct lxc_container *c)
 {
        bool ret = c->restore(c, checkpoint_dir, verbose);
@@ -229,6 +266,8 @@ int main(int argc, char *argv[])
 
        if (do_restore)
                ret = restore(c);
+       else if (do_pre_checkpoint)
+               ret = pre_checkpoint(c);
        else
                ret = checkpoint(c);
 
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 1c103e8..5e15a1b 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -380,6 +380,16 @@ static rettype fnname(struct lxc_container *c, t1 a1, t2 
a2, t3 a3)        \
        return ret;                                                     \
 }
 
+#define WRAP_API_4(rettype, fnname, t1, t2, t3, t4)                    \
+static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3, t4 a4)\
+{                                                                      \
+       rettype ret;                                                    \
+       current_config = c ? c->lxc_conf : NULL;                        \
+       ret = do_##fnname(c, a1, a2, a3, a4);                           \
+       current_config = NULL;                                          \
+       return ret;                                                     \
+}
+
 WRAP_API(bool, lxcapi_is_defined)
 
 static const char *do_lxcapi_state(struct lxc_container *c)
@@ -3712,7 +3722,7 @@ static bool do_lxcapi_detach_interface(struct 
lxc_container *c, const char *ifna
 
 WRAP_API_2(bool, lxcapi_detach_interface, const char *, const char *)
 
-static bool do_lxcapi_checkpoint(struct lxc_container *c, char *directory, 
bool stop, bool verbose)
+static bool do_lxcapi_checkpoint(struct lxc_container *c, char *directory, 
char *prev_dir, bool stop, bool verbose)
 {
        pid_t pid;
        int status;
@@ -3745,6 +3755,7 @@ static bool do_lxcapi_checkpoint(struct lxc_container *c, 
char *directory, bool
 
                os.action = "dump";
                os.directory = directory;
+               os.prev_dir = prev_dir;
                os.c = c;
                os.stop = stop;
                os.verbose = verbose;
@@ -3767,7 +3778,61 @@ static bool do_lxcapi_checkpoint(struct lxc_container 
*c, char *directory, bool
        }
 }
 
-WRAP_API_3(bool, lxcapi_checkpoint, char *, bool, bool)
+WRAP_API_4(bool, lxcapi_checkpoint, char *, char *, bool, bool)
+
+static bool do_lxcapi_pre_checkpoint(struct lxc_container *c, char *directory, 
char *prev_dir, bool verbose)
+{
+       pid_t pid;
+       int status;
+       char path[PATH_MAX];
+
+       if (!criu_ok(c))
+               return false;
+
+       if (mkdir(directory, 0700) < 0 && errno != EEXIST)
+               return false;
+
+       status = snprintf(path, sizeof(path), "%s/inventory.img", directory);
+       if (status < 0 || status >= sizeof(path))
+               return false;
+
+       if (access(path, F_OK) == 0) {
+               ERROR("please use a fresh directory for the dump directory\n");
+               return false;
+       }
+
+       pid = fork();
+       if (pid < 0)
+               return false;
+
+       if (pid == 0) {
+               struct criu_opts os;
+
+               os.action = "pre-dump";
+               os.directory = directory;
+               os.prev_dir = prev_dir;
+               os.c = c;
+               os.verbose = verbose;
+
+               /* exec_criu() returning is an error */
+               exec_criu(&os);
+               exit(1);
+       } else {
+               pid_t w = waitpid(pid, &status, 0);
+               if (w == -1) {
+                       SYSERROR("waitpid");
+                       return false;
+               }
+
+               if (WIFEXITED(status)) {
+                       return !WEXITSTATUS(status);
+               }
+
+               return false;
+       }
+}
+
+WRAP_API_3(bool, lxcapi_pre_checkpoint, char *, char *, bool)
 
 static bool do_lxcapi_restore(struct lxc_container *c, char *directory, bool 
verbose)
 {
@@ -3966,6 +4031,7 @@ struct lxc_container *lxc_container_new(const char *name, 
const char *configpath
        c->detach_interface = lxcapi_detach_interface;
        c->checkpoint = lxcapi_checkpoint;
        c->restore = lxcapi_restore;
+       c->pre_checkpoint = lxcapi_pre_checkpoint;
 
        return c;
 
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index d60e19a..1faded2 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -773,7 +773,7 @@ struct lxc_container {
         * \return \c true on success, else \c false.
         * present at compile time).
         */
-       bool (*checkpoint)(struct lxc_container *c, char *directory, bool stop, 
bool verbose);
+       bool (*checkpoint)(struct lxc_container *c, char *directory, char 
*prev_dir, bool stop, bool verbose);
 
        /*!
         * \brief Restore a container from a checkpoint.
@@ -808,6 +808,19 @@ struct lxc_container {
        bool (*snapshot_destroy_all)(struct lxc_container *c);
 
        /* Post LXC-1.1 additions */
+
+       /*!
+        * \brief Pre-checkpoint a container.
+        *
+        * \param c Container.
+        * \param directory The directory to dump the container to.
+        * \param prev_dir The directory with previous dump.
+        * \param verbose Enable criu's verbose logs.
+        *
+        * \return \c true on success, else \c false.
+        * present at compile time).
+        */
+       bool (*pre_checkpoint)(struct lxc_container *c, char *directory, char 
*prev_dir, bool verbose);
 };
 
 /*!
-- 
2.1.0

_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to