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

Cyrill Gorcunov gorcunov at openvz.org
Fri Mar 23 09:30:53 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 |  136 ++++++++++++++++++++++++++++++++++---------------------------
 1 files changed, 76 insertions(+), 60 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index a71f1fa..b5c9a3c 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;
@@ -285,57 +317,42 @@ 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;
+	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;
 
-	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);
-
-	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;
+	int err;
 
-	if (read_fd_params(pid, d_name, &p))
-		return -1;
+	fill_fd_params(pid, fd, lfd, &p);
 
-	lfd = openat(pid_fd_dir, d_name, O_RDONLY);
-	if (lfd < 0) {
-		err = try_dump_socket(pid, p.fd_name, cr_fdset, sk_queue);
+	err = open_proc_nocheck(pid, "fd/%d", fd);
+	if (err < 0) {
+		err = try_dump_socket(pid, fd, cr_fdset, sk_queue);
 		if (err != 1)
 			return err;
-
-		pr_perror("Failed to open %d/%ld", pid_fd_dir, p.fd_name);
+		pr_perror("Failed to open %d", fd);
 		return -1;
-	}
+	} else
+		close(err);
+
+	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;
 	}
 
@@ -345,8 +362,7 @@ static int dump_one_fd(pid_t pid, int pid_fd_dir, const char *d_name,
 		/* 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;
@@ -366,52 +382,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;
 }
 
@@ -1343,6 +1350,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");
@@ -1370,9 +1380,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;
 	}
 
@@ -1382,6 +1392,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