[CRIU] [PATCH 3/8] cr-restore: set cr_error to EEXIST if such pid already exists

Ruslan Kuprieiev kupruser at gmail.com
Mon Dec 1 14:52:38 PST 2014


This is a very common error when using criu.

The problem here is that we need to somehow transfer cr_errno
from one process to another. I suggest using pipe to give
one end to children and read cr_errno on other after restore
is finished.

Signed-off-by: Ruslan Kuprieiev <kupruser at gmail.com>
---
 cr-restore.c         | 40 ++++++++++++++++++++++++++++++++++++++++
 crtools.c            |  1 +
 include/cr-errno.h   |  1 +
 include/cr_options.h |  1 +
 4 files changed, 43 insertions(+)

diff --git a/cr-restore.c b/cr-restore.c
index 93a6ca6..08b8b66 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -85,6 +85,8 @@
 
 #include "asm/restore.h"
 
+#include "cr-errno.h"
+
 static struct pstree_item *current;
 
 static int restore_task_with_children(void *);
@@ -1412,6 +1414,10 @@ static int restore_task_with_children(void *_arg)
 	pid = getpid();
 	if (current->pid.virt != pid) {
 		pr_err("Pid %d do not match expected %d\n", pid, current->pid.virt);
+		cr_errno = EEXIST;
+		ret = write(opts.errno_fd, &cr_errno, sizeof(cr_errno));
+		if (ret != sizeof(cr_errno))
+			pr_perror("Can't send cr_errno");
 		goto err;
 	}
 
@@ -1501,6 +1507,9 @@ err_fini_mnt:
 		fini_mnt_ns();
 
 err:
+	ret = write(opts.errno_fd, &cr_errno, sizeof(cr_errno));
+	if (ret != sizeof(cr_errno))
+		perror("Can't send cr_errno");
 	if (current->parent == NULL)
 		futex_abort_and_wake(&task_entries->nr_in_progress);
 	exit(1);
@@ -1857,9 +1866,29 @@ static int prepare_task_entries(void)
 	return 0;
 }
 
+static int get_cr_errno_fd(void)
+{
+	int p[2];
+
+	if (pipe(p)) {
+		pr_perror("Can't open pipe for cr_errno");
+		return -1;
+	}
+
+	opts.errno_fd = p[1];
+
+	if (fcntl(p[0], F_SETFL, O_NONBLOCK)) {
+		pr_perror("Can't set O_NONBLOCK on pipe");
+		return -1;
+	}
+
+	return p[0];
+}
+
 int cr_restore_tasks(void)
 {
 	int ret = -1;
+	int cr_errno_fd = -1, count;
 
 	if (cr_plugin_init(CR_PLUGIN_STAGE__RESTORE))
 		return -1;
@@ -1898,12 +1927,23 @@ int cr_restore_tasks(void)
 	if (criu_signals_setup() < 0)
 		goto err;
 
+	cr_errno_fd = get_cr_errno_fd();
+	if (cr_errno_fd < 0)
+		goto err;
+
 	if (restore_root_task(root_item) < 0)
 		goto err;
 
 	ret = prepare_cgroup_properties();
 
 err:
+	if (cr_errno_fd) {
+		count = read(cr_errno_fd, &cr_errno, sizeof(cr_errno));
+		if (count != sizeof(cr_errno) && !(count == -1 && errno == EAGAIN))
+			pr_perror("Can't read cr_errno");
+	}
+	close_safe(&cr_errno_fd);
+	close_safe(&opts.errno_fd);
 	fini_cgroup();
 	cr_plugin_fini(CR_PLUGIN_STAGE__RESTORE, ret);
 	return ret;
diff --git a/crtools.c b/crtools.c
index 0ac667c..3f6231d 100644
--- a/crtools.c
+++ b/crtools.c
@@ -57,6 +57,7 @@ void init_opts(void)
 	opts.cpu_cap = CPU_CAP_DEFAULT;
 	opts.manage_cgroups = false;
 	opts.ps_socket = -1;
+	opts.errno_fd = -1;
 }
 
 static int parse_ns_string(const char *ptr)
diff --git a/include/cr-errno.h b/include/cr-errno.h
index bec72a8..f86bba8 100644
--- a/include/cr-errno.h
+++ b/include/cr-errno.h
@@ -4,6 +4,7 @@ extern int cr_errno;
 /*
  * List of symbolic error names:
  * ESRCH	- no process can be found corresponding to that specified by pid
+ * EEXIST	- process with such pid already exists
  */
 
 #endif /* __CR_ERRNO_H__ */
diff --git a/include/cr_options.h b/include/cr_options.h
index a9f9e92..a32584f 100644
--- a/include/cr_options.h
+++ b/include/cr_options.h
@@ -58,6 +58,7 @@ struct cr_options {
 	char			*new_global_cg_root;
 	struct list_head	new_cgroup_roots;
 	bool			aufs;		/* auto-deteced, not via cli */
+	int			errno_fd;	/* pipe used to trasfer cr_errno */
 };
 
 extern struct cr_options opts;
-- 
1.9.3



More information about the CRIU mailing list