Commit 4a1b6726 authored by Wu Fengguang's avatar Wu Fengguang Committed by Linus Torvalds

page-types: make standalone pagemap/kpageflags read routines

Refactor the code to be more modular and easier to reuse.
Signed-off-by: default avatarWu Fengguang <fengguang.wu@intel.com>
Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 31bbf66e
...@@ -161,8 +161,6 @@ static unsigned long pg_start[MAX_VMAS]; ...@@ -161,8 +161,6 @@ static unsigned long pg_start[MAX_VMAS];
static unsigned long pg_end[MAX_VMAS]; static unsigned long pg_end[MAX_VMAS];
static unsigned long voffset; static unsigned long voffset;
static int pagemap_fd;
#define MAX_BIT_FILTERS 64 #define MAX_BIT_FILTERS 64
static int nr_bit_filters; static int nr_bit_filters;
static uint64_t opt_mask[MAX_BIT_FILTERS]; static uint64_t opt_mask[MAX_BIT_FILTERS];
...@@ -170,7 +168,7 @@ static uint64_t opt_bits[MAX_BIT_FILTERS]; ...@@ -170,7 +168,7 @@ static uint64_t opt_bits[MAX_BIT_FILTERS];
static int page_size; static int page_size;
#define PAGES_BATCH (64 << 10) /* 64k pages */ static int pagemap_fd;
static int kpageflags_fd; static int kpageflags_fd;
#define HASH_SHIFT 13 #define HASH_SHIFT 13
...@@ -226,6 +224,62 @@ int checked_open(const char *pathname, int flags) ...@@ -226,6 +224,62 @@ int checked_open(const char *pathname, int flags)
return fd; return fd;
} }
/*
* pagemap/kpageflags routines
*/
static unsigned long do_u64_read(int fd, char *name,
uint64_t *buf,
unsigned long index,
unsigned long count)
{
long bytes;
if (index > ULONG_MAX / 8)
fatal("index overflow: %lu\n", index);
if (lseek(fd, index * 8, SEEK_SET) < 0) {
perror(name);
exit(EXIT_FAILURE);
}
bytes = read(fd, buf, count * 8);
if (bytes < 0) {
perror(name);
exit(EXIT_FAILURE);
}
if (bytes % 8)
fatal("partial read: %lu bytes\n", bytes);
return bytes / 8;
}
static unsigned long kpageflags_read(uint64_t *buf,
unsigned long index,
unsigned long pages)
{
return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);
}
static unsigned long pagemap_read(uint64_t *buf,
unsigned long index,
unsigned long pages)
{
return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages);
}
static unsigned long pagemap_pfn(uint64_t val)
{
unsigned long pfn;
if (val & PM_PRESENT)
pfn = PM_PFRAME(val);
else
pfn = 0;
return pfn;
}
/* /*
* page flag names * page flag names
...@@ -432,79 +486,53 @@ static void add_page(unsigned long offset, uint64_t flags) ...@@ -432,79 +486,53 @@ static void add_page(unsigned long offset, uint64_t flags)
total_pages++; total_pages++;
} }
#define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */
static void walk_pfn(unsigned long index, unsigned long count) static void walk_pfn(unsigned long index, unsigned long count)
{ {
uint64_t buf[KPAGEFLAGS_BATCH];
unsigned long batch; unsigned long batch;
unsigned long n; unsigned long pages;
unsigned long i; unsigned long i;
if (index > ULONG_MAX / KPF_BYTES)
fatal("index overflow: %lu\n", index);
lseek(kpageflags_fd, index * KPF_BYTES, SEEK_SET);
while (count) { while (count) {
uint64_t kpageflags_buf[KPF_BYTES * PAGES_BATCH]; batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
pages = kpageflags_read(buf, index, batch);
batch = min_t(unsigned long, count, PAGES_BATCH); if (pages == 0)
n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES);
if (n == 0)
break; break;
if (n < 0) {
perror(PROC_KPAGEFLAGS);
exit(EXIT_FAILURE);
}
if (n % KPF_BYTES != 0)
fatal("partial read: %lu bytes\n", n);
n = n / KPF_BYTES;
for (i = 0; i < n; i++) for (i = 0; i < pages; i++)
add_page(index + i, kpageflags_buf[i]); add_page(index + i, buf[i]);
index += batch; index += pages;
count -= batch; count -= pages;
} }
} }
#define PAGEMAP_BATCH (64 << 10)
#define PAGEMAP_BATCH 4096 static void walk_vma(unsigned long index, unsigned long count)
static unsigned long task_pfn(unsigned long pgoff)
{ {
static uint64_t buf[PAGEMAP_BATCH]; uint64_t buf[PAGEMAP_BATCH];
static unsigned long start; unsigned long batch;
static long count; unsigned long pages;
uint64_t pfn; unsigned long pfn;
unsigned long i;
if (pgoff < start || pgoff >= start + count) { while (count) {
if (lseek64(pagemap_fd, batch = min_t(unsigned long, count, PAGEMAP_BATCH);
(uint64_t)pgoff * PM_ENTRY_BYTES, pages = pagemap_read(buf, index, batch);
SEEK_SET) < 0) { if (pages == 0)
perror("pagemap seek"); break;
exit(EXIT_FAILURE);
}
count = read(pagemap_fd, buf, sizeof(buf));
if (count == 0)
return 0;
if (count < 0) {
perror("pagemap read");
exit(EXIT_FAILURE);
}
if (count % PM_ENTRY_BYTES) {
fatal("pagemap read not aligned.\n");
exit(EXIT_FAILURE);
}
count /= PM_ENTRY_BYTES;
start = pgoff;
}
pfn = buf[pgoff - start]; for (i = 0; i < pages; i++) {
if (pfn & PM_PRESENT) pfn = pagemap_pfn(buf[i]);
pfn = PM_PFRAME(pfn); voffset = index + i;
else if (pfn)
pfn = 0; walk_pfn(pfn, 1);
}
return pfn; index += pages;
count -= pages;
}
} }
static void walk_task(unsigned long index, unsigned long count) static void walk_task(unsigned long index, unsigned long count)
...@@ -524,11 +552,7 @@ static void walk_task(unsigned long index, unsigned long count) ...@@ -524,11 +552,7 @@ static void walk_task(unsigned long index, unsigned long count)
index = min_t(unsigned long, pg_end[i], end); index = min_t(unsigned long, pg_end[i], end);
assert(voffset < index); assert(voffset < index);
for (; voffset < index; voffset++) { walk_vma(voffset, index - voffset);
unsigned long pfn = task_pfn(voffset);
if (pfn)
walk_pfn(pfn, 1);
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment