When debug_pagealloc is enabled, we currently allocate the page_ext array to mark guard pages with the PAGE_EXT_DEBUG_GUARD flag. Now that we have the page_type field in struct page, we can use that instead, as guard pages are neither PageSlab nor mapped to userspace. This reduces memory overhead when debug_pagealloc is enabled and there are no other features requiring the page_ext array.
Unified · Split
| @@ -805,12 +805,10 @@ · 804 unmodified lines | |||
| 805 | tracking down these problems. | 805 | tracking down these problems. |
| 806 | 806 | ||
| 807 | debug_pagealloc= | 807 | debug_pagealloc= |
| 808 | [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this | 808 | [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this parameter |
| 809 | parameter enables the feature at boot time. In | 809 | enables the feature at boot time. By default, it is |
| 810 | default, it is disabled. We can avoid allocating huge | 810 | disabled and the system will work mostly the same as a |
| 811 | chunk of memory for debug pagealloc if we don't enable | 811 | kernel built without CONFIG_DEBUG_PAGEALLOC. |
| 812 | it at boot time and the system will work mostly same | ||
| 813 | with the kernel built without CONFIG_DEBUG_PAGEALLOC. | ||
| 814 | on: enable the feature | 812 | on: enable the feature |
| 815 | 813 | ||
| 816 | debugpat [X86] Enable PAT debugging | 814 | debugpat [X86] Enable PAT debugging |
| @@ -2862,8 +2862,6 @@ extern long copy_huge_page_from_user(struct page *dst_page, · 2861 unmodified lines | |||
| 2862 | bool allow_pagefault); | 2862 | bool allow_pagefault); |
| 2863 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLBFS */ | 2863 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLBFS */ |
| 2864 | 2864 | ||
| 2865 | extern struct page_ext_operations debug_guardpage_ops; | ||
| 2866 | |||
| 2867 | #ifdef CONFIG_DEBUG_PAGEALLOC | 2865 | #ifdef CONFIG_DEBUG_PAGEALLOC |
| 2868 | extern unsigned int _debug_guardpage_minorder; | 2866 | extern unsigned int _debug_guardpage_minorder; |
| 2869 | DECLARE_STATIC_KEY_FALSE(_debug_guardpage_enabled); | 2867 | DECLARE_STATIC_KEY_FALSE(_debug_guardpage_enabled); |
| @@ -2880,16 +2878,10 @@ static inline bool debug_guardpage_enabled(void) · 10 unmodified lines | |||
| 2880 | 2878 | ||
| 2881 | static inline bool page_is_guard(struct page *page) | 2879 | static inline bool page_is_guard(struct page *page) |
| 2882 | { | 2880 | { |
| 2883 | struct page_ext *page_ext; | ||
| 2884 | |||
| 2885 | if (!debug_guardpage_enabled()) | 2881 | if (!debug_guardpage_enabled()) |
| 2886 | return false; | 2882 | return false; |
| 2887 | 2883 | ||
| 2888 | page_ext = lookup_page_ext(page); | 2884 | return PageGuard(page); |
| 2889 | if (unlikely(!page_ext)) | ||
| 2890 | return false; | ||
| 2891 | |||
| 2892 | return test_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags); | ||
| 2893 | } | 2885 | } |
| 2894 | #else | 2886 | #else |
| 2895 | static inline unsigned int debug_guardpage_minorder(void) { return 0; } | 2887 | static inline unsigned int debug_guardpage_minorder(void) { return 0; } |
| @@ -703,6 +703,7 @@ PAGEFLAG_FALSE(DoubleMap) · 702 unmodified lines | |||
| 703 | #define PG_offline 0x00000100 | 703 | #define PG_offline 0x00000100 |
| 704 | #define PG_kmemcg 0x00000200 | 704 | #define PG_kmemcg 0x00000200 |
| 705 | #define PG_table 0x00000400 | 705 | #define PG_table 0x00000400 |
| 706 | #define PG_guard 0x00000800 | ||
| 706 | 707 | ||
| 707 | #define PageType(page, flag) \ | 708 | #define PageType(page, flag) \ |
| 708 | ((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE) | 709 | ((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE) |
| @@ -754,6 +755,11 @@ PAGE_TYPE_OPS(Kmemcg, kmemcg) · 45 unmodified lines | |||
| 754 | */ | 755 | */ |
| 755 | PAGE_TYPE_OPS(Table, table) | 756 | PAGE_TYPE_OPS(Table, table) |
| 756 | 757 | ||
| 758 | /* | ||
| 759 | * Marks guardpages used with debug_pagealloc. | ||
| 760 | */ | ||
| 761 | PAGE_TYPE_OPS(Guard, guard) | ||
| 762 | |||
| 757 | extern bool is_free_buddy_page(struct page *page); | 763 | extern bool is_free_buddy_page(struct page *page); |
| 758 | 764 | ||
| 759 | __PAGEFLAG(Isolated, isolated, PF_ANY); | 765 | __PAGEFLAG(Isolated, isolated, PF_ANY); |
| @@ -17,7 +17,6 @@ struct page_ext_operations { · 16 unmodified lines | |||
| 17 | #ifdef CONFIG_PAGE_EXTENSION | 17 | #ifdef CONFIG_PAGE_EXTENSION |
| 18 | 18 | ||
| 19 | enum page_ext_flags { | 19 | enum page_ext_flags { |
| 20 | PAGE_EXT_DEBUG_GUARD, | ||
| 21 | PAGE_EXT_OWNER, | 20 | PAGE_EXT_OWNER, |
| 22 | #if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) | 21 | #if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) |
| 23 | PAGE_EXT_YOUNG, | 22 | PAGE_EXT_YOUNG, |
| @@ -12,7 +12,6 @@ config DEBUG_PAGEALLOC · 11 unmodified lines | |||
| 12 | bool "Debug page memory allocations" | 12 | bool "Debug page memory allocations" |
| 13 | depends on DEBUG_KERNEL | 13 | depends on DEBUG_KERNEL |
| 14 | depends on !HIBERNATION || ARCH_SUPPORTS_DEBUG_PAGEALLOC && !PPC && !SPARC | 14 | depends on !HIBERNATION || ARCH_SUPPORTS_DEBUG_PAGEALLOC && !PPC && !SPARC |
| 15 | select PAGE_EXTENSION | ||
| 16 | select PAGE_POISONING if !ARCH_SUPPORTS_DEBUG_PAGEALLOC | 15 | select PAGE_POISONING if !ARCH_SUPPORTS_DEBUG_PAGEALLOC |
| 17 | ---help--- | 16 | ---help--- |
| 18 | Unmap pages from the kernel linear mapping after free_pages(). | 17 | Unmap pages from the kernel linear mapping after free_pages(). |
| @@ -50,7 +50,6 @@ · 49 unmodified lines | |||
| 50 | #include <linux/backing-dev.h> | 50 | #include <linux/backing-dev.h> |
| 51 | #include <linux/fault-inject.h> | 51 | #include <linux/fault-inject.h> |
| 52 | #include <linux/page-isolation.h> | 52 | #include <linux/page-isolation.h> |
| 53 | #include <linux/page_ext.h> | ||
| 54 | #include <linux/debugobjects.h> | 53 | #include <linux/debugobjects.h> |
| 55 | #include <linux/kmemleak.h> | 54 | #include <linux/kmemleak.h> |
| 56 | #include <linux/compaction.h> | 55 | #include <linux/compaction.h> |
| @@ -668,18 +667,6 @@ static int __init early_debug_pagealloc(char *buf) · 611 unmodified lines | |||
| 668 | } | 667 | } |
| 669 | early_param("debug_pagealloc", early_debug_pagealloc); | 668 | early_param("debug_pagealloc", early_debug_pagealloc); |
| 670 | 669 | ||
| 671 | static bool need_debug_guardpage(void) | ||
| 672 | { | ||
| 673 | /* If we don't use debug_pagealloc, we don't need guard page */ | ||
| 674 | if (!debug_pagealloc_enabled()) | ||
| 675 | return false; | ||
| 676 | |||
| 677 | if (!debug_guardpage_minorder()) | ||
| 678 | return false; | ||
| 679 | |||
| 680 | return true; | ||
| 681 | } | ||
| 682 | |||
| 683 | static void init_debug_guardpage(void) | 670 | static void init_debug_guardpage(void) |
| 684 | { | 671 | { |
| 685 | if (!debug_pagealloc_enabled()) | 672 | if (!debug_pagealloc_enabled()) |
| @@ -691,11 +678,6 @@ static void init_debug_guardpage(void) · 5 unmodified lines | |||
| 691 | static_branch_enable(&_debug_guardpage_enabled); | 678 | static_branch_enable(&_debug_guardpage_enabled); |
| 692 | } | 679 | } |
| 693 | 680 | ||
| 694 | struct page_ext_operations debug_guardpage_ops = { | ||
| 695 | .need = need_debug_guardpage, | ||
| 696 | .init = init_debug_guardpage, | ||
| 697 | }; | ||
| 698 | |||
| 699 | static int __init debug_guardpage_minorder_setup(char *buf) | 681 | static int __init debug_guardpage_minorder_setup(char *buf) |
| 700 | { | 682 | { |
| 701 | unsigned long res; | 683 | unsigned long res; |
| @@ -713,20 +695,13 @@ early_param("debug_guardpage_minorder", debug_guardpage_minorder_setup); · 11 unmodified lines | |||
| 713 | static inline bool set_page_guard(struct zone *zone, struct page *page, | 695 | static inline bool set_page_guard(struct zone *zone, struct page *page, |
| 714 | unsigned int order, int migratetype) | 696 | unsigned int order, int migratetype) |
| 715 | { | 697 | { |
| 716 | struct page_ext *page_ext; | ||
| 717 | |||
| 718 | if (!debug_guardpage_enabled()) | 698 | if (!debug_guardpage_enabled()) |
| 719 | return false; | 699 | return false; |
| 720 | 700 | ||
| 721 | if (order >= debug_guardpage_minorder()) | 701 | if (order >= debug_guardpage_minorder()) |
| 722 | return false; | 702 | return false; |
| 723 | 703 | ||
| 724 | page_ext = lookup_page_ext(page); | 704 | __SetPageGuard(page); |
| 725 | if (unlikely(!page_ext)) | ||
| 726 | return false; | ||
| 727 | |||
| 728 | __set_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags); | ||
| 729 | |||
| 730 | INIT_LIST_HEAD(&page->lru); | 705 | INIT_LIST_HEAD(&page->lru); |
| 731 | set_page_private(page, order); | 706 | set_page_private(page, order); |
| 732 | /* Guard pages are not available for any usage */ | 707 | /* Guard pages are not available for any usage */ |
| @@ -738,23 +713,16 @@ static inline bool set_page_guard(struct zone *zone, struct page *page, · 5 unmodified lines | |||
| 738 | static inline void clear_page_guard(struct zone *zone, struct page *page, | 713 | static inline void clear_page_guard(struct zone *zone, struct page *page, |
| 739 | unsigned int order, int migratetype) | 714 | unsigned int order, int migratetype) |
| 740 | { | 715 | { |
| 741 | struct page_ext *page_ext; | ||
| 742 | |||
| 743 | if (!debug_guardpage_enabled()) | 716 | if (!debug_guardpage_enabled()) |
| 744 | return; | 717 | return; |
| 745 | 718 | ||
| 746 | page_ext = lookup_page_ext(page); | 719 | __ClearPageGuard(page); |
| 747 | if (unlikely(!page_ext)) | ||
| 748 | return; | ||
| 749 | |||
| 750 | __clear_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags); | ||
| 751 | 720 | ||
| 752 | set_page_private(page, 0); | 721 | set_page_private(page, 0); |
| 753 | if (!is_migrate_isolate(migratetype)) | 722 | if (!is_migrate_isolate(migratetype)) |
| 754 | __mod_zone_freepage_state(zone, (1 << order), migratetype); | 723 | __mod_zone_freepage_state(zone, (1 << order), migratetype); |
| 755 | } | 724 | } |
| 756 | #else | 725 | #else |
| 757 | struct page_ext_operations debug_guardpage_ops; | ||
| 758 | static inline bool set_page_guard(struct zone *zone, struct page *page, | 726 | static inline bool set_page_guard(struct zone *zone, struct page *page, |
| 759 | unsigned int order, int migratetype) { return false; } | 727 | unsigned int order, int migratetype) { return false; } |
| 760 | static inline void clear_page_guard(struct zone *zone, struct page *page, | 728 | static inline void clear_page_guard(struct zone *zone, struct page *page, |
| @@ -1930,6 +1898,10 @@ void __init page_alloc_init_late(void) · 1169 unmodified lines | |||
| 1930 | 1898 | ||
| 1931 | for_each_populated_zone(zone) | 1899 | for_each_populated_zone(zone) |
| 1932 | set_zone_contiguous(zone); | 1900 | set_zone_contiguous(zone); |
| 1901 | |||
| 1902 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 1903 | init_debug_guardpage(); | ||
| 1904 | #endif | ||
| 1933 | } | 1905 | } |
| 1934 | 1906 | ||
| 1935 | #ifdef CONFIG_CMA | 1907 | #ifdef CONFIG_CMA |
| @@ -59,9 +59,6 @@ · 58 unmodified lines | |||
| 59 | */ | 59 | */ |
| 60 | 60 | ||
| 61 | static struct page_ext_operations *page_ext_ops[] = { | 61 | static struct page_ext_operations *page_ext_ops[] = { |
| 62 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 63 | &debug_guardpage_ops, | ||
| 64 | #endif | ||
| 65 | #ifdef CONFIG_PAGE_OWNER | 62 | #ifdef CONFIG_PAGE_OWNER |
| 66 | &page_owner_ops, | 63 | &page_owner_ops, |
| 67 | #endif | 64 | #endif |