Commit 5d712b74 authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

cr-restore: remove unshared pages from inherited private mappings (v2)

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.

v2: don't check page_bitmap on NULL
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 52247b12
...@@ -187,6 +187,7 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr, ...@@ -187,6 +187,7 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr,
{ {
int ret; int ret;
void *addr, *paddr = NULL; void *addr, *paddr = NULL;
unsigned long nr_pages;
struct vma_area *p = *pvma; struct vma_area *p = *pvma;
if (vma_entry_is(&vma->vma, VMA_FILE_PRIVATE)) { if (vma_entry_is(&vma->vma, VMA_FILE_PRIVATE)) {
...@@ -200,6 +201,11 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr, ...@@ -200,6 +201,11 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr,
vma->vma.shmid = 0; 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) { list_for_each_entry_continue(p, pvma_list, list) {
if (p->vma.start > vma->vma.start) if (p->vma.start > vma->vma.start)
break; break;
...@@ -230,6 +236,8 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr, ...@@ -230,6 +236,8 @@ static int map_private_vma(pid_t pid, struct vma_area *vma, void *tgt_addr,
return -1; return -1;
} }
} else { } else {
vma->ppage_bitmap = p->page_bitmap;
addr = mremap(paddr, vma_area_len(vma), vma_area_len(vma), addr = mremap(paddr, vma_area_len(vma), vma_area_len(vma),
MREMAP_FIXED | MREMAP_MAYMOVE, tgt_addr); MREMAP_FIXED | MREMAP_MAYMOVE, tgt_addr);
if (addr != tgt_addr) { if (addr != tgt_addr) {
...@@ -262,7 +270,7 @@ static int restore_priv_vma_content(pid_t pid) ...@@ -262,7 +270,7 @@ static int restore_priv_vma_content(pid_t pid)
* Read page contents. * Read page contents.
*/ */
while (1) { while (1) {
u64 va; u64 va, page_offset;
char buf[PAGE_SIZE]; char buf[PAGE_SIZE];
void *p; void *p;
...@@ -282,6 +290,12 @@ static int restore_priv_vma_content(pid_t pid) ...@@ -282,6 +290,12 @@ static int restore_priv_vma_content(pid_t pid)
vma = list_entry(vma->list.next, struct vma_area, list); vma = list_entry(vma->list.next, struct vma_area, list);
} }
page_offset = (va - vma->vma.start) / PAGE_SIZE;
set_bit(page_offset, vma->page_bitmap);
if (vma->ppage_bitmap)
clear_bit(page_offset, vma->ppage_bitmap);
ret = read(fd, buf, PAGE_SIZE); ret = read(fd, buf, PAGE_SIZE);
if (ret != PAGE_SIZE) { if (ret != PAGE_SIZE) {
pr_err("Can'r read mapping page %d\n", ret); pr_err("Can'r read mapping page %d\n", ret);
...@@ -297,6 +311,32 @@ static int restore_priv_vma_content(pid_t pid) ...@@ -297,6 +311,32 @@ static int restore_priv_vma_content(pid_t pid)
} }
close(fd); close(fd);
/* Remove pages, which were not shared with a child */
list_for_each_entry(vma, &rst_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 are not shared with this child */
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; return 0;
} }
......
...@@ -216,6 +216,8 @@ struct vma_area { ...@@ -216,6 +216,8 @@ struct vma_area {
int vm_file_fd; int vm_file_fd;
int vm_socket_id; int vm_socket_id;
}; };
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) #define vma_area_is(vma_area, s) vma_entry_is(&((vma_area)->vma), s)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment