diff options
author | Kirill A. Shutemov <kirill.shutemov@linux.intel.com> | 2016-01-15 19:54:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-15 20:56:32 -0500 |
commit | 49071d436b51b58aeaf7abcd1877f38ca0146e31 (patch) | |
tree | 2adf8f687cc81072646412a97c07d2abc077182a /mm/huge_memory.c | |
parent | b20ce5e03b936be077463015661dcf52be274e5b (diff) |
thp: add debugfs handle to split all huge pages
Writing 1 into 'split_huge_pages' will try to find and split all huge
pages in the system. This is useful for debuging.
[akpm@linux-foundation.org: fix printk text, per Vlastimil]
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/huge_memory.c')
-rw-r--r-- | mm/huge_memory.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index ab544b145b52..a0b910a0c2cb 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/freezer.h> | 23 | #include <linux/freezer.h> |
24 | #include <linux/mman.h> | 24 | #include <linux/mman.h> |
25 | #include <linux/pagemap.h> | 25 | #include <linux/pagemap.h> |
26 | #include <linux/debugfs.h> | ||
26 | #include <linux/migrate.h> | 27 | #include <linux/migrate.h> |
27 | #include <linux/hashtable.h> | 28 | #include <linux/hashtable.h> |
28 | #include <linux/userfaultfd_k.h> | 29 | #include <linux/userfaultfd_k.h> |
@@ -3350,3 +3351,61 @@ static struct shrinker deferred_split_shrinker = { | |||
3350 | .scan_objects = deferred_split_scan, | 3351 | .scan_objects = deferred_split_scan, |
3351 | .seeks = DEFAULT_SEEKS, | 3352 | .seeks = DEFAULT_SEEKS, |
3352 | }; | 3353 | }; |
3354 | |||
3355 | #ifdef CONFIG_DEBUG_FS | ||
3356 | static int split_huge_pages_set(void *data, u64 val) | ||
3357 | { | ||
3358 | struct zone *zone; | ||
3359 | struct page *page; | ||
3360 | unsigned long pfn, max_zone_pfn; | ||
3361 | unsigned long total = 0, split = 0; | ||
3362 | |||
3363 | if (val != 1) | ||
3364 | return -EINVAL; | ||
3365 | |||
3366 | for_each_populated_zone(zone) { | ||
3367 | max_zone_pfn = zone_end_pfn(zone); | ||
3368 | for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) { | ||
3369 | if (!pfn_valid(pfn)) | ||
3370 | continue; | ||
3371 | |||
3372 | page = pfn_to_page(pfn); | ||
3373 | if (!get_page_unless_zero(page)) | ||
3374 | continue; | ||
3375 | |||
3376 | if (zone != page_zone(page)) | ||
3377 | goto next; | ||
3378 | |||
3379 | if (!PageHead(page) || !PageAnon(page) || | ||
3380 | PageHuge(page)) | ||
3381 | goto next; | ||
3382 | |||
3383 | total++; | ||
3384 | lock_page(page); | ||
3385 | if (!split_huge_page(page)) | ||
3386 | split++; | ||
3387 | unlock_page(page); | ||
3388 | next: | ||
3389 | put_page(page); | ||
3390 | } | ||
3391 | } | ||
3392 | |||
3393 | pr_info("%lu of %lu THP split", split, total); | ||
3394 | |||
3395 | return 0; | ||
3396 | } | ||
3397 | DEFINE_SIMPLE_ATTRIBUTE(split_huge_pages_fops, NULL, split_huge_pages_set, | ||
3398 | "%llu\n"); | ||
3399 | |||
3400 | static int __init split_huge_pages_debugfs(void) | ||
3401 | { | ||
3402 | void *ret; | ||
3403 | |||
3404 | ret = debugfs_create_file("split_huge_pages", 0644, NULL, NULL, | ||
3405 | &split_huge_pages_fops); | ||
3406 | if (!ret) | ||
3407 | pr_warn("Failed to create split_huge_pages in debugfs"); | ||
3408 | return 0; | ||
3409 | } | ||
3410 | late_initcall(split_huge_pages_debugfs); | ||
3411 | #endif | ||