at v2.6.39 1100 lines 24 kB view raw
1/* 2 * page-types: Tool for querying page flags 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the Free 6 * Software Foundation; version 2. 7 * 8 * This program is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should find a copy of v2 of the GNU General Public License somewhere on 14 * your Linux system; if not, write to the Free Software Foundation, Inc., 59 15 * Temple Place, Suite 330, Boston, MA 02111-1307 USA. 16 * 17 * Copyright (C) 2009 Intel corporation 18 * 19 * Authors: Wu Fengguang <fengguang.wu@intel.com> 20 */ 21 22#define _LARGEFILE64_SOURCE 23#include <stdio.h> 24#include <stdlib.h> 25#include <unistd.h> 26#include <stdint.h> 27#include <stdarg.h> 28#include <string.h> 29#include <getopt.h> 30#include <limits.h> 31#include <assert.h> 32#include <sys/types.h> 33#include <sys/errno.h> 34#include <sys/fcntl.h> 35#include <sys/mount.h> 36#include <sys/statfs.h> 37#include "../../include/linux/magic.h" 38 39 40#ifndef MAX_PATH 41# define MAX_PATH 256 42#endif 43 44#ifndef STR 45# define _STR(x) #x 46# define STR(x) _STR(x) 47#endif 48 49/* 50 * pagemap kernel ABI bits 51 */ 52 53#define PM_ENTRY_BYTES sizeof(uint64_t) 54#define PM_STATUS_BITS 3 55#define PM_STATUS_OFFSET (64 - PM_STATUS_BITS) 56#define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET) 57#define PM_STATUS(nr) (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK) 58#define PM_PSHIFT_BITS 6 59#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) 60#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) 61#define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) 62#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) 63#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) 64 65#define PM_PRESENT PM_STATUS(4LL) 66#define PM_SWAP PM_STATUS(2LL) 67 68 69/* 70 * kernel page flags 71 */ 72 73#define KPF_BYTES 8 74#define PROC_KPAGEFLAGS "/proc/kpageflags" 75 76/* copied from kpageflags_read() */ 77#define KPF_LOCKED 0 78#define KPF_ERROR 1 79#define KPF_REFERENCED 2 80#define KPF_UPTODATE 3 81#define KPF_DIRTY 4 82#define KPF_LRU 5 83#define KPF_ACTIVE 6 84#define KPF_SLAB 7 85#define KPF_WRITEBACK 8 86#define KPF_RECLAIM 9 87#define KPF_BUDDY 10 88 89/* [11-20] new additions in 2.6.31 */ 90#define KPF_MMAP 11 91#define KPF_ANON 12 92#define KPF_SWAPCACHE 13 93#define KPF_SWAPBACKED 14 94#define KPF_COMPOUND_HEAD 15 95#define KPF_COMPOUND_TAIL 16 96#define KPF_HUGE 17 97#define KPF_UNEVICTABLE 18 98#define KPF_HWPOISON 19 99#define KPF_NOPAGE 20 100#define KPF_KSM 21 101 102/* [32-] kernel hacking assistances */ 103#define KPF_RESERVED 32 104#define KPF_MLOCKED 33 105#define KPF_MAPPEDTODISK 34 106#define KPF_PRIVATE 35 107#define KPF_PRIVATE_2 36 108#define KPF_OWNER_PRIVATE 37 109#define KPF_ARCH 38 110#define KPF_UNCACHED 39 111 112/* [48-] take some arbitrary free slots for expanding overloaded flags 113 * not part of kernel API 114 */ 115#define KPF_READAHEAD 48 116#define KPF_SLOB_FREE 49 117#define KPF_SLUB_FROZEN 50 118#define KPF_SLUB_DEBUG 51 119 120#define KPF_ALL_BITS ((uint64_t)~0ULL) 121#define KPF_HACKERS_BITS (0xffffULL << 32) 122#define KPF_OVERLOADED_BITS (0xffffULL << 48) 123#define BIT(name) (1ULL << KPF_##name) 124#define BITS_COMPOUND (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL)) 125 126static const char *page_flag_names[] = { 127 [KPF_LOCKED] = "L:locked", 128 [KPF_ERROR] = "E:error", 129 [KPF_REFERENCED] = "R:referenced", 130 [KPF_UPTODATE] = "U:uptodate", 131 [KPF_DIRTY] = "D:dirty", 132 [KPF_LRU] = "l:lru", 133 [KPF_ACTIVE] = "A:active", 134 [KPF_SLAB] = "S:slab", 135 [KPF_WRITEBACK] = "W:writeback", 136 [KPF_RECLAIM] = "I:reclaim", 137 [KPF_BUDDY] = "B:buddy", 138 139 [KPF_MMAP] = "M:mmap", 140 [KPF_ANON] = "a:anonymous", 141 [KPF_SWAPCACHE] = "s:swapcache", 142 [KPF_SWAPBACKED] = "b:swapbacked", 143 [KPF_COMPOUND_HEAD] = "H:compound_head", 144 [KPF_COMPOUND_TAIL] = "T:compound_tail", 145 [KPF_HUGE] = "G:huge", 146 [KPF_UNEVICTABLE] = "u:unevictable", 147 [KPF_HWPOISON] = "X:hwpoison", 148 [KPF_NOPAGE] = "n:nopage", 149 [KPF_KSM] = "x:ksm", 150 151 [KPF_RESERVED] = "r:reserved", 152 [KPF_MLOCKED] = "m:mlocked", 153 [KPF_MAPPEDTODISK] = "d:mappedtodisk", 154 [KPF_PRIVATE] = "P:private", 155 [KPF_PRIVATE_2] = "p:private_2", 156 [KPF_OWNER_PRIVATE] = "O:owner_private", 157 [KPF_ARCH] = "h:arch", 158 [KPF_UNCACHED] = "c:uncached", 159 160 [KPF_READAHEAD] = "I:readahead", 161 [KPF_SLOB_FREE] = "P:slob_free", 162 [KPF_SLUB_FROZEN] = "A:slub_frozen", 163 [KPF_SLUB_DEBUG] = "E:slub_debug", 164}; 165 166 167static const char *debugfs_known_mountpoints[] = { 168 "/sys/kernel/debug", 169 "/debug", 170 0, 171}; 172 173/* 174 * data structures 175 */ 176 177static int opt_raw; /* for kernel developers */ 178static int opt_list; /* list pages (in ranges) */ 179static int opt_no_summary; /* don't show summary */ 180static pid_t opt_pid; /* process to walk */ 181 182#define MAX_ADDR_RANGES 1024 183static int nr_addr_ranges; 184static unsigned long opt_offset[MAX_ADDR_RANGES]; 185static unsigned long opt_size[MAX_ADDR_RANGES]; 186 187#define MAX_VMAS 10240 188static int nr_vmas; 189static unsigned long pg_start[MAX_VMAS]; 190static unsigned long pg_end[MAX_VMAS]; 191 192#define MAX_BIT_FILTERS 64 193static int nr_bit_filters; 194static uint64_t opt_mask[MAX_BIT_FILTERS]; 195static uint64_t opt_bits[MAX_BIT_FILTERS]; 196 197static int page_size; 198 199static int pagemap_fd; 200static int kpageflags_fd; 201 202static int opt_hwpoison; 203static int opt_unpoison; 204 205static char hwpoison_debug_fs[MAX_PATH+1]; 206static int hwpoison_inject_fd; 207static int hwpoison_forget_fd; 208 209#define HASH_SHIFT 13 210#define HASH_SIZE (1 << HASH_SHIFT) 211#define HASH_MASK (HASH_SIZE - 1) 212#define HASH_KEY(flags) (flags & HASH_MASK) 213 214static unsigned long total_pages; 215static unsigned long nr_pages[HASH_SIZE]; 216static uint64_t page_flags[HASH_SIZE]; 217 218 219/* 220 * helper functions 221 */ 222 223#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 224 225#define min_t(type, x, y) ({ \ 226 type __min1 = (x); \ 227 type __min2 = (y); \ 228 __min1 < __min2 ? __min1 : __min2; }) 229 230#define max_t(type, x, y) ({ \ 231 type __max1 = (x); \ 232 type __max2 = (y); \ 233 __max1 > __max2 ? __max1 : __max2; }) 234 235static unsigned long pages2mb(unsigned long pages) 236{ 237 return (pages * page_size) >> 20; 238} 239 240static void fatal(const char *x, ...) 241{ 242 va_list ap; 243 244 va_start(ap, x); 245 vfprintf(stderr, x, ap); 246 va_end(ap); 247 exit(EXIT_FAILURE); 248} 249 250static int checked_open(const char *pathname, int flags) 251{ 252 int fd = open(pathname, flags); 253 254 if (fd < 0) { 255 perror(pathname); 256 exit(EXIT_FAILURE); 257 } 258 259 return fd; 260} 261 262/* 263 * pagemap/kpageflags routines 264 */ 265 266static unsigned long do_u64_read(int fd, char *name, 267 uint64_t *buf, 268 unsigned long index, 269 unsigned long count) 270{ 271 long bytes; 272 273 if (index > ULONG_MAX / 8) 274 fatal("index overflow: %lu\n", index); 275 276 if (lseek(fd, index * 8, SEEK_SET) < 0) { 277 perror(name); 278 exit(EXIT_FAILURE); 279 } 280 281 bytes = read(fd, buf, count * 8); 282 if (bytes < 0) { 283 perror(name); 284 exit(EXIT_FAILURE); 285 } 286 if (bytes % 8) 287 fatal("partial read: %lu bytes\n", bytes); 288 289 return bytes / 8; 290} 291 292static unsigned long kpageflags_read(uint64_t *buf, 293 unsigned long index, 294 unsigned long pages) 295{ 296 return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages); 297} 298 299static unsigned long pagemap_read(uint64_t *buf, 300 unsigned long index, 301 unsigned long pages) 302{ 303 return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages); 304} 305 306static unsigned long pagemap_pfn(uint64_t val) 307{ 308 unsigned long pfn; 309 310 if (val & PM_PRESENT) 311 pfn = PM_PFRAME(val); 312 else 313 pfn = 0; 314 315 return pfn; 316} 317 318 319/* 320 * page flag names 321 */ 322 323static char *page_flag_name(uint64_t flags) 324{ 325 static char buf[65]; 326 int present; 327 int i, j; 328 329 for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { 330 present = (flags >> i) & 1; 331 if (!page_flag_names[i]) { 332 if (present) 333 fatal("unknown flag bit %d\n", i); 334 continue; 335 } 336 buf[j++] = present ? page_flag_names[i][0] : '_'; 337 } 338 339 return buf; 340} 341 342static char *page_flag_longname(uint64_t flags) 343{ 344 static char buf[1024]; 345 int i, n; 346 347 for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) { 348 if (!page_flag_names[i]) 349 continue; 350 if ((flags >> i) & 1) 351 n += snprintf(buf + n, sizeof(buf) - n, "%s,", 352 page_flag_names[i] + 2); 353 } 354 if (n) 355 n--; 356 buf[n] = '\0'; 357 358 return buf; 359} 360 361 362/* 363 * page list and summary 364 */ 365 366static void show_page_range(unsigned long voffset, 367 unsigned long offset, uint64_t flags) 368{ 369 static uint64_t flags0; 370 static unsigned long voff; 371 static unsigned long index; 372 static unsigned long count; 373 374 if (flags == flags0 && offset == index + count && 375 (!opt_pid || voffset == voff + count)) { 376 count++; 377 return; 378 } 379 380 if (count) { 381 if (opt_pid) 382 printf("%lx\t", voff); 383 printf("%lx\t%lx\t%s\n", 384 index, count, page_flag_name(flags0)); 385 } 386 387 flags0 = flags; 388 index = offset; 389 voff = voffset; 390 count = 1; 391} 392 393static void show_page(unsigned long voffset, 394 unsigned long offset, uint64_t flags) 395{ 396 if (opt_pid) 397 printf("%lx\t", voffset); 398 printf("%lx\t%s\n", offset, page_flag_name(flags)); 399} 400 401static void show_summary(void) 402{ 403 int i; 404 405 printf(" flags\tpage-count MB" 406 " symbolic-flags\t\t\tlong-symbolic-flags\n"); 407 408 for (i = 0; i < ARRAY_SIZE(nr_pages); i++) { 409 if (nr_pages[i]) 410 printf("0x%016llx\t%10lu %8lu %s\t%s\n", 411 (unsigned long long)page_flags[i], 412 nr_pages[i], 413 pages2mb(nr_pages[i]), 414 page_flag_name(page_flags[i]), 415 page_flag_longname(page_flags[i])); 416 } 417 418 printf(" total\t%10lu %8lu\n", 419 total_pages, pages2mb(total_pages)); 420} 421 422 423/* 424 * page flag filters 425 */ 426 427static int bit_mask_ok(uint64_t flags) 428{ 429 int i; 430 431 for (i = 0; i < nr_bit_filters; i++) { 432 if (opt_bits[i] == KPF_ALL_BITS) { 433 if ((flags & opt_mask[i]) == 0) 434 return 0; 435 } else { 436 if ((flags & opt_mask[i]) != opt_bits[i]) 437 return 0; 438 } 439 } 440 441 return 1; 442} 443 444static uint64_t expand_overloaded_flags(uint64_t flags) 445{ 446 /* SLOB/SLUB overload several page flags */ 447 if (flags & BIT(SLAB)) { 448 if (flags & BIT(PRIVATE)) 449 flags ^= BIT(PRIVATE) | BIT(SLOB_FREE); 450 if (flags & BIT(ACTIVE)) 451 flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN); 452 if (flags & BIT(ERROR)) 453 flags ^= BIT(ERROR) | BIT(SLUB_DEBUG); 454 } 455 456 /* PG_reclaim is overloaded as PG_readahead in the read path */ 457 if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM)) 458 flags ^= BIT(RECLAIM) | BIT(READAHEAD); 459 460 return flags; 461} 462 463static uint64_t well_known_flags(uint64_t flags) 464{ 465 /* hide flags intended only for kernel hacker */ 466 flags &= ~KPF_HACKERS_BITS; 467 468 /* hide non-hugeTLB compound pages */ 469 if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE))) 470 flags &= ~BITS_COMPOUND; 471 472 return flags; 473} 474 475static uint64_t kpageflags_flags(uint64_t flags) 476{ 477 flags = expand_overloaded_flags(flags); 478 479 if (!opt_raw) 480 flags = well_known_flags(flags); 481 482 return flags; 483} 484 485/* verify that a mountpoint is actually a debugfs instance */ 486static int debugfs_valid_mountpoint(const char *debugfs) 487{ 488 struct statfs st_fs; 489 490 if (statfs(debugfs, &st_fs) < 0) 491 return -ENOENT; 492 else if (st_fs.f_type != (long) DEBUGFS_MAGIC) 493 return -ENOENT; 494 495 return 0; 496} 497 498/* find the path to the mounted debugfs */ 499static const char *debugfs_find_mountpoint(void) 500{ 501 const char **ptr; 502 char type[100]; 503 FILE *fp; 504 505 ptr = debugfs_known_mountpoints; 506 while (*ptr) { 507 if (debugfs_valid_mountpoint(*ptr) == 0) { 508 strcpy(hwpoison_debug_fs, *ptr); 509 return hwpoison_debug_fs; 510 } 511 ptr++; 512 } 513 514 /* give up and parse /proc/mounts */ 515 fp = fopen("/proc/mounts", "r"); 516 if (fp == NULL) 517 perror("Can't open /proc/mounts for read"); 518 519 while (fscanf(fp, "%*s %" 520 STR(MAX_PATH) 521 "s %99s %*s %*d %*d\n", 522 hwpoison_debug_fs, type) == 2) { 523 if (strcmp(type, "debugfs") == 0) 524 break; 525 } 526 fclose(fp); 527 528 if (strcmp(type, "debugfs") != 0) 529 return NULL; 530 531 return hwpoison_debug_fs; 532} 533 534/* mount the debugfs somewhere if it's not mounted */ 535 536static void debugfs_mount(void) 537{ 538 const char **ptr; 539 540 /* see if it's already mounted */ 541 if (debugfs_find_mountpoint()) 542 return; 543 544 ptr = debugfs_known_mountpoints; 545 while (*ptr) { 546 if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) { 547 /* save the mountpoint */ 548 strcpy(hwpoison_debug_fs, *ptr); 549 break; 550 } 551 ptr++; 552 } 553 554 if (*ptr == NULL) { 555 perror("mount debugfs"); 556 exit(EXIT_FAILURE); 557 } 558} 559 560/* 561 * page actions 562 */ 563 564static void prepare_hwpoison_fd(void) 565{ 566 char buf[MAX_PATH + 1]; 567 568 debugfs_mount(); 569 570 if (opt_hwpoison && !hwpoison_inject_fd) { 571 snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn", 572 hwpoison_debug_fs); 573 hwpoison_inject_fd = checked_open(buf, O_WRONLY); 574 } 575 576 if (opt_unpoison && !hwpoison_forget_fd) { 577 snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn", 578 hwpoison_debug_fs); 579 hwpoison_forget_fd = checked_open(buf, O_WRONLY); 580 } 581} 582 583static int hwpoison_page(unsigned long offset) 584{ 585 char buf[100]; 586 int len; 587 588 len = sprintf(buf, "0x%lx\n", offset); 589 len = write(hwpoison_inject_fd, buf, len); 590 if (len < 0) { 591 perror("hwpoison inject"); 592 return len; 593 } 594 return 0; 595} 596 597static int unpoison_page(unsigned long offset) 598{ 599 char buf[100]; 600 int len; 601 602 len = sprintf(buf, "0x%lx\n", offset); 603 len = write(hwpoison_forget_fd, buf, len); 604 if (len < 0) { 605 perror("hwpoison forget"); 606 return len; 607 } 608 return 0; 609} 610 611/* 612 * page frame walker 613 */ 614 615static int hash_slot(uint64_t flags) 616{ 617 int k = HASH_KEY(flags); 618 int i; 619 620 /* Explicitly reserve slot 0 for flags 0: the following logic 621 * cannot distinguish an unoccupied slot from slot (flags==0). 622 */ 623 if (flags == 0) 624 return 0; 625 626 /* search through the remaining (HASH_SIZE-1) slots */ 627 for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) { 628 if (!k || k >= ARRAY_SIZE(page_flags)) 629 k = 1; 630 if (page_flags[k] == 0) { 631 page_flags[k] = flags; 632 return k; 633 } 634 if (page_flags[k] == flags) 635 return k; 636 } 637 638 fatal("hash table full: bump up HASH_SHIFT?\n"); 639 exit(EXIT_FAILURE); 640} 641 642static void add_page(unsigned long voffset, 643 unsigned long offset, uint64_t flags) 644{ 645 flags = kpageflags_flags(flags); 646 647 if (!bit_mask_ok(flags)) 648 return; 649 650 if (opt_hwpoison) 651 hwpoison_page(offset); 652 if (opt_unpoison) 653 unpoison_page(offset); 654 655 if (opt_list == 1) 656 show_page_range(voffset, offset, flags); 657 else if (opt_list == 2) 658 show_page(voffset, offset, flags); 659 660 nr_pages[hash_slot(flags)]++; 661 total_pages++; 662} 663 664#define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */ 665static void walk_pfn(unsigned long voffset, 666 unsigned long index, 667 unsigned long count) 668{ 669 uint64_t buf[KPAGEFLAGS_BATCH]; 670 unsigned long batch; 671 long pages; 672 unsigned long i; 673 674 while (count) { 675 batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH); 676 pages = kpageflags_read(buf, index, batch); 677 if (pages == 0) 678 break; 679 680 for (i = 0; i < pages; i++) 681 add_page(voffset + i, index + i, buf[i]); 682 683 index += pages; 684 count -= pages; 685 } 686} 687 688#define PAGEMAP_BATCH (64 << 10) 689static void walk_vma(unsigned long index, unsigned long count) 690{ 691 uint64_t buf[PAGEMAP_BATCH]; 692 unsigned long batch; 693 unsigned long pages; 694 unsigned long pfn; 695 unsigned long i; 696 697 while (count) { 698 batch = min_t(unsigned long, count, PAGEMAP_BATCH); 699 pages = pagemap_read(buf, index, batch); 700 if (pages == 0) 701 break; 702 703 for (i = 0; i < pages; i++) { 704 pfn = pagemap_pfn(buf[i]); 705 if (pfn) 706 walk_pfn(index + i, pfn, 1); 707 } 708 709 index += pages; 710 count -= pages; 711 } 712} 713 714static void walk_task(unsigned long index, unsigned long count) 715{ 716 const unsigned long end = index + count; 717 unsigned long start; 718 int i = 0; 719 720 while (index < end) { 721 722 while (pg_end[i] <= index) 723 if (++i >= nr_vmas) 724 return; 725 if (pg_start[i] >= end) 726 return; 727 728 start = max_t(unsigned long, pg_start[i], index); 729 index = min_t(unsigned long, pg_end[i], end); 730 731 assert(start < index); 732 walk_vma(start, index - start); 733 } 734} 735 736static void add_addr_range(unsigned long offset, unsigned long size) 737{ 738 if (nr_addr_ranges >= MAX_ADDR_RANGES) 739 fatal("too many addr ranges\n"); 740 741 opt_offset[nr_addr_ranges] = offset; 742 opt_size[nr_addr_ranges] = min_t(unsigned long, size, ULONG_MAX-offset); 743 nr_addr_ranges++; 744} 745 746static void walk_addr_ranges(void) 747{ 748 int i; 749 750 kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY); 751 752 if (!nr_addr_ranges) 753 add_addr_range(0, ULONG_MAX); 754 755 for (i = 0; i < nr_addr_ranges; i++) 756 if (!opt_pid) 757 walk_pfn(0, opt_offset[i], opt_size[i]); 758 else 759 walk_task(opt_offset[i], opt_size[i]); 760 761 close(kpageflags_fd); 762} 763 764 765/* 766 * user interface 767 */ 768 769static const char *page_flag_type(uint64_t flag) 770{ 771 if (flag & KPF_HACKERS_BITS) 772 return "(r)"; 773 if (flag & KPF_OVERLOADED_BITS) 774 return "(o)"; 775 return " "; 776} 777 778static void usage(void) 779{ 780 int i, j; 781 782 printf( 783"page-types [options]\n" 784" -r|--raw Raw mode, for kernel developers\n" 785" -d|--describe flags Describe flags\n" 786" -a|--addr addr-spec Walk a range of pages\n" 787" -b|--bits bits-spec Walk pages with specified bits\n" 788" -p|--pid pid Walk process address space\n" 789#if 0 /* planned features */ 790" -f|--file filename Walk file address space\n" 791#endif 792" -l|--list Show page details in ranges\n" 793" -L|--list-each Show page details one by one\n" 794" -N|--no-summary Don't show summary info\n" 795" -X|--hwpoison hwpoison pages\n" 796" -x|--unpoison unpoison pages\n" 797" -h|--help Show this usage message\n" 798"flags:\n" 799" 0x10 bitfield format, e.g.\n" 800" anon bit-name, e.g.\n" 801" 0x10,anon comma-separated list, e.g.\n" 802"addr-spec:\n" 803" N one page at offset N (unit: pages)\n" 804" N+M pages range from N to N+M-1\n" 805" N,M pages range from N to M-1\n" 806" N, pages range from N to end\n" 807" ,M pages range from 0 to M-1\n" 808"bits-spec:\n" 809" bit1,bit2 (flags & (bit1|bit2)) != 0\n" 810" bit1,bit2=bit1 (flags & (bit1|bit2)) == bit1\n" 811" bit1,~bit2 (flags & (bit1|bit2)) == bit1\n" 812" =bit1,bit2 flags == (bit1|bit2)\n" 813"bit-names:\n" 814 ); 815 816 for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { 817 if (!page_flag_names[i]) 818 continue; 819 printf("%16s%s", page_flag_names[i] + 2, 820 page_flag_type(1ULL << i)); 821 if (++j > 3) { 822 j = 0; 823 putchar('\n'); 824 } 825 } 826 printf("\n " 827 "(r) raw mode bits (o) overloaded bits\n"); 828} 829 830static unsigned long long parse_number(const char *str) 831{ 832 unsigned long long n; 833 834 n = strtoll(str, NULL, 0); 835 836 if (n == 0 && str[0] != '0') 837 fatal("invalid name or number: %s\n", str); 838 839 return n; 840} 841 842static void parse_pid(const char *str) 843{ 844 FILE *file; 845 char buf[5000]; 846 847 opt_pid = parse_number(str); 848 849 sprintf(buf, "/proc/%d/pagemap", opt_pid); 850 pagemap_fd = checked_open(buf, O_RDONLY); 851 852 sprintf(buf, "/proc/%d/maps", opt_pid); 853 file = fopen(buf, "r"); 854 if (!file) { 855 perror(buf); 856 exit(EXIT_FAILURE); 857 } 858 859 while (fgets(buf, sizeof(buf), file) != NULL) { 860 unsigned long vm_start; 861 unsigned long vm_end; 862 unsigned long long pgoff; 863 int major, minor; 864 char r, w, x, s; 865 unsigned long ino; 866 int n; 867 868 n = sscanf(buf, "%lx-%lx %c%c%c%c %llx %x:%x %lu", 869 &vm_start, 870 &vm_end, 871 &r, &w, &x, &s, 872 &pgoff, 873 &major, &minor, 874 &ino); 875 if (n < 10) { 876 fprintf(stderr, "unexpected line: %s\n", buf); 877 continue; 878 } 879 pg_start[nr_vmas] = vm_start / page_size; 880 pg_end[nr_vmas] = vm_end / page_size; 881 if (++nr_vmas >= MAX_VMAS) { 882 fprintf(stderr, "too many VMAs\n"); 883 break; 884 } 885 } 886 fclose(file); 887} 888 889static void parse_file(const char *name) 890{ 891} 892 893static void parse_addr_range(const char *optarg) 894{ 895 unsigned long offset; 896 unsigned long size; 897 char *p; 898 899 p = strchr(optarg, ','); 900 if (!p) 901 p = strchr(optarg, '+'); 902 903 if (p == optarg) { 904 offset = 0; 905 size = parse_number(p + 1); 906 } else if (p) { 907 offset = parse_number(optarg); 908 if (p[1] == '\0') 909 size = ULONG_MAX; 910 else { 911 size = parse_number(p + 1); 912 if (*p == ',') { 913 if (size < offset) 914 fatal("invalid range: %lu,%lu\n", 915 offset, size); 916 size -= offset; 917 } 918 } 919 } else { 920 offset = parse_number(optarg); 921 size = 1; 922 } 923 924 add_addr_range(offset, size); 925} 926 927static void add_bits_filter(uint64_t mask, uint64_t bits) 928{ 929 if (nr_bit_filters >= MAX_BIT_FILTERS) 930 fatal("too much bit filters\n"); 931 932 opt_mask[nr_bit_filters] = mask; 933 opt_bits[nr_bit_filters] = bits; 934 nr_bit_filters++; 935} 936 937static uint64_t parse_flag_name(const char *str, int len) 938{ 939 int i; 940 941 if (!*str || !len) 942 return 0; 943 944 if (len <= 8 && !strncmp(str, "compound", len)) 945 return BITS_COMPOUND; 946 947 for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) { 948 if (!page_flag_names[i]) 949 continue; 950 if (!strncmp(str, page_flag_names[i] + 2, len)) 951 return 1ULL << i; 952 } 953 954 return parse_number(str); 955} 956 957static uint64_t parse_flag_names(const char *str, int all) 958{ 959 const char *p = str; 960 uint64_t flags = 0; 961 962 while (1) { 963 if (*p == ',' || *p == '=' || *p == '\0') { 964 if ((*str != '~') || (*str == '~' && all && *++str)) 965 flags |= parse_flag_name(str, p - str); 966 if (*p != ',') 967 break; 968 str = p + 1; 969 } 970 p++; 971 } 972 973 return flags; 974} 975 976static void parse_bits_mask(const char *optarg) 977{ 978 uint64_t mask; 979 uint64_t bits; 980 const char *p; 981 982 p = strchr(optarg, '='); 983 if (p == optarg) { 984 mask = KPF_ALL_BITS; 985 bits = parse_flag_names(p + 1, 0); 986 } else if (p) { 987 mask = parse_flag_names(optarg, 0); 988 bits = parse_flag_names(p + 1, 0); 989 } else if (strchr(optarg, '~')) { 990 mask = parse_flag_names(optarg, 1); 991 bits = parse_flag_names(optarg, 0); 992 } else { 993 mask = parse_flag_names(optarg, 0); 994 bits = KPF_ALL_BITS; 995 } 996 997 add_bits_filter(mask, bits); 998} 999 1000static void describe_flags(const char *optarg) 1001{ 1002 uint64_t flags = parse_flag_names(optarg, 0); 1003 1004 printf("0x%016llx\t%s\t%s\n", 1005 (unsigned long long)flags, 1006 page_flag_name(flags), 1007 page_flag_longname(flags)); 1008} 1009 1010static const struct option opts[] = { 1011 { "raw" , 0, NULL, 'r' }, 1012 { "pid" , 1, NULL, 'p' }, 1013 { "file" , 1, NULL, 'f' }, 1014 { "addr" , 1, NULL, 'a' }, 1015 { "bits" , 1, NULL, 'b' }, 1016 { "describe" , 1, NULL, 'd' }, 1017 { "list" , 0, NULL, 'l' }, 1018 { "list-each" , 0, NULL, 'L' }, 1019 { "no-summary", 0, NULL, 'N' }, 1020 { "hwpoison" , 0, NULL, 'X' }, 1021 { "unpoison" , 0, NULL, 'x' }, 1022 { "help" , 0, NULL, 'h' }, 1023 { NULL , 0, NULL, 0 } 1024}; 1025 1026int main(int argc, char *argv[]) 1027{ 1028 int c; 1029 1030 page_size = getpagesize(); 1031 1032 while ((c = getopt_long(argc, argv, 1033 "rp:f:a:b:d:lLNXxh", opts, NULL)) != -1) { 1034 switch (c) { 1035 case 'r': 1036 opt_raw = 1; 1037 break; 1038 case 'p': 1039 parse_pid(optarg); 1040 break; 1041 case 'f': 1042 parse_file(optarg); 1043 break; 1044 case 'a': 1045 parse_addr_range(optarg); 1046 break; 1047 case 'b': 1048 parse_bits_mask(optarg); 1049 break; 1050 case 'd': 1051 describe_flags(optarg); 1052 exit(0); 1053 case 'l': 1054 opt_list = 1; 1055 break; 1056 case 'L': 1057 opt_list = 2; 1058 break; 1059 case 'N': 1060 opt_no_summary = 1; 1061 break; 1062 case 'X': 1063 opt_hwpoison = 1; 1064 prepare_hwpoison_fd(); 1065 break; 1066 case 'x': 1067 opt_unpoison = 1; 1068 prepare_hwpoison_fd(); 1069 break; 1070 case 'h': 1071 usage(); 1072 exit(0); 1073 default: 1074 usage(); 1075 exit(1); 1076 } 1077 } 1078 1079 if (opt_list && opt_pid) 1080 printf("voffset\t"); 1081 if (opt_list == 1) 1082 printf("offset\tlen\tflags\n"); 1083 if (opt_list == 2) 1084 printf("offset\tflags\n"); 1085 1086 walk_addr_ranges(); 1087 1088 if (opt_list == 1) 1089 show_page_range(0, 0, 0); /* drain the buffer */ 1090 1091 if (opt_no_summary) 1092 return 0; 1093 1094 if (opt_list) 1095 printf("\n\n"); 1096 1097 show_summary(); 1098 1099 return 0; 1100}