tools/vm/page-types.c: Hack in mapcount

Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index e92903f..0eb7b48 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -75,6 +75,7 @@
 
 #define KPF_BYTES		8
 #define PROC_KPAGEFLAGS		"/proc/kpageflags"
+#define PROC_KPAGECOUNT		"/proc/kpagecount"
 #define PROC_KPAGECGROUP	"/proc/kpagecgroup"
 
 /* [32-] kernel hacking assistances */
@@ -192,6 +193,7 @@
 
 static int		pagemap_fd;
 static int		kpageflags_fd;
+static int		kpagecount_fd;
 static int		kpagecgroup_fd = -1;
 
 static int		opt_hwpoison;
@@ -286,6 +288,13 @@
 	return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);
 }
 
+static unsigned long kpagecount_read(uint64_t *buf,
+				     unsigned long index,
+				     unsigned long pages)
+{
+	return do_u64_read(kpagecount_fd, PROC_KPAGEFLAGS, buf, index, pages);
+}
+
 static unsigned long kpagecgroup_read(uint64_t *buf,
 				      unsigned long index,
 				      unsigned long pages)
@@ -368,16 +377,17 @@
  */
 
 static void show_page_range(unsigned long voffset, unsigned long offset,
-			    unsigned long size, uint64_t flags, uint64_t cgroup)
+			    unsigned long size, uint64_t flags, uint64_t mapcount, uint64_t cgroup)
 {
 	static uint64_t      flags0;
+	static uint64_t      mapcount0;
 	static uint64_t	     cgroup0;
 	static unsigned long voff;
 	static unsigned long index;
 	static unsigned long count;
 
 	if (flags == flags0 && cgroup == cgroup0 && offset == index + count &&
-	    size && voffset == voff + count) {
+	    size && voffset == voff + count && mapcount == mapcount0) {
 		count += size;
 		return;
 	}
@@ -389,11 +399,12 @@
 			printf("%lu\t", voff);
 		if (opt_list_cgroup)
 			printf("@%llu\t", (unsigned long long)cgroup0);
-		printf("%lx\t%lx\t%s\n",
-				index, count, page_flag_name(flags0));
+		printf("%lx\t%lx\t%s\t%lx\n",
+				index, count, page_flag_name(flags0), mapcount0);
 	}
 
 	flags0 = flags;
+	mapcount0 = mapcount;
 	cgroup0= cgroup;
 	index  = offset;
 	voff   = voffset;
@@ -402,11 +413,11 @@
 
 static void flush_page_range(void)
 {
-	show_page_range(0, 0, 0, 0, 0);
+	show_page_range(0, 0, 0, 0, 0, 0);
 }
 
 static void show_page(unsigned long voffset, unsigned long offset,
-		      uint64_t flags, uint64_t cgroup)
+		      uint64_t flags, uint64_t mapcount, uint64_t cgroup)
 {
 	if (opt_pid)
 		printf("%lx\t", voffset);
@@ -414,7 +425,7 @@
 		printf("%lu\t", voffset);
 	if (opt_list_cgroup)
 		printf("@%llu\t", (unsigned long long)cgroup);
-	printf("%lx\t%s\n", offset, page_flag_name(flags));
+	printf("%lx\t%s\t%lx\n", offset, page_flag_name(flags), mapcount);
 }
 
 static void show_summary(void)
@@ -597,7 +608,7 @@
 }
 
 static void add_page(unsigned long voffset, unsigned long offset,
-		     uint64_t flags, uint64_t cgroup, uint64_t pme)
+		     uint64_t flags, uint64_t mapcount, uint64_t cgroup, uint64_t pme)
 {
 	flags = kpageflags_flags(flags, pme);
 
@@ -613,9 +624,9 @@
 		unpoison_page(offset);
 
 	if (opt_list == 1)
-		show_page_range(voffset, offset, 1, flags, cgroup);
+		show_page_range(voffset, offset, 1, flags, mapcount, cgroup);
 	else if (opt_list == 2)
-		show_page(voffset, offset, flags, cgroup);
+		show_page(voffset, offset, flags, mapcount, cgroup);
 
 	nr_pages[hash_slot(flags)]++;
 	total_pages++;
@@ -628,6 +639,7 @@
 		     uint64_t pme)
 {
 	uint64_t buf[KPAGEFLAGS_BATCH];
+	uint64_t  mc[KPAGEFLAGS_BATCH];
 	uint64_t cgi[KPAGEFLAGS_BATCH];
 	unsigned long batch;
 	unsigned long pages;
@@ -649,11 +661,14 @@
 		if (pages == 0)
 			break;
 
+		if (kpagecount_read(mc, index, batch) != pages)
+			fatal("kpagecount returned fewer pages than expected");
+
 		if (kpagecgroup_read(cgi, index, pages) != pages)
 			fatal("kpagecgroup returned fewer pages than expected");
 
 		for (i = 0; i < pages; i++)
-			add_page(voffset + i, index + i, buf[i], cgi[i], pme);
+			add_page(voffset + i, index + i, buf[i], mc[i], cgi[i], pme);
 
 		index += pages;
 		count -= pages;
@@ -671,9 +686,9 @@
 		return;
 
 	if (opt_list == 1)
-		show_page_range(voffset, pagemap_swap_offset(pme), 1, flags, 0);
+		show_page_range(voffset, pagemap_swap_offset(pme), 1, flags, -1, 0);
 	else if (opt_list == 2)
-		show_page(voffset, pagemap_swap_offset(pme), flags, 0);
+		show_page(voffset, pagemap_swap_offset(pme), flags, -1, 0);
 
 	nr_pages[hash_slot(flags)]++;
 	total_pages++;
@@ -744,6 +759,7 @@
 	int i;
 
 	kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
+	kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY);
 
 	if (!nr_addr_ranges)
 		add_addr_range(0, ULONG_MAX);
@@ -844,6 +860,7 @@
 
 	sprintf(buf, "/proc/%d/pagemap", opt_pid);
 	pagemap_fd = checked_open(buf, O_RDONLY);
+	kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY);
 
 	sprintf(buf, "/proc/%d/maps", opt_pid);
 	file = fopen(buf, "r");
@@ -987,7 +1004,7 @@
 				show_file(name, st);
 			}
 			add_page(off / page_size + i, pfn,
-				 flags, cgroup, buf[i]);
+				 flags, -1, cgroup, buf[i]);
 		}
 	}
 
@@ -1014,6 +1031,7 @@
 	struct stat st;
 
 	kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
+	kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY);
 	pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY);
 	sigaction(SIGBUS, &sigbus_action, NULL);