[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