[lxc-devel] [PATCH] lxc-checkpoint: add pre-checkpoint
Ruslan Kuprieiev
kupruser at gmail.com
Thu Jun 25 16:50:55 UTC 2015
Looks like date on my VM got messed-up.
Should I resend?
Sorry.
On 05/19/2015 05:09 AM, Ruslan Kuprieiev wrote:
> 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 <kupruser at 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);
> };
>
> /*!
More information about the lxc-devel
mailing list