Blame view
tools/vm/page-types.c
29.9 KB
af7c5f890 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
35efa5e99 pagemap: add page... |
2 3 4 5 |
/* * page-types: Tool for querying page flags * * Copyright (C) 2009 Intel corporation |
0c57effe2 page-types: add G... |
6 7 |
* * Authors: Wu Fengguang <fengguang.wu@intel.com> |
35efa5e99 pagemap: add page... |
8 |
*/ |
65a6a4105 tools/vm/page-typ... |
9 10 |
#define _FILE_OFFSET_BITS 64 #define _GNU_SOURCE |
35efa5e99 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 page-types: add f... |
19 |
#include <assert.h> |
65a6a4105 tools/vm/page-typ... |
20 21 |
#include <ftw.h> #include <time.h> |
1d46598b7 tools/vm/page-typ... |
22 23 |
#include <setjmp.h> #include <signal.h> |
35efa5e99 pagemap: add page... |
24 25 26 |
#include <sys/types.h> #include <sys/errno.h> #include <sys/fcntl.h> |
12da58b0c Documentation/vm/... |
27 28 |
#include <sys/mount.h> #include <sys/statfs.h> |
65a6a4105 tools/vm/page-typ... |
29 |
#include <sys/mman.h> |
607ca46e9 UAPI: (Scripted) ... |
30 |
#include "../../include/uapi/linux/magic.h" |
59ce8764b UAPI: fix tools/v... |
31 |
#include "../../include/uapi/linux/kernel-page-flags.h" |
f6489bc2d tools vm: Fix bui... |
32 |
#include <api/fs/fs.h> |
35efa5e99 pagemap: add page... |
33 |
|
12da58b0c 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 pagemap: add page... |
42 |
/* |
0b4b2ad53 page-types: add f... |
43 44 |
* pagemap kernel ABI bits */ |
deb945441 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 tools/vm/page-typ... |
49 50 |
#define MAX_SWAPFILES_SHIFT 5 #define PM_SWAP_OFFSET(x) (((x) & PM_PFRAME_MASK) >> MAX_SWAPFILES_SHIFT) |
deb945441 pagemap: switch t... |
51 |
#define PM_SOFT_DIRTY (1ULL << 55) |
77bb499bb pagemap: add mmap... |
52 |
#define PM_MMAP_EXCLUSIVE (1ULL << 56) |
deb945441 pagemap: switch t... |
53 54 55 |
#define PM_FILE (1ULL << 61) #define PM_SWAP (1ULL << 62) #define PM_PRESENT (1ULL << 63) |
0b4b2ad53 page-types: add f... |
56 57 |
/* |
35efa5e99 pagemap: add page... |
58 59 60 61 62 |
* kernel page flags */ #define KPF_BYTES 8 #define PROC_KPAGEFLAGS "/proc/kpageflags" |
7f1d23e60 tools/vm/page-typ... |
63 |
#define PROC_KPAGECOUNT "/proc/kpagecount" |
075db1502 tools/vm/page-typ... |
64 |
#define PROC_KPAGECGROUP "/proc/kpagecgroup" |
35efa5e99 pagemap: add page... |
65 |
|
59ae96ffc tools/vm/page-typ... |
66 |
#define SYS_KERNEL_MM_PAGE_IDLE "/sys/kernel/mm/page_idle/bitmap" |
35efa5e99 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 tools/vm/page-typ... |
76 |
#define KPF_SOFTDIRTY 40 |
4beba9486 mm: Add PG_arch_2... |
77 |
#define KPF_ARCH_2 41 |
35efa5e99 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 tools/vm/page-typ... |
86 87 |
#define KPF_FILE 61 #define KPF_SWAP 62 |
77bb499bb pagemap: add mmap... |
88 |
#define KPF_MMAP_EXCLUSIVE 63 |
35efa5e99 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 mm: move page-typ... |
95 |
static const char * const page_flag_names[] = { |
35efa5e99 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 pagemap: export K... |
116 |
[KPF_HWPOISON] = "X:hwpoison", |
35efa5e99 pagemap: add page... |
117 |
[KPF_NOPAGE] = "n:nopage", |
a1bbb5ec3 pagemap: document... |
118 |
[KPF_KSM] = "x:ksm", |
807f0ccfe pagemap: document... |
119 |
[KPF_THP] = "t:thp", |
ca215086b mm: convert PG_ba... |
120 |
[KPF_OFFLINE] = "o:offline", |
1d40a5ea0 mm: mark pages in... |
121 |
[KPF_PGTABLE] = "g:pgtable", |
56873f43a mm:add KPF_ZERO_P... |
122 |
[KPF_ZERO_PAGE] = "z:zero_page", |
429d48622 tools/vm/page-typ... |
123 |
[KPF_IDLE] = "i:idle_page", |
35efa5e99 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 tools/vm/page-typ... |
133 |
[KPF_SOFTDIRTY] = "f:softdirty", |
4beba9486 mm: Add PG_arch_2... |
134 |
[KPF_ARCH_2] = "H:arch_2", |
35efa5e99 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 pagemap: add mmap... |
140 141 |
[KPF_FILE] = "F:file", |
0335ddd34 tools/vm/page-typ... |
142 |
[KPF_SWAP] = "w:swap", |
77bb499bb pagemap: add mmap... |
143 |
[KPF_MMAP_EXCLUSIVE] = "1:mmap_exclusive", |
35efa5e99 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 tools/vm/page-typ... |
153 |
static int opt_mark_idle; /* set accessed bit */ |
35efa5e99 pagemap: add page... |
154 155 |
static int opt_no_summary; /* don't show summary */ static pid_t opt_pid; /* process to walk */ |
c7905f200 tools, vm: new op... |
156 |
const char *opt_file; /* file or directory path */ |
075db1502 tools/vm/page-typ... |
157 158 |
static uint64_t opt_cgroup; /* cgroup inode */ static int opt_list_cgroup;/* list page cgroup */ |
7f1d23e60 tools/vm/page-typ... |
159 |
static int opt_list_mapcnt;/* list page map count */ |
c7905f200 tools, vm: new op... |
160 |
static const char *opt_kpageflags;/* kpageflags file to parse */ |
35efa5e99 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 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 page-types: add f... |
170 |
|
35efa5e99 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 page-types: make ... |
177 |
static int pagemap_fd; |
35efa5e99 pagemap: add page... |
178 |
static int kpageflags_fd; |
7f1d23e60 tools/vm/page-typ... |
179 |
static int kpagecount_fd = -1; |
075db1502 tools/vm/page-typ... |
180 |
static int kpagecgroup_fd = -1; |
59ae96ffc tools/vm/page-typ... |
181 |
static int page_idle_fd = -1; |
35efa5e99 pagemap: add page... |
182 |
|
a54fed9f7 page-types: add h... |
183 184 |
static int opt_hwpoison; static int opt_unpoison; |
f6489bc2d tools vm: Fix bui... |
185 |
static const char *hwpoison_debug_fs; |
a54fed9f7 page-types: add h... |
186 187 |
static int hwpoison_inject_fd; static int hwpoison_forget_fd; |
35efa5e99 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 mm: move page-typ... |
195 |
static uint64_t page_flags[HASH_SIZE]; |
35efa5e99 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 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 Documentation/: f... |
212 |
static unsigned long pages2mb(unsigned long pages) |
35efa5e99 pagemap: add page... |
213 214 215 |
{ return (pages * page_size) >> 20; } |
b7ed698cc Documentation/: f... |
216 |
static void fatal(const char *x, ...) |
35efa5e99 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 Documentation/vm/... |
225 |
static int checked_open(const char *pathname, int flags) |
31bbf66ea 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 page-types: make ... |
236 237 238 |
/* * pagemap/kpageflags routines */ |
c7905f200 tools, vm: new op... |
239 |
static unsigned long do_u64_read(int fd, const char *name, |
4a1b6726f 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 tools/vm/page-typ... |
249 |
bytes = pread(fd, buf, count * 8, (off_t)index * 8); |
4a1b6726f 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 tools, vm: new op... |
265 |
return do_u64_read(kpageflags_fd, opt_kpageflags, buf, index, pages); |
4a1b6726f page-types: make ... |
266 |
} |
075db1502 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 tools, vm: new op... |
273 |
return do_u64_read(kpagecgroup_fd, opt_kpageflags, buf, index, pages); |
075db1502 tools/vm/page-typ... |
274 |
} |
7f1d23e60 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 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 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 pagemap: add page... |
305 306 307 308 |
/* * page flag names */ |
b7ed698cc Documentation/: f... |
309 |
static char *page_flag_name(uint64_t flags) |
35efa5e99 pagemap: add page... |
310 311 312 |
{ static char buf[65]; int present; |
e30d539b3 tools/vm/page-typ... |
313 |
size_t i, j; |
35efa5e99 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 tree-wide: fix as... |
319 320 |
fatal("unknown flag bit %d ", i); |
35efa5e99 pagemap: add page... |
321 322 323 324 325 326 327 |
continue; } buf[j++] = present ? page_flag_names[i][0] : '_'; } return buf; } |
b7ed698cc Documentation/: f... |
328 |
static char *page_flag_longname(uint64_t flags) |
35efa5e99 pagemap: add page... |
329 330 |
{ static char buf[1024]; |
e30d539b3 tools/vm/page-typ... |
331 |
size_t i, n; |
35efa5e99 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 tools/vm/page-typ... |
351 |
static void show_page_range(unsigned long voffset, unsigned long offset, |
7f1d23e60 tools/vm/page-typ... |
352 353 |
unsigned long size, uint64_t flags, uint64_t cgroup, uint64_t mapcnt) |
35efa5e99 pagemap: add page... |
354 355 |
{ static uint64_t flags0; |
075db1502 tools/vm/page-typ... |
356 |
static uint64_t cgroup0; |
7f1d23e60 tools/vm/page-typ... |
357 |
static uint64_t mapcnt0; |
0b4b2ad53 page-types: add f... |
358 |
static unsigned long voff; |
35efa5e99 pagemap: add page... |
359 360 |
static unsigned long index; static unsigned long count; |
7f1d23e60 tools/vm/page-typ... |
361 362 |
if (flags == flags0 && cgroup == cgroup0 && mapcnt == mapcnt0 && offset == index + count && size && voffset == voff + count) { |
65a6a4105 tools/vm/page-typ... |
363 |
count += size; |
35efa5e99 pagemap: add page... |
364 365 |
return; } |
0b4b2ad53 page-types: add f... |
366 367 368 |
if (count) { if (opt_pid) printf("%lx\t", voff); |
65a6a4105 tools/vm/page-typ... |
369 370 |
if (opt_file) printf("%lu\t", voff); |
075db1502 tools/vm/page-typ... |
371 372 |
if (opt_list_cgroup) printf("@%llu\t", (unsigned long long)cgroup0); |
7f1d23e60 tools/vm/page-typ... |
373 374 |
if (opt_list_mapcnt) printf("%lu\t", mapcnt0); |
0b4b2ad53 page-types: add f... |
375 376 |
printf("%lx\t%lx\t%s ", |
35efa5e99 pagemap: add page... |
377 |
index, count, page_flag_name(flags0)); |
0b4b2ad53 page-types: add f... |
378 |
} |
35efa5e99 pagemap: add page... |
379 380 |
flags0 = flags; |
7f1d23e60 tools/vm/page-typ... |
381 382 |
cgroup0 = cgroup; mapcnt0 = mapcnt; |
35efa5e99 pagemap: add page... |
383 |
index = offset; |
0b4b2ad53 page-types: add f... |
384 |
voff = voffset; |
65a6a4105 tools/vm/page-typ... |
385 386 387 388 389 |
count = size; } static void flush_page_range(void) { |
7f1d23e60 tools/vm/page-typ... |
390 |
show_page_range(0, 0, 0, 0, 0, 0); |
35efa5e99 pagemap: add page... |
391 |
} |
075db1502 tools/vm/page-typ... |
392 |
static void show_page(unsigned long voffset, unsigned long offset, |
7f1d23e60 tools/vm/page-typ... |
393 |
uint64_t flags, uint64_t cgroup, uint64_t mapcnt) |
35efa5e99 pagemap: add page... |
394 |
{ |
0b4b2ad53 page-types: add f... |
395 396 |
if (opt_pid) printf("%lx\t", voffset); |
65a6a4105 tools/vm/page-typ... |
397 398 |
if (opt_file) printf("%lu\t", voffset); |
075db1502 tools/vm/page-typ... |
399 400 |
if (opt_list_cgroup) printf("@%llu\t", (unsigned long long)cgroup); |
7f1d23e60 tools/vm/page-typ... |
401 402 |
if (opt_list_mapcnt) printf("%lu\t", mapcnt); |
0b4b2ad53 page-types: add f... |
403 404 |
printf("%lx\t%s ", offset, page_flag_name(flags)); |
35efa5e99 pagemap: add page... |
405 |
} |
b7ed698cc Documentation/: f... |
406 |
static void show_summary(void) |
35efa5e99 pagemap: add page... |
407 |
{ |
e30d539b3 tools/vm/page-typ... |
408 |
size_t i; |
35efa5e99 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 Documentation/: f... |
434 |
static int bit_mask_ok(uint64_t flags) |
35efa5e99 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 tools/vm/page-typ... |
450 |
static uint64_t expand_overloaded_flags(uint64_t flags, uint64_t pme) |
35efa5e99 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 tools/vm/page-typ... |
465 466 |
if (pme & PM_SOFT_DIRTY) flags |= BIT(SOFTDIRTY); |
77bb499bb pagemap: add mmap... |
467 468 |
if (pme & PM_FILE) flags |= BIT(FILE); |
0335ddd34 tools/vm/page-typ... |
469 470 |
if (pme & PM_SWAP) flags |= BIT(SWAP); |
77bb499bb pagemap: add mmap... |
471 472 |
if (pme & PM_MMAP_EXCLUSIVE) flags |= BIT(MMAP_EXCLUSIVE); |
46c77e2bb tools/vm/page-typ... |
473 |
|
35efa5e99 pagemap: add page... |
474 475 |
return flags; } |
b7ed698cc Documentation/: f... |
476 |
static uint64_t well_known_flags(uint64_t flags) |
35efa5e99 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 tools/vm/page-typ... |
487 |
static uint64_t kpageflags_flags(uint64_t flags, uint64_t pme) |
48640d69f page-types: intro... |
488 |
{ |
46c77e2bb tools/vm/page-typ... |
489 490 491 |
if (opt_raw) flags = expand_overloaded_flags(flags, pme); else |
48640d69f page-types: intro... |
492 493 494 495 |
flags = well_known_flags(flags); return flags; } |
35efa5e99 pagemap: add page... |
496 |
/* |
a54fed9f7 page-types: add h... |
497 498 499 500 501 |
* page actions */ static void prepare_hwpoison_fd(void) { |
12da58b0c Documentation/vm/... |
502 |
char buf[MAX_PATH + 1]; |
f6489bc2d tools vm: Fix bui... |
503 |
hwpoison_debug_fs = debugfs__mount(); |
5a439645e tools/vm: Switch ... |
504 505 506 507 |
if (!hwpoison_debug_fs) { perror("mount debugfs"); exit(EXIT_FAILURE); } |
a54fed9f7 page-types: add h... |
508 509 |
if (opt_hwpoison && !hwpoison_inject_fd) { |
12da58b0c Documentation/vm/... |
510 511 |
snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn", hwpoison_debug_fs); |
a54fed9f7 page-types: add h... |
512 513 514 515 |
hwpoison_inject_fd = checked_open(buf, O_WRONLY); } if (opt_unpoison && !hwpoison_forget_fd) { |
12da58b0c Documentation/vm/... |
516 517 |
snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn", hwpoison_debug_fs); |
a54fed9f7 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 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 page-types: add h... |
574 |
/* |
35efa5e99 pagemap: add page... |
575 576 |
* page frame walker */ |
e30d539b3 tools/vm/page-typ... |
577 |
static size_t hash_slot(uint64_t flags) |
35efa5e99 pagemap: add page... |
578 |
{ |
e30d539b3 tools/vm/page-typ... |
579 580 |
size_t k = HASH_KEY(flags); size_t i; |
35efa5e99 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 tools/vm/page-typ... |
604 |
static void add_page(unsigned long voffset, unsigned long offset, |
7f1d23e60 tools/vm/page-typ... |
605 606 |
uint64_t flags, uint64_t cgroup, uint64_t mapcnt, uint64_t pme) |
35efa5e99 pagemap: add page... |
607 |
{ |
46c77e2bb tools/vm/page-typ... |
608 |
flags = kpageflags_flags(flags, pme); |
35efa5e99 pagemap: add page... |
609 610 611 |
if (!bit_mask_ok(flags)) return; |
075db1502 tools/vm/page-typ... |
612 613 |
if (opt_cgroup && cgroup != (uint64_t)opt_cgroup) return; |
a54fed9f7 page-types: add h... |
614 615 616 617 |
if (opt_hwpoison) hwpoison_page(offset); if (opt_unpoison) unpoison_page(offset); |
59ae96ffc tools/vm/page-typ... |
618 619 |
if (opt_mark_idle) mark_page_idle(offset); |
35efa5e99 pagemap: add page... |
620 |
if (opt_list == 1) |
7f1d23e60 tools/vm/page-typ... |
621 |
show_page_range(voffset, offset, 1, flags, cgroup, mapcnt); |
35efa5e99 pagemap: add page... |
622 |
else if (opt_list == 2) |
7f1d23e60 tools/vm/page-typ... |
623 |
show_page(voffset, offset, flags, cgroup, mapcnt); |
35efa5e99 pagemap: add page... |
624 625 626 627 |
nr_pages[hash_slot(flags)]++; total_pages++; } |
4a1b6726f page-types: make ... |
628 |
#define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */ |
e577ebde9 page-types: make ... |
629 630 |
static void walk_pfn(unsigned long voffset, unsigned long index, |
46c77e2bb tools/vm/page-typ... |
631 632 |
unsigned long count, uint64_t pme) |
35efa5e99 pagemap: add page... |
633 |
{ |
4a1b6726f page-types: make ... |
634 |
uint64_t buf[KPAGEFLAGS_BATCH]; |
075db1502 tools/vm/page-typ... |
635 |
uint64_t cgi[KPAGEFLAGS_BATCH]; |
7f1d23e60 tools/vm/page-typ... |
636 |
uint64_t cnt[KPAGEFLAGS_BATCH]; |
35efa5e99 pagemap: add page... |
637 |
unsigned long batch; |
e30d539b3 tools/vm/page-typ... |
638 |
unsigned long pages; |
35efa5e99 pagemap: add page... |
639 |
unsigned long i; |
d9b2ddf80 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 tools/vm/page-typ... |
649 |
|
35efa5e99 pagemap: add page... |
650 |
while (count) { |
4a1b6726f page-types: make ... |
651 652 653 |
batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH); pages = kpageflags_read(buf, index, batch); if (pages == 0) |
35efa5e99 pagemap: add page... |
654 |
break; |
35efa5e99 pagemap: add page... |
655 |
|
075db1502 tools/vm/page-typ... |
656 657 |
if (kpagecgroup_read(cgi, index, pages) != pages) fatal("kpagecgroup returned fewer pages than expected"); |
b6fb87b8e tools/vm/page-typ... |
658 |
if (kpagecount_read(cnt, index, pages) != pages) |
7f1d23e60 tools/vm/page-typ... |
659 |
fatal("kpagecount returned fewer pages than expected"); |
4a1b6726f page-types: make ... |
660 |
for (i = 0; i < pages; i++) |
7f1d23e60 tools/vm/page-typ... |
661 662 |
add_page(voffset + i, index + i, buf[i], cgi[i], cnt[i], pme); |
35efa5e99 pagemap: add page... |
663 |
|
4a1b6726f page-types: make ... |
664 665 |
index += pages; count -= pages; |
35efa5e99 pagemap: add page... |
666 667 |
} } |
0335ddd34 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 tools/vm/page-typ... |
674 675 |
if (opt_cgroup) return; |
0335ddd34 tools/vm/page-typ... |
676 |
if (opt_list == 1) |
7f1d23e60 tools/vm/page-typ... |
677 678 |
show_page_range(voffset, pagemap_swap_offset(pme), 1, flags, 0, 0); |
0335ddd34 tools/vm/page-typ... |
679 |
else if (opt_list == 2) |
7f1d23e60 tools/vm/page-typ... |
680 |
show_page(voffset, pagemap_swap_offset(pme), flags, 0, 0); |
0335ddd34 tools/vm/page-typ... |
681 682 683 684 |
nr_pages[hash_slot(flags)]++; total_pages++; } |
4a1b6726f page-types: make ... |
685 686 |
#define PAGEMAP_BATCH (64 << 10) static void walk_vma(unsigned long index, unsigned long count) |
0b4b2ad53 page-types: add f... |
687 |
{ |
4a1b6726f 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 page-types: add f... |
693 |
|
4a1b6726f 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 page-types: add f... |
699 |
|
4a1b6726f page-types: make ... |
700 701 |
for (i = 0; i < pages; i++) { pfn = pagemap_pfn(buf[i]); |
4a1b6726f page-types: make ... |
702 |
if (pfn) |
46c77e2bb tools/vm/page-typ... |
703 |
walk_pfn(index + i, pfn, 1, buf[i]); |
0335ddd34 tools/vm/page-typ... |
704 705 |
if (buf[i] & PM_SWAP) walk_swap(index + i, buf[i]); |
4a1b6726f page-types: make ... |
706 707 708 709 710 |
} index += pages; count -= pages; } |
0b4b2ad53 page-types: add f... |
711 712 713 714 |
} static void walk_task(unsigned long index, unsigned long count) { |
0b4b2ad53 page-types: add f... |
715 |
const unsigned long end = index + count; |
e577ebde9 page-types: make ... |
716 717 |
unsigned long start; int i = 0; |
0b4b2ad53 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 page-types: make ... |
726 727 |
start = max_t(unsigned long, pg_start[i], index); index = min_t(unsigned long, pg_end[i], end); |
0b4b2ad53 page-types: add f... |
728 |
|
e577ebde9 page-types: make ... |
729 730 |
assert(start < index); walk_vma(start, index - start); |
0b4b2ad53 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 Documentation/: f... |
744 |
static void walk_addr_ranges(void) |
35efa5e99 pagemap: add page... |
745 746 |
{ int i; |
c7905f200 tools, vm: new op... |
747 |
kpageflags_fd = checked_open(opt_kpageflags, O_RDONLY); |
35efa5e99 pagemap: add page... |
748 749 |
if (!nr_addr_ranges) |
0b4b2ad53 page-types: add f... |
750 |
add_addr_range(0, ULONG_MAX); |
35efa5e99 pagemap: add page... |
751 752 |
for (i = 0; i < nr_addr_ranges; i++) |
0b4b2ad53 page-types: add f... |
753 |
if (!opt_pid) |
65a6a4105 tools/vm/page-typ... |
754 |
walk_pfn(opt_offset[i], opt_offset[i], opt_size[i], 0); |
0b4b2ad53 page-types: add f... |
755 756 |
else walk_task(opt_offset[i], opt_size[i]); |
35efa5e99 pagemap: add page... |
757 |
|
59ae96ffc tools/vm/page-typ... |
758 759 |
if (opt_mark_idle) mark_page_idle(0); |
35efa5e99 pagemap: add page... |
760 761 762 763 764 765 766 |
close(kpageflags_fd); } /* * user interface */ |
b7ed698cc Documentation/: f... |
767 |
static const char *page_flag_type(uint64_t flag) |
35efa5e99 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 Documentation/: f... |
775 |
static void usage(void) |
35efa5e99 pagemap: add page... |
776 |
{ |
e30d539b3 tools/vm/page-typ... |
777 |
size_t i, j; |
35efa5e99 pagemap: add page... |
778 779 780 781 |
printf( "page-types [options] " |
9fdcd886a page-types: white... |
782 783 |
" -r|--raw Raw mode, for kernel developers " |
dcfe730c6 page-types: learn... |
784 785 |
" -d|--describe flags Describe flags " |
9fdcd886a 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 tools/vm/page-typ... |
790 791 |
" -c|--cgroup path|@inode Walk pages within memory cgroup " |
9fdcd886a page-types: white... |
792 793 |
" -p|--pid pid Walk process address space " |
9fdcd886a page-types: white... |
794 795 |
" -f|--file filename Walk file address space " |
59ae96ffc tools/vm/page-typ... |
796 797 |
" -i|--mark-idle Mark pages idle " |
9fdcd886a page-types: white... |
798 799 800 801 |
" -l|--list Show page details in ranges " " -L|--list-each Show page details one by one " |
075db1502 tools/vm/page-typ... |
802 803 |
" -C|--list-cgroup Show cgroup inode for pages " |
7f1d23e60 tools/vm/page-typ... |
804 805 |
" -M|--list-mapcnt Show page map count " |
c7825cfac Documentation/vm:... |
806 807 |
" -N|--no-summary Don't show summary info " |
9fdcd886a page-types: white... |
808 809 810 811 |
" -X|--hwpoison hwpoison pages " " -x|--unpoison unpoison pages " |
c7905f200 tools, vm: new op... |
812 813 |
" -F|--kpageflags filename kpageflags file to parse " |
9fdcd886a page-types: white... |
814 815 |
" -h|--help Show this usage message " |
dcfe730c6 page-types: learn... |
816 817 |
"flags: " |
9fdcd886a 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 pagemap: add page... |
824 825 |
"addr-spec: " |
9fdcd886a 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 pagemap: add page... |
836 837 |
"bits-spec: " |
9fdcd886a 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 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 Documentation/: f... |
866 |
static unsigned long long parse_number(const char *str) |
35efa5e99 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 Documentation/: f... |
878 |
static void parse_pid(const char *str) |
35efa5e99 pagemap: add page... |
879 |
{ |
0b4b2ad53 page-types: add f... |
880 881 |
FILE *file; char buf[5000]; |
35efa5e99 pagemap: add page... |
882 |
opt_pid = parse_number(str); |
35efa5e99 pagemap: add page... |
883 |
|
0b4b2ad53 page-types: add f... |
884 |
sprintf(buf, "/proc/%d/pagemap", opt_pid); |
31bbf66ea page-types: intro... |
885 |
pagemap_fd = checked_open(buf, O_RDONLY); |
0b4b2ad53 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 pagemap: add page... |
924 |
} |
65a6a4105 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 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 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 tools/vm/page-typ... |
965 |
uint64_t cgroup = 0; |
7f1d23e60 tools/vm/page-typ... |
966 |
uint64_t mapcnt = 0; |
65a6a4105 tools/vm/page-typ... |
967 |
unsigned long nr_pages, pfn, i; |
1d46598b7 tools/vm/page-typ... |
968 |
off_t off, end = st->st_size; |
65a6a4105 tools/vm/page-typ... |
969 |
int fd; |
65a6a4105 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 tools/vm/page-typ... |
975 976 |
for (off = 0; off < end; off += len) { nr_pages = (end - off + page_size - 1) / page_size; |
65a6a4105 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 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 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 tools/vm/page-typ... |
1004 |
got_sigbus: |
65a6a4105 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 tools/vm/page-typ... |
1022 1023 |
if (!kpagecgroup_read(&cgroup, pfn, 1)) fatal("kpagecgroup_read failed"); |
7f1d23e60 tools/vm/page-typ... |
1024 1025 |
if (!kpagecount_read(&mapcnt, pfn, 1)) fatal("kpagecount_read failed"); |
65a6a4105 tools/vm/page-typ... |
1026 1027 1028 1029 1030 |
if (first && opt_list) { first = 0; flush_page_range(); show_file(name, st); } |
075db1502 tools/vm/page-typ... |
1031 |
add_page(off / page_size + i, pfn, |
7f1d23e60 tools/vm/page-typ... |
1032 |
flags, cgroup, mapcnt, buf[i]); |
65a6a4105 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 tools, vm: new op... |
1058 |
kpageflags_fd = checked_open(opt_kpageflags, O_RDONLY); |
65a6a4105 tools/vm/page-typ... |
1059 |
pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY); |
1d46598b7 tools/vm/page-typ... |
1060 |
sigaction(SIGBUS, &sigbus_action, NULL); |
65a6a4105 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 tools/vm/page-typ... |
1079 |
signal(SIGBUS, SIG_DFL); |
65a6a4105 tools/vm/page-typ... |
1080 |
} |
0b4b2ad53 page-types: add f... |
1081 |
static void parse_file(const char *name) |
35efa5e99 pagemap: add page... |
1082 |
{ |
65a6a4105 tools/vm/page-typ... |
1083 |
opt_file = name; |
35efa5e99 pagemap: add page... |
1084 |
} |
075db1502 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 Documentation/: f... |
1104 |
static void parse_addr_range(const char *optarg) |
35efa5e99 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 Documentation/: f... |
1138 |
static void add_bits_filter(uint64_t mask, uint64_t bits) |
35efa5e99 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 Documentation/: f... |
1148 |
static uint64_t parse_flag_name(const char *str, int len) |
35efa5e99 pagemap: add page... |
1149 |
{ |
e30d539b3 tools/vm/page-typ... |
1150 |
size_t i; |
35efa5e99 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 Documentation/: f... |
1167 |
static uint64_t parse_flag_names(const char *str, int all) |
35efa5e99 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 Documentation/: f... |
1185 |
static void parse_bits_mask(const char *optarg) |
35efa5e99 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 tools, vm: new op... |
1208 1209 1210 1211 |
static void parse_kpageflags(const char *name) { opt_kpageflags = name; } |
dcfe730c6 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 pagemap: add page... |
1222 |
|
3428838d8 page-types: const... |
1223 |
static const struct option opts[] = { |
35efa5e99 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 tools/vm/page-typ... |
1229 |
{ "cgroup" , 1, NULL, 'c' }, |
dcfe730c6 page-types: learn... |
1230 |
{ "describe" , 1, NULL, 'd' }, |
59ae96ffc tools/vm/page-typ... |
1231 |
{ "mark-idle" , 0, NULL, 'i' }, |
35efa5e99 pagemap: add page... |
1232 1233 |
{ "list" , 0, NULL, 'l' }, { "list-each" , 0, NULL, 'L' }, |
075db1502 tools/vm/page-typ... |
1234 |
{ "list-cgroup", 0, NULL, 'C' }, |
7f1d23e60 tools/vm/page-typ... |
1235 |
{ "list-mapcnt", 0, NULL, 'M' }, |
35efa5e99 pagemap: add page... |
1236 |
{ "no-summary", 0, NULL, 'N' }, |
a54fed9f7 page-types: add h... |
1237 1238 |
{ "hwpoison" , 0, NULL, 'X' }, { "unpoison" , 0, NULL, 'x' }, |
c7905f200 tools, vm: new op... |
1239 |
{ "kpageflags", 0, NULL, 'F' }, |
35efa5e99 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 tools/vm/page-typ... |
1251 |
"rp:f:a:b:d:c:CilLMNXxF:h", |
7f1d23e60 tools/vm/page-typ... |
1252 |
opts, NULL)) != -1) { |
35efa5e99 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 tools/vm/page-typ... |
1269 1270 1271 1272 1273 1274 |
case 'c': parse_cgroup(optarg); break; case 'C': opt_list_cgroup = 1; break; |
dcfe730c6 page-types: learn... |
1275 |
case 'd': |
dcfe730c6 page-types: learn... |
1276 |
describe_flags(optarg); |
bb86a7338 page-types: exit ... |
1277 |
exit(0); |
59ae96ffc tools/vm/page-typ... |
1278 1279 1280 |
case 'i': opt_mark_idle = 1; break; |
35efa5e99 pagemap: add page... |
1281 1282 1283 1284 1285 1286 |
case 'l': opt_list = 1; break; case 'L': opt_list = 2; break; |
7f1d23e60 tools/vm/page-typ... |
1287 1288 1289 |
case 'M': opt_list_mapcnt = 1; break; |
35efa5e99 pagemap: add page... |
1290 1291 1292 |
case 'N': opt_no_summary = 1; break; |
a54fed9f7 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 tools, vm: new op... |
1301 1302 1303 |
case 'F': parse_kpageflags(optarg); break; |
35efa5e99 pagemap: add page... |
1304 1305 1306 1307 1308 1309 1310 1311 |
case 'h': usage(); exit(0); default: usage(); exit(1); } } |
c7905f200 tools, vm: new op... |
1312 1313 |
if (!opt_kpageflags) opt_kpageflags = PROC_KPAGEFLAGS; |
075db1502 tools/vm/page-typ... |
1314 1315 |
if (opt_cgroup || opt_list_cgroup) kpagecgroup_fd = checked_open(PROC_KPAGECGROUP, O_RDONLY); |
7f1d23e60 tools/vm/page-typ... |
1316 1317 |
if (opt_list && opt_list_mapcnt) kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY); |
59ae96ffc 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 page-types: add f... |
1320 1321 |
if (opt_list && opt_pid) printf("voffset\t"); |
65a6a4105 tools/vm/page-typ... |
1322 1323 |
if (opt_list && opt_file) printf("foffset\t"); |
075db1502 tools/vm/page-typ... |
1324 1325 |
if (opt_list && opt_list_cgroup) printf("cgroup\t"); |
7f1d23e60 tools/vm/page-typ... |
1326 1327 |
if (opt_list && opt_list_mapcnt) printf("map-cnt\t"); |
35efa5e99 pagemap: add page... |
1328 |
if (opt_list == 1) |
0b4b2ad53 page-types: add f... |
1329 1330 |
printf("offset\tlen\tflags "); |
35efa5e99 pagemap: add page... |
1331 1332 1333 |
if (opt_list == 2) printf("offset\tflags "); |
65a6a4105 tools/vm/page-typ... |
1334 1335 1336 1337 |
if (opt_file) walk_page_cache(); else walk_addr_ranges(); |
35efa5e99 pagemap: add page... |
1338 1339 |
if (opt_list == 1) |
65a6a4105 tools/vm/page-typ... |
1340 |
flush_page_range(); |
35efa5e99 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 tools/vm/page-typ... |
1351 1352 |
if (opt_list_mapcnt) close(kpagecount_fd); |
59ae96ffc tools/vm/page-typ... |
1353 1354 |
if (page_idle_fd >= 0) close(page_idle_fd); |
35efa5e99 pagemap: add page... |
1355 1356 |
return 0; } |