Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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