diff options
Diffstat (limited to 'Documentation/vm')
-rw-r--r-- | Documentation/vm/ksm.txt | 13 | ||||
-rw-r--r-- | Documentation/vm/page-types.c | 304 | ||||
-rw-r--r-- | Documentation/vm/pagemap.txt | 8 |
3 files changed, 225 insertions, 100 deletions
diff --git a/Documentation/vm/ksm.txt b/Documentation/vm/ksm.txt index 72a22f65960e..262d8e6793a3 100644 --- a/Documentation/vm/ksm.txt +++ b/Documentation/vm/ksm.txt | |||
@@ -52,15 +52,15 @@ The KSM daemon is controlled by sysfs files in /sys/kernel/mm/ksm/, | |||
52 | readable by all but writable only by root: | 52 | readable by all but writable only by root: |
53 | 53 | ||
54 | max_kernel_pages - set to maximum number of kernel pages that KSM may use | 54 | max_kernel_pages - set to maximum number of kernel pages that KSM may use |
55 | e.g. "echo 2000 > /sys/kernel/mm/ksm/max_kernel_pages" | 55 | e.g. "echo 100000 > /sys/kernel/mm/ksm/max_kernel_pages" |
56 | Value 0 imposes no limit on the kernel pages KSM may use; | 56 | Value 0 imposes no limit on the kernel pages KSM may use; |
57 | but note that any process using MADV_MERGEABLE can cause | 57 | but note that any process using MADV_MERGEABLE can cause |
58 | KSM to allocate these pages, unswappable until it exits. | 58 | KSM to allocate these pages, unswappable until it exits. |
59 | Default: 2000 (chosen for demonstration purposes) | 59 | Default: quarter of memory (chosen to not pin too much) |
60 | 60 | ||
61 | pages_to_scan - how many present pages to scan before ksmd goes to sleep | 61 | pages_to_scan - how many present pages to scan before ksmd goes to sleep |
62 | e.g. "echo 200 > /sys/kernel/mm/ksm/pages_to_scan" | 62 | e.g. "echo 100 > /sys/kernel/mm/ksm/pages_to_scan" |
63 | Default: 200 (chosen for demonstration purposes) | 63 | Default: 100 (chosen for demonstration purposes) |
64 | 64 | ||
65 | sleep_millisecs - how many milliseconds ksmd should sleep before next scan | 65 | sleep_millisecs - how many milliseconds ksmd should sleep before next scan |
66 | e.g. "echo 20 > /sys/kernel/mm/ksm/sleep_millisecs" | 66 | e.g. "echo 20 > /sys/kernel/mm/ksm/sleep_millisecs" |
@@ -70,7 +70,8 @@ run - set 0 to stop ksmd from running but keep merged pages, | |||
70 | set 1 to run ksmd e.g. "echo 1 > /sys/kernel/mm/ksm/run", | 70 | set 1 to run ksmd e.g. "echo 1 > /sys/kernel/mm/ksm/run", |
71 | set 2 to stop ksmd and unmerge all pages currently merged, | 71 | set 2 to stop ksmd and unmerge all pages currently merged, |
72 | but leave mergeable areas registered for next run | 72 | but leave mergeable areas registered for next run |
73 | Default: 1 (for immediate use by apps which register) | 73 | Default: 0 (must be changed to 1 to activate KSM, |
74 | except if CONFIG_SYSFS is disabled) | ||
74 | 75 | ||
75 | The effectiveness of KSM and MADV_MERGEABLE is shown in /sys/kernel/mm/ksm/: | 76 | The effectiveness of KSM and MADV_MERGEABLE is shown in /sys/kernel/mm/ksm/: |
76 | 77 | ||
@@ -86,4 +87,4 @@ pages_volatile embraces several different kinds of activity, but a high | |||
86 | proportion there would also indicate poor use of madvise MADV_MERGEABLE. | 87 | proportion there would also indicate poor use of madvise MADV_MERGEABLE. |
87 | 88 | ||
88 | Izik Eidus, | 89 | Izik Eidus, |
89 | Hugh Dickins, 30 July 2009 | 90 | Hugh Dickins, 24 Sept 2009 |
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c index fa1a30d9e9d5..3ec4f2a22585 100644 --- a/Documentation/vm/page-types.c +++ b/Documentation/vm/page-types.c | |||
@@ -2,7 +2,10 @@ | |||
2 | * page-types: Tool for querying page flags | 2 | * page-types: Tool for querying page flags |
3 | * | 3 | * |
4 | * Copyright (C) 2009 Intel corporation | 4 | * Copyright (C) 2009 Intel corporation |
5 | * Copyright (C) 2009 Wu Fengguang <fengguang.wu@intel.com> | 5 | * |
6 | * Authors: Wu Fengguang <fengguang.wu@intel.com> | ||
7 | * | ||
8 | * Released under the General Public License (GPL). | ||
6 | */ | 9 | */ |
7 | 10 | ||
8 | #define _LARGEFILE64_SOURCE | 11 | #define _LARGEFILE64_SOURCE |
@@ -69,7 +72,9 @@ | |||
69 | #define KPF_COMPOUND_TAIL 16 | 72 | #define KPF_COMPOUND_TAIL 16 |
70 | #define KPF_HUGE 17 | 73 | #define KPF_HUGE 17 |
71 | #define KPF_UNEVICTABLE 18 | 74 | #define KPF_UNEVICTABLE 18 |
75 | #define KPF_HWPOISON 19 | ||
72 | #define KPF_NOPAGE 20 | 76 | #define KPF_NOPAGE 20 |
77 | #define KPF_KSM 21 | ||
73 | 78 | ||
74 | /* [32-] kernel hacking assistances */ | 79 | /* [32-] kernel hacking assistances */ |
75 | #define KPF_RESERVED 32 | 80 | #define KPF_RESERVED 32 |
@@ -116,7 +121,9 @@ static char *page_flag_names[] = { | |||
116 | [KPF_COMPOUND_TAIL] = "T:compound_tail", | 121 | [KPF_COMPOUND_TAIL] = "T:compound_tail", |
117 | [KPF_HUGE] = "G:huge", | 122 | [KPF_HUGE] = "G:huge", |
118 | [KPF_UNEVICTABLE] = "u:unevictable", | 123 | [KPF_UNEVICTABLE] = "u:unevictable", |
124 | [KPF_HWPOISON] = "X:hwpoison", | ||
119 | [KPF_NOPAGE] = "n:nopage", | 125 | [KPF_NOPAGE] = "n:nopage", |
126 | [KPF_KSM] = "x:ksm", | ||
120 | 127 | ||
121 | [KPF_RESERVED] = "r:reserved", | 128 | [KPF_RESERVED] = "r:reserved", |
122 | [KPF_MLOCKED] = "m:mlocked", | 129 | [KPF_MLOCKED] = "m:mlocked", |
@@ -152,9 +159,6 @@ static unsigned long opt_size[MAX_ADDR_RANGES]; | |||
152 | static int nr_vmas; | 159 | static int nr_vmas; |
153 | static unsigned long pg_start[MAX_VMAS]; | 160 | static unsigned long pg_start[MAX_VMAS]; |
154 | static unsigned long pg_end[MAX_VMAS]; | 161 | static unsigned long pg_end[MAX_VMAS]; |
155 | static unsigned long voffset; | ||
156 | |||
157 | static int pagemap_fd; | ||
158 | 162 | ||
159 | #define MAX_BIT_FILTERS 64 | 163 | #define MAX_BIT_FILTERS 64 |
160 | static int nr_bit_filters; | 164 | static int nr_bit_filters; |
@@ -163,9 +167,16 @@ static uint64_t opt_bits[MAX_BIT_FILTERS]; | |||
163 | 167 | ||
164 | static int page_size; | 168 | static int page_size; |
165 | 169 | ||
166 | #define PAGES_BATCH (64 << 10) /* 64k pages */ | 170 | static int pagemap_fd; |
167 | static int kpageflags_fd; | 171 | static int kpageflags_fd; |
168 | 172 | ||
173 | static int opt_hwpoison; | ||
174 | static int opt_unpoison; | ||
175 | |||
176 | static char *hwpoison_debug_fs = "/debug/hwpoison"; | ||
177 | static int hwpoison_inject_fd; | ||
178 | static int hwpoison_forget_fd; | ||
179 | |||
169 | #define HASH_SHIFT 13 | 180 | #define HASH_SHIFT 13 |
170 | #define HASH_SIZE (1 << HASH_SHIFT) | 181 | #define HASH_SIZE (1 << HASH_SHIFT) |
171 | #define HASH_MASK (HASH_SIZE - 1) | 182 | #define HASH_MASK (HASH_SIZE - 1) |
@@ -207,6 +218,74 @@ static void fatal(const char *x, ...) | |||
207 | exit(EXIT_FAILURE); | 218 | exit(EXIT_FAILURE); |
208 | } | 219 | } |
209 | 220 | ||
221 | int checked_open(const char *pathname, int flags) | ||
222 | { | ||
223 | int fd = open(pathname, flags); | ||
224 | |||
225 | if (fd < 0) { | ||
226 | perror(pathname); | ||
227 | exit(EXIT_FAILURE); | ||
228 | } | ||
229 | |||
230 | return fd; | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * pagemap/kpageflags routines | ||
235 | */ | ||
236 | |||
237 | static unsigned long do_u64_read(int fd, char *name, | ||
238 | uint64_t *buf, | ||
239 | unsigned long index, | ||
240 | unsigned long count) | ||
241 | { | ||
242 | long bytes; | ||
243 | |||
244 | if (index > ULONG_MAX / 8) | ||
245 | fatal("index overflow: %lu\n", index); | ||
246 | |||
247 | if (lseek(fd, index * 8, SEEK_SET) < 0) { | ||
248 | perror(name); | ||
249 | exit(EXIT_FAILURE); | ||
250 | } | ||
251 | |||
252 | bytes = read(fd, buf, count * 8); | ||
253 | if (bytes < 0) { | ||
254 | perror(name); | ||
255 | exit(EXIT_FAILURE); | ||
256 | } | ||
257 | if (bytes % 8) | ||
258 | fatal("partial read: %lu bytes\n", bytes); | ||
259 | |||
260 | return bytes / 8; | ||
261 | } | ||
262 | |||
263 | static unsigned long kpageflags_read(uint64_t *buf, | ||
264 | unsigned long index, | ||
265 | unsigned long pages) | ||
266 | { | ||
267 | return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages); | ||
268 | } | ||
269 | |||
270 | static unsigned long pagemap_read(uint64_t *buf, | ||
271 | unsigned long index, | ||
272 | unsigned long pages) | ||
273 | { | ||
274 | return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages); | ||
275 | } | ||
276 | |||
277 | static unsigned long pagemap_pfn(uint64_t val) | ||
278 | { | ||
279 | unsigned long pfn; | ||
280 | |||
281 | if (val & PM_PRESENT) | ||
282 | pfn = PM_PFRAME(val); | ||
283 | else | ||
284 | pfn = 0; | ||
285 | |||
286 | return pfn; | ||
287 | } | ||
288 | |||
210 | 289 | ||
211 | /* | 290 | /* |
212 | * page flag names | 291 | * page flag names |
@@ -255,7 +334,8 @@ static char *page_flag_longname(uint64_t flags) | |||
255 | * page list and summary | 334 | * page list and summary |
256 | */ | 335 | */ |
257 | 336 | ||
258 | static void show_page_range(unsigned long offset, uint64_t flags) | 337 | static void show_page_range(unsigned long voffset, |
338 | unsigned long offset, uint64_t flags) | ||
259 | { | 339 | { |
260 | static uint64_t flags0; | 340 | static uint64_t flags0; |
261 | static unsigned long voff; | 341 | static unsigned long voff; |
@@ -281,7 +361,8 @@ static void show_page_range(unsigned long offset, uint64_t flags) | |||
281 | count = 1; | 361 | count = 1; |
282 | } | 362 | } |
283 | 363 | ||
284 | static void show_page(unsigned long offset, uint64_t flags) | 364 | static void show_page(unsigned long voffset, |
365 | unsigned long offset, uint64_t flags) | ||
285 | { | 366 | { |
286 | if (opt_pid) | 367 | if (opt_pid) |
287 | printf("%lx\t", voffset); | 368 | printf("%lx\t", voffset); |
@@ -362,6 +443,62 @@ static uint64_t well_known_flags(uint64_t flags) | |||
362 | return flags; | 443 | return flags; |
363 | } | 444 | } |
364 | 445 | ||
446 | static uint64_t kpageflags_flags(uint64_t flags) | ||
447 | { | ||
448 | flags = expand_overloaded_flags(flags); | ||
449 | |||
450 | if (!opt_raw) | ||
451 | flags = well_known_flags(flags); | ||
452 | |||
453 | return flags; | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * page actions | ||
458 | */ | ||
459 | |||
460 | static void prepare_hwpoison_fd(void) | ||
461 | { | ||
462 | char buf[100]; | ||
463 | |||
464 | if (opt_hwpoison && !hwpoison_inject_fd) { | ||
465 | sprintf(buf, "%s/corrupt-pfn", hwpoison_debug_fs); | ||
466 | hwpoison_inject_fd = checked_open(buf, O_WRONLY); | ||
467 | } | ||
468 | |||
469 | if (opt_unpoison && !hwpoison_forget_fd) { | ||
470 | sprintf(buf, "%s/renew-pfn", hwpoison_debug_fs); | ||
471 | hwpoison_forget_fd = checked_open(buf, O_WRONLY); | ||
472 | } | ||
473 | } | ||
474 | |||
475 | static int hwpoison_page(unsigned long offset) | ||
476 | { | ||
477 | char buf[100]; | ||
478 | int len; | ||
479 | |||
480 | len = sprintf(buf, "0x%lx\n", offset); | ||
481 | len = write(hwpoison_inject_fd, buf, len); | ||
482 | if (len < 0) { | ||
483 | perror("hwpoison inject"); | ||
484 | return len; | ||
485 | } | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int unpoison_page(unsigned long offset) | ||
490 | { | ||
491 | char buf[100]; | ||
492 | int len; | ||
493 | |||
494 | len = sprintf(buf, "0x%lx\n", offset); | ||
495 | len = write(hwpoison_forget_fd, buf, len); | ||
496 | if (len < 0) { | ||
497 | perror("hwpoison forget"); | ||
498 | return len; | ||
499 | } | ||
500 | return 0; | ||
501 | } | ||
365 | 502 | ||
366 | /* | 503 | /* |
367 | * page frame walker | 504 | * page frame walker |
@@ -394,104 +531,83 @@ static int hash_slot(uint64_t flags) | |||
394 | exit(EXIT_FAILURE); | 531 | exit(EXIT_FAILURE); |
395 | } | 532 | } |
396 | 533 | ||
397 | static void add_page(unsigned long offset, uint64_t flags) | 534 | static void add_page(unsigned long voffset, |
535 | unsigned long offset, uint64_t flags) | ||
398 | { | 536 | { |
399 | flags = expand_overloaded_flags(flags); | 537 | flags = kpageflags_flags(flags); |
400 | |||
401 | if (!opt_raw) | ||
402 | flags = well_known_flags(flags); | ||
403 | 538 | ||
404 | if (!bit_mask_ok(flags)) | 539 | if (!bit_mask_ok(flags)) |
405 | return; | 540 | return; |
406 | 541 | ||
542 | if (opt_hwpoison) | ||
543 | hwpoison_page(offset); | ||
544 | if (opt_unpoison) | ||
545 | unpoison_page(offset); | ||
546 | |||
407 | if (opt_list == 1) | 547 | if (opt_list == 1) |
408 | show_page_range(offset, flags); | 548 | show_page_range(voffset, offset, flags); |
409 | else if (opt_list == 2) | 549 | else if (opt_list == 2) |
410 | show_page(offset, flags); | 550 | show_page(voffset, offset, flags); |
411 | 551 | ||
412 | nr_pages[hash_slot(flags)]++; | 552 | nr_pages[hash_slot(flags)]++; |
413 | total_pages++; | 553 | total_pages++; |
414 | } | 554 | } |
415 | 555 | ||
416 | static void walk_pfn(unsigned long index, unsigned long count) | 556 | #define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */ |
557 | static void walk_pfn(unsigned long voffset, | ||
558 | unsigned long index, | ||
559 | unsigned long count) | ||
417 | { | 560 | { |
561 | uint64_t buf[KPAGEFLAGS_BATCH]; | ||
418 | unsigned long batch; | 562 | unsigned long batch; |
419 | unsigned long n; | 563 | unsigned long pages; |
420 | unsigned long i; | 564 | unsigned long i; |
421 | 565 | ||
422 | if (index > ULONG_MAX / KPF_BYTES) | ||
423 | fatal("index overflow: %lu\n", index); | ||
424 | |||
425 | lseek(kpageflags_fd, index * KPF_BYTES, SEEK_SET); | ||
426 | |||
427 | while (count) { | 566 | while (count) { |
428 | uint64_t kpageflags_buf[KPF_BYTES * PAGES_BATCH]; | 567 | batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH); |
429 | 568 | pages = kpageflags_read(buf, index, batch); | |
430 | batch = min_t(unsigned long, count, PAGES_BATCH); | 569 | if (pages == 0) |
431 | n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES); | ||
432 | if (n == 0) | ||
433 | break; | 570 | break; |
434 | if (n < 0) { | ||
435 | perror(PROC_KPAGEFLAGS); | ||
436 | exit(EXIT_FAILURE); | ||
437 | } | ||
438 | 571 | ||
439 | if (n % KPF_BYTES != 0) | 572 | for (i = 0; i < pages; i++) |
440 | fatal("partial read: %lu bytes\n", n); | 573 | add_page(voffset + i, index + i, buf[i]); |
441 | n = n / KPF_BYTES; | ||
442 | 574 | ||
443 | for (i = 0; i < n; i++) | 575 | index += pages; |
444 | add_page(index + i, kpageflags_buf[i]); | 576 | count -= pages; |
445 | |||
446 | index += batch; | ||
447 | count -= batch; | ||
448 | } | 577 | } |
449 | } | 578 | } |
450 | 579 | ||
451 | 580 | #define PAGEMAP_BATCH (64 << 10) | |
452 | #define PAGEMAP_BATCH 4096 | 581 | static void walk_vma(unsigned long index, unsigned long count) |
453 | static unsigned long task_pfn(unsigned long pgoff) | ||
454 | { | 582 | { |
455 | static uint64_t buf[PAGEMAP_BATCH]; | 583 | uint64_t buf[PAGEMAP_BATCH]; |
456 | static unsigned long start; | 584 | unsigned long batch; |
457 | static long count; | 585 | unsigned long pages; |
458 | uint64_t pfn; | 586 | unsigned long pfn; |
587 | unsigned long i; | ||
459 | 588 | ||
460 | if (pgoff < start || pgoff >= start + count) { | 589 | while (count) { |
461 | if (lseek64(pagemap_fd, | 590 | batch = min_t(unsigned long, count, PAGEMAP_BATCH); |
462 | (uint64_t)pgoff * PM_ENTRY_BYTES, | 591 | pages = pagemap_read(buf, index, batch); |
463 | SEEK_SET) < 0) { | 592 | if (pages == 0) |
464 | perror("pagemap seek"); | 593 | break; |
465 | exit(EXIT_FAILURE); | ||
466 | } | ||
467 | count = read(pagemap_fd, buf, sizeof(buf)); | ||
468 | if (count == 0) | ||
469 | return 0; | ||
470 | if (count < 0) { | ||
471 | perror("pagemap read"); | ||
472 | exit(EXIT_FAILURE); | ||
473 | } | ||
474 | if (count % PM_ENTRY_BYTES) { | ||
475 | fatal("pagemap read not aligned.\n"); | ||
476 | exit(EXIT_FAILURE); | ||
477 | } | ||
478 | count /= PM_ENTRY_BYTES; | ||
479 | start = pgoff; | ||
480 | } | ||
481 | 594 | ||
482 | pfn = buf[pgoff - start]; | 595 | for (i = 0; i < pages; i++) { |
483 | if (pfn & PM_PRESENT) | 596 | pfn = pagemap_pfn(buf[i]); |
484 | pfn = PM_PFRAME(pfn); | 597 | if (pfn) |
485 | else | 598 | walk_pfn(index + i, pfn, 1); |
486 | pfn = 0; | 599 | } |
487 | 600 | ||
488 | return pfn; | 601 | index += pages; |
602 | count -= pages; | ||
603 | } | ||
489 | } | 604 | } |
490 | 605 | ||
491 | static void walk_task(unsigned long index, unsigned long count) | 606 | static void walk_task(unsigned long index, unsigned long count) |
492 | { | 607 | { |
493 | int i = 0; | ||
494 | const unsigned long end = index + count; | 608 | const unsigned long end = index + count; |
609 | unsigned long start; | ||
610 | int i = 0; | ||
495 | 611 | ||
496 | while (index < end) { | 612 | while (index < end) { |
497 | 613 | ||
@@ -501,15 +617,11 @@ static void walk_task(unsigned long index, unsigned long count) | |||
501 | if (pg_start[i] >= end) | 617 | if (pg_start[i] >= end) |
502 | return; | 618 | return; |
503 | 619 | ||
504 | voffset = max_t(unsigned long, pg_start[i], index); | 620 | start = max_t(unsigned long, pg_start[i], index); |
505 | index = min_t(unsigned long, pg_end[i], end); | 621 | index = min_t(unsigned long, pg_end[i], end); |
506 | 622 | ||
507 | assert(voffset < index); | 623 | assert(start < index); |
508 | for (; voffset < index; voffset++) { | 624 | walk_vma(start, index - start); |
509 | unsigned long pfn = task_pfn(voffset); | ||
510 | if (pfn) | ||
511 | walk_pfn(pfn, 1); | ||
512 | } | ||
513 | } | 625 | } |
514 | } | 626 | } |
515 | 627 | ||
@@ -527,18 +639,14 @@ static void walk_addr_ranges(void) | |||
527 | { | 639 | { |
528 | int i; | 640 | int i; |
529 | 641 | ||
530 | kpageflags_fd = open(PROC_KPAGEFLAGS, O_RDONLY); | 642 | kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY); |
531 | if (kpageflags_fd < 0) { | ||
532 | perror(PROC_KPAGEFLAGS); | ||
533 | exit(EXIT_FAILURE); | ||
534 | } | ||
535 | 643 | ||
536 | if (!nr_addr_ranges) | 644 | if (!nr_addr_ranges) |
537 | add_addr_range(0, ULONG_MAX); | 645 | add_addr_range(0, ULONG_MAX); |
538 | 646 | ||
539 | for (i = 0; i < nr_addr_ranges; i++) | 647 | for (i = 0; i < nr_addr_ranges; i++) |
540 | if (!opt_pid) | 648 | if (!opt_pid) |
541 | walk_pfn(opt_offset[i], opt_size[i]); | 649 | walk_pfn(0, opt_offset[i], opt_size[i]); |
542 | else | 650 | else |
543 | walk_task(opt_offset[i], opt_size[i]); | 651 | walk_task(opt_offset[i], opt_size[i]); |
544 | 652 | ||
@@ -575,6 +683,8 @@ static void usage(void) | |||
575 | " -l|--list Show page details in ranges\n" | 683 | " -l|--list Show page details in ranges\n" |
576 | " -L|--list-each Show page details one by one\n" | 684 | " -L|--list-each Show page details one by one\n" |
577 | " -N|--no-summary Don't show summay info\n" | 685 | " -N|--no-summary Don't show summay info\n" |
686 | " -X|--hwpoison hwpoison pages\n" | ||
687 | " -x|--unpoison unpoison pages\n" | ||
578 | " -h|--help Show this usage message\n" | 688 | " -h|--help Show this usage message\n" |
579 | "addr-spec:\n" | 689 | "addr-spec:\n" |
580 | " N one page at offset N (unit: pages)\n" | 690 | " N one page at offset N (unit: pages)\n" |
@@ -624,11 +734,7 @@ static void parse_pid(const char *str) | |||
624 | opt_pid = parse_number(str); | 734 | opt_pid = parse_number(str); |
625 | 735 | ||
626 | sprintf(buf, "/proc/%d/pagemap", opt_pid); | 736 | sprintf(buf, "/proc/%d/pagemap", opt_pid); |
627 | pagemap_fd = open(buf, O_RDONLY); | 737 | pagemap_fd = checked_open(buf, O_RDONLY); |
628 | if (pagemap_fd < 0) { | ||
629 | perror(buf); | ||
630 | exit(EXIT_FAILURE); | ||
631 | } | ||
632 | 738 | ||
633 | sprintf(buf, "/proc/%d/maps", opt_pid); | 739 | sprintf(buf, "/proc/%d/maps", opt_pid); |
634 | file = fopen(buf, "r"); | 740 | file = fopen(buf, "r"); |
@@ -788,6 +894,8 @@ static struct option opts[] = { | |||
788 | { "list" , 0, NULL, 'l' }, | 894 | { "list" , 0, NULL, 'l' }, |
789 | { "list-each" , 0, NULL, 'L' }, | 895 | { "list-each" , 0, NULL, 'L' }, |
790 | { "no-summary", 0, NULL, 'N' }, | 896 | { "no-summary", 0, NULL, 'N' }, |
897 | { "hwpoison" , 0, NULL, 'X' }, | ||
898 | { "unpoison" , 0, NULL, 'x' }, | ||
791 | { "help" , 0, NULL, 'h' }, | 899 | { "help" , 0, NULL, 'h' }, |
792 | { NULL , 0, NULL, 0 } | 900 | { NULL , 0, NULL, 0 } |
793 | }; | 901 | }; |
@@ -799,7 +907,7 @@ int main(int argc, char *argv[]) | |||
799 | page_size = getpagesize(); | 907 | page_size = getpagesize(); |
800 | 908 | ||
801 | while ((c = getopt_long(argc, argv, | 909 | while ((c = getopt_long(argc, argv, |
802 | "rp:f:a:b:lLNh", opts, NULL)) != -1) { | 910 | "rp:f:a:b:lLNXxh", opts, NULL)) != -1) { |
803 | switch (c) { | 911 | switch (c) { |
804 | case 'r': | 912 | case 'r': |
805 | opt_raw = 1; | 913 | opt_raw = 1; |
@@ -825,6 +933,14 @@ int main(int argc, char *argv[]) | |||
825 | case 'N': | 933 | case 'N': |
826 | opt_no_summary = 1; | 934 | opt_no_summary = 1; |
827 | break; | 935 | break; |
936 | case 'X': | ||
937 | opt_hwpoison = 1; | ||
938 | prepare_hwpoison_fd(); | ||
939 | break; | ||
940 | case 'x': | ||
941 | opt_unpoison = 1; | ||
942 | prepare_hwpoison_fd(); | ||
943 | break; | ||
828 | case 'h': | 944 | case 'h': |
829 | usage(); | 945 | usage(); |
830 | exit(0); | 946 | exit(0); |
@@ -844,7 +960,7 @@ int main(int argc, char *argv[]) | |||
844 | walk_addr_ranges(); | 960 | walk_addr_ranges(); |
845 | 961 | ||
846 | if (opt_list == 1) | 962 | if (opt_list == 1) |
847 | show_page_range(0, 0); /* drain the buffer */ | 963 | show_page_range(0, 0, 0); /* drain the buffer */ |
848 | 964 | ||
849 | if (opt_no_summary) | 965 | if (opt_no_summary) |
850 | return 0; | 966 | return 0; |
diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt index 600a304a828c..df09b9650a81 100644 --- a/Documentation/vm/pagemap.txt +++ b/Documentation/vm/pagemap.txt | |||
@@ -57,7 +57,9 @@ There are three components to pagemap: | |||
57 | 16. COMPOUND_TAIL | 57 | 16. COMPOUND_TAIL |
58 | 16. HUGE | 58 | 16. HUGE |
59 | 18. UNEVICTABLE | 59 | 18. UNEVICTABLE |
60 | 19. HWPOISON | ||
60 | 20. NOPAGE | 61 | 20. NOPAGE |
62 | 21. KSM | ||
61 | 63 | ||
62 | Short descriptions to the page flags: | 64 | Short descriptions to the page flags: |
63 | 65 | ||
@@ -86,9 +88,15 @@ Short descriptions to the page flags: | |||
86 | 17. HUGE | 88 | 17. HUGE |
87 | this is an integral part of a HugeTLB page | 89 | this is an integral part of a HugeTLB page |
88 | 90 | ||
91 | 19. HWPOISON | ||
92 | hardware detected memory corruption on this page: don't touch the data! | ||
93 | |||
89 | 20. NOPAGE | 94 | 20. NOPAGE |
90 | no page frame exists at the requested address | 95 | no page frame exists at the requested address |
91 | 96 | ||
97 | 21. KSM | ||
98 | identical memory pages dynamically shared between one or more processes | ||
99 | |||
92 | [IO related page flags] | 100 | [IO related page flags] |
93 | 1. ERROR IO error occurred | 101 | 1. ERROR IO error occurred |
94 | 3. UPTODATE page has up-to-date data | 102 | 3. UPTODATE page has up-to-date data |