From 9f99a33fa97a81d395b6522fe7bd51e0ef6af454 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 14 Nov 2016 14:44:04 +0000 Subject: [PATCH] lxc-checkpoint: enable dirty memory tracking in criu CRIU supports dirty memory tracking to take incremental checkpoints. Incremental checkpoints are one way of reducing downtime during migration. The first checkpoint dumps all the memory pages and the second (and third, and fourth, ...) only dumps pages which have changed. Most of the necessary code has already been implemented. This just adds the existing functionality to lxc-checkpoint: -p, --pre-dump Only pre-dump the memory of the container. Container keeps on running and following checkpoints will only dump the changes. --predump-dir=DIR path to images from previous dump (relative to -D) The following is an example from a container running CentOS 7 with psql and tomcat: # lxc-checkpoint -n c7 -D /tmp/cp -p Container keeps on running # du -h /tmp/cp 229M /tmp/cp Sync initial checkpoint to destination # rsync -a /tmp/cp host2:/tmp/ Sync file-system # rsync -a /var/lib/lxc/c7 host2:/var/lib/lxc/ Final dump; container is stopped # lxc-checkpoint -n c7 -D /tmp/cp --predump-dir=../cp -s # du -h /tmp/cp2 90M /tmp/cp2 After transferring the second (incremental checkpoint) and the changes to the container's file system the container can be restored on the second host by pointing lxc-checkpoint to the second checkpoint directory: # lxc-checkpoint -n c7 -D /tmp/cp2 -r Signed-off-by: Adrian Reber --- src/lxc/criu.c | 1 + src/lxc/tools/lxc_checkpoint.c | 43 ++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/lxc/criu.c b/src/lxc/criu.c index 5456cc1e6..9523af3b4 100644 --- a/src/lxc/criu.c +++ b/src/lxc/criu.c @@ -398,6 +398,7 @@ static void exec_criu(struct criu_opts *opts) if (opts->user->predump_dir) { DECLARE_ARG("--prev-images-dir"); DECLARE_ARG(opts->user->predump_dir); + DECLARE_ARG("--track-mem"); } if (opts->user->pageserver_address && opts->user->pageserver_port) { diff --git a/src/lxc/tools/lxc_checkpoint.c b/src/lxc/tools/lxc_checkpoint.c index 462aba3ee..eeddf5916 100644 --- a/src/lxc/tools/lxc_checkpoint.c +++ b/src/lxc/tools/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 bool pre_dump = false; +static char *predump_dir = NULL; + +#define OPT_PREDUMP_DIR OPT_USAGE+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-dump", no_argument, 0, 'p'}, + {"predump-dir", required_argument, 0, OPT_PREDUMP_DIR}, LXC_COMMON_OPTIONS }; @@ -63,6 +69,11 @@ static int my_checker(const struct lxc_arguments *args) return -1; } + if (pre_dump && do_restore) { + lxc_error(args, "-p not compatible with -r."); + return -1; + } + return 0; } @@ -91,6 +102,14 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) args->daemonize = 0; daemonize_set = true; break; + case 'p': + pre_dump = true; + break; + case OPT_PREDUMP_DIR: + predump_dir = strdup(arg); + if (!predump_dir) + return -1; + break; } return 0; } @@ -111,6 +130,10 @@ Options :\n\ -v, --verbose Enable verbose criu logs\n\ Checkpoint options:\n\ -s, --stop Stop the container after checkpointing.\n\ + -p, --pre-dump Only pre-dump the memory of the container.\n\ + Container keeps on running and following\n\ + checkpoints will only dump the changes.\n\ + --predump-dir=DIR path to images from previous dump (relative to -D)\n\ Restore options:\n\ -d, --daemon Daemonize the container (default)\n\ -F, --foreground Start with the current tty attached to /dev/console\n\ @@ -124,7 +147,9 @@ Options :\n\ static bool checkpoint(struct lxc_container *c) { + struct migrate_opts opts; bool ret; + int mode; if (!c->is_running(c)) { fprintf(stderr, "%s not running, not checkpointing.\n", my_args.name); @@ -132,10 +157,24 @@ static bool checkpoint(struct lxc_container *c) return false; } - ret = c->checkpoint(c, checkpoint_dir, stop, verbose); + memset(&opts, 0, sizeof(opts)); + + opts.directory = checkpoint_dir; + opts.stop = stop; + opts.verbose = verbose; + opts.predump_dir = predump_dir; + + if (pre_dump) + mode = MIGRATE_PRE_DUMP; + else + mode = MIGRATE_DUMP; + + ret = c->migrate(c, mode, &opts, sizeof(opts)); lxc_container_put(c); - if (!ret) { + /* the migrate() API does not negate the return code like + * checkpoint() and restore() does. */ + if (ret) { fprintf(stderr, "Checkpointing %s failed.\n", my_args.name); return false; } -- 2.47.2