[CRIU] [PATCHv2 1/9] vdso: Introduce type for checking vdso hint in maps file

Dmitry Safonov dsafonov at virtuozzo.com
Mon Jul 10 21:24:16 MSK 2017


Let's hide those kernel details in enum.
Further in this patches set I'll add kdat test for presence
of "[vdso]" hint after mremap(), so we will skip any checking
on kernels > v3.16 and do not init vdso_pfn also
(skipping parsing of self-pagemap).

Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
 criu/vdso.c | 67 ++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 46 insertions(+), 21 deletions(-)

diff --git a/criu/vdso.c b/criu/vdso.c
index 83f30807eea5..a0b8a4e0b39a 100644
--- a/criu/vdso.c
+++ b/criu/vdso.c
@@ -33,6 +33,42 @@ struct vdso_maps vdso_maps		= VDSO_MAPS_INIT;
 struct vdso_maps vdso_maps_compat	= VDSO_MAPS_INIT;
 
 /*
+ * Starting with 3.16 the [vdso]/[vvar] marks are reported correctly
+ * even when they are remapped into a new place, but only since that
+ * particular version of the kernel!
+ * On previous kernels we need to check if vma is vdso by some means:
+ * - if pagemap is present, by pfn
+ * - by parsing ELF and filling vdso symtable otherwise
+ */
+enum vdso_check_t {
+	/* from slowest to fastest */
+	VDSO_CHECK_SYMS = 0,
+	VDSO_CHECK_PFN,
+	VDSO_NO_CHECK,
+};
+
+static enum vdso_check_t get_vdso_check_type(struct parasite_ctl *ctl)
+{
+	/*
+	 * ia32 C/R depends on mremap() for vdso patches (v4.8),
+	 * so we can omit any check and be sure that "[vdso]"
+	 * hint stays in /proc/../maps file and is correct.
+	 */
+	if (!compel_mode_native(ctl)) {
+		pr_info("Don't check vdso\n");
+		return VDSO_NO_CHECK;
+	}
+
+	if (kdat.pmap == PM_FULL) {
+		pr_info("Check vdso by pfn from pagemap\n");
+		return VDSO_CHECK_PFN;
+	}
+
+	pr_info("Pagemap is unavailable, check vdso by filling symtable\n");
+	return VDSO_CHECK_SYMS;
+}
+
+/*
  * The VMAs list might have proxy vdso/vvar areas left
  * from previous dump/restore cycle so we need to detect
  * them and eliminated from the VMAs list, they will be
@@ -47,18 +83,19 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 	struct vma_area *proxy_vvar_marked = NULL;
 	struct parasite_vdso_vma_entry *args;
 	int fd = -1, ret, exit_code = -1;
+	enum vdso_check_t vcheck;
 	u64 pfn = VDSO_BAD_PFN;
 	struct vma_area *vma;
 	off_t off;
 
+	vcheck = get_vdso_check_type(ctl);
 	args = compel_parasite_args(ctl, struct parasite_vdso_vma_entry);
-	if (kdat.pmap == PM_FULL) {
+	if (vcheck == VDSO_CHECK_PFN) {
 		BUG_ON(vdso_pfn == VDSO_BAD_PFN);
 		fd = open_proc(pid, "pagemap");
 		if (fd < 0)
 			return -1;
-	} else
-		pr_info("Pagemap is unavailable, trying a slow way\n");
+	}
 
 	list_for_each_entry(vma, &vma_area_list->h, list) {
 		if (!vma_area_is(vma, VMA_AREA_REGULAR))
@@ -105,10 +142,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 		 */
 		args->start = vma->e->start;
 		args->len = vma_area_len(vma);
-		if (!compel_mode_native(ctl))
-			args->try_fill_symtable = false;
-		else
-			args->try_fill_symtable = (fd < 0) ? true : false;
+		args->try_fill_symtable = (vcheck == VDSO_CHECK_SYMS);
 		args->is_vdso = false;
 
 		if (compel_rpc_call_sync(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
@@ -132,6 +166,9 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 			continue;
 		}
 
+		if (vcheck == VDSO_NO_CHECK)
+			continue;
+
 		/*
 		 * If we have an access to pagemap we can handle vDSO
 		 * status early. Otherwise, in worst scenario, where
@@ -140,7 +177,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 		 * detected via procfs status so we have to parse
 		 * symbols in parasite code.
 		 */
-		if (fd >= 0) {
+		if (vcheck == VDSO_CHECK_PFN) {
 			off = (vma->e->start / PAGE_SIZE) * sizeof(u64);
 			ret = pread(fd, &pfn, sizeof(pfn), off);
 			if (ret < 0 || ret != sizeof(pfn)) {
@@ -155,13 +192,6 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 			}
 		}
 
-		/*
-		 * Setup proper VMA status. Note starting with 3.16
-		 * the [vdso]/[vvar] marks are reported correctly
-		 * even when they are remapped into a new place,
-		 * but only since that particular version of the
-		 * kernel!
-		 */
 		if ((pfn == vdso_pfn && pfn != VDSO_BAD_PFN) || args->is_vdso) {
 			if (!vma_area_is(vma, VMA_AREA_VDSO)) {
 				pr_debug("Restore vDSO status by pfn/symtable at %lx\n",
@@ -169,12 +199,7 @@ int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
 				vma->e->status |= VMA_AREA_VDSO;
 			}
 		} else {
-			/*
-			 * Compat vDSO mremap support is only after v4.8,
-			 * [vdso] vma name always stays after mremap.
-			 */
-			if (unlikely(vma_area_is(vma, VMA_AREA_VDSO)) &&
-					compel_mode_native(ctl)) {
+			if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) {
 				pr_debug("Drop mishinted vDSO status at %lx\n",
 					 (long)vma->e->start);
 				vma->e->status &= ~VMA_AREA_VDSO;
-- 
2.13.1



More information about the CRIU mailing list