[CRIU] [PATCH] [POC][RFC] send inherit-fd descriptors from the criu process

Andrey Vagin avagin at openvz.org
Thu Nov 27 04:20:42 PST 2014


File descriptors are not copied in other processes, so we don't have
conflicts with restored file descriptors.

Opened questions:
* Do we need one more fd type for inherit-fd-s. If we need, how to
  restore properties, which are specific for sockets, pipes, ets
* How to handle a case, when we have two file descriptors for the same
  file, but one opens the file for read-only and other one opens the
  same file for write-only.
* How to handle shared struct-files. When we have a few sets of file
  descriprots, where a "struct file" is shared inside a set. And all
  these "struct file"-s points on the same physical file, fifo, pipe,
  etc.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 cr-restore.c                         | 14 +++++--
 files.c                              | 24 +----------
 include/files.h                      |  8 +++-
 pipes.c                              | 80 +++++++++++++++++++++++++++++-------
 test/zdtm/live/static/Makefile       |  1 +
 test/zdtm/live/static/pipe-inherit.c | 48 ++++++++++++++++++++++
 util.c                               |  7 ----
 7 files changed, 133 insertions(+), 49 deletions(-)
 create mode 100644 test/zdtm/live/static/pipe-inherit.c

diff --git a/cr-restore.c b/cr-restore.c
index 93a6ca6..b614f4f 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1446,9 +1446,6 @@ static int restore_task_with_children(void *_arg)
 		if (close_old_fds(current))
 			goto err_fini_mnt;
 
-		if (root_prepare_shared())
-			goto err_fini_mnt;
-
 		if (restore_finish_stage(CR_STATE_RESTORE_SHARED) < 0)
 			goto err_fini_mnt;
 	}
@@ -1665,6 +1662,7 @@ static void ignore_kids(void)
 		pr_perror("Restoring CHLD sigaction failed");
 }
 
+extern int inherit_fd_send(int pid);
 static int restore_root_task(struct pstree_item *init)
 {
 	enum trace_flags flag = TRACE_ALL;
@@ -1756,7 +1754,12 @@ static int restore_root_task(struct pstree_item *init)
 
 	timing_stop(TIME_FORK);
 
-	ret = restore_switch_stage(CR_STATE_RESTORE);
+	__restore_switch_stage(CR_STATE_RESTORE);
+
+	if (inherit_fd_send(getpid()))
+		goto out_kill;
+
+	ret = restore_wait_inprogress_tasks();
 	if (ret < 0)
 		goto out_kill;
 
@@ -1898,6 +1901,9 @@ int cr_restore_tasks(void)
 	if (criu_signals_setup() < 0)
 		goto err;
 
+	if (root_prepare_shared())
+		goto err;
+
 	if (restore_root_task(root_item) < 0)
 		goto err;
 
diff --git a/files.c b/files.c
index 7bace3a..84e8d11 100644
--- a/files.c
+++ b/files.c
@@ -1223,12 +1223,6 @@ int shared_fdt_prepare(struct pstree_item *item)
  *       +---> criu restore ... --inherit-fd fd[1]:pipe:[686787] fd[2]:pipe:[686788]
  */
 
-struct inherit_fd {
-	char *inh_id;		/* identifier */
-	int inh_fd;		/* file descriptor to restore from */
-	struct list_head l;
-};
-
 /*
  * We can't print diagnostics messages in this function because the
  * log file isn't initialized yet.
@@ -1286,6 +1280,7 @@ int inherit_fd_add(char *optarg)
 	inh->inh_id = cp;
 	inh->inh_fd = fd;
 	list_add_tail(&inh->l, &opts.inherit_fds);
+	INIT_LIST_HEAD(&inh->files);
 	return 0;
 }
 
@@ -1342,20 +1337,3 @@ int inherit_fd_lookup_id(char *id, bool need_fd)
 
 	return -1;
 }
-
-/*
- * Look up the inherit fd list by a file descriptor.
- */
-bool inherit_fd_lookup_fd(int fd)
-{
-	struct inherit_fd *inh;
-
-	list_for_each_entry(inh, &opts.inherit_fds, l) {
-		if (inh->inh_fd == fd) {
-			pr_info("File descriptor %d in inherit fd list\n", fd);
-			return true;
-		}
-	}
-
-	return false;
-}
diff --git a/include/files.h b/include/files.h
index e4e304f..2bc9fec 100644
--- a/include/files.h
+++ b/include/files.h
@@ -170,10 +170,16 @@ extern int dump_unsupp_fd(struct fd_parms *p, int lfd,
 
 #define INHERIT_FD 0xcafebabe		/* marker */
 
+struct inherit_fd {
+	char *inh_id;		/* identifier */
+	int inh_fd;		/* file descriptor to restore from */
+	struct list_head l;
+	struct list_head files;
+};
+
 extern int inherit_fd_add(char *optarg);
 extern void inherit_fd_log(void);
 extern int inherit_fd_validate_fds(void);
 extern int inherit_fd_lookup_id(char *id, bool need_fd);
-extern bool inherit_fd_lookup_fd(int fd);
 
 #endif /* __CR_FILES_H__ */
diff --git a/pipes.c b/pipes.c
index 73bc790..1469000 100644
--- a/pipes.c
+++ b/pipes.c
@@ -10,6 +10,9 @@
 #include "files.h"
 #include "pipes.h"
 #include "util-pie.h"
+#include "cr_options.h"
+#include "namespaces.h"
+#include "net.h"
 
 #include "protobuf.h"
 #include "protobuf/pipe.pb-c.h"
@@ -109,6 +112,54 @@ int collect_pipe_data(int img_type, struct pipe_data_rst **hash)
 	return ret;
 }
 
+int inherit_fd_collect(char *id, struct pipe_info *pi)
+{
+	struct inherit_fd *inh;
+
+	list_for_each_entry(inh, &opts.inherit_fds, l) {
+		if (!strcmp(inh->inh_id, id)) {
+			pr_info("File identifier %s in inherit fd list\n", id);
+			list_add(&pi->pipe_list, &inh->files);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int inherit_fd_send(int pid)
+{
+	struct inherit_fd *inh;
+	struct pipe_info *p;
+	int rst, sock;
+
+	if (switch_ns(pid, &net_ns_desc, &rst))
+		return -1;
+
+	sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (sock < 0) {
+		pr_perror("Can't create socket");
+		restore_ns(rst, &net_ns_desc);
+		return -1;
+	}
+	restore_ns(rst, &net_ns_desc);
+
+	list_for_each_entry(inh, &opts.inherit_fds, l) {
+		list_for_each_entry(p, &inh->files, pipe_list) {
+			struct fdinfo_list_entry *fle;
+
+			fle = file_master(&p->d);
+
+			if (send_fd_to_peer(inh->inh_fd, fle, sock)) {
+				pr_perror("Can't send file descriptor");
+				return -1;
+			}
+		}
+	}
+	return 0;
+}
+
+static char *pipe_id_string(int pipe_id);
 /* Choose who will restore a pipe. */
 void mark_pipe_master(void)
 {
@@ -120,6 +171,7 @@ void mark_pipe_master(void)
 		struct fdinfo_list_entry *fle;
 		struct pipe_info *pi, *pic, *p;
 		struct pipe_info *pr = NULL, *pw = NULL;
+		char *pipe_name;
 
 		if (list_empty(&pipes))
 			break;
@@ -132,6 +184,18 @@ void mark_pipe_master(void)
 
 		fle = file_master(&pi->d);
 		p = pi;
+
+		pipe_name = pipe_id_string(pi->pe->pipe_id);
+		if (pi->pe->flags == INHERIT_FD) {
+			if (inherit_fd_collect(pipe_name, pi) == 1) {
+				pi->reopen = 0; // FIXME
+				continue;
+			} else {
+				pr_err("No inherit fd for pipe %s\n", pipe_name);
+				BUG(); // FIXME
+			}
+		}
+
 		if (!(pi->pe->flags & O_LARGEFILE)) {
 			if (pi->pe->flags & O_WRONLY) {
 				if (pw == NULL)
@@ -306,7 +370,6 @@ static char *pipe_id_string(int pipe_id)
 
 static int open_pipe(struct file_desc *d)
 {
-	char *pipe_name;
 	struct pipe_info *pi, *p;
 	int ret, tmp;
 	int pfd[2];
@@ -314,19 +377,7 @@ static int open_pipe(struct file_desc *d)
 
 	pi = container_of(d, struct pipe_info, d);
 
-	pr_info("\t\tCreating pipe pipe_id=%#x id=%#x\n", pi->pe->pipe_id, pi->pe->id);
-
-	pipe_name = pipe_id_string(pi->pe->pipe_id);
-	tmp = inherit_fd_lookup_id(pipe_name, true);
-	if (tmp >= 0) {
-		pr_info("Pipe %s will be restored from inherit fd %d\n",
-			pipe_name, tmp);
-		return tmp;
-	}
-	if (pi->pe->flags == INHERIT_FD) {
-		pr_err("No inherit fd for pipe %s\n", pipe_name);
-		return -1;
-	}
+	pr_info("\t\tCreating pipe pipe_id=%d id=%#x\n", pi->pe->pipe_id, pi->pe->id);
 
 	if (!pi->create)
 		return recv_pipe_fd(pi);
@@ -380,6 +431,7 @@ static int want_transport(FdinfoEntry *fe, struct file_desc *d)
 	struct pipe_info *pi;
 
 	pi = container_of(d, struct pipe_info, d);
+
 	return !pi->create;
 }
 
diff --git a/test/zdtm/live/static/Makefile b/test/zdtm/live/static/Makefile
index b5c1a6a..9dc1eed 100644
--- a/test/zdtm/live/static/Makefile
+++ b/test/zdtm/live/static/Makefile
@@ -7,6 +7,7 @@ CFLAGS	= -g -O2 -Wall -Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0
 CFLAGS	+= $(USERCFLAGS)
 
 TST_NOFILE	=				\
+		pipe-inherit			\
 		busyloop00			\
 		sleeping00			\
 		pid00				\
diff --git a/test/zdtm/live/static/pipe-inherit.c b/test/zdtm/live/static/pipe-inherit.c
new file mode 100644
index 0000000..46b1593
--- /dev/null
+++ b/test/zdtm/live/static/pipe-inherit.c
@@ -0,0 +1,48 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "zdtmtst.h"
+
+const char *test_doc	= "Check that environment didn't change";
+const char *test_author	= "Pavel Emelianov <xemul at parallels.com>";
+
+int main(int argc, char **argv)
+{
+	pid_t ext_pid;
+	int p[2];
+
+	if (pipe(p))
+		return -1;
+
+	ext_pid = fork();
+	if (ext_pid < 0)
+		return -1;
+
+	if (ext_pid == 0) {
+		char buf[128];
+		int ret;
+
+		test_ext_init(argc, argv);
+		ret = read(p[0], buf, sizeof(buf));
+		if (ret <= 0)
+			fail();
+		test_msg("%s\n", buf);
+		pass();
+		return 0;
+	}
+
+	test_init(argc, argv);
+
+	close(p[0]);
+
+	test_daemon();
+	test_waitsig();
+
+	write(p[1], "hello", 6);
+	close(p[1]);
+
+	pass();
+	return 0;
+}
diff --git a/util.c b/util.c
index 3b468f2..23ebb60 100644
--- a/util.c
+++ b/util.c
@@ -95,13 +95,6 @@ int close_safe(int *fd)
 {
 	int ret = 0;
 
-	/*
-	 * Don't close files descriptors that criu's caller
-	 * set up to be inherited by the restored process.
-	 */
-	if (inherit_fd_lookup_fd(*fd))
-		return 0;
-
 	if (*fd > -1) {
 		ret = close(*fd);
 		if (!ret)
-- 
1.9.3



More information about the CRIU mailing list