[CRIU] [PATCH] criu: Add exec-cmd option (v2)

Deyan Doychev deyan at 1h.com
Thu Mar 20 09:24:31 PDT 2014


From: Deyan Doychev <deyandoichev at gmail.com>

The --exec-cmd option specifies a command that will be execvp()-ed on successful
restore. This way the command specified here will become the parent process of
the restored process tree.

When this option is specified criu will fork to become a daemon before it starts
restoring the processes. It also implies the -d option so waiting for the
restored processes to finish is responsibility of the command specified here.

This option will be used when restoring LinuX Containers and it seems helpful
for perf or other use cases when restored processes must be supervised by a
parent.

Two directions were researched in order to integrate CRIU and LXC:

1. We tell to CRIU, that after restoring container is should execve()
   lxc properly explaining to it that there's a new container hanging
   around.

2. We make LXC set himself as child subreaper, then fork() criu and ask
   it to detach (-d) from restore container afterwards. Being a subreaper,
   it should get the container's init into his child list after it.

The main reason for choosing the first option is that the second one can't work
with the RPC service. If we call restore via the service then criu service will
be the top-most task in the hierarchy and will not be able to reparent the
restore trees to any other task in the system. Calling execve from service
worker sub-task (and daemonizing it) should solve this.

Signed-off-by: Deyan Doychev <deyandoichev at gmail.com>
---
 cr-restore.c         |    5 ++++-
 cr-service.c         |   22 ++++++++++++++++++++++
 crtools.c            |   33 ++++++++++++++++++++++++++++++++-
 include/cr_options.h |    1 +
 lib/criu.c           |    5 +++++
 protobuf/rpc.proto   |    1 +
 6 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index b352daa..6b3bf10 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1552,7 +1552,7 @@ static int restore_root_task(struct pstree_item *init)
 
 	write_stats(RESTORE_STATS);
 
-	if (!opts.restore_detach)
+	if (!opts.restore_detach && !opts.exec_cmd)
 		wait(NULL);
 
 	return 0;
@@ -1600,6 +1600,9 @@ int cr_restore_tasks(void)
 {
 	int ret = -1;
 
+	if (opts.exec_cmd && opts.restore_detach && daemon(1, 0))
+		return -1;
+
 	if (cr_plugin_init())
 		return -1;
 
diff --git a/cr-service.c b/cr-service.c
index 46a1004..22b7647 100644
--- a/cr-service.c
+++ b/cr-service.c
@@ -265,6 +265,19 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 	if (req->has_force_irmap)
 		opts.force_irmap = req->force_irmap;
 
+	if (req->exec_cmd) {
+		int i;
+		int count = 1;
+
+		for (i = strlen(req->exec_cmd); i >= 0; i--)
+			if (strchr(" \t\r\n", req->exec_cmd[i]))
+				count++;
+
+		opts.exec_cmd = xmalloc(count * sizeof(char *));
+		opts.exec_cmd[0] = strtok(req->exec_cmd, " \t\r\n");
+		for (i = 1; (opts.exec_cmd[i] = strtok(NULL, " \t\r\n")); i++);
+	}
+
 	if (req->ps) {
 		opts.use_page_server = true;
 		opts.addr = req->ps->address;
@@ -342,6 +355,7 @@ static int restore_using_req(int sk, CriuOpts *req)
 		goto exit;
 
 	success = true;
+
 exit:
 	if (send_criu_restore_resp(sk, success,
 				   root_item ? root_item->pid.real : -1) == -1) {
@@ -349,6 +363,13 @@ exit:
 		success = false;
 	}
 
+	if (success && opts.exec_cmd) {
+		close(sk);
+		execvp(opts.exec_cmd[0], opts.exec_cmd);
+		pr_perror("Failed to exec cmd %s", opts.exec_cmd[0]);
+		success = false;
+	}
+
 	return success ? 0 : 1;
 }
 
@@ -657,6 +678,7 @@ int cr_service(bool daemon_mode)
 			close(server_fd);
 			ret = cr_service_work(sk);
 			close(sk);
+
 			exit(ret != 0);
 		}
 
diff --git a/crtools.c b/crtools.c
index 047ac53..d6235fa 100644
--- a/crtools.c
+++ b/crtools.c
@@ -119,6 +119,7 @@ int main(int argc, char *argv[])
 	pid_t pid = 0, tree_id = 0;
 	int ret = -1;
 	bool usage_error = true;
+	bool has_exec_cmd = false;
 	int opt, idx;
 	int log_level = LOG_UNSET;
 	char *imgs_dir = ".";
@@ -162,6 +163,7 @@ int main(int argc, char *argv[])
 		{ "libdir", required_argument, 0, 'L'},
 		{ "cpu-cap", required_argument, 0, 57},
 		{ "force-irmap", no_argument, 0, 58},
+		{ "exec-cmd", no_argument, 0, 59},
 		{ },
 	};
 
@@ -333,6 +335,9 @@ int main(int argc, char *argv[])
 		case 'L':
 			opts.libdir = optarg;
 			break;
+		case 59:
+			has_exec_cmd = true;
+			break;
 		case 'V':
 			pr_msg("Version: %s\n", CRIU_VERSION);
 			if (strcmp(CRIU_GITID, "0"))
@@ -354,6 +359,22 @@ int main(int argc, char *argv[])
 		goto usage;
 	}
 
+	if (has_exec_cmd) {
+		if (argc - optind <= 1) {
+			pr_msg("Error: --exec-cmd requires a command\n");
+			goto usage;
+		}
+
+		if (strcmp(argv[optind], "restore")) {
+			pr_msg("Error: --exec-cmd is available for the restore command only\n");
+			goto usage;
+		}
+
+		opts.exec_cmd = xmalloc((argc - optind) * sizeof(char *));
+		memcpy(opts.exec_cmd, &argv[optind + 1], (argc - optind - 1) * sizeof(char *));
+		opts.exec_cmd[argc - optind - 1] = NULL;
+	}
+
 	/* We must not open imgs dir, if service is called */
 	if (strcmp(argv[optind], "service")) {
 		ret = open_image_dir(imgs_dir);
@@ -390,7 +411,15 @@ int main(int argc, char *argv[])
 	if (!strcmp(argv[optind], "restore")) {
 		if (tree_id)
 			pr_warn("Using -t with criu restore is obsoleted\n");
-		return cr_restore_tasks() != 0;
+
+		ret = cr_restore_tasks();
+		if (ret == 0 && opts.exec_cmd) {
+			execvp(opts.exec_cmd[0], opts.exec_cmd);
+			pr_perror("Failed to exec command %s", opts.exec_cmd[0]);
+			ret = 1;
+		}
+
+		return ret != 0;
 	}
 
 	if (!strcmp(argv[optind], "show"))
@@ -460,6 +489,8 @@ usage:
 "                        (if not specified, value of --images-dir is used)\n"
 "     --cpu-cap CAP      require certain cpu capability. CAP: may be one of:\n"
 "                        'fpu','all'. To disable capability, prefix it with '^'.\n"
+"     --exec-cmd         execute the command specified after '--' on successful\n"
+"                        restore making it the parent of the restored process\n"
 "\n"
 "* Special resources support:\n"
 "  -x|--" USK_EXT_PARAM "      allow external unix connections\n"
diff --git a/include/cr_options.h b/include/cr_options.h
index 782b866..f2106b0 100644
--- a/include/cr_options.h
+++ b/include/cr_options.h
@@ -48,6 +48,7 @@ struct cr_options {
 	bool			auto_dedup;
 	unsigned int		cpu_cap;
 	bool			force_irmap;
+	char			**exec_cmd;
 };
 
 extern struct cr_options opts;
diff --git a/lib/criu.c b/lib/criu.c
index 33927e8..77fdf10 100644
--- a/lib/criu.c
+++ b/lib/criu.c
@@ -110,6 +110,11 @@ void criu_set_cpu_cap(unsigned int cap)
 	opts->cpu_cap		= cap;
 }
 
+void criu_set_exec_cmd(char *cmdline)
+{
+	opts->exec_cmd = strdup(cmdline);
+}
+
 static CriuResp *recv_resp(int socket_fd)
 {
 	unsigned char buf[CR_MAX_MSG_SIZE];
diff --git a/protobuf/rpc.proto b/protobuf/rpc.proto
index 97f51fc..3e061b9 100644
--- a/protobuf/rpc.proto
+++ b/protobuf/rpc.proto
@@ -37,6 +37,7 @@ message criu_opts {
 
 	optional uint32			cpu_cap		= 20 [default = 0xffffffff];
 	optional bool			force_irmap	= 21;
+	optional string			exec_cmd	= 22;
 }
 
 message criu_dump_resp {
-- 
1.7.1



More information about the CRIU mailing list