[CRIU] [PATCH 07/11] dump: Use parasite file descriptors draining

Cyrill Gorcunov gorcunov at openvz.org
Sun Mar 25 09:35:20 EDT 2012


Since we're able to simply drain file descriptors
we're interested in, just do that with parasite
help.

This changes the calling sequence a bit

 1) Collect file descriptors before parasite
    get intected the dumpee and remember them in
    local copy.

 2) Ask parasite to drain collected descriptrs
    into our space.

 3) Operate with file descriptors directly via fcntl
    calls and such.

Overall idea is to prepare ground for fowners
dumping which will be addressed in further patches.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 cr-dump.c |  141 +++++++++++++++++++++++++++++++++----------------------------
 1 files changed, 76 insertions(+), 65 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index bda6e2a..9a33ee7 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -31,6 +31,7 @@
 #include "namespaces.h"
 #include "image.h"
 #include "proc_parse.h"
+#include "parasite.h"
 #include "parasite-syscall.h"
 
 #ifndef CONFIG_X86_64
@@ -87,6 +88,37 @@ err:
 	return ret;
 }
 
+static int collect_fds(pid_t pid, int *fd, int *nr_fd)
+{
+	struct dirent *d;
+	DIR *dir;
+	int n;
+
+	pr_info("\n");
+	pr_info("Collecting fds (pid: %d)\n", pid);
+	pr_info("----------------------------------------\n");
+
+	dir = opendir_proc(pid, "fd");
+	if (!dir)
+		return -1;
+
+	n = 0;
+	while ((d = readdir(dir))) {
+		if (d->d_name[0] == '.')
+			continue;
+
+		if (n > *nr_fd - 1)
+			return -ENOMEM;
+		fd[n++] = atoi(d->d_name);
+	}
+
+	*nr_fd = n;
+	pr_info("Found %d file descriptors\n", n);
+
+	pr_info("----------------------------------------\n");
+	return 0;
+}
+
 struct fd_parms {
 	unsigned long	fd_name;
 	unsigned long	pos;
@@ -279,68 +311,47 @@ err:
 	return ret;
 }
 
-static int read_fd_params(pid_t pid, const char *fd, struct fd_parms *p)
+static void fill_fd_params(pid_t pid, int fd, int lfd, struct fd_parms *p)
 {
-	FILE *file;
-	int ret;
-
-	file = fopen_proc(pid, "fdinfo/%s", fd);
-	if (!file)
-		return -1;
-
-	p->fd_name = atoi(fd);
-	ret = fscanf(file, "pos:\t%li\nflags:\t%o\n", &p->pos, &p->flags);
-	fclose(file);
+	p->fd_name	= fd;
+	p->pos		= lseek(lfd, 0, SEEK_CUR);
+	p->flags	= fcntl(lfd, F_GETFL);
+	p->pid		= pid;
+	p->id		= FD_ID_INVALID;
 
-	if (ret != 2) {
-		pr_err("Bad format of fdinfo file (%d items, want 2)\n", ret);
-		return -1;
-	}
-
-	pr_info("%d fdinfo %s: pos: %16lx flags: %16o\n",
+	pr_info("%d fdinfo %d: pos: %16lx flags: %16o\n",
 		pid, fd, p->pos, p->flags);
-
-	p->pid	= pid;
-	p->id	= FD_ID_INVALID;
-
-	return 0;
 }
 
-static int dump_one_fd(pid_t pid, int pid_fd_dir, const char *d_name,
+static int dump_one_fd(pid_t pid, int fd, int lfd,
 		       const struct cr_fdset *cr_fdset,
 		       struct sk_queue *sk_queue)
 {
 	struct stat fd_stat;
-	int err = -1;
 	struct fd_parms p;
-	int lfd;
-
-	if (read_fd_params(pid, d_name, &p))
-		return -1;
-
-	lfd = openat(pid_fd_dir, d_name, O_RDONLY);
-	if (lfd < 0) {
-		err = try_dump_socket(pid, p.fd_name, cr_fdset, sk_queue);
-		if (err != 1)
-			return err;
-
-		pr_perror("Failed to open %d/%ld", pid_fd_dir, p.fd_name);
-		return -1;
-	}
+	int err = -1;
 
 	if (fstat(lfd, &fd_stat) < 0) {
-		pr_perror("Can't get stat on %ld", p.fd_name);
+		pr_perror("Can't get stat on %d", fd);
 		goto out_close;
 	}
 
+	if (S_ISSOCK(fd_stat.st_mode)) {
+		err = try_dump_socket(pid, fd, cr_fdset, sk_queue);
+		if (err)
+			pr_perror("Failed to open %d", fd);
+		return err;
+	}
+
+	fill_fd_params(pid, fd, lfd, &p);
+
 	if (S_ISCHR(fd_stat.st_mode) &&
 	    (major(fd_stat.st_rdev) == TTY_MAJOR ||
 	     major(fd_stat.st_rdev) == UNIX98_PTY_SLAVE_MAJOR)) {
 		/* skip only standard destriptors */
 		if (p.fd_name < 3) {
 			err = 0;
-			pr_info("... Skipping tty ... %d/%ld\n",
-				pid_fd_dir, p.fd_name);
+			pr_info("... Skipping tty ... %d\n", fd);
 			goto out_close;
 		}
 		goto err;
@@ -360,52 +371,43 @@ static int dump_one_fd(pid_t pid, int pid_fd_dir, const char *d_name,
 		return dump_one_pipe(&p, fd_stat.st_ino, lfd, cr_fdset);
 
 err:
-	pr_err("Can't dump file %ld of that type [%x]\n", p.fd_name, fd_stat.st_mode);
+	pr_err("Can't dump file %d of that type [%x]\n", fd, fd_stat.st_mode);
 
 out_close:
 	close_safe(&lfd);
 	return err;
 }
 
-static int dump_task_files(pid_t pid, const struct cr_fdset *cr_fdset,
-			   struct sk_queue *sk_queue)
+static int dump_task_files_seized(struct parasite_ctl *ctl, const struct cr_fdset *cr_fdset,
+				  int *fds, int nr_fds, struct sk_queue *sk_queue)
 {
-	struct dirent *de;
-	unsigned long pos;
-	unsigned int flags;
-	DIR *fd_dir;
+	int lfds[PARASITE_MAX_FDS];
+	int i;
 
 	pr_info("\n");
-	pr_info("Dumping opened files (pid: %d)\n", pid);
+	pr_info("Dumping opened files (pid: %d)\n", ctl->pid);
 	pr_info("----------------------------------------\n");
 
+	if (parasite_drain_fds_seized(ctl, fds, lfds, nr_fds))
+		return -1;
+
 	/*
 	 * Dump special files at the beginning. We might need
 	 * to re-read them in restorer, so better to make it
 	 * fast.
 	 */
-	if (dump_task_special_files(pid, cr_fdset)) {
+	if (dump_task_special_files(ctl->pid, cr_fdset)) {
 		pr_err("Can't dump special files\n");
 		return -1;
 	}
 
-	fd_dir = opendir_proc(pid, "fd");
-	if (!fd_dir)
-		return -1;
-
-	while ((de = readdir(fd_dir))) {
-		if (!strcmp(de->d_name, "."))
-			continue;
-		if (!strcmp(de->d_name, ".."))
-			continue;
-		if (dump_one_fd(pid, dirfd(fd_dir), de->d_name, cr_fdset,
-				sk_queue))
+	for (i = 0; i < nr_fds; i++) {
+		if (dump_one_fd(ctl->pid, fds[i], lfds[i],
+				cr_fdset, sk_queue))
 			return -1;
 	}
 
 	pr_info("----------------------------------------\n");
-
-	closedir(fd_dir);
 	return 0;
 }
 
@@ -1276,6 +1278,9 @@ static int dump_one_task(const struct pstree_item *item, struct cr_fdset *cr_fds
 	struct parasite_dump_misc misc;
 	struct sk_queue sk_queue = { };
 
+	int nr_fds = PARASITE_MAX_FDS;
+	int fds[nr_fds];
+
 	pr_info("========================================\n");
 	pr_info("Dumping task (pid: %d)\n", pid);
 	pr_info("========================================\n");
@@ -1303,9 +1308,9 @@ static int dump_one_task(const struct pstree_item *item, struct cr_fdset *cr_fds
 		goto err;
 	}
 
-	ret = dump_task_files(pid, cr_fdset, &sk_queue);
+	ret = collect_fds(pid, fds, &nr_fds);
 	if (ret) {
-		pr_err("Dump files (pid: %d) failed with %d\n", pid, ret);
+		pr_err("Collect fds (pid: %d) failed with %d\n", pid, ret);
 		goto err;
 	}
 
@@ -1315,6 +1320,12 @@ static int dump_one_task(const struct pstree_item *item, struct cr_fdset *cr_fds
 		goto err;
 	}
 
+	ret = dump_task_files_seized(parasite_ctl, cr_fdset, fds, nr_fds, &sk_queue);
+	if (ret) {
+		pr_err("Dump files (pid: %d) failed with %d\n", pid, ret);
+		goto err;
+	}
+
 	ret = parasite_dump_pages_seized(parasite_ctl, &vma_area_list, cr_fdset);
 	if (ret) {
 		pr_err("Can't dump pages (pid: %d) with parasite\n", pid);
-- 
1.7.7.6



More information about the CRIU mailing list