Based on kernel version 3.3. Page generated on 2012-03-23 21:41 EST.
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 126 static 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 167 static const char *debugfs_known_mountpoints[] = { 168 "/sys/kernel/debug", 169 "/debug", 170 0, 171 }; 172 173 /* 174 * data structures 175 */ 176 177 static int opt_raw; /* for kernel developers */ 178 static int opt_list; /* list pages (in ranges) */ 179 static int opt_no_summary; /* don't show summary */ 180 static pid_t opt_pid; /* process to walk */ 181 182 #define MAX_ADDR_RANGES 1024 183 static int nr_addr_ranges; 184 static unsigned long opt_offset[MAX_ADDR_RANGES]; 185 static unsigned long opt_size[MAX_ADDR_RANGES]; 186 187 #define MAX_VMAS 10240 188 static int nr_vmas; 189 static unsigned long pg_start[MAX_VMAS]; 190 static unsigned long pg_end[MAX_VMAS]; 191 192 #define MAX_BIT_FILTERS 64 193 static int nr_bit_filters; 194 static uint64_t opt_mask[MAX_BIT_FILTERS]; 195 static uint64_t opt_bits[MAX_BIT_FILTERS]; 196 197 static int page_size; 198 199 static int pagemap_fd; 200 static int kpageflags_fd; 201 202 static int opt_hwpoison; 203 static int opt_unpoison; 204 205 static char hwpoison_debug_fs[MAX_PATH+1]; 206 static int hwpoison_inject_fd; 207 static 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 214 static unsigned long total_pages; 215 static unsigned long nr_pages[HASH_SIZE]; 216 static 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 235 static unsigned long pages2mb(unsigned long pages) 236 { 237 return (pages * page_size) >> 20; 238 } 239 240 static 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 250 static 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 266 static 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 292 static 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 299 static 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 306 static 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 323 static 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 342 static 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 366 static 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 393 static 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 401 static 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 427 static 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 444 static 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 463 static 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 475 static 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 */ 486 static 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 */ 499 static 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 536 static 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 564 static 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 583 static 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 597 static 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 615 static 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 642 static 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 */ 665 static 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) 689 static 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 714 static 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 736 static 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 746 static 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 769 static 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 778 static 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 830 static 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 842 static 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 889 static void parse_file(const char *name) 890 { 891 } 892 893 static 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 927 static 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 937 static 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 957 static 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 976 static 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 1000 static 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 1010 static 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 1026 int 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 }