[CRIU] [PATCH cr 08/16] restore: don't unmap premmapped private
vma-s
Andrey Vagin
avagin at openvz.org
Tue Oct 23 06:02:20 EDT 2012
Private vma-s are mapped before forking children, then they are
remapped to corrected places in restorer.c.
In restorer all unneeded vma-s are unmaped. VMA-s from premmapped
regions should not be unmaped.
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
cr-restore.c | 41 +++++++++++++++++++++++++++++++++++++++--
include/restorer.h | 2 ++
restorer.c | 4 ++++
3 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/cr-restore.c b/cr-restore.c
index b11fae3..1f22df0 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -66,6 +66,8 @@ static int prepare_restorer_blob(void);
static LIST_HEAD(vma_list);
static int nr_vmas;
+static void *premmapped_addr;
+static unsigned long premmapped_len;
static int shmem_remap(void *old_addr, void *new_addr, unsigned long size)
{
@@ -231,6 +233,23 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr,
return 0;
}
+/* Prevent merging vma-s outside and inside the premmapped region */
+static int unmap_priv_guard_pages()
+{
+ if (munmap(premmapped_addr, PAGE_SIZE)) {
+ pr_perror("Could not unmap a guard page %p", premmapped_addr);
+ return -1;
+ }
+
+ if (munmap(premmapped_addr + premmapped_len - PAGE_SIZE, PAGE_SIZE)) {
+ pr_perror("Could not unmap a guard page %p",
+ premmapped_addr + premmapped_len);
+ return -1;
+ }
+
+ return 0;
+}
+
static int read_vmas(int pid)
{
int fd, ret = 0;
@@ -280,13 +299,26 @@ static int read_vmas(int pid)
priv_size += vma_area_len(vma);
}
- /* Reserve a place for mapping private vma-s one by one */
- addr = mmap(NULL, priv_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ /*
+ * Reserve a place for mapping private vma-s one by one.
+ *
+ * Add two guard pages from both sides. This pages will be
+ * unmaped before reading a current vmas for this process.
+ * In this case we can be sure, that vmas outside and inside
+ * of the premmapped region are not merged to each other.
+ */
+ addr = mmap(NULL, priv_size + 2 * PAGE_SIZE,
+ PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (addr == MAP_FAILED) {
pr_perror("Unable to reserve memory");
return -1;
}
+ premmapped_addr = addr;
+ premmapped_len = priv_size + 2 * PAGE_SIZE;
+
+ addr += PAGE_SIZE;
+
list_for_each_entry(vma, &vma_list, list) {
if (!vma_priv(&vma->vma))
continue;
@@ -1433,6 +1465,9 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core, struct list_head *tgt_v
restore_task_vma_len = 0;
restore_thread_vma_len = 0;
+ if (unmap_priv_guard_pages())
+ goto err;
+
ret = parse_smaps(pid, &self_vma_list, false);
close_proc();
if (ret < 0)
@@ -1545,6 +1580,8 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core, struct list_head *tgt_v
mem += self_vmas_len;
task_args->tgt_vmas = vma_list_remap(mem, vmas_len, tgt_vmas);
+ task_args->premmapped_addr = (unsigned long) premmapped_addr;
+ task_args->premmapped_len = premmapped_len;
if (!task_args->tgt_vmas)
goto err;
diff --git a/include/restorer.h b/include/restorer.h
index 93e4160..aed8ea2 100644
--- a/include/restorer.h
+++ b/include/restorer.h
@@ -89,6 +89,8 @@ struct task_restore_core_args {
struct task_entries *task_entries;
VmaEntry *self_vmas;
VmaEntry *tgt_vmas;
+ unsigned long premmapped_addr;
+ unsigned long premmapped_len;
rt_sigaction_t sigchld_act;
struct itimerval itimers[3];
diff --git a/restorer.c b/restorer.c
index 04337a9..1a5cff0 100644
--- a/restorer.c
+++ b/restorer.c
@@ -321,6 +321,10 @@ long __export_restore_task(struct task_restore_core_args *args)
if (!vma_entry_is(vma_entry, VMA_AREA_REGULAR))
continue;
+ if (args->premmapped_addr <= vma_entry->start &&
+ vma_entry->end <= args->premmapped_addr + args->premmapped_len)
+ continue;
+
if (sys_munmap((void *)vma_entry->start, vma_entry_len(vma_entry))) {
pr_err("Munmap fail for %lx\n", vma_entry->start);
goto core_restore_end;
--
1.7.1
More information about the CRIU
mailing list