[CRIU] [PATCH 2/4] vdso: merge per arch vdso.c file in a common one

Laurent Dufour ldufour at linux.vnet.ibm.com
Thu Sep 3 07:26:29 PDT 2015


Merge arch/*/vdso.c files in vdso.c.

The merge has been done by copying arch/x86/vdso.c in vdso.c since it
contains patch a67e9f7bb930 ("vdso: don't play with a function exit code").

The commit f9ae6d9dd4e4 ("Replace remaining hard-coded TASK_SIZE use")
pushed in the aarch64 has been replicated since it should be cross
platform.

CC: Christopher Covington <cov at codeaurora.org>
CC: Pavel Emelyanov <xemul at parallels.com>
Signed-off-by: Laurent Dufour <ldufour at linux.vnet.ibm.com>
---
 Makefile.crtools    |   2 +-
 arch/aarch64/vdso.c | 309 ----------------------------------------------------
 arch/ppc64/vdso.c   | 309 ----------------------------------------------------
 arch/x86/vdso.c     | 294 -------------------------------------------------
 vdso.c              | 294 +++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 295 insertions(+), 913 deletions(-)
 delete mode 100644 arch/aarch64/vdso.c
 delete mode 100644 arch/ppc64/vdso.c
 delete mode 100644 arch/x86/vdso.c
 create mode 100644 vdso.c

diff --git a/Makefile.crtools b/Makefile.crtools
index 42c5a7cf1b81..80f704fb4be1 100644
--- a/Makefile.crtools
+++ b/Makefile.crtools
@@ -66,7 +66,7 @@ obj-y	+= string.o
 obj-y	+= sigframe.o
 obj-y	+= lsm.o
 ifeq ($(VDSO),y)
-obj-y	+= $(ARCH_DIR)/vdso.o
+obj-y	+= vdso.o
 endif
 obj-y	+= cr-service.o
 obj-y	+= sd-daemon.o
diff --git a/arch/aarch64/vdso.c b/arch/aarch64/vdso.c
deleted file mode 100644
index 2c127a43daa0..000000000000
--- a/arch/aarch64/vdso.c
+++ /dev/null
@@ -1,309 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <elf.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include "asm/types.h"
-#include "asm/parasite-syscall.h"
-
-#include "parasite-syscall.h"
-#include "parasite.h"
-#include "compiler.h"
-#include "kerndat.h"
-#include "vdso.h"
-#include "util.h"
-#include "log.h"
-#include "mem.h"
-#include "vma.h"
-
-#ifdef LOG_PREFIX
-# undef LOG_PREFIX
-#endif
-#define LOG_PREFIX "vdso: "
-
-struct vdso_symtable vdso_sym_rt = VDSO_SYMTABLE_INIT;
-u64 vdso_pfn = VDSO_BAD_PFN;
-/*
- * 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
- * generated again on restore if needed.
- */
-int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
-			struct vm_area_list *vma_area_list)
-{
-	unsigned long proxy_vdso_addr = VDSO_BAD_ADDR;
-	unsigned long proxy_vvar_addr = VVAR_BAD_ADDR;
-	struct vma_area *proxy_vdso_marked = NULL;
-	struct vma_area *proxy_vvar_marked = NULL;
-	struct parasite_vdso_vma_entry *args;
-	struct vma_area *vma;
-	int fd, ret = -1;
-	off_t off;
-	u64 pfn;
-
-	args = parasite_args(ctl, struct parasite_vdso_vma_entry);
-	fd = open_proc(pid, "pagemap");
-	if (fd < 0)
-		return -1;
-
-	list_for_each_entry(vma, &vma_area_list->h, list) {
-		if (!vma_area_is(vma, VMA_AREA_REGULAR))
-			continue;
-
-		if (vma_area_is(vma, VMA_FILE_SHARED) ||
-				vma_area_is(vma, VMA_FILE_PRIVATE))
-			continue;
-		/*
-		 * It might be possible VVAR area from marked
-		 * vDSO zone, we need to detect it earlier than
-		 * VDSO_PROT test because VVAR_PROT is a subset
-		 * of it but don't yield continue here,
-		 * sigh... what a mess.
-		 */
-		BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT));
-
-		if ((vma->e->prot & VVAR_PROT) == VVAR_PROT) {
-			if (proxy_vvar_addr != VVAR_BAD_ADDR &&
-			    proxy_vvar_addr == vma->e->start) {
-				BUG_ON(proxy_vvar_marked);
-				proxy_vvar_marked = vma;
-				continue;
-			}
-		}
-
-		if ((vma->e->prot & VDSO_PROT) != VDSO_PROT)
-			continue;
-
-		if (vma->e->prot != VDSO_PROT) {
-			pr_debug("Dropping %lx using extra protection test\n",
-				 vma->e->start);
-			continue;
-		}
-
-		if (vma->e->start > kdat.task_size)
-			continue;
-
-		if (vma->e->flags & MAP_GROWSDOWN)
-			continue;
-
-		/*
-		 * I need to poke every potentially marked vma,
-		 * otherwise if task never called for vdso functions
-		 * page frame number won't be reported.
-		 */
-		args->start = vma->e->start;
-		args->len = vma_area_len(vma);
-
-		if (parasite_execute_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
-			pr_err("vdso: Parasite failed to poke for mark\n");
-			ret = -1;
-			goto err;
-		}
-
-		/*
-		 * Defer handling marked vdso until we walked over
-		 * all vmas and restore potentially remapped vDSO
-		 * area status.
-		 */
-		if (unlikely(args->is_marked)) {
-			if (proxy_vdso_marked) {
-				pr_err("Ow! Second vdso mark detected!\n");
-				ret = -1;
-				goto err;
-			}
-			proxy_vdso_marked = vma;
-			proxy_vdso_addr = args->proxy_vdso_addr;
-			proxy_vvar_addr = args->proxy_vvar_addr;
-			continue;
-		}
-
-		off = (vma->e->start / PAGE_SIZE) * sizeof(u64);
-		ret = pread(fd, &pfn, sizeof(pfn), off);
-		if (ret < 0 || ret != sizeof(pfn)) {
-			pr_perror("Can't read pme for pid %d", pid);
-			ret = -1;
-			goto err;
-		}
-
-		pfn = PME_PFRAME(pfn);
-		if (!pfn) {
-			pr_err("Unexpected page fram number 0 for pid %d\n", pid);
-			ret = -1;
-			goto err;
-		}
-
-		/*
-		 * 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) {
-			if (!vma_area_is(vma, VMA_AREA_VDSO)) {
-				pr_debug("vdso: Restore vDSO status by pfn at %lx\n",
-					 (long)vma->e->start);
-				vma->e->status |= VMA_AREA_VDSO;
-			}
-		} else {
-			if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) {
-				pr_debug("vdso: Drop mishinted vDSO status at %lx\n",
-					 (long)vma->e->start);
-				vma->e->status &= ~VMA_AREA_VDSO;
-			}
-		}
-	}
-
-	/*
-	 * There is marked vdso, it means such vdso is autogenerated
-	 * and must be dropped from vma list.
-	 */
-	if (proxy_vdso_marked) {
-		pr_debug("vdso: Found marked at %lx (proxy vDSO at %lx VVAR at %lx)\n",
-			 (long)proxy_vdso_marked->e->start,
-			 (long)proxy_vdso_addr, (long)proxy_vvar_addr);
-
-		/*
-		 * Don't forget to restore the proxy vdso/vvar status, since
-		 * it's unknown to the kernel.
-		 */
-		list_for_each_entry(vma, &vma_area_list->h, list) {
-			if (vma->e->start == proxy_vdso_addr) {
-				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
-				pr_debug("vdso: Restore proxy vDSO status at %lx\n",
-					 (long)vma->e->start);
-			} else if (vma->e->start == proxy_vvar_addr) {
-				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR;
-				pr_debug("vdso: Restore proxy VVAR status at %lx\n",
-					 (long)vma->e->start);
-			}
-		}
-
-		pr_debug("vdso: Droppping marked vdso at %lx\n",
-			 (long)proxy_vdso_marked->e->start);
-		list_del(&proxy_vdso_marked->list);
-		xfree(proxy_vdso_marked);
-		vma_area_list->nr--;
-
-		if (proxy_vvar_marked) {
-			pr_debug("vdso: Droppping marked vvar at %lx\n",
-				 (long)proxy_vvar_marked->e->start);
-			list_del(&proxy_vvar_marked->list);
-			xfree(proxy_vvar_marked);
-			vma_area_list->nr--;
-		}
-	}
-	ret = 0;
-err:
-	close(fd);
-	return ret;
-}
-
-static int vdso_fill_self_symtable(struct vdso_symtable *s)
-{
-	char buf[512];
-	int ret = -1;
-	FILE *maps;
-
-	*s = (struct vdso_symtable)VDSO_SYMTABLE_INIT;
-
-	maps = fopen_proc(PROC_SELF, "maps");
-	if (!maps) {
-		pr_perror("Can't open self-vma");
-		return -1;
-	}
-
-	while (fgets(buf, sizeof(buf), maps)) {
-		unsigned long start, end;
-		char *has_vdso, *has_vvar;
-
-		has_vdso = strstr(buf, "[vdso]");
-		if (!has_vdso)
-			has_vvar = strstr(buf, "[vvar]");
-		else
-			has_vvar = NULL;
-
-		if (!has_vdso && !has_vvar)
-			continue;
-
-		ret = sscanf(buf, "%lx-%lx", &start, &end);
-		if (ret != 2) {
-			ret = -1;
-			pr_err("Can't find vDSO/VVAR bounds\n");
-			goto err;
-		}
-
-		if (has_vdso) {
-			if (s->vma_start != VDSO_BAD_ADDR) {
-				pr_err("Got second vDSO entry\n");
-				ret = -1;
-				goto err;
-			}
-			s->vma_start = start;
-			s->vma_end = end;
-
-			ret = vdso_fill_symtable((void *)start, end - start, s);
-			if (ret)
-				goto err;
-		} else {
-			if (s->vvar_start != VVAR_BAD_ADDR) {
-				pr_err("Got second VVAR entry\n");
-				ret = -1;
-				goto err;
-			}
-			s->vvar_start = start;
-			s->vvar_end = end;
-		}
-	}
-
-	/*
-	 * Validate its structure -- for new vDSO format the
-	 * structure must be like
-	 *
-	 * 7fff1f5fd000-7fff1f5fe000 r-xp 00000000 00:00 0 [vdso]
-	 * 7fff1f5fe000-7fff1f600000 r--p 00000000 00:00 0 [vvar]
-	 *
-	 * The areas may be in reverse order.
-	 *
-	 * 7fffc3502000-7fffc3504000 r--p 00000000 00:00 0 [vvar]
-	 * 7fffc3504000-7fffc3506000 r-xp 00000000 00:00 0 [vdso]
-	 *
-	 */
-	ret = 0;
-	if (s->vma_start != VDSO_BAD_ADDR) {
-		if (s->vvar_start != VVAR_BAD_ADDR) {
-			if (s->vma_end != s->vvar_start &&
-			    s->vvar_end != s->vma_start) {
-				ret = -1;
-				pr_err("Unexpected rt vDSO area bounds\n");
-				goto err;
-			}
-		}
-	} else {
-		ret = -1;
-		pr_err("Can't find rt vDSO\n");
-		goto err;
-	}
-
-	pr_debug("rt [vdso] %lx-%lx [vvar] %lx-%lx\n",
-		 s->vma_start, s->vma_end,
-		 s->vvar_start, s->vvar_end);
-
-err:
-	fclose(maps);
-	return ret;
-}
-
-int vdso_init(void)
-{
-	if (vdso_fill_self_symtable(&vdso_sym_rt))
-		return -1;
-	return vaddr_to_pfn(vdso_sym_rt.vma_start, &vdso_pfn);
-}
diff --git a/arch/ppc64/vdso.c b/arch/ppc64/vdso.c
deleted file mode 100644
index 43d9637f00af..000000000000
--- a/arch/ppc64/vdso.c
+++ /dev/null
@@ -1,309 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <elf.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include "asm/types.h"
-#include "asm/parasite-syscall.h"
-
-#include "parasite-syscall.h"
-#include "parasite.h"
-#include "compiler.h"
-#include "kerndat.h"
-#include "vdso.h"
-#include "util.h"
-#include "log.h"
-#include "mem.h"
-#include "vma.h"
-
-#ifdef LOG_PREFIX
-# undef LOG_PREFIX
-#endif
-#define LOG_PREFIX "vdso: "
-
-struct vdso_symtable vdso_sym_rt = VDSO_SYMTABLE_INIT;
-u64 vdso_pfn = VDSO_BAD_PFN;
-/*
- * 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
- * generated again on restore if needed.
- */
-int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
-			struct vm_area_list *vma_area_list)
-{
-	unsigned long proxy_vdso_addr = VDSO_BAD_ADDR;
-	unsigned long proxy_vvar_addr = VVAR_BAD_ADDR;
-	struct vma_area *proxy_vdso_marked = NULL;
-	struct vma_area *proxy_vvar_marked = NULL;
-	struct parasite_vdso_vma_entry *args;
-	struct vma_area *vma;
-	int fd, ret = -1;
-	off_t off;
-	u64 pfn;
-
-	args = parasite_args(ctl, struct parasite_vdso_vma_entry);
-	fd = open_proc(pid, "pagemap");
-	if (fd < 0)
-		return -1;
-
-	list_for_each_entry(vma, &vma_area_list->h, list) {
-		if (!vma_area_is(vma, VMA_AREA_REGULAR))
-			continue;
-
-		if (vma_area_is(vma, VMA_FILE_SHARED) ||
-				vma_area_is(vma, VMA_FILE_PRIVATE))
-			continue;
-		/*
-		 * It might be possible VVAR area from marked
-		 * vDSO zone, we need to detect it earlier than
-		 * VDSO_PROT test because VVAR_PROT is a subset
-		 * of it but don't yield continue here,
-		 * sigh... what a mess.
-		 */
-		BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT));
-
-		if ((vma->e->prot & VVAR_PROT) == VVAR_PROT) {
-			if (proxy_vvar_addr != VVAR_BAD_ADDR &&
-			    proxy_vvar_addr == vma->e->start) {
-				BUG_ON(proxy_vvar_marked);
-				proxy_vvar_marked = vma;
-				continue;
-			}
-		}
-
-		if ((vma->e->prot & VDSO_PROT) != VDSO_PROT)
-			continue;
-
-		if (vma->e->prot != VDSO_PROT) {
-			pr_debug("Dropping %lx using extra protection test\n",
-				 vma->e->start);
-			continue;
-		}
-
-		if (vma->e->start > TASK_SIZE)
-			continue;
-
-		if (vma->e->flags & MAP_GROWSDOWN)
-			continue;
-
-		/*
-		 * I need to poke every potentially marked vma,
-		 * otherwise if task never called for vdso functions
-		 * page frame number won't be reported.
-		 */
-		args->start = vma->e->start;
-		args->len = vma_area_len(vma);
-
-		if (parasite_execute_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
-			pr_err("vdso: Parasite failed to poke for mark\n");
-			ret = -1;
-			goto err;
-		}
-
-		/*
-		 * Defer handling marked vdso until we walked over
-		 * all vmas and restore potentially remapped vDSO
-		 * area status.
-		 */
-		if (unlikely(args->is_marked)) {
-			if (proxy_vdso_marked) {
-				pr_err("Ow! Second vdso mark detected!\n");
-				ret = -1;
-				goto err;
-			}
-			proxy_vdso_marked = vma;
-			proxy_vdso_addr = args->proxy_vdso_addr;
-			proxy_vvar_addr = args->proxy_vvar_addr;
-			continue;
-		}
-
-		off = (vma->e->start / PAGE_SIZE) * sizeof(u64);
-		ret = pread(fd, &pfn, sizeof(pfn), off);
-		if (ret < 0 || ret != sizeof(pfn)) {
-			pr_perror("Can't read pme for pid %d", pid);
-			ret = -1;
-			goto err;
-		}
-
-		pfn = PME_PFRAME(pfn);
-		if (!pfn) {
-			pr_err("Unexpected page fram number 0 for pid %d\n", pid);
-			ret = -1;
-			goto err;
-		}
-
-		/*
-		 * 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) {
-			if (!vma_area_is(vma, VMA_AREA_VDSO)) {
-				pr_debug("vdso: Restore vDSO status by pfn at %lx\n",
-					 (long)vma->e->start);
-				vma->e->status |= VMA_AREA_VDSO;
-			}
-		} else {
-			if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) {
-				pr_debug("vdso: Drop mishinted vDSO status at %lx\n",
-					 (long)vma->e->start);
-				vma->e->status &= ~VMA_AREA_VDSO;
-			}
-		}
-	}
-
-	/*
-	 * There is marked vdso, it means such vdso is autogenerated
-	 * and must be dropped from vma list.
-	 */
-	if (proxy_vdso_marked) {
-		pr_debug("vdso: Found marked at %lx (proxy vDSO at %lx VVAR at %lx)\n",
-			 (long)proxy_vdso_marked->e->start,
-			 (long)proxy_vdso_addr, (long)proxy_vvar_addr);
-
-		/*
-		 * Don't forget to restore the proxy vdso/vvar status, since
-		 * it's unknown to the kernel.
-		 */
-		list_for_each_entry(vma, &vma_area_list->h, list) {
-			if (vma->e->start == proxy_vdso_addr) {
-				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
-				pr_debug("vdso: Restore proxy vDSO status at %lx\n",
-					 (long)vma->e->start);
-			} else if (vma->e->start == proxy_vvar_addr) {
-				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR;
-				pr_debug("vdso: Restore proxy VVAR status at %lx\n",
-					 (long)vma->e->start);
-			}
-		}
-
-		pr_debug("vdso: Droppping marked vdso at %lx\n",
-			 (long)proxy_vdso_marked->e->start);
-		list_del(&proxy_vdso_marked->list);
-		xfree(proxy_vdso_marked);
-		vma_area_list->nr--;
-
-		if (proxy_vvar_marked) {
-			pr_debug("vdso: Droppping marked vvar at %lx\n",
-				 (long)proxy_vvar_marked->e->start);
-			list_del(&proxy_vvar_marked->list);
-			xfree(proxy_vvar_marked);
-			vma_area_list->nr--;
-		}
-	}
-	ret = 0;
-err:
-	close(fd);
-	return ret;
-}
-
-static int vdso_fill_self_symtable(struct vdso_symtable *s)
-{
-	char buf[512];
-	int ret = -1;
-	FILE *maps;
-
-	*s = (struct vdso_symtable)VDSO_SYMTABLE_INIT;
-
-	maps = fopen_proc(PROC_SELF, "maps");
-	if (!maps) {
-		pr_perror("Can't open self-vma");
-		return -1;
-	}
-
-	while (fgets(buf, sizeof(buf), maps)) {
-		unsigned long start, end;
-		char *has_vdso, *has_vvar;
-
-		has_vdso = strstr(buf, "[vdso]");
-		if (!has_vdso)
-			has_vvar = strstr(buf, "[vvar]");
-		else
-			has_vvar = NULL;
-
-		if (!has_vdso && !has_vvar)
-			continue;
-
-		ret = sscanf(buf, "%lx-%lx", &start, &end);
-		if (ret != 2) {
-			ret = -1;
-			pr_err("Can't find vDSO/VVAR bounds\n");
-			goto err;
-		}
-
-		if (has_vdso) {
-			if (s->vma_start != VDSO_BAD_ADDR) {
-				pr_err("Got second vDSO entry\n");
-				ret = -1;
-				goto err;
-			}
-			s->vma_start = start;
-			s->vma_end = end;
-
-			ret = vdso_fill_symtable((void *)start, end - start, s);
-			if (ret)
-				goto err;
-		} else {
-			if (s->vvar_start != VVAR_BAD_ADDR) {
-				pr_err("Got second VVAR entry\n");
-				ret = -1;
-				goto err;
-			}
-			s->vvar_start = start;
-			s->vvar_end = end;
-		}
-	}
-
-	/*
-	 * Validate its structure -- for new vDSO format the
-	 * structure must be like
-	 *
-	 * 7fff1f5fd000-7fff1f5fe000 r-xp 00000000 00:00 0 [vdso]
-	 * 7fff1f5fe000-7fff1f600000 r--p 00000000 00:00 0 [vvar]
-	 *
-	 * The areas may be in reverse order.
-	 *
-	 * 7fffc3502000-7fffc3504000 r--p 00000000 00:00 0 [vvar]
-	 * 7fffc3504000-7fffc3506000 r-xp 00000000 00:00 0 [vdso]
-	 *
-	 */
-	ret = 0;
-	if (s->vma_start != VDSO_BAD_ADDR) {
-		if (s->vvar_start != VVAR_BAD_ADDR) {
-			if (s->vma_end != s->vvar_start &&
-			    s->vvar_end != s->vma_start) {
-				ret = -1;
-				pr_err("Unexpected rt vDSO area bounds\n");
-				goto err;
-			}
-		}
-	} else {
-		ret = -1;
-		pr_err("Can't find rt vDSO\n");
-		goto err;
-	}
-
-	pr_debug("rt [vdso] %lx-%lx [vvar] %lx-%lx\n",
-		 s->vma_start, s->vma_end,
-		 s->vvar_start, s->vvar_end);
-
-err:
-	fclose(maps);
-	return ret;
-}
-
-int vdso_init(void)
-{
-	if (vdso_fill_self_symtable(&vdso_sym_rt))
-		return -1;
-	return vaddr_to_pfn(vdso_sym_rt.vma_start, &vdso_pfn);
-}
diff --git a/arch/x86/vdso.c b/arch/x86/vdso.c
deleted file mode 100644
index 68805fdd0876..000000000000
--- a/arch/x86/vdso.c
+++ /dev/null
@@ -1,294 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <elf.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include "asm/types.h"
-#include "asm/parasite-syscall.h"
-
-#include "parasite-syscall.h"
-#include "parasite.h"
-#include "compiler.h"
-#include "kerndat.h"
-#include "vdso.h"
-#include "util.h"
-#include "log.h"
-#include "mem.h"
-#include "vma.h"
-
-#ifdef LOG_PREFIX
-# undef LOG_PREFIX
-#endif
-#define LOG_PREFIX "vdso: "
-
-struct vdso_symtable vdso_sym_rt = VDSO_SYMTABLE_INIT;
-u64 vdso_pfn = VDSO_BAD_PFN;
-/*
- * 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
- * generated again on restore if needed.
- */
-int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
-			struct vm_area_list *vma_area_list)
-{
-	unsigned long proxy_vdso_addr = VDSO_BAD_ADDR;
-	unsigned long proxy_vvar_addr = VVAR_BAD_ADDR;
-	struct vma_area *proxy_vdso_marked = NULL;
-	struct vma_area *proxy_vvar_marked = NULL;
-	struct parasite_vdso_vma_entry *args;
-	struct vma_area *vma;
-	int fd, ret, exit_code = -1;
-	off_t off;
-	u64 pfn;
-
-	args = parasite_args(ctl, struct parasite_vdso_vma_entry);
-	fd = open_proc(pid, "pagemap");
-	if (fd < 0)
-		return -1;
-
-	list_for_each_entry(vma, &vma_area_list->h, list) {
-		if (!vma_area_is(vma, VMA_AREA_REGULAR))
-			continue;
-
-		if (vma_area_is(vma, VMA_FILE_SHARED) ||
-				vma_area_is(vma, VMA_FILE_PRIVATE))
-			continue;
-		/*
-		 * It might be possible VVAR area from marked
-		 * vDSO zone, we need to detect it earlier than
-		 * VDSO_PROT test because VVAR_PROT is a subset
-		 * of it but don't yield continue here,
-		 * sigh... what a mess.
-		 */
-		BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT));
-
-		if ((vma->e->prot & VVAR_PROT) == VVAR_PROT) {
-			if (proxy_vvar_addr != VVAR_BAD_ADDR &&
-			    proxy_vvar_addr == vma->e->start) {
-				BUG_ON(proxy_vvar_marked);
-				proxy_vvar_marked = vma;
-				continue;
-			}
-		}
-
-		if ((vma->e->prot & VDSO_PROT) != VDSO_PROT)
-			continue;
-
-		if (vma->e->start > TASK_SIZE)
-			continue;
-
-		if (vma->e->flags & MAP_GROWSDOWN)
-			continue;
-
-		/*
-		 * I need to poke every potentially marked vma,
-		 * otherwise if task never called for vdso functions
-		 * page frame number won't be reported.
-		 */
-		args->start = vma->e->start;
-		args->len = vma_area_len(vma);
-
-		if (parasite_execute_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
-			pr_err("vdso: Parasite failed to poke for mark\n");
-			goto err;
-		}
-
-		/*
-		 * Defer handling marked vdso until we walked over
-		 * all vmas and restore potentially remapped vDSO
-		 * area status.
-		 */
-		if (unlikely(args->is_marked)) {
-			if (proxy_vdso_marked) {
-				pr_err("Ow! Second vdso mark detected!\n");
-				goto err;
-			}
-			proxy_vdso_marked = vma;
-			proxy_vdso_addr = args->proxy_vdso_addr;
-			proxy_vvar_addr = args->proxy_vvar_addr;
-			continue;
-		}
-
-		off = (vma->e->start / PAGE_SIZE) * sizeof(u64);
-		ret = pread(fd, &pfn, sizeof(pfn), off);
-		if (ret < 0 || ret != sizeof(pfn)) {
-			pr_perror("Can't read pme for pid %d", pid);
-			goto err;
-		}
-
-		pfn = PME_PFRAME(pfn);
-		if (!pfn) {
-			pr_err("Unexpected page fram number 0 for pid %d\n", pid);
-			goto err;
-		}
-
-		/*
-		 * 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) {
-			if (!vma_area_is(vma, VMA_AREA_VDSO)) {
-				pr_debug("vdso: Restore vDSO status by pfn at %lx\n",
-					 (long)vma->e->start);
-				vma->e->status |= VMA_AREA_VDSO;
-			}
-		} else {
-			if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) {
-				pr_debug("vdso: Drop mishinted vDSO status at %lx\n",
-					 (long)vma->e->start);
-				vma->e->status &= ~VMA_AREA_VDSO;
-			}
-		}
-	}
-
-	/*
-	 * There is marked vdso, it means such vdso is autogenerated
-	 * and must be dropped from vma list.
-	 */
-	if (proxy_vdso_marked) {
-		pr_debug("vdso: Found marked at %lx (proxy vDSO at %lx VVAR at %lx)\n",
-			 (long)proxy_vdso_marked->e->start,
-			 (long)proxy_vdso_addr, (long)proxy_vvar_addr);
-
-		/*
-		 * Don't forget to restore the proxy vdso/vvar status, since
-		 * it's unknown to the kernel.
-		 */
-		list_for_each_entry(vma, &vma_area_list->h, list) {
-			if (vma->e->start == proxy_vdso_addr) {
-				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
-				pr_debug("vdso: Restore proxy vDSO status at %lx\n",
-					 (long)vma->e->start);
-			} else if (vma->e->start == proxy_vvar_addr) {
-				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR;
-				pr_debug("vdso: Restore proxy VVAR status at %lx\n",
-					 (long)vma->e->start);
-			}
-		}
-
-		pr_debug("vdso: Droppping marked vdso at %lx\n",
-			 (long)proxy_vdso_marked->e->start);
-		list_del(&proxy_vdso_marked->list);
-		xfree(proxy_vdso_marked);
-		vma_area_list->nr--;
-
-		if (proxy_vvar_marked) {
-			pr_debug("vdso: Droppping marked vvar at %lx\n",
-				 (long)proxy_vvar_marked->e->start);
-			list_del(&proxy_vvar_marked->list);
-			xfree(proxy_vvar_marked);
-			vma_area_list->nr--;
-		}
-	}
-	exit_code = 0;
-err:
-	close(fd);
-	return exit_code;
-}
-
-static int vdso_fill_self_symtable(struct vdso_symtable *s)
-{
-	char buf[512];
-	int ret, exit_code = -1;
-	FILE *maps;
-
-	*s = (struct vdso_symtable)VDSO_SYMTABLE_INIT;
-
-	maps = fopen_proc(PROC_SELF, "maps");
-	if (!maps) {
-		pr_perror("Can't open self-vma");
-		return -1;
-	}
-
-	while (fgets(buf, sizeof(buf), maps)) {
-		unsigned long start, end;
-		char *has_vdso, *has_vvar;
-
-		has_vdso = strstr(buf, "[vdso]");
-		if (!has_vdso)
-			has_vvar = strstr(buf, "[vvar]");
-		else
-			has_vvar = NULL;
-
-		if (!has_vdso && !has_vvar)
-			continue;
-
-		ret = sscanf(buf, "%lx-%lx", &start, &end);
-		if (ret != 2) {
-			pr_err("Can't find vDSO/VVAR bounds\n");
-			goto err;
-		}
-
-		if (has_vdso) {
-			if (s->vma_start != VDSO_BAD_ADDR) {
-				pr_err("Got second vDSO entry\n");
-				goto err;
-			}
-			s->vma_start = start;
-			s->vma_end = end;
-
-			ret = vdso_fill_symtable((void *)start, end - start, s);
-			if (ret)
-				goto err;
-		} else {
-			if (s->vvar_start != VVAR_BAD_ADDR) {
-				pr_err("Got second VVAR entry\n");
-				goto err;
-			}
-			s->vvar_start = start;
-			s->vvar_end = end;
-		}
-	}
-
-	/*
-	 * Validate its structure -- for new vDSO format the
-	 * structure must be like
-	 *
-	 * 7fff1f5fd000-7fff1f5fe000 r-xp 00000000 00:00 0 [vdso]
-	 * 7fff1f5fe000-7fff1f600000 r--p 00000000 00:00 0 [vvar]
-	 *
-	 * The areas may be in reverse order.
-	 *
-	 * 7fffc3502000-7fffc3504000 r--p 00000000 00:00 0 [vvar]
-	 * 7fffc3504000-7fffc3506000 r-xp 00000000 00:00 0 [vdso]
-	 *
-	 */
-	if (s->vma_start != VDSO_BAD_ADDR) {
-		if (s->vvar_start != VVAR_BAD_ADDR) {
-			if (s->vma_end != s->vvar_start &&
-			    s->vvar_end != s->vma_start) {
-				pr_err("Unexpected rt vDSO area bounds\n");
-				goto err;
-			}
-		}
-	} else {
-		pr_err("Can't find rt vDSO\n");
-		goto err;
-	}
-
-	pr_debug("rt [vdso] %lx-%lx [vvar] %lx-%lx\n",
-		 s->vma_start, s->vma_end,
-		 s->vvar_start, s->vvar_end);
-
-	exit_code = 0;
-err:
-	fclose(maps);
-	return exit_code;
-}
-
-int vdso_init(void)
-{
-	if (vdso_fill_self_symtable(&vdso_sym_rt))
-		return -1;
-	return vaddr_to_pfn(vdso_sym_rt.vma_start, &vdso_pfn);
-}
diff --git a/vdso.c b/vdso.c
new file mode 100644
index 000000000000..1524d475cb01
--- /dev/null
+++ b/vdso.c
@@ -0,0 +1,294 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <elf.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "asm/types.h"
+#include "asm/parasite-syscall.h"
+
+#include "parasite-syscall.h"
+#include "parasite.h"
+#include "compiler.h"
+#include "kerndat.h"
+#include "vdso.h"
+#include "util.h"
+#include "log.h"
+#include "mem.h"
+#include "vma.h"
+
+#ifdef LOG_PREFIX
+# undef LOG_PREFIX
+#endif
+#define LOG_PREFIX "vdso: "
+
+struct vdso_symtable vdso_sym_rt = VDSO_SYMTABLE_INIT;
+u64 vdso_pfn = VDSO_BAD_PFN;
+/*
+ * 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
+ * generated again on restore if needed.
+ */
+int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
+			struct vm_area_list *vma_area_list)
+{
+	unsigned long proxy_vdso_addr = VDSO_BAD_ADDR;
+	unsigned long proxy_vvar_addr = VVAR_BAD_ADDR;
+	struct vma_area *proxy_vdso_marked = NULL;
+	struct vma_area *proxy_vvar_marked = NULL;
+	struct parasite_vdso_vma_entry *args;
+	struct vma_area *vma;
+	int fd, ret, exit_code = -1;
+	off_t off;
+	u64 pfn;
+
+	args = parasite_args(ctl, struct parasite_vdso_vma_entry);
+	fd = open_proc(pid, "pagemap");
+	if (fd < 0)
+		return -1;
+
+	list_for_each_entry(vma, &vma_area_list->h, list) {
+		if (!vma_area_is(vma, VMA_AREA_REGULAR))
+			continue;
+
+		if (vma_area_is(vma, VMA_FILE_SHARED) ||
+				vma_area_is(vma, VMA_FILE_PRIVATE))
+			continue;
+		/*
+		 * It might be possible VVAR area from marked
+		 * vDSO zone, we need to detect it earlier than
+		 * VDSO_PROT test because VVAR_PROT is a subset
+		 * of it but don't yield continue here,
+		 * sigh... what a mess.
+		 */
+		BUILD_BUG_ON(!(VDSO_PROT & VVAR_PROT));
+
+		if ((vma->e->prot & VVAR_PROT) == VVAR_PROT) {
+			if (proxy_vvar_addr != VVAR_BAD_ADDR &&
+			    proxy_vvar_addr == vma->e->start) {
+				BUG_ON(proxy_vvar_marked);
+				proxy_vvar_marked = vma;
+				continue;
+			}
+		}
+
+		if ((vma->e->prot & VDSO_PROT) != VDSO_PROT)
+			continue;
+
+		if (vma->e->start > kdat.task_size)
+			continue;
+
+		if (vma->e->flags & MAP_GROWSDOWN)
+			continue;
+
+		/*
+		 * I need to poke every potentially marked vma,
+		 * otherwise if task never called for vdso functions
+		 * page frame number won't be reported.
+		 */
+		args->start = vma->e->start;
+		args->len = vma_area_len(vma);
+
+		if (parasite_execute_daemon(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
+			pr_err("vdso: Parasite failed to poke for mark\n");
+			goto err;
+		}
+
+		/*
+		 * Defer handling marked vdso until we walked over
+		 * all vmas and restore potentially remapped vDSO
+		 * area status.
+		 */
+		if (unlikely(args->is_marked)) {
+			if (proxy_vdso_marked) {
+				pr_err("Ow! Second vdso mark detected!\n");
+				goto err;
+			}
+			proxy_vdso_marked = vma;
+			proxy_vdso_addr = args->proxy_vdso_addr;
+			proxy_vvar_addr = args->proxy_vvar_addr;
+			continue;
+		}
+
+		off = (vma->e->start / PAGE_SIZE) * sizeof(u64);
+		ret = pread(fd, &pfn, sizeof(pfn), off);
+		if (ret < 0 || ret != sizeof(pfn)) {
+			pr_perror("Can't read pme for pid %d", pid);
+			goto err;
+		}
+
+		pfn = PME_PFRAME(pfn);
+		if (!pfn) {
+			pr_err("Unexpected page fram number 0 for pid %d\n", pid);
+			goto err;
+		}
+
+		/*
+		 * 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) {
+			if (!vma_area_is(vma, VMA_AREA_VDSO)) {
+				pr_debug("vdso: Restore vDSO status by pfn at %lx\n",
+					 (long)vma->e->start);
+				vma->e->status |= VMA_AREA_VDSO;
+			}
+		} else {
+			if (unlikely(vma_area_is(vma, VMA_AREA_VDSO))) {
+				pr_debug("vdso: Drop mishinted vDSO status at %lx\n",
+					 (long)vma->e->start);
+				vma->e->status &= ~VMA_AREA_VDSO;
+			}
+		}
+	}
+
+	/*
+	 * There is marked vdso, it means such vdso is autogenerated
+	 * and must be dropped from vma list.
+	 */
+	if (proxy_vdso_marked) {
+		pr_debug("vdso: Found marked at %lx (proxy vDSO at %lx VVAR at %lx)\n",
+			 (long)proxy_vdso_marked->e->start,
+			 (long)proxy_vdso_addr, (long)proxy_vvar_addr);
+
+		/*
+		 * Don't forget to restore the proxy vdso/vvar status, since
+		 * it's unknown to the kernel.
+		 */
+		list_for_each_entry(vma, &vma_area_list->h, list) {
+			if (vma->e->start == proxy_vdso_addr) {
+				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
+				pr_debug("vdso: Restore proxy vDSO status at %lx\n",
+					 (long)vma->e->start);
+			} else if (vma->e->start == proxy_vvar_addr) {
+				vma->e->status |= VMA_AREA_REGULAR | VMA_AREA_VVAR;
+				pr_debug("vdso: Restore proxy VVAR status at %lx\n",
+					 (long)vma->e->start);
+			}
+		}
+
+		pr_debug("vdso: Droppping marked vdso at %lx\n",
+			 (long)proxy_vdso_marked->e->start);
+		list_del(&proxy_vdso_marked->list);
+		xfree(proxy_vdso_marked);
+		vma_area_list->nr--;
+
+		if (proxy_vvar_marked) {
+			pr_debug("vdso: Droppping marked vvar at %lx\n",
+				 (long)proxy_vvar_marked->e->start);
+			list_del(&proxy_vvar_marked->list);
+			xfree(proxy_vvar_marked);
+			vma_area_list->nr--;
+		}
+	}
+	exit_code = 0;
+err:
+	close(fd);
+	return exit_code;
+}
+
+static int vdso_fill_self_symtable(struct vdso_symtable *s)
+{
+	char buf[512];
+	int ret, exit_code = -1;
+	FILE *maps;
+
+	*s = (struct vdso_symtable)VDSO_SYMTABLE_INIT;
+
+	maps = fopen_proc(PROC_SELF, "maps");
+	if (!maps) {
+		pr_perror("Can't open self-vma");
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), maps)) {
+		unsigned long start, end;
+		char *has_vdso, *has_vvar;
+
+		has_vdso = strstr(buf, "[vdso]");
+		if (!has_vdso)
+			has_vvar = strstr(buf, "[vvar]");
+		else
+			has_vvar = NULL;
+
+		if (!has_vdso && !has_vvar)
+			continue;
+
+		ret = sscanf(buf, "%lx-%lx", &start, &end);
+		if (ret != 2) {
+			pr_err("Can't find vDSO/VVAR bounds\n");
+			goto err;
+		}
+
+		if (has_vdso) {
+			if (s->vma_start != VDSO_BAD_ADDR) {
+				pr_err("Got second vDSO entry\n");
+				goto err;
+			}
+			s->vma_start = start;
+			s->vma_end = end;
+
+			ret = vdso_fill_symtable((void *)start, end - start, s);
+			if (ret)
+				goto err;
+		} else {
+			if (s->vvar_start != VVAR_BAD_ADDR) {
+				pr_err("Got second VVAR entry\n");
+				goto err;
+			}
+			s->vvar_start = start;
+			s->vvar_end = end;
+		}
+	}
+
+	/*
+	 * Validate its structure -- for new vDSO format the
+	 * structure must be like
+	 *
+	 * 7fff1f5fd000-7fff1f5fe000 r-xp 00000000 00:00 0 [vdso]
+	 * 7fff1f5fe000-7fff1f600000 r--p 00000000 00:00 0 [vvar]
+	 *
+	 * The areas may be in reverse order.
+	 *
+	 * 7fffc3502000-7fffc3504000 r--p 00000000 00:00 0 [vvar]
+	 * 7fffc3504000-7fffc3506000 r-xp 00000000 00:00 0 [vdso]
+	 *
+	 */
+	if (s->vma_start != VDSO_BAD_ADDR) {
+		if (s->vvar_start != VVAR_BAD_ADDR) {
+			if (s->vma_end != s->vvar_start &&
+			    s->vvar_end != s->vma_start) {
+				pr_err("Unexpected rt vDSO area bounds\n");
+				goto err;
+			}
+		}
+	} else {
+		pr_err("Can't find rt vDSO\n");
+		goto err;
+	}
+
+	pr_debug("rt [vdso] %lx-%lx [vvar] %lx-%lx\n",
+		 s->vma_start, s->vma_end,
+		 s->vvar_start, s->vvar_end);
+
+	exit_code = 0;
+err:
+	fclose(maps);
+	return exit_code;
+}
+
+int vdso_init(void)
+{
+	if (vdso_fill_self_symtable(&vdso_sym_rt))
+		return -1;
+	return vaddr_to_pfn(vdso_sym_rt.vma_start, &vdso_pfn);
+}
-- 
1.9.1



More information about the CRIU mailing list