[CRIU] [PATCH] libcriu: add CRIU_COMM_BIN mode

Ruslan Kuprieiev kupruser at gmail.com
Sat Jul 18 19:20:31 PDT 2015


In this mode libcriu will execute criu binary in swrk
mode, so users are not always obliged to run criu service
daemon.

Signed-off-by: Ruslan Kuprieiev <kupruser at gmail.com>
---
 lib/criu.c | 153 ++++++++++++++++++++++++++++++++++++++++++++-----------------
 lib/criu.h |   7 ++-
 2 files changed, 117 insertions(+), 43 deletions(-)

diff --git a/lib/criu.c b/lib/criu.c
index da6288a..8008981 100644
--- a/lib/criu.c
+++ b/lib/criu.c
@@ -16,6 +16,8 @@
 #include "criu.h"
 #include "cr-service-const.h"
 
+#define CR_DEFAULT_SERVICE_BIN "criu"
+
 const char *criu_lib_version = CRIU_VERSION;
 
 static criu_opts *global_opts;
@@ -54,6 +56,19 @@ void criu_set_service_fd(int fd)
 	criu_local_set_service_fd(global_opts, fd);
 }
 
+void criu_local_set_service_bin(criu_opts *opts, char *path)
+{
+	if (path)
+		opts->service_bin = path;
+	else
+		opts->service_bin = CR_DEFAULT_SERVICE_BIN;
+}
+
+void criu_set_service_bin(char *path)
+{
+	criu_local_set_service_bin(global_opts, path);
+}
+
 int criu_local_init_opts(criu_opts **o)
 {
 	criu_opts *opts = NULL;
@@ -663,6 +678,63 @@ static int send_notify_ack(int socket_fd, int ret)
 	return ret ? : send_ret;
 }
 
+static int swrk_connect(criu_opts *opts)
+{
+	int pid;
+	int sks[2];
+
+	if (socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sks)) {
+		perror("Failed to create socket pair");
+		return -1;
+	}
+
+	/*
+	 * Can't setup a SIGCHLD handler here, as it
+	 * would alter signal handlers of the caller.
+	 */
+
+	pid = fork();
+	if (pid < 0) {
+		perror("Failed to fork");
+		return -1;
+	}
+
+	if (pid == 0) {
+		sigset_t mask;
+		char fds[11];
+
+		/*
+		 * Unblock SIGCHLD.
+		 *
+		 * The caller of this function is supposed to have
+		 * this signal blocked. Otherwise it risks to get
+		 * into situation, when this routine is not yet
+		 * returned, but the restore subtree exits and
+		 * emits the SIGCHLD.
+		 *
+		 * In turn, unblocked SIGCHLD is required to make
+		 * criu restoration process work -- it catches
+		 * subtasks restore errors in this handler.
+		 */
+
+		sigemptyset(&mask);
+		sigaddset(&mask, SIGCHLD);
+		sigprocmask(SIG_UNBLOCK, &mask, NULL);
+
+		close(sks[0]);
+		sprintf(fds, "%d", sks[1]);
+
+		execlp(opts->service_bin, opts->service_bin, "swrk", fds, NULL);
+		perror("Can't exec criu swrk");
+		exit(1);
+	}
+
+	close(sks[1]);
+	opts->swrk_pid = pid;
+
+	return sks[0];
+}
+
 static int criu_connect(criu_opts *opts)
 {
 	int fd, ret;
@@ -671,6 +743,8 @@ static int criu_connect(criu_opts *opts)
 
 	if (opts->service_comm == CRIU_COMM_FD)
 		return opts->service_fd;
+	else if (opts->service_comm == CRIU_COMM_BIN)
+		return swrk_connect(opts);
 
 	fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
 	if (fd < 0) {
@@ -759,6 +833,11 @@ static int send_req_and_recv_resp(criu_opts *opts, CriuReq *req, CriuResp **resp
 	return ret;
 }
 
+static void swrk_wait(criu_opts *opts)
+{
+	waitpid(opts->swrk_pid, NULL, 0);
+}
+
 int criu_local_check(criu_opts *opts)
 {
 	int ret = -1;
@@ -779,6 +858,8 @@ exit:
 	if (resp)
 		criu_resp__free_unpacked(resp, NULL);
 
+	swrk_wait(opts);
+
 	errno = saved_errno;
 
 	return ret;
@@ -816,6 +897,8 @@ exit:
 	if (resp)
 		criu_resp__free_unpacked(resp, NULL);
 
+	swrk_wait(opts);
+
 	errno = saved_errno;
 
 	return ret;
@@ -885,6 +968,8 @@ exit:
 	if (resp)
 		criu_resp__free_unpacked(resp, NULL);
 
+	swrk_wait(opts);
+
 	errno = saved_errno;
 
 	return ret;
@@ -919,6 +1004,8 @@ exit:
 	if (resp)
 		criu_resp__free_unpacked(resp, NULL);
 
+	swrk_wait(opts);
+
 	errno = saved_errno;
 
 	return ret;
@@ -931,59 +1018,44 @@ int criu_restore(void)
 
 int criu_local_restore_child(criu_opts *opts)
 {
-	int sks[2], pid, ret = -1;
+	int fd, ret = -1;
+	enum criu_service_comm saved_comm;
+	char *saved_comm_data;
+	bool save_comm;
 	CriuReq req	= CRIU_REQ__INIT;
 	CriuResp *resp	= NULL;
 
-	if (socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sks))
-		goto out;
-
-	pid = fork();
-	if (pid < 0)
-		goto err;
-
-	if (pid == 0) {
-		sigset_t mask;
-		char fds[11];
+	saved_errno = 0;
 
-		/*
-		 * Unblock SIGCHLD.
-		 *
-		 * The caller of this function is supposed to have
-		 * this signal blocked. Otherwise it risks to get
-		 * into situation, when this routine is not yet
-		 * returned, but the restore subtree exits and
-		 * emits the SIGCHLD.
-		 *
-		 * In turn, unblocked SIGCHLD is required to make
-		 * criu restoration process work -- it catches
-		 * subtasks restore errors in this handler.
-		 */
+	save_comm = opts->service_comm != CRIU_COMM_BIN;
+	if (save_comm) {
+		/* Save comm data */
+		saved_comm = opts->service_comm;
+		saved_comm_data = opts->service_address;
 
-		sigemptyset(&mask);
-		sigaddset(&mask, SIGCHLD);
-		sigprocmask(SIG_UNBLOCK, &mask, NULL);
+		opts->service_comm = CRIU_COMM_BIN;
+		opts->service_bin = CR_DEFAULT_SERVICE_BIN;
+	}
 
-		close(sks[0]);
-		sprintf(fds, "%d", sks[1]);
+	fd = swrk_connect(opts);
+	if (fd < 0)
+		goto out;
 
-		execlp("criu", "criu", "swrk", fds, NULL);
-		perror("Can't exec criu swrk");
-		exit(1);
+	if (save_comm) {
+		/* Restore comm data */
+		opts->service_comm = saved_comm;
+		opts->service_address = saved_comm_data;
 	}
 
-	close(sks[1]);
-
 	req.type	= CRIU_REQ_TYPE__RESTORE;
 	req.opts	= opts->rpc;
 
 	req.opts->has_rst_sibling = true;
 	req.opts->rst_sibling = true;
 
-	ret = send_req_and_recv_resp_sk(sks[0], opts, &req, &resp);
+	ret = send_req_and_recv_resp_sk(fd, opts, &req, &resp);
 
-	close(sks[0]);
-	waitpid(pid, NULL, 0);
+	swrk_wait(opts);
 
 	if (!ret) {
 		ret = resp->success ? resp->restore->pid : -EBADE;
@@ -991,12 +1063,9 @@ int criu_local_restore_child(criu_opts *opts)
 	}
 
 out:
-	return ret;
+	errno = saved_errno;
 
-err:
-	close(sks[1]);
-	close(sks[0]);
-	goto out;
+	return ret;
 }
 
 int criu_restore_child(void)
diff --git a/lib/criu.h b/lib/criu.h
index 81d3396..ef3a886 100644
--- a/lib/criu.h
+++ b/lib/criu.h
@@ -23,11 +23,13 @@
 
 enum criu_service_comm {
 	CRIU_COMM_SK,
-	CRIU_COMM_FD
+	CRIU_COMM_FD,
+	CRIU_COMM_BIN
 };
 
 void criu_set_service_address(char *path);
 void criu_set_service_fd(int fd);
+void criu_set_service_bin(char *path);
 
 /*
  * You can choose if you want libcriu to connect to service socket
@@ -141,13 +143,16 @@ typedef struct {
 	union {
 		char		*service_address;
 		int		service_fd;
+		char		*service_bin;
 	};
+	int			swrk_pid;
 } criu_opts;
 
 int criu_local_init_opts(criu_opts **opts);
 
 void criu_local_set_service_address(criu_opts *opts, char *path);
 void criu_local_set_service_fd(criu_opts *opts, int fd);
+void criu_local_set_service_bin(criu_opts *opts, char *path);
 void criu_local_set_service_comm(criu_opts *opts, enum criu_service_comm);
 
 void criu_local_set_service_fd(criu_opts *opts, int fd);
-- 
2.1.0



More information about the CRIU mailing list