Blame view

tools/vm/page-types.c 29.9 KB
af7c5f890   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
35efa5e99   Wu Fengguang   pagemap: add page...
2
3
4
5
  /*
   * page-types: Tool for querying page flags
   *
   * Copyright (C) 2009 Intel corporation
0c57effe2   Wu Fengguang   page-types: add G...
6
7
   *
   * Authors: Wu Fengguang <fengguang.wu@intel.com>
35efa5e99   Wu Fengguang   pagemap: add page...
8
   */
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
9
10
  #define _FILE_OFFSET_BITS 64
  #define _GNU_SOURCE
35efa5e99   Wu Fengguang   pagemap: add page...
11
12
13
14
15
16
17
18
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <stdint.h>
  #include <stdarg.h>
  #include <string.h>
  #include <getopt.h>
  #include <limits.h>
0b4b2ad53   Wu Fengguang   page-types: add f...
19
  #include <assert.h>
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
20
21
  #include <ftw.h>
  #include <time.h>
1d46598b7   Konstantin Khlebnikov   tools/vm/page-typ...
22
23
  #include <setjmp.h>
  #include <signal.h>
35efa5e99   Wu Fengguang   pagemap: add page...
24
25
26
  #include <sys/types.h>
  #include <sys/errno.h>
  #include <sys/fcntl.h>
12da58b0c   Chen Gong   Documentation/vm/...
27
28
  #include <sys/mount.h>
  #include <sys/statfs.h>
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
29
  #include <sys/mman.h>
607ca46e9   David Howells   UAPI: (Scripted) ...
30
  #include "../../include/uapi/linux/magic.h"
59ce8764b   David Howells   UAPI: fix tools/v...
31
  #include "../../include/uapi/linux/kernel-page-flags.h"
f6489bc2d   Arnaldo Carvalho de Melo   tools vm: Fix bui...
32
  #include <api/fs/fs.h>
35efa5e99   Wu Fengguang   pagemap: add page...
33

12da58b0c   Chen Gong   Documentation/vm/...
34
35
36
37
38
39
40
41
  #ifndef MAX_PATH
  # define MAX_PATH 256
  #endif
  
  #ifndef STR
  # define _STR(x) #x
  # define STR(x) _STR(x)
  #endif
35efa5e99   Wu Fengguang   pagemap: add page...
42
  /*
0b4b2ad53   Wu Fengguang   page-types: add f...
43
44
   * pagemap kernel ABI bits
   */
deb945441   Konstantin Khlebnikov   pagemap: switch t...
45
46
47
48
  #define PM_ENTRY_BYTES		8
  #define PM_PFRAME_BITS		55
  #define PM_PFRAME_MASK		((1LL << PM_PFRAME_BITS) - 1)
  #define PM_PFRAME(x)		((x) & PM_PFRAME_MASK)
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
49
50
  #define MAX_SWAPFILES_SHIFT	5
  #define PM_SWAP_OFFSET(x)	(((x) & PM_PFRAME_MASK) >> MAX_SWAPFILES_SHIFT)
deb945441   Konstantin Khlebnikov   pagemap: switch t...
51
  #define PM_SOFT_DIRTY		(1ULL << 55)
77bb499bb   Konstantin Khlebnikov   pagemap: add mmap...
52
  #define PM_MMAP_EXCLUSIVE	(1ULL << 56)
deb945441   Konstantin Khlebnikov   pagemap: switch t...
53
54
55
  #define PM_FILE			(1ULL << 61)
  #define PM_SWAP			(1ULL << 62)
  #define PM_PRESENT		(1ULL << 63)
0b4b2ad53   Wu Fengguang   page-types: add f...
56
57
  
  /*
35efa5e99   Wu Fengguang   pagemap: add page...
58
59
60
61
62
   * kernel page flags
   */
  
  #define KPF_BYTES		8
  #define PROC_KPAGEFLAGS		"/proc/kpageflags"
7f1d23e60   Christian Hansen   tools/vm/page-typ...
63
  #define PROC_KPAGECOUNT		"/proc/kpagecount"
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
64
  #define PROC_KPAGECGROUP	"/proc/kpagecgroup"
35efa5e99   Wu Fengguang   pagemap: add page...
65

59ae96ffc   Christian Hansen   tools/vm/page-typ...
66
  #define SYS_KERNEL_MM_PAGE_IDLE "/sys/kernel/mm/page_idle/bitmap"
35efa5e99   Wu Fengguang   pagemap: add page...
67
68
69
70
71
72
73
74
75
  /* [32-] kernel hacking assistances */
  #define KPF_RESERVED		32
  #define KPF_MLOCKED		33
  #define KPF_MAPPEDTODISK	34
  #define KPF_PRIVATE		35
  #define KPF_PRIVATE_2		36
  #define KPF_OWNER_PRIVATE	37
  #define KPF_ARCH		38
  #define KPF_UNCACHED		39
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
76
  #define KPF_SOFTDIRTY		40
4beba9486   Steven Price   mm: Add PG_arch_2...
77
  #define KPF_ARCH_2		41
35efa5e99   Wu Fengguang   pagemap: add page...
78
79
80
81
82
83
84
85
  
  /* [48-] take some arbitrary free slots for expanding overloaded flags
   * not part of kernel API
   */
  #define KPF_READAHEAD		48
  #define KPF_SLOB_FREE		49
  #define KPF_SLUB_FROZEN		50
  #define KPF_SLUB_DEBUG		51
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
86
87
  #define KPF_FILE		61
  #define KPF_SWAP		62
77bb499bb   Konstantin Khlebnikov   pagemap: add mmap...
88
  #define KPF_MMAP_EXCLUSIVE	63
35efa5e99   Wu Fengguang   pagemap: add page...
89
90
91
92
93
94
  
  #define KPF_ALL_BITS		((uint64_t)~0ULL)
  #define KPF_HACKERS_BITS	(0xffffULL << 32)
  #define KPF_OVERLOADED_BITS	(0xffffULL << 48)
  #define BIT(name)		(1ULL << KPF_##name)
  #define BITS_COMPOUND		(BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL))
c6dd897f3   Dave Young   mm: move page-typ...
95
  static const char * const page_flag_names[] = {
35efa5e99   Wu Fengguang   pagemap: add page...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  	[KPF_LOCKED]		= "L:locked",
  	[KPF_ERROR]		= "E:error",
  	[KPF_REFERENCED]	= "R:referenced",
  	[KPF_UPTODATE]		= "U:uptodate",
  	[KPF_DIRTY]		= "D:dirty",
  	[KPF_LRU]		= "l:lru",
  	[KPF_ACTIVE]		= "A:active",
  	[KPF_SLAB]		= "S:slab",
  	[KPF_WRITEBACK]		= "W:writeback",
  	[KPF_RECLAIM]		= "I:reclaim",
  	[KPF_BUDDY]		= "B:buddy",
  
  	[KPF_MMAP]		= "M:mmap",
  	[KPF_ANON]		= "a:anonymous",
  	[KPF_SWAPCACHE]		= "s:swapcache",
  	[KPF_SWAPBACKED]	= "b:swapbacked",
  	[KPF_COMPOUND_HEAD]	= "H:compound_head",
  	[KPF_COMPOUND_TAIL]	= "T:compound_tail",
  	[KPF_HUGE]		= "G:huge",
  	[KPF_UNEVICTABLE]	= "u:unevictable",
253fb02d6   Wu Fengguang   pagemap: export K...
116
  	[KPF_HWPOISON]		= "X:hwpoison",
35efa5e99   Wu Fengguang   pagemap: add page...
117
  	[KPF_NOPAGE]		= "n:nopage",
a1bbb5ec3   Wu Fengguang   pagemap: document...
118
  	[KPF_KSM]		= "x:ksm",
807f0ccfe   Naoya Horiguchi   pagemap: document...
119
  	[KPF_THP]		= "t:thp",
ca215086b   David Hildenbrand   mm: convert PG_ba...
120
  	[KPF_OFFLINE]		= "o:offline",
1d40a5ea0   Matthew Wilcox   mm: mark pages in...
121
  	[KPF_PGTABLE]		= "g:pgtable",
56873f43a   Wang, Yalin   mm:add KPF_ZERO_P...
122
  	[KPF_ZERO_PAGE]		= "z:zero_page",
429d48622   Naoya Horiguchi   tools/vm/page-typ...
123
  	[KPF_IDLE]              = "i:idle_page",
35efa5e99   Wu Fengguang   pagemap: add page...
124
125
126
127
128
129
130
131
132
  
  	[KPF_RESERVED]		= "r:reserved",
  	[KPF_MLOCKED]		= "m:mlocked",
  	[KPF_MAPPEDTODISK]	= "d:mappedtodisk",
  	[KPF_PRIVATE]		= "P:private",
  	[KPF_PRIVATE_2]		= "p:private_2",
  	[KPF_OWNER_PRIVATE]	= "O:owner_private",
  	[KPF_ARCH]		= "h:arch",
  	[KPF_UNCACHED]		= "c:uncached",
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
133
  	[KPF_SOFTDIRTY]		= "f:softdirty",
4beba9486   Steven Price   mm: Add PG_arch_2...
134
  	[KPF_ARCH_2]		= "H:arch_2",
35efa5e99   Wu Fengguang   pagemap: add page...
135
136
137
138
139
  
  	[KPF_READAHEAD]		= "I:readahead",
  	[KPF_SLOB_FREE]		= "P:slob_free",
  	[KPF_SLUB_FROZEN]	= "A:slub_frozen",
  	[KPF_SLUB_DEBUG]	= "E:slub_debug",
77bb499bb   Konstantin Khlebnikov   pagemap: add mmap...
140
141
  
  	[KPF_FILE]		= "F:file",
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
142
  	[KPF_SWAP]		= "w:swap",
77bb499bb   Konstantin Khlebnikov   pagemap: add mmap...
143
  	[KPF_MMAP_EXCLUSIVE]	= "1:mmap_exclusive",
35efa5e99   Wu Fengguang   pagemap: add page...
144
145
146
147
148
149
150
151
152
  };
  
  
  /*
   * data structures
   */
  
  static int		opt_raw;	/* for kernel developers */
  static int		opt_list;	/* list pages (in ranges) */
59ae96ffc   Christian Hansen   tools/vm/page-typ...
153
  static int		opt_mark_idle;	/* set accessed bit */
35efa5e99   Wu Fengguang   pagemap: add page...
154
155
  static int		opt_no_summary;	/* don't show summary */
  static pid_t		opt_pid;	/* process to walk */
c7905f200   David Rientjes   tools, vm: new op...
156
  const char		*opt_file;	/* file or directory path */
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
157
158
  static uint64_t		opt_cgroup;	/* cgroup inode */
  static int		opt_list_cgroup;/* list page cgroup */
7f1d23e60   Christian Hansen   tools/vm/page-typ...
159
  static int		opt_list_mapcnt;/* list page map count */
c7905f200   David Rientjes   tools, vm: new op...
160
  static const char	*opt_kpageflags;/* kpageflags file to parse */
35efa5e99   Wu Fengguang   pagemap: add page...
161
162
163
164
165
  
  #define MAX_ADDR_RANGES	1024
  static int		nr_addr_ranges;
  static unsigned long	opt_offset[MAX_ADDR_RANGES];
  static unsigned long	opt_size[MAX_ADDR_RANGES];
0b4b2ad53   Wu Fengguang   page-types: add f...
166
167
168
169
  #define MAX_VMAS	10240
  static int		nr_vmas;
  static unsigned long	pg_start[MAX_VMAS];
  static unsigned long	pg_end[MAX_VMAS];
0b4b2ad53   Wu Fengguang   page-types: add f...
170

35efa5e99   Wu Fengguang   pagemap: add page...
171
172
173
174
175
176
  #define MAX_BIT_FILTERS	64
  static int		nr_bit_filters;
  static uint64_t		opt_mask[MAX_BIT_FILTERS];
  static uint64_t		opt_bits[MAX_BIT_FILTERS];
  
  static int		page_size;
4a1b6726f   Wu Fengguang   page-types: make ...
177
  static int		pagemap_fd;
35efa5e99   Wu Fengguang   pagemap: add page...
178
  static int		kpageflags_fd;
7f1d23e60   Christian Hansen   tools/vm/page-typ...
179
  static int		kpagecount_fd = -1;
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
180
  static int		kpagecgroup_fd = -1;
59ae96ffc   Christian Hansen   tools/vm/page-typ...
181
  static int		page_idle_fd = -1;
35efa5e99   Wu Fengguang   pagemap: add page...
182

a54fed9f7   Wu Fengguang   page-types: add h...
183
184
  static int		opt_hwpoison;
  static int		opt_unpoison;
f6489bc2d   Arnaldo Carvalho de Melo   tools vm: Fix bui...
185
  static const char	*hwpoison_debug_fs;
a54fed9f7   Wu Fengguang   page-types: add h...
186
187
  static int		hwpoison_inject_fd;
  static int		hwpoison_forget_fd;
35efa5e99   Wu Fengguang   pagemap: add page...
188
189
190
191
192
193
194
  #define HASH_SHIFT	13
  #define HASH_SIZE	(1 << HASH_SHIFT)
  #define HASH_MASK	(HASH_SIZE - 1)
  #define HASH_KEY(flags)	(flags & HASH_MASK)
  
  static unsigned long	total_pages;
  static unsigned long	nr_pages[HASH_SIZE];
c6dd897f3   Dave Young   mm: move page-typ...
195
  static uint64_t		page_flags[HASH_SIZE];
35efa5e99   Wu Fengguang   pagemap: add page...
196
197
198
199
200
201
202
203
204
205
206
207
  
  
  /*
   * helper functions
   */
  
  #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  
  #define min_t(type, x, y) ({			\
  	type __min1 = (x);			\
  	type __min2 = (y);			\
  	__min1 < __min2 ? __min1 : __min2; })
0b4b2ad53   Wu Fengguang   page-types: add f...
208
209
210
211
  #define max_t(type, x, y) ({			\
  	type __max1 = (x);			\
  	type __max2 = (y);			\
  	__max1 > __max2 ? __max1 : __max2; })
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
212
  static unsigned long pages2mb(unsigned long pages)
35efa5e99   Wu Fengguang   pagemap: add page...
213
214
215
  {
  	return (pages * page_size) >> 20;
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
216
  static void fatal(const char *x, ...)
35efa5e99   Wu Fengguang   pagemap: add page...
217
218
219
220
221
222
223
224
  {
  	va_list ap;
  
  	va_start(ap, x);
  	vfprintf(stderr, x, ap);
  	va_end(ap);
  	exit(EXIT_FAILURE);
  }
1b98c00bf   Josh Triplett   Documentation/vm/...
225
  static int checked_open(const char *pathname, int flags)
31bbf66ea   Wu Fengguang   page-types: intro...
226
227
228
229
230
231
232
233
234
235
  {
  	int fd = open(pathname, flags);
  
  	if (fd < 0) {
  		perror(pathname);
  		exit(EXIT_FAILURE);
  	}
  
  	return fd;
  }
4a1b6726f   Wu Fengguang   page-types: make ...
236
237
238
  /*
   * pagemap/kpageflags routines
   */
c7905f200   David Rientjes   tools, vm: new op...
239
  static unsigned long do_u64_read(int fd, const char *name,
4a1b6726f   Wu Fengguang   page-types: make ...
240
241
242
243
244
245
246
247
248
  				 uint64_t *buf,
  				 unsigned long index,
  				 unsigned long count)
  {
  	long bytes;
  
  	if (index > ULONG_MAX / 8)
  		fatal("index overflow: %lu
  ", index);
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
249
  	bytes = pread(fd, buf, count * 8, (off_t)index * 8);
4a1b6726f   Wu Fengguang   page-types: make ...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  	if (bytes < 0) {
  		perror(name);
  		exit(EXIT_FAILURE);
  	}
  	if (bytes % 8)
  		fatal("partial read: %lu bytes
  ", bytes);
  
  	return bytes / 8;
  }
  
  static unsigned long kpageflags_read(uint64_t *buf,
  				     unsigned long index,
  				     unsigned long pages)
  {
c7905f200   David Rientjes   tools, vm: new op...
265
  	return do_u64_read(kpageflags_fd, opt_kpageflags, buf, index, pages);
4a1b6726f   Wu Fengguang   page-types: make ...
266
  }
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
267
268
269
270
271
272
  static unsigned long kpagecgroup_read(uint64_t *buf,
  				      unsigned long index,
  				      unsigned long pages)
  {
  	if (kpagecgroup_fd < 0)
  		return pages;
c7905f200   David Rientjes   tools, vm: new op...
273
  	return do_u64_read(kpagecgroup_fd, opt_kpageflags, buf, index, pages);
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
274
  }
7f1d23e60   Christian Hansen   tools/vm/page-typ...
275
276
277
278
279
280
281
282
  static unsigned long kpagecount_read(uint64_t *buf,
  				     unsigned long index,
  				     unsigned long pages)
  {
  	return kpagecount_fd < 0 ? pages :
  		do_u64_read(kpagecount_fd, PROC_KPAGECOUNT,
  			    buf, index, pages);
  }
4a1b6726f   Wu Fengguang   page-types: make ...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  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;
  }
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
301
302
303
304
  static unsigned long pagemap_swap_offset(uint64_t val)
  {
  	return val & PM_SWAP ? PM_SWAP_OFFSET(val) : 0;
  }
35efa5e99   Wu Fengguang   pagemap: add page...
305
306
307
308
  
  /*
   * page flag names
   */
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
309
  static char *page_flag_name(uint64_t flags)
35efa5e99   Wu Fengguang   pagemap: add page...
310
311
312
  {
  	static char buf[65];
  	int present;
e30d539b3   Ulrich Drepper   tools/vm/page-typ...
313
  	size_t i, j;
35efa5e99   Wu Fengguang   pagemap: add page...
314
315
316
317
318
  
  	for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
  		present = (flags >> i) & 1;
  		if (!page_flag_names[i]) {
  			if (present)
af901ca18   André Goddard Rosa   tree-wide: fix as...
319
320
  				fatal("unknown flag bit %d
  ", i);
35efa5e99   Wu Fengguang   pagemap: add page...
321
322
323
324
325
326
327
  			continue;
  		}
  		buf[j++] = present ? page_flag_names[i][0] : '_';
  	}
  
  	return buf;
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
328
  static char *page_flag_longname(uint64_t flags)
35efa5e99   Wu Fengguang   pagemap: add page...
329
330
  {
  	static char buf[1024];
e30d539b3   Ulrich Drepper   tools/vm/page-typ...
331
  	size_t i, n;
35efa5e99   Wu Fengguang   pagemap: add page...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
  
  	for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) {
  		if (!page_flag_names[i])
  			continue;
  		if ((flags >> i) & 1)
  			n += snprintf(buf + n, sizeof(buf) - n, "%s,",
  					page_flag_names[i] + 2);
  	}
  	if (n)
  		n--;
  	buf[n] = '\0';
  
  	return buf;
  }
  
  
  /*
   * page list and summary
   */
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
351
  static void show_page_range(unsigned long voffset, unsigned long offset,
7f1d23e60   Christian Hansen   tools/vm/page-typ...
352
353
  			    unsigned long size, uint64_t flags,
  			    uint64_t cgroup, uint64_t mapcnt)
35efa5e99   Wu Fengguang   pagemap: add page...
354
355
  {
  	static uint64_t      flags0;
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
356
  	static uint64_t	     cgroup0;
7f1d23e60   Christian Hansen   tools/vm/page-typ...
357
  	static uint64_t      mapcnt0;
0b4b2ad53   Wu Fengguang   page-types: add f...
358
  	static unsigned long voff;
35efa5e99   Wu Fengguang   pagemap: add page...
359
360
  	static unsigned long index;
  	static unsigned long count;
7f1d23e60   Christian Hansen   tools/vm/page-typ...
361
362
  	if (flags == flags0 && cgroup == cgroup0 && mapcnt == mapcnt0 &&
  	    offset == index + count && size && voffset == voff + count) {
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
363
  		count += size;
35efa5e99   Wu Fengguang   pagemap: add page...
364
365
  		return;
  	}
0b4b2ad53   Wu Fengguang   page-types: add f...
366
367
368
  	if (count) {
  		if (opt_pid)
  			printf("%lx\t", voff);
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
369
370
  		if (opt_file)
  			printf("%lu\t", voff);
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
371
372
  		if (opt_list_cgroup)
  			printf("@%llu\t", (unsigned long long)cgroup0);
7f1d23e60   Christian Hansen   tools/vm/page-typ...
373
374
  		if (opt_list_mapcnt)
  			printf("%lu\t", mapcnt0);
0b4b2ad53   Wu Fengguang   page-types: add f...
375
376
  		printf("%lx\t%lx\t%s
  ",
35efa5e99   Wu Fengguang   pagemap: add page...
377
  				index, count, page_flag_name(flags0));
0b4b2ad53   Wu Fengguang   page-types: add f...
378
  	}
35efa5e99   Wu Fengguang   pagemap: add page...
379
380
  
  	flags0 = flags;
7f1d23e60   Christian Hansen   tools/vm/page-typ...
381
382
  	cgroup0 = cgroup;
  	mapcnt0 = mapcnt;
35efa5e99   Wu Fengguang   pagemap: add page...
383
  	index  = offset;
0b4b2ad53   Wu Fengguang   page-types: add f...
384
  	voff   = voffset;
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
385
386
387
388
389
  	count  = size;
  }
  
  static void flush_page_range(void)
  {
7f1d23e60   Christian Hansen   tools/vm/page-typ...
390
  	show_page_range(0, 0, 0, 0, 0, 0);
35efa5e99   Wu Fengguang   pagemap: add page...
391
  }
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
392
  static void show_page(unsigned long voffset, unsigned long offset,
7f1d23e60   Christian Hansen   tools/vm/page-typ...
393
  		      uint64_t flags, uint64_t cgroup, uint64_t mapcnt)
35efa5e99   Wu Fengguang   pagemap: add page...
394
  {
0b4b2ad53   Wu Fengguang   page-types: add f...
395
396
  	if (opt_pid)
  		printf("%lx\t", voffset);
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
397
398
  	if (opt_file)
  		printf("%lu\t", voffset);
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
399
400
  	if (opt_list_cgroup)
  		printf("@%llu\t", (unsigned long long)cgroup);
7f1d23e60   Christian Hansen   tools/vm/page-typ...
401
402
  	if (opt_list_mapcnt)
  		printf("%lu\t", mapcnt);
0b4b2ad53   Wu Fengguang   page-types: add f...
403
404
  	printf("%lx\t%s
  ", offset, page_flag_name(flags));
35efa5e99   Wu Fengguang   pagemap: add page...
405
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
406
  static void show_summary(void)
35efa5e99   Wu Fengguang   pagemap: add page...
407
  {
e30d539b3   Ulrich Drepper   tools/vm/page-typ...
408
  	size_t i;
35efa5e99   Wu Fengguang   pagemap: add page...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  
  	printf("             flags\tpage-count       MB"
  		"  symbolic-flags\t\t\tlong-symbolic-flags
  ");
  
  	for (i = 0; i < ARRAY_SIZE(nr_pages); i++) {
  		if (nr_pages[i])
  			printf("0x%016llx\t%10lu %8lu  %s\t%s
  ",
  				(unsigned long long)page_flags[i],
  				nr_pages[i],
  				pages2mb(nr_pages[i]),
  				page_flag_name(page_flags[i]),
  				page_flag_longname(page_flags[i]));
  	}
  
  	printf("             total\t%10lu %8lu
  ",
  			total_pages, pages2mb(total_pages));
  }
  
  
  /*
   * page flag filters
   */
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
434
  static int bit_mask_ok(uint64_t flags)
35efa5e99   Wu Fengguang   pagemap: add page...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
  {
  	int i;
  
  	for (i = 0; i < nr_bit_filters; i++) {
  		if (opt_bits[i] == KPF_ALL_BITS) {
  			if ((flags & opt_mask[i]) == 0)
  				return 0;
  		} else {
  			if ((flags & opt_mask[i]) != opt_bits[i])
  				return 0;
  		}
  	}
  
  	return 1;
  }
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
450
  static uint64_t expand_overloaded_flags(uint64_t flags, uint64_t pme)
35efa5e99   Wu Fengguang   pagemap: add page...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  {
  	/* SLOB/SLUB overload several page flags */
  	if (flags & BIT(SLAB)) {
  		if (flags & BIT(PRIVATE))
  			flags ^= BIT(PRIVATE) | BIT(SLOB_FREE);
  		if (flags & BIT(ACTIVE))
  			flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN);
  		if (flags & BIT(ERROR))
  			flags ^= BIT(ERROR) | BIT(SLUB_DEBUG);
  	}
  
  	/* PG_reclaim is overloaded as PG_readahead in the read path */
  	if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM))
  		flags ^= BIT(RECLAIM) | BIT(READAHEAD);
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
465
466
  	if (pme & PM_SOFT_DIRTY)
  		flags |= BIT(SOFTDIRTY);
77bb499bb   Konstantin Khlebnikov   pagemap: add mmap...
467
468
  	if (pme & PM_FILE)
  		flags |= BIT(FILE);
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
469
470
  	if (pme & PM_SWAP)
  		flags |= BIT(SWAP);
77bb499bb   Konstantin Khlebnikov   pagemap: add mmap...
471
472
  	if (pme & PM_MMAP_EXCLUSIVE)
  		flags |= BIT(MMAP_EXCLUSIVE);
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
473

35efa5e99   Wu Fengguang   pagemap: add page...
474
475
  	return flags;
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
476
  static uint64_t well_known_flags(uint64_t flags)
35efa5e99   Wu Fengguang   pagemap: add page...
477
478
479
480
481
482
483
484
485
486
  {
  	/* hide flags intended only for kernel hacker */
  	flags &= ~KPF_HACKERS_BITS;
  
  	/* hide non-hugeTLB compound pages */
  	if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE)))
  		flags &= ~BITS_COMPOUND;
  
  	return flags;
  }
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
487
  static uint64_t kpageflags_flags(uint64_t flags, uint64_t pme)
48640d69f   Wu Fengguang   page-types: intro...
488
  {
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
489
490
491
  	if (opt_raw)
  		flags = expand_overloaded_flags(flags, pme);
  	else
48640d69f   Wu Fengguang   page-types: intro...
492
493
494
495
  		flags = well_known_flags(flags);
  
  	return flags;
  }
35efa5e99   Wu Fengguang   pagemap: add page...
496
  /*
a54fed9f7   Wu Fengguang   page-types: add h...
497
498
499
500
501
   * page actions
   */
  
  static void prepare_hwpoison_fd(void)
  {
12da58b0c   Chen Gong   Documentation/vm/...
502
  	char buf[MAX_PATH + 1];
f6489bc2d   Arnaldo Carvalho de Melo   tools vm: Fix bui...
503
  	hwpoison_debug_fs = debugfs__mount();
5a439645e   Borislav Petkov   tools/vm: Switch ...
504
505
506
507
  	if (!hwpoison_debug_fs) {
  		perror("mount debugfs");
  		exit(EXIT_FAILURE);
  	}
a54fed9f7   Wu Fengguang   page-types: add h...
508
509
  
  	if (opt_hwpoison && !hwpoison_inject_fd) {
12da58b0c   Chen Gong   Documentation/vm/...
510
511
  		snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",
  			hwpoison_debug_fs);
a54fed9f7   Wu Fengguang   page-types: add h...
512
513
514
515
  		hwpoison_inject_fd = checked_open(buf, O_WRONLY);
  	}
  
  	if (opt_unpoison && !hwpoison_forget_fd) {
12da58b0c   Chen Gong   Documentation/vm/...
516
517
  		snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn",
  			hwpoison_debug_fs);
a54fed9f7   Wu Fengguang   page-types: add h...
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  		hwpoison_forget_fd = checked_open(buf, O_WRONLY);
  	}
  }
  
  static int hwpoison_page(unsigned long offset)
  {
  	char buf[100];
  	int len;
  
  	len = sprintf(buf, "0x%lx
  ", offset);
  	len = write(hwpoison_inject_fd, buf, len);
  	if (len < 0) {
  		perror("hwpoison inject");
  		return len;
  	}
  	return 0;
  }
  
  static int unpoison_page(unsigned long offset)
  {
  	char buf[100];
  	int len;
  
  	len = sprintf(buf, "0x%lx
  ", offset);
  	len = write(hwpoison_forget_fd, buf, len);
  	if (len < 0) {
  		perror("hwpoison forget");
  		return len;
  	}
  	return 0;
  }
59ae96ffc   Christian Hansen   tools/vm/page-typ...
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  static int mark_page_idle(unsigned long offset)
  {
  	static unsigned long off;
  	static uint64_t buf;
  	int len;
  
  	if ((offset / 64 == off / 64) || buf == 0) {
  		buf |= 1UL << (offset % 64);
  		off = offset;
  		return 0;
  	}
  
  	len = pwrite(page_idle_fd, &buf, 8, 8 * (off / 64));
  	if (len < 0) {
  		perror("mark page idle");
  		return len;
  	}
  
  	buf = 1UL << (offset % 64);
  	off = offset;
  
  	return 0;
  }
a54fed9f7   Wu Fengguang   page-types: add h...
574
  /*
35efa5e99   Wu Fengguang   pagemap: add page...
575
576
   * page frame walker
   */
e30d539b3   Ulrich Drepper   tools/vm/page-typ...
577
  static size_t hash_slot(uint64_t flags)
35efa5e99   Wu Fengguang   pagemap: add page...
578
  {
e30d539b3   Ulrich Drepper   tools/vm/page-typ...
579
580
  	size_t k = HASH_KEY(flags);
  	size_t i;
35efa5e99   Wu Fengguang   pagemap: add page...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
  
  	/* Explicitly reserve slot 0 for flags 0: the following logic
  	 * cannot distinguish an unoccupied slot from slot (flags==0).
  	 */
  	if (flags == 0)
  		return 0;
  
  	/* search through the remaining (HASH_SIZE-1) slots */
  	for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) {
  		if (!k || k >= ARRAY_SIZE(page_flags))
  			k = 1;
  		if (page_flags[k] == 0) {
  			page_flags[k] = flags;
  			return k;
  		}
  		if (page_flags[k] == flags)
  			return k;
  	}
  
  	fatal("hash table full: bump up HASH_SHIFT?
  ");
  	exit(EXIT_FAILURE);
  }
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
604
  static void add_page(unsigned long voffset, unsigned long offset,
7f1d23e60   Christian Hansen   tools/vm/page-typ...
605
606
  		     uint64_t flags, uint64_t cgroup, uint64_t mapcnt,
  		     uint64_t pme)
35efa5e99   Wu Fengguang   pagemap: add page...
607
  {
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
608
  	flags = kpageflags_flags(flags, pme);
35efa5e99   Wu Fengguang   pagemap: add page...
609
610
611
  
  	if (!bit_mask_ok(flags))
  		return;
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
612
613
  	if (opt_cgroup && cgroup != (uint64_t)opt_cgroup)
  		return;
a54fed9f7   Wu Fengguang   page-types: add h...
614
615
616
617
  	if (opt_hwpoison)
  		hwpoison_page(offset);
  	if (opt_unpoison)
  		unpoison_page(offset);
59ae96ffc   Christian Hansen   tools/vm/page-typ...
618
619
  	if (opt_mark_idle)
  		mark_page_idle(offset);
35efa5e99   Wu Fengguang   pagemap: add page...
620
  	if (opt_list == 1)
7f1d23e60   Christian Hansen   tools/vm/page-typ...
621
  		show_page_range(voffset, offset, 1, flags, cgroup, mapcnt);
35efa5e99   Wu Fengguang   pagemap: add page...
622
  	else if (opt_list == 2)
7f1d23e60   Christian Hansen   tools/vm/page-typ...
623
  		show_page(voffset, offset, flags, cgroup, mapcnt);
35efa5e99   Wu Fengguang   pagemap: add page...
624
625
626
627
  
  	nr_pages[hash_slot(flags)]++;
  	total_pages++;
  }
4a1b6726f   Wu Fengguang   page-types: make ...
628
  #define KPAGEFLAGS_BATCH	(64 << 10)	/* 64k pages */
e577ebde9   Wu Fengguang   page-types: make ...
629
630
  static void walk_pfn(unsigned long voffset,
  		     unsigned long index,
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
631
632
  		     unsigned long count,
  		     uint64_t pme)
35efa5e99   Wu Fengguang   pagemap: add page...
633
  {
4a1b6726f   Wu Fengguang   page-types: make ...
634
  	uint64_t buf[KPAGEFLAGS_BATCH];
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
635
  	uint64_t cgi[KPAGEFLAGS_BATCH];
7f1d23e60   Christian Hansen   tools/vm/page-typ...
636
  	uint64_t cnt[KPAGEFLAGS_BATCH];
35efa5e99   Wu Fengguang   pagemap: add page...
637
  	unsigned long batch;
e30d539b3   Ulrich Drepper   tools/vm/page-typ...
638
  	unsigned long pages;
35efa5e99   Wu Fengguang   pagemap: add page...
639
  	unsigned long i;
d9b2ddf80   Naoya Horiguchi   tools/vm/page-typ...
640
641
642
643
644
645
646
647
648
  	/*
  	 * kpagecgroup_read() reads only if kpagecgroup were opened, but
  	 * /proc/kpagecgroup might even not exist, so it's better to fill
  	 * them with zeros here.
  	 */
  	if (count == 1)
  		cgi[0] = 0;
  	else
  		memset(cgi, 0, sizeof cgi);
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
649

35efa5e99   Wu Fengguang   pagemap: add page...
650
  	while (count) {
4a1b6726f   Wu Fengguang   page-types: make ...
651
652
653
  		batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
  		pages = kpageflags_read(buf, index, batch);
  		if (pages == 0)
35efa5e99   Wu Fengguang   pagemap: add page...
654
  			break;
35efa5e99   Wu Fengguang   pagemap: add page...
655

075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
656
657
  		if (kpagecgroup_read(cgi, index, pages) != pages)
  			fatal("kpagecgroup returned fewer pages than expected");
b6fb87b8e   Anthony Yznaga   tools/vm/page-typ...
658
  		if (kpagecount_read(cnt, index, pages) != pages)
7f1d23e60   Christian Hansen   tools/vm/page-typ...
659
  			fatal("kpagecount returned fewer pages than expected");
4a1b6726f   Wu Fengguang   page-types: make ...
660
  		for (i = 0; i < pages; i++)
7f1d23e60   Christian Hansen   tools/vm/page-typ...
661
662
  			add_page(voffset + i, index + i,
  				 buf[i], cgi[i], cnt[i], pme);
35efa5e99   Wu Fengguang   pagemap: add page...
663

4a1b6726f   Wu Fengguang   page-types: make ...
664
665
  		index += pages;
  		count -= pages;
35efa5e99   Wu Fengguang   pagemap: add page...
666
667
  	}
  }
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
668
669
670
671
672
673
  static void walk_swap(unsigned long voffset, uint64_t pme)
  {
  	uint64_t flags = kpageflags_flags(0, pme);
  
  	if (!bit_mask_ok(flags))
  		return;
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
674
675
  	if (opt_cgroup)
  		return;
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
676
  	if (opt_list == 1)
7f1d23e60   Christian Hansen   tools/vm/page-typ...
677
678
  		show_page_range(voffset, pagemap_swap_offset(pme),
  				1, flags, 0, 0);
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
679
  	else if (opt_list == 2)
7f1d23e60   Christian Hansen   tools/vm/page-typ...
680
  		show_page(voffset, pagemap_swap_offset(pme), flags, 0, 0);
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
681
682
683
684
  
  	nr_pages[hash_slot(flags)]++;
  	total_pages++;
  }
4a1b6726f   Wu Fengguang   page-types: make ...
685
686
  #define PAGEMAP_BATCH	(64 << 10)
  static void walk_vma(unsigned long index, unsigned long count)
0b4b2ad53   Wu Fengguang   page-types: add f...
687
  {
4a1b6726f   Wu Fengguang   page-types: make ...
688
689
690
691
692
  	uint64_t buf[PAGEMAP_BATCH];
  	unsigned long batch;
  	unsigned long pages;
  	unsigned long pfn;
  	unsigned long i;
0b4b2ad53   Wu Fengguang   page-types: add f...
693

4a1b6726f   Wu Fengguang   page-types: make ...
694
695
696
697
698
  	while (count) {
  		batch = min_t(unsigned long, count, PAGEMAP_BATCH);
  		pages = pagemap_read(buf, index, batch);
  		if (pages == 0)
  			break;
0b4b2ad53   Wu Fengguang   page-types: add f...
699

4a1b6726f   Wu Fengguang   page-types: make ...
700
701
  		for (i = 0; i < pages; i++) {
  			pfn = pagemap_pfn(buf[i]);
4a1b6726f   Wu Fengguang   page-types: make ...
702
  			if (pfn)
46c77e2bb   Naoya Horiguchi   tools/vm/page-typ...
703
  				walk_pfn(index + i, pfn, 1, buf[i]);
0335ddd34   Naoya Horiguchi   tools/vm/page-typ...
704
705
  			if (buf[i] & PM_SWAP)
  				walk_swap(index + i, buf[i]);
4a1b6726f   Wu Fengguang   page-types: make ...
706
707
708
709
710
  		}
  
  		index += pages;
  		count -= pages;
  	}
0b4b2ad53   Wu Fengguang   page-types: add f...
711
712
713
714
  }
  
  static void walk_task(unsigned long index, unsigned long count)
  {
0b4b2ad53   Wu Fengguang   page-types: add f...
715
  	const unsigned long end = index + count;
e577ebde9   Wu Fengguang   page-types: make ...
716
717
  	unsigned long start;
  	int i = 0;
0b4b2ad53   Wu Fengguang   page-types: add f...
718
719
720
721
722
723
724
725
  
  	while (index < end) {
  
  		while (pg_end[i] <= index)
  			if (++i >= nr_vmas)
  				return;
  		if (pg_start[i] >= end)
  			return;
e577ebde9   Wu Fengguang   page-types: make ...
726
727
  		start = max_t(unsigned long, pg_start[i], index);
  		index = min_t(unsigned long, pg_end[i], end);
0b4b2ad53   Wu Fengguang   page-types: add f...
728

e577ebde9   Wu Fengguang   page-types: make ...
729
730
  		assert(start < index);
  		walk_vma(start, index - start);
0b4b2ad53   Wu Fengguang   page-types: add f...
731
732
733
734
735
736
737
738
739
740
741
742
743
  	}
  }
  
  static void add_addr_range(unsigned long offset, unsigned long size)
  {
  	if (nr_addr_ranges >= MAX_ADDR_RANGES)
  		fatal("too many addr ranges
  ");
  
  	opt_offset[nr_addr_ranges] = offset;
  	opt_size[nr_addr_ranges] = min_t(unsigned long, size, ULONG_MAX-offset);
  	nr_addr_ranges++;
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
744
  static void walk_addr_ranges(void)
35efa5e99   Wu Fengguang   pagemap: add page...
745
746
  {
  	int i;
c7905f200   David Rientjes   tools, vm: new op...
747
  	kpageflags_fd = checked_open(opt_kpageflags, O_RDONLY);
35efa5e99   Wu Fengguang   pagemap: add page...
748
749
  
  	if (!nr_addr_ranges)
0b4b2ad53   Wu Fengguang   page-types: add f...
750
  		add_addr_range(0, ULONG_MAX);
35efa5e99   Wu Fengguang   pagemap: add page...
751
752
  
  	for (i = 0; i < nr_addr_ranges; i++)
0b4b2ad53   Wu Fengguang   page-types: add f...
753
  		if (!opt_pid)
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
754
  			walk_pfn(opt_offset[i], opt_offset[i], opt_size[i], 0);
0b4b2ad53   Wu Fengguang   page-types: add f...
755
756
  		else
  			walk_task(opt_offset[i], opt_size[i]);
35efa5e99   Wu Fengguang   pagemap: add page...
757

59ae96ffc   Christian Hansen   tools/vm/page-typ...
758
759
  	if (opt_mark_idle)
  		mark_page_idle(0);
35efa5e99   Wu Fengguang   pagemap: add page...
760
761
762
763
764
765
766
  	close(kpageflags_fd);
  }
  
  
  /*
   * user interface
   */
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
767
  static const char *page_flag_type(uint64_t flag)
35efa5e99   Wu Fengguang   pagemap: add page...
768
769
770
771
772
773
774
  {
  	if (flag & KPF_HACKERS_BITS)
  		return "(r)";
  	if (flag & KPF_OVERLOADED_BITS)
  		return "(o)";
  	return "   ";
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
775
  static void usage(void)
35efa5e99   Wu Fengguang   pagemap: add page...
776
  {
e30d539b3   Ulrich Drepper   tools/vm/page-typ...
777
  	size_t i, j;
35efa5e99   Wu Fengguang   pagemap: add page...
778
779
780
781
  
  	printf(
  "page-types [options]
  "
9fdcd886a   Alex Chiang   page-types: white...
782
783
  "            -r|--raw                   Raw mode, for kernel developers
  "
dcfe730c6   Alex Chiang   page-types: learn...
784
785
  "            -d|--describe flags        Describe flags
  "
9fdcd886a   Alex Chiang   page-types: white...
786
787
788
789
  "            -a|--addr    addr-spec     Walk a range of pages
  "
  "            -b|--bits    bits-spec     Walk pages with specified bits
  "
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
790
791
  "            -c|--cgroup  path|@inode   Walk pages within memory cgroup
  "
9fdcd886a   Alex Chiang   page-types: white...
792
793
  "            -p|--pid     pid           Walk process address space
  "
9fdcd886a   Alex Chiang   page-types: white...
794
795
  "            -f|--file    filename      Walk file address space
  "
59ae96ffc   Christian Hansen   tools/vm/page-typ...
796
797
  "            -i|--mark-idle             Mark pages idle
  "
9fdcd886a   Alex Chiang   page-types: white...
798
799
800
801
  "            -l|--list                  Show page details in ranges
  "
  "            -L|--list-each             Show page details one by one
  "
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
802
803
  "            -C|--list-cgroup           Show cgroup inode for pages
  "
7f1d23e60   Christian Hansen   tools/vm/page-typ...
804
805
  "            -M|--list-mapcnt           Show page map count
  "
c7825cfac   Tommi Rantala   Documentation/vm:...
806
807
  "            -N|--no-summary            Don't show summary info
  "
9fdcd886a   Alex Chiang   page-types: white...
808
809
810
811
  "            -X|--hwpoison              hwpoison pages
  "
  "            -x|--unpoison              unpoison pages
  "
c7905f200   David Rientjes   tools, vm: new op...
812
813
  "            -F|--kpageflags filename   kpageflags file to parse
  "
9fdcd886a   Alex Chiang   page-types: white...
814
815
  "            -h|--help                  Show this usage message
  "
dcfe730c6   Alex Chiang   page-types: learn...
816
817
  "flags:
  "
9fdcd886a   Alex Chiang   page-types: white...
818
819
820
821
822
823
  "            0x10                       bitfield format, e.g.
  "
  "            anon                       bit-name, e.g.
  "
  "            0x10,anon                  comma-separated list, e.g.
  "
35efa5e99   Wu Fengguang   pagemap: add page...
824
825
  "addr-spec:
  "
9fdcd886a   Alex Chiang   page-types: white...
826
827
828
829
830
831
832
833
834
835
  "            N                          one page at offset N (unit: pages)
  "
  "            N+M                        pages range from N to N+M-1
  "
  "            N,M                        pages range from N to M-1
  "
  "            N,                         pages range from N to end
  "
  "            ,M                         pages range from 0 to M-1
  "
35efa5e99   Wu Fengguang   pagemap: add page...
836
837
  "bits-spec:
  "
9fdcd886a   Alex Chiang   page-types: white...
838
839
840
841
842
843
844
845
  "            bit1,bit2                  (flags & (bit1|bit2)) != 0
  "
  "            bit1,bit2=bit1             (flags & (bit1|bit2)) == bit1
  "
  "            bit1,~bit2                 (flags & (bit1|bit2)) == bit1
  "
  "            =bit1,bit2                 flags == (bit1|bit2)
  "
35efa5e99   Wu Fengguang   pagemap: add page...
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
  "bit-names:
  "
  	);
  
  	for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
  		if (!page_flag_names[i])
  			continue;
  		printf("%16s%s", page_flag_names[i] + 2,
  				 page_flag_type(1ULL << i));
  		if (++j > 3) {
  			j = 0;
  			putchar('
  ');
  		}
  	}
  	printf("
                                     "
  		"(r) raw mode bits  (o) overloaded bits
  ");
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
866
  static unsigned long long parse_number(const char *str)
35efa5e99   Wu Fengguang   pagemap: add page...
867
868
869
870
871
872
873
874
875
876
877
  {
  	unsigned long long n;
  
  	n = strtoll(str, NULL, 0);
  
  	if (n == 0 && str[0] != '0')
  		fatal("invalid name or number: %s
  ", str);
  
  	return n;
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
878
  static void parse_pid(const char *str)
35efa5e99   Wu Fengguang   pagemap: add page...
879
  {
0b4b2ad53   Wu Fengguang   page-types: add f...
880
881
  	FILE *file;
  	char buf[5000];
35efa5e99   Wu Fengguang   pagemap: add page...
882
  	opt_pid = parse_number(str);
35efa5e99   Wu Fengguang   pagemap: add page...
883

0b4b2ad53   Wu Fengguang   page-types: add f...
884
  	sprintf(buf, "/proc/%d/pagemap", opt_pid);
31bbf66ea   Wu Fengguang   page-types: intro...
885
  	pagemap_fd = checked_open(buf, O_RDONLY);
0b4b2ad53   Wu Fengguang   page-types: add f...
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
  
  	sprintf(buf, "/proc/%d/maps", opt_pid);
  	file = fopen(buf, "r");
  	if (!file) {
  		perror(buf);
  		exit(EXIT_FAILURE);
  	}
  
  	while (fgets(buf, sizeof(buf), file) != NULL) {
  		unsigned long vm_start;
  		unsigned long vm_end;
  		unsigned long long pgoff;
  		int major, minor;
  		char r, w, x, s;
  		unsigned long ino;
  		int n;
  
  		n = sscanf(buf, "%lx-%lx %c%c%c%c %llx %x:%x %lu",
  			   &vm_start,
  			   &vm_end,
  			   &r, &w, &x, &s,
  			   &pgoff,
  			   &major, &minor,
  			   &ino);
  		if (n < 10) {
  			fprintf(stderr, "unexpected line: %s
  ", buf);
  			continue;
  		}
  		pg_start[nr_vmas] = vm_start / page_size;
  		pg_end[nr_vmas] = vm_end / page_size;
  		if (++nr_vmas >= MAX_VMAS) {
  			fprintf(stderr, "too many VMAs
  ");
  			break;
  		}
  	}
  	fclose(file);
35efa5e99   Wu Fengguang   pagemap: add page...
924
  }
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
  static void show_file(const char *name, const struct stat *st)
  {
  	unsigned long long size = st->st_size;
  	char atime[64], mtime[64];
  	long now = time(NULL);
  
  	printf("%s\tInode: %u\tSize: %llu (%llu pages)
  ",
  			name, (unsigned)st->st_ino,
  			size, (size + page_size - 1) / page_size);
  
  	strftime(atime, sizeof(atime), "%c", localtime(&st->st_atime));
  	strftime(mtime, sizeof(mtime), "%c", localtime(&st->st_mtime));
  
  	printf("Modify: %s (%ld seconds ago)
  Access: %s (%ld seconds ago)
  ",
  			mtime, now - st->st_mtime,
  			atime, now - st->st_atime);
  }
1d46598b7   Konstantin Khlebnikov   tools/vm/page-typ...
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
  static sigjmp_buf sigbus_jmp;
  
  static void * volatile sigbus_addr;
  
  static void sigbus_handler(int sig, siginfo_t *info, void *ucontex)
  {
  	(void)sig;
  	(void)ucontex;
  	sigbus_addr = info ? info->si_addr : NULL;
  	siglongjmp(sigbus_jmp, 1);
  }
  
  static struct sigaction sigbus_action = {
  	.sa_sigaction = sigbus_handler,
  	.sa_flags = SA_SIGINFO,
  };
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
961
962
963
964
  static void walk_file(const char *name, const struct stat *st)
  {
  	uint8_t vec[PAGEMAP_BATCH];
  	uint64_t buf[PAGEMAP_BATCH], flags;
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
965
  	uint64_t cgroup = 0;
7f1d23e60   Christian Hansen   tools/vm/page-typ...
966
  	uint64_t mapcnt = 0;
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
967
  	unsigned long nr_pages, pfn, i;
1d46598b7   Konstantin Khlebnikov   tools/vm/page-typ...
968
  	off_t off, end = st->st_size;
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
969
  	int fd;
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
970
971
972
973
974
  	ssize_t len;
  	void *ptr;
  	int first = 1;
  
  	fd = checked_open(name, O_RDONLY|O_NOATIME|O_NOFOLLOW);
1d46598b7   Konstantin Khlebnikov   tools/vm/page-typ...
975
976
  	for (off = 0; off < end; off += len) {
  		nr_pages = (end - off + page_size - 1) / page_size;
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
  		if (nr_pages > PAGEMAP_BATCH)
  			nr_pages = PAGEMAP_BATCH;
  		len = nr_pages * page_size;
  
  		ptr = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, off);
  		if (ptr == MAP_FAILED)
  			fatal("mmap failed: %s", name);
  
  		/* determine cached pages */
  		if (mincore(ptr, len, vec))
  			fatal("mincore failed: %s", name);
  
  		/* turn off readahead */
  		if (madvise(ptr, len, MADV_RANDOM))
  			fatal("madvice failed: %s", name);
1d46598b7   Konstantin Khlebnikov   tools/vm/page-typ...
992
993
994
995
996
997
998
  		if (sigsetjmp(sigbus_jmp, 1)) {
  			end = off + sigbus_addr ? sigbus_addr - ptr : 0;
  			fprintf(stderr, "got sigbus at offset %lld: %s
  ",
  					(long long)end, name);
  			goto got_sigbus;
  		}
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
999
1000
1001
1002
1003
  		/* populate ptes */
  		for (i = 0; i < nr_pages ; i++) {
  			if (vec[i] & 1)
  				(void)*(volatile int *)(ptr + i * page_size);
  		}
1d46598b7   Konstantin Khlebnikov   tools/vm/page-typ...
1004
  got_sigbus:
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
  
  		/* turn off harvesting reference bits */
  		if (madvise(ptr, len, MADV_SEQUENTIAL))
  			fatal("madvice failed: %s", name);
  
  		if (pagemap_read(buf, (unsigned long)ptr / page_size,
  					nr_pages) != nr_pages)
  			fatal("cannot read pagemap");
  
  		munmap(ptr, len);
  
  		for (i = 0; i < nr_pages; i++) {
  			pfn = pagemap_pfn(buf[i]);
  			if (!pfn)
  				continue;
  			if (!kpageflags_read(&flags, pfn, 1))
  				continue;
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
1022
1023
  			if (!kpagecgroup_read(&cgroup, pfn, 1))
  				fatal("kpagecgroup_read failed");
7f1d23e60   Christian Hansen   tools/vm/page-typ...
1024
1025
  			if (!kpagecount_read(&mapcnt, pfn, 1))
  				fatal("kpagecount_read failed");
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1026
1027
1028
1029
1030
  			if (first && opt_list) {
  				first = 0;
  				flush_page_range();
  				show_file(name, st);
  			}
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
1031
  			add_page(off / page_size + i, pfn,
7f1d23e60   Christian Hansen   tools/vm/page-typ...
1032
  				 flags, cgroup, mapcnt, buf[i]);
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
  		}
  	}
  
  	close(fd);
  }
  
  int walk_tree(const char *name, const struct stat *st, int type, struct FTW *f)
  {
  	(void)f;
  	switch (type) {
  	case FTW_F:
  		if (S_ISREG(st->st_mode))
  			walk_file(name, st);
  		break;
  	case FTW_DNR:
  		fprintf(stderr, "cannot read dir: %s
  ", name);
  		break;
  	}
  	return 0;
  }
  
  static void walk_page_cache(void)
  {
  	struct stat st;
c7905f200   David Rientjes   tools, vm: new op...
1058
  	kpageflags_fd = checked_open(opt_kpageflags, O_RDONLY);
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1059
  	pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY);
1d46598b7   Konstantin Khlebnikov   tools/vm/page-typ...
1060
  	sigaction(SIGBUS, &sigbus_action, NULL);
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
  
  	if (stat(opt_file, &st))
  		fatal("stat failed: %s
  ", opt_file);
  
  	if (S_ISREG(st.st_mode)) {
  		walk_file(opt_file, &st);
  	} else if (S_ISDIR(st.st_mode)) {
  		/* do not follow symlinks and mountpoints */
  		if (nftw(opt_file, walk_tree, 64, FTW_MOUNT | FTW_PHYS) < 0)
  			fatal("nftw failed: %s
  ", opt_file);
  	} else
  		fatal("unhandled file type: %s
  ", opt_file);
  
  	close(kpageflags_fd);
  	close(pagemap_fd);
1d46598b7   Konstantin Khlebnikov   tools/vm/page-typ...
1079
  	signal(SIGBUS, SIG_DFL);
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1080
  }
0b4b2ad53   Wu Fengguang   page-types: add f...
1081
  static void parse_file(const char *name)
35efa5e99   Wu Fengguang   pagemap: add page...
1082
  {
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1083
  	opt_file = name;
35efa5e99   Wu Fengguang   pagemap: add page...
1084
  }
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
  static void parse_cgroup(const char *path)
  {
  	if (path[0] == '@') {
  		opt_cgroup = parse_number(path + 1);
  		return;
  	}
  
  	struct stat st;
  
  	if (stat(path, &st))
  		fatal("stat failed: %s: %m
  ", path);
  
  	if (!S_ISDIR(st.st_mode))
  		fatal("cgroup supposed to be a directory: %s
  ", path);
  
  	opt_cgroup = st.st_ino;
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
1104
  static void parse_addr_range(const char *optarg)
35efa5e99   Wu Fengguang   pagemap: add page...
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  {
  	unsigned long offset;
  	unsigned long size;
  	char *p;
  
  	p = strchr(optarg, ',');
  	if (!p)
  		p = strchr(optarg, '+');
  
  	if (p == optarg) {
  		offset = 0;
  		size   = parse_number(p + 1);
  	} else if (p) {
  		offset = parse_number(optarg);
  		if (p[1] == '\0')
  			size = ULONG_MAX;
  		else {
  			size = parse_number(p + 1);
  			if (*p == ',') {
  				if (size < offset)
  					fatal("invalid range: %lu,%lu
  ",
  							offset, size);
  				size -= offset;
  			}
  		}
  	} else {
  		offset = parse_number(optarg);
  		size   = 1;
  	}
  
  	add_addr_range(offset, size);
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
1138
  static void add_bits_filter(uint64_t mask, uint64_t bits)
35efa5e99   Wu Fengguang   pagemap: add page...
1139
1140
1141
1142
1143
1144
1145
1146
1147
  {
  	if (nr_bit_filters >= MAX_BIT_FILTERS)
  		fatal("too much bit filters
  ");
  
  	opt_mask[nr_bit_filters] = mask;
  	opt_bits[nr_bit_filters] = bits;
  	nr_bit_filters++;
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
1148
  static uint64_t parse_flag_name(const char *str, int len)
35efa5e99   Wu Fengguang   pagemap: add page...
1149
  {
e30d539b3   Ulrich Drepper   tools/vm/page-typ...
1150
  	size_t i;
35efa5e99   Wu Fengguang   pagemap: add page...
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
  
  	if (!*str || !len)
  		return 0;
  
  	if (len <= 8 && !strncmp(str, "compound", len))
  		return BITS_COMPOUND;
  
  	for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) {
  		if (!page_flag_names[i])
  			continue;
  		if (!strncmp(str, page_flag_names[i] + 2, len))
  			return 1ULL << i;
  	}
  
  	return parse_number(str);
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
1167
  static uint64_t parse_flag_names(const char *str, int all)
35efa5e99   Wu Fengguang   pagemap: add page...
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
  {
  	const char *p    = str;
  	uint64_t   flags = 0;
  
  	while (1) {
  		if (*p == ',' || *p == '=' || *p == '\0') {
  			if ((*str != '~') || (*str == '~' && all && *++str))
  				flags |= parse_flag_name(str, p - str);
  			if (*p != ',')
  				break;
  			str = p + 1;
  		}
  		p++;
  	}
  
  	return flags;
  }
b7ed698cc   Ladinu Chandrasinghe   Documentation/: f...
1185
  static void parse_bits_mask(const char *optarg)
35efa5e99   Wu Fengguang   pagemap: add page...
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
  {
  	uint64_t mask;
  	uint64_t bits;
  	const char *p;
  
  	p = strchr(optarg, '=');
  	if (p == optarg) {
  		mask = KPF_ALL_BITS;
  		bits = parse_flag_names(p + 1, 0);
  	} else if (p) {
  		mask = parse_flag_names(optarg, 0);
  		bits = parse_flag_names(p + 1, 0);
  	} else if (strchr(optarg, '~')) {
  		mask = parse_flag_names(optarg, 1);
  		bits = parse_flag_names(optarg, 0);
  	} else {
  		mask = parse_flag_names(optarg, 0);
  		bits = KPF_ALL_BITS;
  	}
  
  	add_bits_filter(mask, bits);
  }
c7905f200   David Rientjes   tools, vm: new op...
1208
1209
1210
1211
  static void parse_kpageflags(const char *name)
  {
  	opt_kpageflags = name;
  }
dcfe730c6   Alex Chiang   page-types: learn...
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
  static void describe_flags(const char *optarg)
  {
  	uint64_t flags = parse_flag_names(optarg, 0);
  
  	printf("0x%016llx\t%s\t%s
  ",
  		(unsigned long long)flags,
  		page_flag_name(flags),
  		page_flag_longname(flags));
  }
35efa5e99   Wu Fengguang   pagemap: add page...
1222

3428838d8   Tommi Rantala   page-types: const...
1223
  static const struct option opts[] = {
35efa5e99   Wu Fengguang   pagemap: add page...
1224
1225
1226
1227
1228
  	{ "raw"       , 0, NULL, 'r' },
  	{ "pid"       , 1, NULL, 'p' },
  	{ "file"      , 1, NULL, 'f' },
  	{ "addr"      , 1, NULL, 'a' },
  	{ "bits"      , 1, NULL, 'b' },
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
1229
  	{ "cgroup"    , 1, NULL, 'c' },
dcfe730c6   Alex Chiang   page-types: learn...
1230
  	{ "describe"  , 1, NULL, 'd' },
59ae96ffc   Christian Hansen   tools/vm/page-typ...
1231
  	{ "mark-idle" , 0, NULL, 'i' },
35efa5e99   Wu Fengguang   pagemap: add page...
1232
1233
  	{ "list"      , 0, NULL, 'l' },
  	{ "list-each" , 0, NULL, 'L' },
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
1234
  	{ "list-cgroup", 0, NULL, 'C' },
7f1d23e60   Christian Hansen   tools/vm/page-typ...
1235
  	{ "list-mapcnt", 0, NULL, 'M' },
35efa5e99   Wu Fengguang   pagemap: add page...
1236
  	{ "no-summary", 0, NULL, 'N' },
a54fed9f7   Wu Fengguang   page-types: add h...
1237
1238
  	{ "hwpoison"  , 0, NULL, 'X' },
  	{ "unpoison"  , 0, NULL, 'x' },
c7905f200   David Rientjes   tools, vm: new op...
1239
  	{ "kpageflags", 0, NULL, 'F' },
35efa5e99   Wu Fengguang   pagemap: add page...
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
  	{ "help"      , 0, NULL, 'h' },
  	{ NULL        , 0, NULL, 0 }
  };
  
  int main(int argc, char *argv[])
  {
  	int c;
  
  	page_size = getpagesize();
  
  	while ((c = getopt_long(argc, argv,
59ae96ffc   Christian Hansen   tools/vm/page-typ...
1251
  				"rp:f:a:b:d:c:CilLMNXxF:h",
7f1d23e60   Christian Hansen   tools/vm/page-typ...
1252
  				opts, NULL)) != -1) {
35efa5e99   Wu Fengguang   pagemap: add page...
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
  		switch (c) {
  		case 'r':
  			opt_raw = 1;
  			break;
  		case 'p':
  			parse_pid(optarg);
  			break;
  		case 'f':
  			parse_file(optarg);
  			break;
  		case 'a':
  			parse_addr_range(optarg);
  			break;
  		case 'b':
  			parse_bits_mask(optarg);
  			break;
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
1269
1270
1271
1272
1273
1274
  		case 'c':
  			parse_cgroup(optarg);
  			break;
  		case 'C':
  			opt_list_cgroup = 1;
  			break;
dcfe730c6   Alex Chiang   page-types: learn...
1275
  		case 'd':
dcfe730c6   Alex Chiang   page-types: learn...
1276
  			describe_flags(optarg);
bb86a7338   Alex Chiang   page-types: exit ...
1277
  			exit(0);
59ae96ffc   Christian Hansen   tools/vm/page-typ...
1278
1279
1280
  		case 'i':
  			opt_mark_idle = 1;
  			break;
35efa5e99   Wu Fengguang   pagemap: add page...
1281
1282
1283
1284
1285
1286
  		case 'l':
  			opt_list = 1;
  			break;
  		case 'L':
  			opt_list = 2;
  			break;
7f1d23e60   Christian Hansen   tools/vm/page-typ...
1287
1288
1289
  		case 'M':
  			opt_list_mapcnt = 1;
  			break;
35efa5e99   Wu Fengguang   pagemap: add page...
1290
1291
1292
  		case 'N':
  			opt_no_summary = 1;
  			break;
a54fed9f7   Wu Fengguang   page-types: add h...
1293
1294
1295
1296
1297
1298
1299
1300
  		case 'X':
  			opt_hwpoison = 1;
  			prepare_hwpoison_fd();
  			break;
  		case 'x':
  			opt_unpoison = 1;
  			prepare_hwpoison_fd();
  			break;
c7905f200   David Rientjes   tools, vm: new op...
1301
1302
1303
  		case 'F':
  			parse_kpageflags(optarg);
  			break;
35efa5e99   Wu Fengguang   pagemap: add page...
1304
1305
1306
1307
1308
1309
1310
1311
  		case 'h':
  			usage();
  			exit(0);
  		default:
  			usage();
  			exit(1);
  		}
  	}
c7905f200   David Rientjes   tools, vm: new op...
1312
1313
  	if (!opt_kpageflags)
  		opt_kpageflags = PROC_KPAGEFLAGS;
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
1314
1315
  	if (opt_cgroup || opt_list_cgroup)
  		kpagecgroup_fd = checked_open(PROC_KPAGECGROUP, O_RDONLY);
7f1d23e60   Christian Hansen   tools/vm/page-typ...
1316
1317
  	if (opt_list && opt_list_mapcnt)
  		kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY);
59ae96ffc   Christian Hansen   tools/vm/page-typ...
1318
1319
  	if (opt_mark_idle && opt_file)
  		page_idle_fd = checked_open(SYS_KERNEL_MM_PAGE_IDLE, O_RDWR);
0b4b2ad53   Wu Fengguang   page-types: add f...
1320
1321
  	if (opt_list && opt_pid)
  		printf("voffset\t");
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1322
1323
  	if (opt_list && opt_file)
  		printf("foffset\t");
075db1502   Konstantin Khlebnikov   tools/vm/page-typ...
1324
1325
  	if (opt_list && opt_list_cgroup)
  		printf("cgroup\t");
7f1d23e60   Christian Hansen   tools/vm/page-typ...
1326
1327
  	if (opt_list && opt_list_mapcnt)
  		printf("map-cnt\t");
35efa5e99   Wu Fengguang   pagemap: add page...
1328
  	if (opt_list == 1)
0b4b2ad53   Wu Fengguang   page-types: add f...
1329
1330
  		printf("offset\tlen\tflags
  ");
35efa5e99   Wu Fengguang   pagemap: add page...
1331
1332
1333
  	if (opt_list == 2)
  		printf("offset\tflags
  ");
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1334
1335
1336
1337
  	if (opt_file)
  		walk_page_cache();
  	else
  		walk_addr_ranges();
35efa5e99   Wu Fengguang   pagemap: add page...
1338
1339
  
  	if (opt_list == 1)
65a6a4105   Konstantin Khlebnikov   tools/vm/page-typ...
1340
  		flush_page_range();
35efa5e99   Wu Fengguang   pagemap: add page...
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
  
  	if (opt_no_summary)
  		return 0;
  
  	if (opt_list)
  		printf("
  
  ");
  
  	show_summary();
7f1d23e60   Christian Hansen   tools/vm/page-typ...
1351
1352
  	if (opt_list_mapcnt)
  		close(kpagecount_fd);
59ae96ffc   Christian Hansen   tools/vm/page-typ...
1353
1354
  	if (page_idle_fd >= 0)
  		close(page_idle_fd);
35efa5e99   Wu Fengguang   pagemap: add page...
1355
1356
  	return 0;
  }