[CRIU] [PATCH 3/4] files: ghost -- Defer dumping of ghost files contents

Cyrill Gorcunov gorcunov at openvz.org
Thu Sep 4 11:23:37 PDT 2014


It might happen that a ghost file is laying under directory
on which inotify is set. Thus when we are trying to open
such ghost file there this action generates inotify event
which prevents criu from proceeding dumping because now
we require events queue to be empty.

To do that we

 - encapsulate parameters needed for dumping into ghost_file structure
 - call for dump_ghost_files at very late stage when all fsnotify
   should be already dumped

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 cr-dump.c           |   3 ++
 files-reg.c         | 121 +++++++++++++++++++++++++++++++++-------------------
 include/files-reg.h |   1 +
 3 files changed, 80 insertions(+), 45 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index 0d28403b8702..a77b636c65ae 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -1820,6 +1820,9 @@ int cr_dump_tasks(pid_t pid)
 	if (dump_mnt_namespaces() < 0)
 		goto err;
 
+	if (dump_ghost_files())
+		goto err;
+
 	if (dump_file_locks())
 		goto err;
 
diff --git a/files-reg.c b/files-reg.c
index 0ffce0e0880f..4c3b358c7e7a 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -44,7 +44,14 @@ struct ghost_file {
 	u32			dev;
 	u32			ino;
 
-	struct file_remap	remap;
+	union {
+		struct {
+			GhostFileEntry	gfe;
+			size_t		size;
+			int		lfd;
+		} s;				/* for dump */
+		struct file_remap	remap;	/* for restore */
+	};
 };
 
 static u32 ghost_file_ids = 1;
@@ -260,55 +267,48 @@ struct collect_image_info remap_cinfo = {
 	.collect = collect_one_remap,
 };
 
-static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_dev)
+int dump_ghost_files(void)
 {
-	int img;
-	GhostFileEntry gfe = GHOST_FILE_ENTRY__INIT;
-
-	pr_info("Dumping ghost file contents (id %#x)\n", id);
-
-	img = open_image(CR_FD_GHOST_FILE, O_DUMP, id);
-	if (img < 0)
-		return -1;
+	struct ghost_file *gf;
+	int img = -1, ret = -1;
 
-	gfe.uid = st->st_uid;
-	gfe.gid = st->st_gid;
-	gfe.mode = st->st_mode;
+	list_for_each_entry(gf, &ghost_files, list) {
+		pr_info("Dumping ghost file contents (id %#x)\n", gf->id);
 
-	gfe.has_dev = gfe.has_ino = true;
-	gfe.dev = phys_dev;
-	gfe.ino = st->st_ino;
+		img = open_image(CR_FD_GHOST_FILE, O_DUMP, gf->id);
+		if (img < 0)
+			goto err;
 
-	if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
-		gfe.has_rdev = true;
-		gfe.rdev = st->st_rdev;
-	}
+		if (pb_write_one(img, &gf->s.gfe, PB_GHOST_FILE))
+			goto err;
 
-	if (pb_write_one(img, &gfe, PB_GHOST_FILE))
-		return -1;
+		if (gf->s.lfd >= 0) {
+			char lpath[PSFDS];
+			int fd, rc;
 
-	if (S_ISREG(st->st_mode)) {
-		int fd, ret;
-		char lpath[PSFDS];
+			/*
+			 * Reopen file locally since it may have no read
+			 * permissions when drained
+			 */
+			sprintf(lpath, "/proc/self/fd/%d", gf->s.lfd);
+			fd = open(lpath, O_RDONLY);
+			if (fd < 0) {
+				pr_perror("Can't open ghost original file");
+				goto err;
+			}
 
-		/*
-		 * Reopen file locally since it may have no read
-		 * permissions when drained
-		 */
-		sprintf(lpath, "/proc/self/fd/%d", _fd);
-		fd = open(lpath, O_RDONLY);
-		if (fd < 0) {
-			pr_perror("Can't open ghost original file");
-			return -1;
+			rc = copy_file(fd, img, gf->s.size);
+			close(fd);
+			if (rc)
+				goto err;
 		}
-		ret = copy_file(fd, img, st->st_size);
-		close(fd);
-		if (ret)
-			return -1;
-	}
 
-	close(img);
-	return 0;
+		close_safe(&img);
+	}
+	ret = 0;
+err:
+	close_safe(&img);
+	return ret;
 }
 
 void remap_put(struct file_remap *remap)
@@ -360,7 +360,7 @@ static int dump_ghost_remap(char *path, const struct stat *st,
 	phys_dev = phys_stat_resolve_dev(nsid, st->st_dev, path);
 	list_for_each_entry(gf, &ghost_files, list)
 		if ((gf->dev == phys_dev) && (gf->ino == st->st_ino))
-			goto dump_entry;
+			goto write_remap;
 
 	gf = xmalloc(sizeof(*gf));
 	if (gf == NULL)
@@ -369,12 +369,43 @@ static int dump_ghost_remap(char *path, const struct stat *st,
 	gf->dev = phys_dev;
 	gf->ino = st->st_ino;
 	gf->id = ghost_file_ids++;
+
+	ghost_file_entry__init(&gf->s.gfe);
+	gf->s.lfd = -1;
+	gf->s.size = 0;
+
 	list_add_tail(&gf->list, &ghost_files);
 
-	if (dump_ghost_file(lfd, gf->id, st, phys_dev))
-		return -1;
+	/*
+	 * We can't dump ghost file contesnt immediately
+	 * because this may generate fsnotify events. So
+	 * defer dumping until very late stage but fetch
+	 * parameters needed for ghost entry right here.
+	 */
+
+	gf->s.gfe.uid = st->st_uid;
+	gf->s.gfe.gid = st->st_gid;
+	gf->s.gfe.mode = st->st_mode;
+
+	gf->s.gfe.has_dev = gf->s.gfe.has_ino = true;
+	gf->s.gfe.dev = phys_dev;
+	gf->s.gfe.ino = st->st_ino;
+
+	if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
+		gf->s.gfe.has_rdev = true;
+		gf->s.gfe.rdev = st->st_rdev;
+	}
+
+	if (S_ISREG(st->st_mode)) {
+		gf->s.lfd = dup(lfd);
+		if (gf->s.lfd < 0) {
+			pr_perror("Can't dup local file");
+			return -1;
+		}
+		gf->s.size = st->st_size;
+	}
 
-dump_entry:
+write_remap:
 	BUG_ON(gf->id & REMAP_GHOST);
 
 	rpe.orig_id = id;
diff --git a/include/files-reg.h b/include/files-reg.h
index bc5f5a7732b3..c3fa24690743 100644
--- a/include/files-reg.h
+++ b/include/files-reg.h
@@ -30,6 +30,7 @@ extern int open_reg_by_id(u32 id);
 extern int open_reg_fd(struct file_desc *);
 extern int open_path(struct file_desc *, int (*open_cb)(int ns_root_fd,
 			struct reg_file_info *, void *), void *arg);
+extern int dump_ghost_files(void);
 extern void clear_ghost_files(void);
 
 extern int prepare_shared_reg_files(void);
-- 
1.9.3



More information about the CRIU mailing list