Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+89 −65
Original line number Diff line number Diff line
@@ -161,8 +161,6 @@ static unsigned long pg_start[MAX_VMAS];
static unsigned long	pg_end[MAX_VMAS];
static unsigned long	voffset;

static int		pagemap_fd;

#define MAX_BIT_FILTERS	64
static int		nr_bit_filters;
static uint64_t		opt_mask[MAX_BIT_FILTERS];
@@ -170,7 +168,7 @@ static uint64_t opt_bits[MAX_BIT_FILTERS];

static int		page_size;

#define PAGES_BATCH	(64 << 10)	/* 64k pages */
static int		pagemap_fd;
static int		kpageflags_fd;

#define HASH_SHIFT	13
@@ -226,6 +224,62 @@ int checked_open(const char *pathname, int flags)
	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
@@ -432,79 +486,53 @@ static void add_page(unsigned long offset, uint64_t flags)
	total_pages++;
}

#define KPAGEFLAGS_BATCH	(64 << 10)	/* 64k pages */
static void walk_pfn(unsigned long index, unsigned long count)
{
	uint64_t buf[KPAGEFLAGS_BATCH];
	unsigned long batch;
	unsigned long n;
	unsigned long pages;
	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) {
		uint64_t kpageflags_buf[KPF_BYTES * PAGES_BATCH];

		batch = min_t(unsigned long, count, PAGES_BATCH);
		n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES);
		if (n == 0)
		batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
		pages = kpageflags_read(buf, index, batch);
		if (pages == 0)
			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++)
			add_page(index + i, kpageflags_buf[i]);
		for (i = 0; i < pages; i++)
			add_page(index + i, buf[i]);

		index += batch;
		count -= batch;
		index += pages;
		count -= pages;
	}
}


#define PAGEMAP_BATCH	4096
static unsigned long task_pfn(unsigned long pgoff)
#define PAGEMAP_BATCH	(64 << 10)
static void walk_vma(unsigned long index, unsigned long count)
{
	static uint64_t buf[PAGEMAP_BATCH];
	static unsigned long start;
	static long count;
	uint64_t pfn;
	uint64_t buf[PAGEMAP_BATCH];
	unsigned long batch;
	unsigned long pages;
	unsigned long pfn;
	unsigned long i;

	if (pgoff < start || pgoff >= start + count) {
		if (lseek64(pagemap_fd,
			    (uint64_t)pgoff * PM_ENTRY_BYTES,
			    SEEK_SET) < 0) {
			perror("pagemap seek");
			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;
	}
	while (count) {
		batch = min_t(unsigned long, count, PAGEMAP_BATCH);
		pages = pagemap_read(buf, index, batch);
		if (pages == 0)
			break;

	pfn = buf[pgoff - start];
	if (pfn & PM_PRESENT)
		pfn = PM_PFRAME(pfn);
	else
		pfn = 0;
		for (i = 0; i < pages; i++) {
			pfn = pagemap_pfn(buf[i]);
			voffset = index + i;
			if (pfn)
				walk_pfn(pfn, 1);
		}

	return pfn;
		index += pages;
		count -= pages;
	}
}

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);

		assert(voffset < index);
		for (; voffset < index; voffset++) {
			unsigned long pfn = task_pfn(voffset);
			if (pfn)
				walk_pfn(pfn, 1);
		}
		walk_vma(voffset, index - voffset);
	}
}