[CRIU] [PATCH] restore: Don't open same files to mmap mutiple times (v2)
Pavel Emelyanov
xemul at virtuozzo.com
Fri Apr 14 05:54:39 PDT 2017
This is symmetrical to dump -- it's typical when one file
is mapped several times in a row. On dump we don't open
the mapping's map_files links for each of such files, thus
it makes sence to do the same on restore.
This speeds restore a little bit due to lower amount of
openat() and close() calls.
v2: Sometimes cached/merged descriptors were closed when they
were not supposed to.
Signed-off-by: Pavel Emelyanov <xemul at virtuozzo.com>
---
criu/files-reg.c | 62 +++++++++++++++++++++++++++++++++++++++++++++---
criu/include/files-reg.h | 2 +-
criu/include/vma.h | 1 +
criu/mem.c | 10 ++++----
criu/pie/restorer.c | 26 ++++++++++++++++----
5 files changed, 88 insertions(+), 13 deletions(-)
diff --git a/criu/files-reg.c b/criu/files-reg.c
index 4514275..539f2ee 100644
--- a/criu/files-reg.c
+++ b/criu/files-reg.c
@@ -1616,6 +1616,30 @@ int open_reg_by_id(u32 id)
return open_reg_fd(fd);
}
+/*
+ * In many cases subsequent areas have the same file mapped,
+ * so we may save some open-s when mapping them and map the
+ * same descriptor many times (provided fdflags match).
+ */
+static struct {
+ struct file_desc *d;
+ u32 flags;
+ int fd;
+} prev_filemap;
+
+void filemap_fin_opens(void)
+{
+ if (prev_filemap.d) {
+ close(prev_filemap.fd);
+ prev_filemap.d = NULL;
+ }
+}
+
+static inline bool prev_open_match(struct vma_area *vma, u32 flags)
+{
+ return (prev_filemap.d == vma->vmfd) && (prev_filemap.flags == flags);
+}
+
static int open_filemap(int pid, struct vma_area *vma)
{
u32 flags;
@@ -1636,14 +1660,45 @@ static int open_filemap(int pid, struct vma_area *vma)
else
flags = O_RDONLY;
- ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags);
- if (ret < 0)
- return ret;
+ if (prev_open_match(vma, flags)) {
+ BUG_ON(prev_filemap.fd < 0);
+ ret = prev_filemap.fd;
+ } else {
+ ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags);
+ if (ret < 0)
+ return ret;
+ }
vma->e->fd = ret;
return 0;
}
+static void close_filemap(struct vma_area *vma)
+{
+ if (unlikely(!vma->e->has_fdflags)) {
+ /*
+ * For fdflags-less images ... ah, don't care.
+ */
+ close(vma->e->fd);
+ goto out;
+ }
+
+ if (prev_open_match(vma, vma->e->fdflags))
+ /*
+ * Keep opened fd for future ->vm_open-s
+ */
+ goto out;
+
+ if (prev_filemap.d)
+ close(prev_filemap.fd);
+
+ prev_filemap.d = vma->vmfd;
+ prev_filemap.flags = vma->e->fdflags;
+ prev_filemap.fd = vma->e->fd;
+out:
+ vma->e->fd = -1;
+}
+
int collect_filemap(struct vma_area *vma)
{
struct file_desc *fd;
@@ -1654,6 +1709,7 @@ int collect_filemap(struct vma_area *vma)
vma->vmfd = fd;
vma->vm_open = open_filemap;
+ vma->vm_close = close_filemap;
return 0;
}
diff --git a/criu/include/files-reg.h b/criu/include/files-reg.h
index 5a6c691..5ef5e88 100644
--- a/criu/include/files-reg.h
+++ b/criu/include/files-reg.h
@@ -52,7 +52,7 @@ extern int prepare_remaps(void);
extern int try_clean_remaps(bool only_ghosts);
extern int strip_deleted(struct fd_link *link);
-
+extern void filemap_fin_opens(void);
extern int prepare_procfs_remaps(void);
extern int dead_pid_conflict(void);
diff --git a/criu/include/vma.h b/criu/include/vma.h
index 37f8b4b..5134505 100644
--- a/criu/include/vma.h
+++ b/criu/include/vma.h
@@ -53,6 +53,7 @@ struct vma_area {
struct /* for restore */ {
int (*vm_open)(int pid, struct vma_area *vma);
+ void (*vm_close)(struct vma_area *vma);
struct file_desc *vmfd;
unsigned long *page_bitmap; /* existent pages */
unsigned long *ppage_bitmap; /* parent's existent pages */
diff --git a/criu/mem.c b/criu/mem.c
index 3bcf467..56d775d 100644
--- a/criu/mem.c
+++ b/criu/mem.c
@@ -568,8 +568,6 @@ static int map_private_vma(struct pstree_item *t,
pr_err("Can't fixup VMA's fd\n");
return -1;
}
-
- vma->vm_open = NULL; /* prevent from 2nd open in prepare_vmas */
}
nr_pages = vma_entry_len(vma->e) / PAGE_SIZE;
@@ -667,8 +665,10 @@ static int map_private_vma(struct pstree_item *t,
vma->premmaped_addr += PAGE_SIZE;
}
- if (vma_area_is(vma, VMA_FILE_PRIVATE))
- close(vma->e->fd);
+ if (vma_area_is(vma, VMA_FILE_PRIVATE)) {
+ vma->vm_open = NULL; /* prevent from 2nd open in prepare_vmas */
+ vma->vm_close(vma);
+ }
*tgt_addr += size;
return 0;
@@ -709,6 +709,8 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas, vo
break;
}
+ filemap_fin_opens();
+
return ret;
}
diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c
index 53ecaa0..2520fde 100644
--- a/criu/pie/restorer.c
+++ b/criu/pie/restorer.c
@@ -543,12 +543,14 @@ static long restore_self_exe_late(struct task_restore_args *args)
return ret;
}
-static unsigned long restore_mapping(VmaEntry *vma_entry)
+static unsigned long restore_mapping(VmaEntry *vma_entry, int *fdp)
{
int prot = vma_entry->prot;
int flags = vma_entry->flags | MAP_FIXED;
unsigned long addr;
+ *fdp = -1;
+
if (vma_entry_is(vma_entry, VMA_AREA_SYSVIPC)) {
int att_flags;
/*
@@ -595,8 +597,7 @@ static unsigned long restore_mapping(VmaEntry *vma_entry)
vma_entry->fd,
vma_entry->pgoff);
- if (vma_entry->fd != -1)
- sys_close(vma_entry->fd);
+ *fdp = vma_entry->fd;
return addr;
}
@@ -1135,7 +1136,7 @@ static int wait_zombies(struct task_restore_args *task_args)
long __export_restore_task(struct task_restore_args *args)
{
long ret = -1;
- int i;
+ int i, fd_to_close = -1;
VmaEntry *vma_entry;
unsigned long va;
@@ -1245,6 +1246,8 @@ long __export_restore_task(struct task_restore_args *args)
* OK, lets try to map new one.
*/
for (i = 0; i < args->vmas_n; i++) {
+ int this_fd;
+
vma_entry = args->vmas + i;
if (!vma_entry_is(vma_entry, VMA_AREA_REGULAR))
@@ -1253,14 +1256,27 @@ long __export_restore_task(struct task_restore_args *args)
if (vma_entry_is_private(vma_entry, args->task_size))
continue;
- va = restore_mapping(vma_entry);
+ va = restore_mapping(vma_entry, &this_fd);
if (va != vma_entry->start) {
pr_err("Can't restore %"PRIx64" mapping with %lx\n", vma_entry->start, va);
goto core_restore_end;
}
+
+ if (this_fd != -1) {
+ /*
+ * Descriptors on VMA-s may be shared on subsequent
+ * areas. See close_filemap() and filemap_fin_opens()
+ */
+ if (fd_to_close != -1 && fd_to_close != this_fd)
+ sys_close(fd_to_close);
+ fd_to_close = this_fd;
+ }
}
+ if (fd_to_close != -1)
+ sys_close(fd_to_close);
+
#ifdef CONFIG_VDSO
/*
* Proxify vDSO.
--
2.5.5
More information about the CRIU
mailing list