[CRIU] [PATCH] mem: Don't do unneeded mprotects

Pavel Emelyanov xemul at virtuozzo.com
Mon May 15 07:14:31 PDT 2017


When a vma we restore doesn't have any pages in pagemaps there's
not need to enforce PROT_WRITE bit on it.

This only applies to non-premmaped vmas.

Signed-off-by: Pavel Emelyanov <xemul at virtuozzo.com>
---
 criu/include/image.h |  1 +
 criu/mem.c           | 27 ++++++++++++++++++++++++++-
 criu/pie/restorer.c  |  6 ++++--
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/criu/include/image.h b/criu/include/image.h
index 24fb828..1dcd18c 100644
--- a/criu/include/image.h
+++ b/criu/include/image.h
@@ -89,6 +89,7 @@
 #define VMA_AREA_VVAR		(1 <<  12)
 #define VMA_AREA_AIORING	(1 <<  13)
 
+#define VMA_NO_PROT_WRITE	(1 <<  29)
 #define VMA_PREMMAPED		(1 <<  30)
 #define VMA_UNSUPP		(1 <<  31)
 
diff --git a/criu/mem.c b/criu/mem.c
index 942d5d9..db7279a 100644
--- a/criu/mem.c
+++ b/criu/mem.c
@@ -690,6 +690,13 @@ static int premap_private_vma(struct pstree_item *t, struct vma_area *vma, void
 			}
 		}
 
+		/*
+		 * All mappings here get PROT_WRITE regardless of whether we
+		 * put any data into it or not, because this area will get
+		 * mremap()-ed (branch below) so we MIGHT need to have WRITE 
+		 * bits there. Ideally we'd check for the whole COW-chain
+		 * having any data in.
+		 */
 		addr = mmap(*tgt_addr, size,
 				vma->e->prot | PROT_WRITE,
 				vma->e->flags | MAP_FIXED | flag,
@@ -786,14 +793,26 @@ static int premap_priv_vmas(struct pstree_item *t, struct vm_area_list *vmas,
 		if (!vma_area_is_private(vma, kdat.task_size))
 			continue;
 
-		if (vma->pvma == NULL && pr->pieok && !vma_force_premap(vma, &vmas->h))
+		if (vma->pvma == NULL && pr->pieok && !vma_force_premap(vma, &vmas->h)) {
 			/*
 			 * VMA in question is not shared with anyone. We'll
 			 * restore it with its contents in restorer.
+			 * Now let's check whether we need to map it with
+			 * PROT_WRITE or not.
 			 */
+			do {
+				if (pr->pe->vaddr + pr->pe->nr_pages * PAGE_SIZE <= vma->e->start)
+					continue;
+				if (pr->pe->vaddr > vma->e->end)
+					vma->e->status |= VMA_NO_PROT_WRITE;
+				break;
+			} while (pr->advance(pr));
+
 			continue;
+		}
 
 		ret = premap_private_vma(t, vma, at);
+
 		if (ret < 0)
 			break;
 	}
@@ -879,6 +898,12 @@ static int restore_priv_vma_content(struct pstree_item *t, struct page_read *pr)
 						(nr_pages - i) * PAGE_SIZE,
 						vma->e->end - va);
 
+				if (vma->e->status & VMA_NO_PROT_WRITE) {
+					pr_debug("VMA 0x%"PRIx64":0x%"PRIx64" RO %#lx:%lu IO\n",
+							vma->e->start, vma->e->end, va, nr_pages);
+					BUG();
+				}
+
 				if (pagemap_enqueue_iovec(pr, (void *)va, len, vma_io))
 					return -1;
 
diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c
index 98c81f3..1758883 100644
--- a/criu/pie/restorer.c
+++ b/criu/pie/restorer.c
@@ -621,7 +621,8 @@ static unsigned long restore_mapping(VmaEntry *vma_entry)
 		flags |= MAP_ANONYMOUS;
 
 	/* A mapping of file with MAP_SHARED is up to date */
-	if (vma_entry->fd == -1 || !(vma_entry->flags & MAP_SHARED))
+	if ((vma_entry->fd == -1 || !(vma_entry->flags & MAP_SHARED)) &&
+			!(vma_entry->status & VMA_NO_PROT_WRITE))
 		prot |= PROT_WRITE;
 
 	pr_debug("\tmmap(%"PRIx64" -> %"PRIx64", %x %x %d)\n",
@@ -1348,7 +1349,8 @@ long __export_restore_task(struct task_restore_args *args)
 		if (!(vma_entry_is(vma_entry, VMA_AREA_REGULAR)))
 			continue;
 
-		if (vma_entry->prot & PROT_WRITE)
+		if ((vma_entry->prot & PROT_WRITE) ||
+				(vma_entry->status & VMA_NO_PROT_WRITE))
 			continue;
 
 		sys_mprotect(decode_pointer(vma_entry->start),
-- 
2.1.4


More information about the CRIU mailing list