[CRIU] [PATCH cr 13/16] cr-restore: remove unshared pages from
inherited private mappings
Andrey Vagin
avagin at openvz.org
Tue Oct 23 06:02:25 EDT 2012
A parent process can change a few pages after forking a child and
all this pages should not be avaliable from the child.
Each vma has a bitmap of existent pages. Parent's and child's bitmaps
can be compared and all pages which are not present in a child bitmap
are dropped.
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
cr-restore.c | 42 +++++++++++++++++++++++++++++++++++++++++-
include/crtools.h | 2 ++
2 files changed, 43 insertions(+), 1 deletions(-)
diff --git a/cr-restore.c b/cr-restore.c
index 4dd68b4..16b08d2 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -181,6 +181,7 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr,
{
int ret;
void *addr;
+ unsigned long nr_pages;
struct vma_area *p = *pvma;
if (vma_entry_is(&vma->vma, VMA_FILE_PRIVATE)) {
@@ -194,6 +195,11 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr,
vma->vma.shmid = 0;
}
+ nr_pages = vma_entry_len(&vma->vma) / PAGE_SIZE;
+ vma->page_bitmap = xzalloc(BITS_TO_LONGS(nr_pages) * sizeof(long));
+ if (vma->page_bitmap == NULL)
+ return -1;
+
list_for_each_entry_continue(p, pvma_list, list) {
if (p->vma.start > vma->vma.start)
break;
@@ -225,6 +231,8 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr,
}
vma->vma.shmid = (unsigned long) addr;
} else {
+ vma->ppage_bitmap = p->page_bitmap;
+
addr = mremap((void *)vma_premmaped_start(&vma->vma),
vma_area_len(vma), vma_area_len(vma),
MREMAP_FIXED | MREMAP_MAYMOVE, tgt_addr);
@@ -277,7 +285,7 @@ static int restore_priv_vma_content(pid_t pid)
* Read page contents.
*/
while (1) {
- u64 va;
+ u64 va, page_offset;
char buf[PAGE_SIZE];
void *p;
@@ -297,6 +305,12 @@ static int restore_priv_vma_content(pid_t pid)
vma = list_entry(vma->list.next, struct vma_area, list);
}
+ page_offset = (va - vma->vma.start) / PAGE_SIZE;
+ if (vma->page_bitmap)
+ set_bit(page_offset, vma->page_bitmap);
+ if (vma->ppage_bitmap)
+ clear_bit(page_offset, vma->ppage_bitmap);
+
ret = read(fd, buf, PAGE_SIZE);
if (ret != PAGE_SIZE) {
pr_err("Can'r read mapping page %d\n", ret);
@@ -312,6 +326,32 @@ static int restore_priv_vma_content(pid_t pid)
}
close(fd);
+ /* Remove pages, which were not shared with a child */
+ list_for_each_entry(vma, &vma_list, list) {
+ unsigned long size, i = 0;
+ void *addr = (void *) vma_premmaped_start(&vma->vma);
+
+ if (vma->ppage_bitmap == NULL)
+ continue;
+
+ size = vma_entry_len(&vma->vma) / PAGE_SIZE;
+ while (1) {
+ /* Find all pages, which avaliable only for a parent */
+ i = find_next_bit(vma->ppage_bitmap, size, i);
+
+ if ( i >= size)
+ break;
+
+ ret = madvise(addr + PAGE_SIZE * i,
+ PAGE_SIZE, MADV_DONTNEED);
+ if (ret < 0) {
+ pr_perror("madvise failed\n");
+ return -1;
+ }
+ i++;
+ }
+ }
+
return 0;
}
diff --git a/include/crtools.h b/include/crtools.h
index 146524d..c3e9e5b 100644
--- a/include/crtools.h
+++ b/include/crtools.h
@@ -213,6 +213,8 @@ struct vma_area {
struct list_head list;
VmaEntry vma;
int vm_file_fd;
+ unsigned long *page_bitmap; /* existent pages */
+ unsigned long *ppage_bitmap; /* parent's existent pages */
};
#define vma_area_is(vma_area, s) vma_entry_is(&((vma_area)->vma), s)
--
1.7.1
More information about the CRIU
mailing list