[CRIU] [PATCH] rst: Re-use opened fd when restoring private mappings

Pavel Emelyanov xemul at parallels.com
Fri Nov 6 07:08:09 PST 2015


On restore we do a sequence of open+mmap+close steps. On real apps
there exists chains of private file mappings for the same file with
different pgoffs and/or flags/prots.

Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
---
 cr-restore.c | 44 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index a33273c..de871a4 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -247,9 +247,23 @@ err:
 	return ret;
 }
 
+/*
+ * When mapping a file in several VMAs we can use one descriptor
+ * for all mappings, no need to re-open it for every mmap. By
+ * doing this we save many open-s since typically applications
+ * have sequences of VMAs for the same file with different pgoffs
+ * and/or prots. This is restore-side analogue of the VMA file
+ * borrowing in proc_parse.c.
+ */
+
+struct vma_fd_cache {
+	struct file_desc *d;
+	int fd;
+};
+
 /* Map a private vma, if it is not mapped by a parent yet */
 static int map_private_vma(struct vma_area *vma, void **tgt_addr,
-			struct vma_area **pvma, struct list_head *pvma_list)
+		struct vma_area **pvma, struct list_head *pvma_list, struct vma_fd_cache *fc)
 {
 	int ret;
 	void *addr, *paddr = NULL;
@@ -257,12 +271,21 @@ static int map_private_vma(struct vma_area *vma, void **tgt_addr,
 	struct vma_area *p = *pvma;
 
 	if (vma_area_is(vma, VMA_FILE_PRIVATE)) {
-		ret = get_filemap_fd(vma);
-		if (ret < 0) {
-			pr_err("Can't fixup VMA's fd\n");
-			return -1;
+		if (fc->d != vma->vmfd) {
+			if (fc->fd != -1)
+				close(fc->fd);
+
+			ret = get_filemap_fd(vma);
+			if (ret < 0) {
+				pr_err("Can't fixup VMA's fd\n");
+				return -1;
+			}
+
+			fc->d = vma->vmfd;
+			fc->fd = ret;
 		}
-		vma->e->fd = ret;
+
+		vma->e->fd = fc->fd;
 	}
 
 	nr_pages = vma_entry_len(vma->e) / PAGE_SIZE;
@@ -352,9 +375,6 @@ static int map_private_vma(struct vma_area *vma, void **tgt_addr,
 		vma->premmaped_addr += PAGE_SIZE;
 	}
 
-	if (vma_area_is(vma, VMA_FILE_PRIVATE))
-		close(vma->e->fd);
-
 	*tgt_addr += size;
 	return 0;
 }
@@ -366,6 +386,7 @@ static int premap_priv_vmas(struct vm_area_list *vmas, void *at)
 	unsigned long pstart = 0;
 	int ret = 0;
 	LIST_HEAD(empty);
+	struct vma_fd_cache fc = { .d = NULL, .fd = -1 };
 
 	/*
 	 * Keep parent vmas at hands to check whether we can "inherit" them.
@@ -389,11 +410,14 @@ static int premap_priv_vmas(struct vm_area_list *vmas, void *at)
 		if (!vma_area_is_private(vma, kdat.task_size))
 			continue;
 
-		ret = map_private_vma(vma, &at, &pvma, parent_vmas);
+		ret = map_private_vma(vma, &at, &pvma, parent_vmas, &fc);
 		if (ret < 0)
 			break;
 	}
 
+	if (fc.fd != -1)
+		close(fc.fd);
+
 	return ret;
 }
 
-- 
1.9.3



More information about the CRIU mailing list