[CRIU] [PATCH] Introducing the --check-only option

Adrian Reber adrian at lisas.de
Thu Oct 6 08:32:48 PDT 2016


From: Adrian Reber <areber at redhat.com>

Talking about criu a common question is, if it is possible to know if a
checkpoint and restore will actually work. Running 'criu dump' with
--leave-running to see if the checkpointing will work and then running
'criu restore' is always an option. If one of those operations (either
'dump' or 'restore') will fail the chances are high that there are
problems with checkpointing or restoring. But a lot of memory might have
already been dumped to disk and transferred to the destination system
which is not necessary to test for a restore failure. If the restore,
however, works the problem exists that the source process has been told
to keep on running (--leave-running) which might be an undesired
situation to have the process now running on the source and destination
system. To avoid a situation like this and to give an easier option to
test if 'criu dump' and 'criu restore' will work, this patch introduces
the '--check-only' option:

 source system:
  # criu dump --check-only -D /tmp/cp -t <PID>
  Only checking if requested operation will succeed
  # rsync -a /tmp/cp dest-system:/tmp

 destination system:
  # criu restore -D /tmp/cp
  Checking mode enabled

criu will detect if a checkpoint is a 'check-only' checkpoint and the
restore will automatically run in '--check-only' mode.

It is also possible to use the '--check-only' switch on a full
checkpoint to see if the restore will succeed and making sure at the
same time that the process will not start running:

 destination system:
  # criu restore --check-only -D /tmp/cp
  Only checking if requested operation will succeed
  Checking mode enabled

Right now only the existing checks (e.g., check binary size) are run in
'check-only' mode but additional checks could be added like:

 * checksums of binaries
 * checksums of used libraries
 * available memory

Signed-off-by: Adrian Reber <areber at redhat.com>
---
 Documentation/criu.txt    | 21 +++++++++++++++++++++
 criu/cr-restore.c         | 14 +++++++++-----
 criu/crtools.c            |  9 +++++++++
 criu/image.c              | 10 ++++++++++
 criu/include/cr_options.h |  1 +
 criu/include/restorer.h   |  2 ++
 criu/mem.c                |  9 +++++++++
 criu/pie/restorer.c       |  9 +++++++++
 images/inventory.proto    |  1 +
 9 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/Documentation/criu.txt b/Documentation/criu.txt
index 48331d7..86d6f58 100644
--- a/Documentation/criu.txt
+++ b/Documentation/criu.txt
@@ -262,6 +262,15 @@ For example, the command line for the above example should look like this:
     engine's default directory for tasks, permissions will not be preserved on
     the upper directories with no tasks in them, which may cause problems.
 
+*--check-only*::
+    Check if the checkpoint operation will actually succeed. An almost
+    complete checkpoint of the specified processes will be performed, except
+    that memory pages will not be dumped to disk. The checkpoint will be
+    marked as a *check-only* checkpoint and *criu* will detect during restore
+    that not a full restore should be performed but only a *check-only*
+    restore. In addition to not dumping memory pages, the checkpointed process
+    will continue running.
+
 *restore*
 ~~~~~~~~~
 Restores previously checkpointed processes.
@@ -366,6 +375,18 @@ The 'mode' may be one of the following:
     *none*:::   Ignore capabilities. Most dangerous mode. The behaviour is
                 implementation dependent. Try to not use it until really
                 required.
+
+*--check-only*::
+    Check if the restore operation will actually succeed. If a checkpoint
+    is a *check-only* checkpoint will be automatically detected by *criu*.
+    A *check-only* checkpoint does not include any memory pages in the dump.
+    This option is therefore only required if a normal (not *check-only*)
+    checkpoint should be used to run in *check-only* mode.
+    A restore in *check-only* mode skips copying the memory pages to the
+    restored process but all other steps to verify that the restore would
+    succeed are performed as if it would be a real restore. Just before
+    giving control to the restored process the restore is aborted as the
+    restored process will crash without its memory pages.
 +
 For example, this option can be used in case *--cpu-cap=cpu* was used
 during *dump*, and images are migrated to a less capable CPU and are
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index a323df9..4459b4c 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -1939,14 +1939,14 @@ static int restore_root_task(struct pstree_item *init)
 	pr_info("Restore finished successfully. Resuming tasks.\n");
 	futex_set_and_wake(&task_entries->start, CR_STATE_COMPLETE);
 
-	if (ret == 0)
+	if (!opts.check_only && ret == 0)
 		ret = parasite_stop_on_syscall(task_entries->nr_threads,
 			__NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag);
 
-	if (clear_breakpoints())
+	if (!opts.check_only && clear_breakpoints())
 		pr_err("Unable to flush breakpoints\n");
 
-	if (ret == 0)
+	if (!opts.check_only && ret == 0)
 		finalize_restore();
 
 	if (restore_freezer_state())
@@ -1954,8 +1954,9 @@ static int restore_root_task(struct pstree_item *init)
 
 	fini_cgroup();
 
-	/* Detaches from processes and they continue run through sigreturn. */
-	finalize_restore_detach(ret);
+	if (!opts.check_only)
+		/* Detaches from processes and they continue run through sigreturn. */
+		finalize_restore_detach(ret);
 
 	write_stats(RESTORE_STATS);
 
@@ -3033,6 +3034,9 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
 		task_args->seccomp_mode = core->tc->seccomp_mode;
 
 	task_args->compatible_mode = core_is_compat(core);
+
+	if (opts.check_only)
+		task_args->check_only = true;
 	/*
 	 * Arguments for task restoration.
 	 */
diff --git a/criu/crtools.c b/criu/crtools.c
index 0e853ee..73d152a 100644
--- a/criu/crtools.c
+++ b/criu/crtools.c
@@ -279,6 +279,7 @@ int main(int argc, char *argv[], char *envp[])
 		{ "cgroup-dump-controller",	required_argument,	0, 1082	},
 		{ SK_INFLIGHT_PARAM,		no_argument,		0, 1083	},
 		{ "deprecated",			no_argument,		0, 1084 },
+		{ "check-only",			no_argument,		0, 1085 },
 		{ },
 	};
 
@@ -594,6 +595,11 @@ int main(int argc, char *argv[], char *envp[])
 			pr_msg("Turn deprecated stuff ON\n");
 			opts.deprecated_ok = true;
 			break;
+		case 1085:
+			pr_msg("Only checking if requested operation will succeed\n");
+			opts.check_only = true;
+			opts.final_state = TASK_ALIVE;
+			break;
 		case 'V':
 			pr_msg("Version: %s\n", CRIU_VERSION);
 			if (strcmp(CRIU_GITID, "0"))
@@ -827,6 +833,9 @@ usage:
 "                        this requires running a second instance of criu\n"
 "                        in lazy-pages mode: 'criu lazy-pages -D DIR'\n"
 "                        --lazy-pages and lazy-pages mode require userfaultfd\n"
+"  --check-only          check if checkpointing/restoring will actually work\n"
+"                        the process will keep on running and memory pages\n"
+"                        will not be dumped\n"
 "\n"
 "* External resources support:\n"
 "  --external RES        dump objects from this list as external resources:\n"
diff --git a/criu/image.c b/criu/image.c
index a3bb285..7cee4ce 100644
--- a/criu/image.c
+++ b/criu/image.c
@@ -72,6 +72,12 @@ int check_img_inventory(void)
 		goto out_err;
 	}
 
+	if (!opts.check_only && he->has_check_only)
+		opts.check_only = he->check_only;
+
+	if (opts.check_only)
+		pr_msg("Checking mode enabled\n");
+
 	ret = 0;
 
 out_err:
@@ -114,6 +120,10 @@ int prepare_inventory(InventoryEntry *he)
 	he->ns_per_id = true;
 	he->has_ns_per_id = true;
 	he->lsmtype = host_lsm_type();
+	if (opts.check_only) {
+		he->has_check_only = true;
+		he->check_only = true;
+	}
 
 	crt.i.pid.state = TASK_ALIVE;
 	crt.i.pid.real = getpid();
diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h
index 8a9427b..51aee66 100644
--- a/criu/include/cr_options.h
+++ b/criu/include/cr_options.h
@@ -114,6 +114,7 @@ struct cr_options {
 	 * to turn one ON while the code is in.
 	 */
 	bool			deprecated_ok;
+	bool			check_only;
 };
 
 extern struct cr_options opts;
diff --git a/criu/include/restorer.h b/criu/include/restorer.h
index c74d25f..bfa3e8f 100644
--- a/criu/include/restorer.h
+++ b/criu/include/restorer.h
@@ -177,6 +177,8 @@ struct task_restore_args {
 
 	bool				compatible_mode;
 
+	bool				check_only;
+
 #ifdef CONFIG_VDSO
 	unsigned long			vdso_rt_size;
 	struct vdso_symtable		vdso_sym_rt;		/* runtime vdso symbols */
diff --git a/criu/mem.c b/criu/mem.c
index 6e6fcc2..2436229 100644
--- a/criu/mem.c
+++ b/criu/mem.c
@@ -269,6 +269,9 @@ static int xfer_pages(struct page_pipe *pp, struct page_xfer *xfer, bool lazy)
 {
 	int ret;
 
+	if (opts.check_only)
+		return 0;
+
 	/*
 	 * Step 3 -- write pages into image (or delay writing for
 	 *           pre-dump action (see pre_dump_one_task)
@@ -294,6 +297,9 @@ static int __parasite_dump_pages_seized(struct pstree_item *item,
 	unsigned cpp_flags = 0;
 	unsigned long pmc_size;
 
+	if (opts.check_only)
+		return 0;
+
 	pr_info("\n");
 	pr_info("Dumping pages (type: %d pid: %d)\n", CR_FD_PAGES, item->pid.real);
 	pr_info("----------------------------------------\n");
@@ -717,6 +723,9 @@ static int restore_priv_vma_content(struct pstree_item *t)
 	unsigned long va;
 	struct page_read pr;
 
+	if (opts.check_only)
+		return 0;
+
 	vma = list_first_entry(vmas, struct vma_area, list);
 
 	ret = open_page_read(t->pid.virt, &pr, PR_TASK);
diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c
index 37e9500..b7741f6 100644
--- a/criu/pie/restorer.c
+++ b/criu/pie/restorer.c
@@ -1237,6 +1237,8 @@ long __export_restore_task(struct task_restore_args *args)
 	 * Proxify vDSO.
 	 */
 	for (i = 0; i < args->vmas_n; i++) {
+		if (args->check_only)
+			break;
 		if (vma_entry_is(&args->vmas[i], VMA_AREA_VDSO) ||
 		    vma_entry_is(&args->vmas[i], VMA_AREA_VVAR)) {
 			if (vdso_proxify("dumpee", &args->vdso_sym_rt,
@@ -1525,6 +1527,13 @@ long __export_restore_task(struct task_restore_args *args)
 
 	restore_finish_stage(task_entries_local, CR_STATE_RESTORE_CREDS);
 
+	if (args->check_only) {
+		pr_info("Restore check was successful.\n");
+		futex_abort_and_wake(&task_entries_local->nr_in_progress);
+		return 0;
+	}
+
+
 	if (ret)
 		BUG();
 
diff --git a/images/inventory.proto b/images/inventory.proto
index f1b01f7..5bc3db2 100644
--- a/images/inventory.proto
+++ b/images/inventory.proto
@@ -15,4 +15,5 @@ message inventory_entry {
 	optional bool			ns_per_id	= 4;
 	optional uint32			root_cg_set	= 5;
 	optional lsmtype		lsmtype		= 6;
+	optional bool			check_only	= 7;
 }
-- 
2.9.3



More information about the CRIU mailing list