2013-04-15 13:24:32 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
2013-04-15 13:02:09 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
2013-04-23 23:22:25 +04:00
|
|
|
#include <errno.h>
|
2013-04-15 13:02:09 +04:00
|
|
|
|
|
|
|
#include "log.h"
|
|
|
|
#include "kerndat.h"
|
2013-05-17 16:13:49 +04:00
|
|
|
#include "mem.h"
|
2013-04-15 13:02:09 +04:00
|
|
|
#include "asm/types.h"
|
|
|
|
|
|
|
|
dev_t kerndat_shmem_dev;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Anonymous shared mappings are backed by hidden tmpfs
|
|
|
|
* mount. Find out its dev to distinguish such mappings
|
|
|
|
* from real tmpfs files maps.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int kerndat_get_shmemdev(void)
|
|
|
|
{
|
|
|
|
void *map;
|
|
|
|
char maps[128];
|
|
|
|
struct stat buf;
|
|
|
|
|
|
|
|
map = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
|
|
|
|
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
|
|
|
|
if (map == MAP_FAILED) {
|
|
|
|
pr_perror("Can't mmap piggie");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(maps, "/proc/self/map_files/%lx-%lx",
|
|
|
|
(unsigned long)map, (unsigned long)map + PAGE_SIZE);
|
|
|
|
if (stat(maps, &buf) < 0) {
|
2013-05-04 22:03:08 +04:00
|
|
|
munmap(map, PAGE_SIZE);
|
2013-04-15 13:02:09 +04:00
|
|
|
pr_perror("Can't stat piggie");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
munmap(map, PAGE_SIZE);
|
|
|
|
|
|
|
|
kerndat_shmem_dev = buf.st_dev;
|
|
|
|
pr_info("Found anon-shmem piggie at %"PRIx64"\n", kerndat_shmem_dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-15 13:24:32 +04:00
|
|
|
/*
|
2013-07-02 09:51:33 +04:00
|
|
|
* Check whether pagemap reports soft dirty bit. Kernel has
|
2013-04-15 13:24:32 +04:00
|
|
|
* this functionality under CONFIG_MEM_SOFT_DIRTY option.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool kerndat_has_dirty_track = false;
|
|
|
|
|
|
|
|
int kerndat_get_dirty_track(void)
|
|
|
|
{
|
|
|
|
char *map;
|
|
|
|
int pm2;
|
|
|
|
u64 pmap = 0;
|
2013-04-16 21:51:27 +04:00
|
|
|
int ret = -1;
|
2013-04-15 13:24:32 +04:00
|
|
|
|
|
|
|
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");
|
2013-04-16 21:51:27 +04:00
|
|
|
return ret;
|
2013-04-15 13:24:32 +04:00
|
|
|
}
|
|
|
|
|
2013-07-02 09:51:33 +04:00
|
|
|
/*
|
|
|
|
* Kernel shows soft-dirty bits only if this soft-dirty
|
|
|
|
* was at least once re-set. (this is to be removed in
|
|
|
|
* a couple of kernel releases)
|
|
|
|
*/
|
|
|
|
do_task_reset_dirty_track(getpid());
|
|
|
|
pm2 = open("/proc/self/pagemap", O_RDONLY);
|
2013-04-15 13:24:32 +04:00
|
|
|
if (pm2 < 0) {
|
2013-07-02 09:51:33 +04:00
|
|
|
pr_perror("Can't open pagemap file");
|
2013-04-23 23:22:25 +04:00
|
|
|
munmap(map, PAGE_SIZE);
|
2013-04-16 21:51:27 +04:00
|
|
|
return ret;
|
2013-04-15 13:24:32 +04:00
|
|
|
}
|
|
|
|
|
2013-05-17 16:13:49 +04:00
|
|
|
map[0] = '\0';
|
|
|
|
|
2013-04-15 13:24:32 +04:00
|
|
|
lseek(pm2, (unsigned long)map / PAGE_SIZE * sizeof(u64), SEEK_SET);
|
2013-04-16 21:51:27 +04:00
|
|
|
ret = read(pm2, &pmap, sizeof(pmap));
|
2013-07-02 09:52:22 +04:00
|
|
|
if (ret < 0)
|
2013-04-16 21:51:27 +04:00
|
|
|
pr_perror("Read pmap err!");
|
|
|
|
|
2013-04-15 13:24:32 +04:00
|
|
|
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
|
2013-07-02 09:15:50 +04:00
|
|
|
pr_info("Dirty tracking support is OFF\n");
|
2013-04-15 13:24:32 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-15 13:02:09 +04:00
|
|
|
int kerndat_init(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = kerndat_get_shmemdev();
|
2013-04-15 13:24:32 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = kerndat_get_dirty_track();
|
2013-04-15 13:02:09 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|