[CRIU] [PATCH 2/2] vma: Do not open similar VMAs multiple times

Pavel Emelyanov xemul at virtuozzo.com
Thu May 18 10:25:14 PDT 2017


On real apps it's typical to have sequences ov VMAs with
absolutely the same file mapped. We've seen this dump-time
and fixed multiple openings of map_files links with the
file_borrowed flag.

Restore situation is the same -- the vm_open() call in many
cases re-open the same path with the same flags. This slows
things down.

To fix this -- chain VMAs with mapped files to each other
and only the first one opens the file and only the last
one closes it.

Signed-off-by: Pavel Emelyanov <xemul at virtuozzo.com>
---
 criu/files-reg.c         | 26 ++++++++++++++++++++++++--
 criu/include/files-reg.h |  7 ++++++-
 criu/include/image.h     |  1 +
 criu/include/vma.h       |  1 +
 criu/mem.c               |  6 ++++--
 criu/pie/restorer.c      |  3 ++-
 6 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/criu/files-reg.c b/criu/files-reg.c
index 44bf528..5296391 100644
--- a/criu/files-reg.c
+++ b/criu/files-reg.c
@@ -1618,6 +1618,16 @@ int open_reg_by_id(u32 id)
 	return open_reg_fd(fd);
 }
 
+static int borrow_filemap(int pid, struct vma_area *vma)
+{
+	struct vma_area *fvma = vma->fvma;
+
+	BUG_ON(!(fvma->e->status & VMA_NO_CLOSE));
+	vma->e->fd = fvma->e->fd;
+
+	return 0;
+}
+
 static int open_filemap(int pid, struct vma_area *vma)
 {
 	u32 flags;
@@ -1640,7 +1650,7 @@ static int open_filemap(int pid, struct vma_area *vma)
 	return 0;
 }
 
-int collect_filemap(struct vma_area *vma)
+int collect_filemap(struct vma_area *vma, struct vma_file_ctx *ctx)
 {
 	struct file_desc *fd;
 
@@ -1659,7 +1669,19 @@ int collect_filemap(struct vma_area *vma)
 		return -1;
 
 	vma->vmfd = fd;
-	vma->vm_open = open_filemap;
+	if (ctx->vma && ctx->flags == vma->e->flags && ctx->fd == fd) {
+		vma->vm_open = borrow_filemap;
+		vma->fvma = ctx->vma;
+		ctx->vma->e->status |= VMA_NO_CLOSE;
+		/* Change VMA so that next borrower sets NO_CLOSE on us */
+		ctx->vma = vma;
+	} else {
+		vma->vm_open = open_filemap;
+		ctx->flags = vma->e->fdflags;
+		ctx->fd = fd;
+		ctx->vma = vma;
+	}
+
 	return 0;
 }
 
diff --git a/criu/include/files-reg.h b/criu/include/files-reg.h
index 5a6c691..477eed7 100644
--- a/criu/include/files-reg.h
+++ b/criu/include/files-reg.h
@@ -42,7 +42,12 @@ extern struct file_remap *lookup_ghost_remap(u32 dev, u32 ino);
 
 extern struct file_desc *try_collect_special_file(u32 id, int optional);
 #define collect_special_file(id)	try_collect_special_file(id, 0)
-extern int collect_filemap(struct vma_area *);
+struct vma_file_ctx {
+	u32 flags;
+	struct file_desc *fd;
+	struct vma_area *vma;
+};
+extern int collect_filemap(struct vma_area *, struct vma_file_ctx *ctx);
 
 extern int collect_remaps_and_regfiles(void);
 
diff --git a/criu/include/image.h b/criu/include/image.h
index 1dcd18c..9846512 100644
--- a/criu/include/image.h
+++ b/criu/include/image.h
@@ -89,6 +89,7 @@
 #define VMA_AREA_VVAR		(1 <<  12)
 #define VMA_AREA_AIORING	(1 <<  13)
 
+#define VMA_NO_CLOSE		(1 <<  28)
 #define VMA_NO_PROT_WRITE	(1 <<  29)
 #define VMA_PREMMAPED		(1 <<  30)
 #define VMA_UNSUPP		(1 <<  31)
diff --git a/criu/include/vma.h b/criu/include/vma.h
index 3e1d9a1..34ad0a7 100644
--- a/criu/include/vma.h
+++ b/criu/include/vma.h
@@ -55,6 +55,7 @@ struct vma_area {
 			int (*vm_open)(int pid, struct vma_area *vma);
 			struct file_desc *vmfd;
 			struct vma_area	*pvma;		/* parent for inherited VMAs */
+			struct vma_area	*fvma;		/* vma from which to borrow a file */
 			unsigned long	*page_bitmap;	/* existent pages */
 			unsigned long	premmaped_addr;	/* restore only */
 
diff --git a/criu/mem.c b/criu/mem.c
index db7279a..0b3c900 100644
--- a/criu/mem.c
+++ b/criu/mem.c
@@ -481,6 +481,7 @@ int prepare_mm_pid(struct pstree_item *i)
 	int ret = -1, vn = 0;
 	struct cr_img *img;
 	struct rst_info *ri = rsti(i);
+	struct vma_file_ctx ctx = {};
 
 	img = open_image(CR_FD_MM, O_RSTR, pid);
 	if (!img)
@@ -540,7 +541,7 @@ int prepare_mm_pid(struct pstree_item *i)
 			ret = collect_shmem(pid, vma);
 		else if (vma_area_is(vma, VMA_FILE_PRIVATE) ||
 				vma_area_is(vma, VMA_FILE_SHARED))
-			ret = collect_filemap(vma);
+			ret = collect_filemap(vma, &ctx);
 		else if (vma_area_is(vma, VMA_AREA_SOCKET))
 			ret = collect_socket_map(vma);
 		else
@@ -707,7 +708,8 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void
 			return -1;
 		}
 
-		if (vma_area_is(vma, VMA_FILE_PRIVATE))
+		if (vma_area_is(vma, VMA_FILE_PRIVATE) &&
+				!vma_area_is(vma, VMA_NO_CLOSE))
 			close(vma->e->fd);
 	} else {
 		void *paddr;
diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c
index a047714..736c125 100644
--- a/criu/pie/restorer.c
+++ b/criu/pie/restorer.c
@@ -639,7 +639,8 @@ static unsigned long restore_mapping(VmaEntry *vma_entry)
 			vma_entry->fd,
 			vma_entry->pgoff);
 
-	if (vma_entry->fd != -1)
+	if ((vma_entry->fd != -1) &&
+			!(vma_entry->status & VMA_NO_CLOSE))
 		sys_close(vma_entry->fd);
 
 	return addr;
-- 
2.1.4



More information about the CRIU mailing list