[CRIU] [PATCH cr 05/11] restore: map private vma-s before forking children

Andrey Vagin avagin at openvz.org
Mon Oct 15 11:32:18 EDT 2012


In this case private vma-s will be inherited by children,
it allows to restore copy-on-write reqions.

This code compares child and parent vma lists. If it found
two vma-s with the same start and end addresses, it decides
that the child inherites this vmas from the parent.

Each anon vma is mapped only once. An address for vma is allocated
by kernel, then it will be remapped in restorer.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 cr-restore.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index 21d6f97..020b489 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -173,20 +173,71 @@ err:
 	return ret;
 }
 
+/* Map a private vma, if it is not mapped by a parrent yet */
+static int map_private_vma(pid_t pid, struct vma_area *vma,
+			struct vma_area **pvma, struct list_head *pvma_list)
+{
+	struct vma_area *p = *pvma;
+
+	if (!vma_priv(&vma->vma))
+		return 0;
+
+	list_for_each_entry_continue(p, pvma_list, list) {
+		if (p->vma.start > vma->vma.start)
+			 break;
+
+		if (p->vma.end == vma->vma.end &&
+		    p->vma.start == vma->vma.start) {
+			pr_info("COW 0x%016lx-0x%016lx 0x%016lx vma\n",
+				vma->vma.start, vma->vma.end, vma->vma.pgoff);
+			vma->vma.shmid = p->vma.shmid;
+		}
+
+	}
+
+	*pvma = list_entry(p->list.prev, struct vma_area, list);
+
+	if (!vma->vma.shmid) {
+		void *addr;
+
+		pr_info("Map 0x%016lx-0x%016lx 0x%016lx vma\n",
+			vma->vma.start, vma->vma.end, vma->vma.pgoff);
+
+		addr = mmap(NULL, vma_entry_len(&vma->vma),
+				vma->vma.prot | PROT_WRITE, vma->vma.flags,
+				vma->vma.fd, vma->vma.pgoff);
+
+		if (addr == MAP_FAILED) {
+			pr_err("Unable to map ANON_VMA");
+			return -1;
+		}
+		vma->vma.shmid = (unsigned long) addr;
+	}
+
+	if (vma_entry_is(&vma->vma, VMA_FILE_PRIVATE))
+		close(vma->vma.fd);
+
+	return 0;
+}
+
 static int read_vmas(int pid)
 {
 	int fd, ret = 0;
+	LIST_HEAD(old);
+	struct vma_area *pvma, *vma;
 
+	list_replace_init(&vma_list, &old);
 	INIT_LIST_HEAD(&vma_list);
 
+	pvma = list_first_entry(&old, struct vma_area, list);
+
 	/* Skip errors, because a zombie doesn't have an image of vmas */
 	fd = open_image_ro(CR_FD_VMAS, pid);
 	if (fd < 0)
-		return ret;
+		goto out;
 
 	nr_vmas = 0;
 	while (1) {
-		struct vma_area *vma;
 		VmaEntry *e;
 
 		ret = -1;
@@ -209,9 +260,21 @@ static int read_vmas(int pid)
 
 		vma->vma = *e;
 		vma_entry__free_unpacked(e, NULL);
+
+		ret = map_private_vma(pid, vma, &pvma, &old);
+		if (ret < 0)
+			break;
 	}
 
 	close(fd);
+
+out:
+	while (!list_empty(&old)) {
+		vma = list_first_entry(&old, struct vma_area, list);
+		list_del(&vma->list);
+		xfree(vma);
+	}
+
 	return ret;
 }
 
-- 
1.7.1



More information about the CRIU mailing list