From 199dba2361d423d293d62f16883194c3a825cb1c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 15 Apr 2013 13:24:32 +0400 Subject: [PATCH] soft-dirty: Check that kernel reports soft-dirty bits Signed-off-by: Pavel Emelyanov --- cr-check.c | 12 ++++++++++++ include/kerndat.h | 5 +++++ kerndat.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ mem.c | 7 +++++++ 4 files changed, 72 insertions(+) diff --git a/cr-check.c b/cr-check.c index 82ec2f807..70d2f5840 100644 --- a/cr-check.c +++ b/cr-check.c @@ -25,6 +25,7 @@ #include "mount.h" #include "tty.h" #include "ptrace.h" +#include "kerndat.h" static int check_tty(void) { @@ -486,6 +487,16 @@ int check_ptrace_peeksiginfo() return ret; } +static int check_mem_dirty_track(void) +{ + if (kerndat_get_dirty_track() < 0) + return -1; + + if (!kerndat_has_dirty_track) + pr_info("Dirty tracking is OFF. Memory snapshot will not work.\n"); + return 0; +} + int cr_check(void) { int ret = 0; @@ -513,6 +524,7 @@ int cr_check(void) ret |= check_ipc(); ret |= check_sigqueuinfo(); ret |= check_ptrace_peeksiginfo(); + ret |= check_mem_dirty_track(); if (!ret) pr_msg("Looks good.\n"); diff --git a/include/kerndat.h b/include/kerndat.h index 38b29391e..9f6b4ede6 100644 --- a/include/kerndat.h +++ b/include/kerndat.h @@ -1,11 +1,16 @@ #ifndef __CR_KERNDAT_H__ #define __CR_KERNDAT_H__ + +#include "asm/types.h" + /* * kerndat stands for "kernel data" and is a collection * of run-time information about current kernel */ int kerndat_init(void); +int kerndat_get_dirty_track(void); extern dev_t kerndat_shmem_dev; +extern bool kerndat_has_dirty_track; #endif diff --git a/kerndat.c b/kerndat.c index 7ae49295e..e9e243d74 100644 --- a/kerndat.c +++ b/kerndat.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -42,11 +44,57 @@ static int kerndat_get_shmemdev(void) return 0; } +/* + * Check whether pagemap2 reports soft dirty bit. Kernel has + * this functionality under CONFIG_MEM_SOFT_DIRTY option. + */ + +#define PME_SOFT_DIRTY (1Ull << 55) + +bool kerndat_has_dirty_track = false; + +int kerndat_get_dirty_track(void) +{ + char *map; + int pm2; + u64 pmap = 0; + + map = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (map == MAP_FAILED) { + pr_perror("Can't mmap piggie2"); + return -1; + } + + map[0] = '\0'; + + pm2 = open("/proc/self/pagemap2", O_RDONLY); + if (pm2 < 0) { + pr_perror("Can't open pagemap2 file"); + return -1; + } + + lseek(pm2, (unsigned long)map / PAGE_SIZE * sizeof(u64), SEEK_SET); + read(pm2, &pmap, sizeof(pmap)); + close(pm2); + munmap(map, PAGE_SIZE); + + if (pmap & PME_SOFT_DIRTY) { + pr_info("Dirty track supported on kernel\n"); + kerndat_has_dirty_track = true; + } else + pr_err("Dirty tracking support is OFF\n"); + + return 0; +} + int kerndat_init(void) { int ret; ret = kerndat_get_shmemdev(); + if (!ret) + ret = kerndat_get_dirty_track(); return ret; } diff --git a/mem.c b/mem.c index 6e7f2f3a4..5716cfbdc 100644 --- a/mem.c +++ b/mem.c @@ -10,6 +10,7 @@ #include "page-pipe.h" #include "page-xfer.h" #include "log.h" +#include "kerndat.h" #include "protobuf.h" #include "protobuf/pagemap.pb-c.h" @@ -62,6 +63,12 @@ static struct mem_snap_ctx *mem_snap_init(struct parasite_ctl *ctl) if (!opts.mem_snapshot) return NULL; + if (!kerndat_has_dirty_track) { + pr_err("Kernel doesn't support dirty tracking. " + "No snapshot available.\n"); + return ERR_PTR(-1); + } + p_fd = get_service_fd(PARENT_FD_OFF); if (p_fd < 0) { pr_debug("Will do full memory dump\n");