From: Kefeng Wang wangkefeng.wang@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8TKCL CVE: NA
--------------------------------
The user wants to reserve a certain amount of memory for normal non-huge page, that is, the hugetlb can't allowed to use all the memory.
Add a new kernel parameters "hugepage_prohibit_sz=" to set size for normal non-huge page reserved, and when alloc huge page, let's fail if the new allocating exceeds the limit.
Signed-off-by: Kefeng Wang wangkefeng.wang@huawei.com Tested-by: Liu Shixin liushixin2@huawei.com Signed-off-by: Liu Shixin liushixin2@huawei.com --- .../admin-guide/kernel-parameters.txt | 10 +++ fs/Kconfig | 14 ++++ mm/hugetlb.c | 78 +++++++++++++++++++ 3 files changed, 102 insertions(+)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 119031470918..c90868d14ecd 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1825,6 +1825,16 @@ feature is enabled. Other vmemmap pages not allocated from the added memory block itself do not be affected.
+ hugepage_prohibit_sz= + [KNL] HugeTLB pages should not alloc page when the rest + of the normal pages less than hugepage_prohibit_sz when + system booting. This setting is to make sure a system + can start successfully even part of physical memory is + broken or wrong hugepage configration, admin users can + adjust this according to typical environment. + + Requires CONFIG_HUGETLB_ALLOC_LIMIT + hung_task_panic= [KNL] Should the hung task detector generate panics. Format: 0 | 1 diff --git a/fs/Kconfig b/fs/Kconfig index aa7e03cc1941..7c9d45ba9b0f 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -282,6 +282,20 @@ config HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON enable HVO by default. It can be disabled via hugetlb_free_vmemmap=off (boot command line) or hugetlb_optimize_vmemmap (sysctl).
+config HUGETLB_ALLOC_LIMIT + bool "Limit hugeTLB pages allocation" + depends on HUGETLB_PAGE + default n + help + HugeTLB pages should not alloc page when the rest of + the normal pages less than hugepage_prohibit_sz. This + setting is to make sure a system can start even when + part of physical memory is broken or wrong hugepage + configration, admin users can adjust this according to + typical environment. + + If unsure, say N. + config ARCH_HAS_GIGANTIC_PAGE bool
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index d996a63ebf50..d370d5c0014c 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2181,6 +2181,74 @@ static struct folio *alloc_buddy_hugetlb_folio(struct hstate *h, return page_folio(page); }
+#ifdef CONFIG_HUGETLB_ALLOC_LIMIT +#define HUGE_PAGE_BOOTMEM_ALLOC 0 +#define HUGE_PAGE_FRESH_ALLOC 1 + +static u64 normal_page_reserve_sz; + +static int __init early_normal_page_reserve(char *p) +{ + unsigned long long size; + + if (!p) + return 1; + + size = memparse(p, &p); + if (*p) { + pr_warn("HugeTLB: Invalid normal page reserved size\n"); + return 1; + } + + normal_page_reserve_sz = size & PAGE_MASK; + + pr_info("HugeTLB: Normal page reserved %lldMB\n", + normal_page_reserve_sz >> 20); + + return 0; +} +early_param("hugepage_prohibit_sz", early_normal_page_reserve); + +static bool __ref huge_page_limit_check(int type, size_t hsize, int nid) +{ + u64 mem_usable = 0; + char *str = NULL; + char buf[32]; + + if (!normal_page_reserve_sz) + return true; + + if (system_state > SYSTEM_SCHEDULING) + return true; + + if (normal_page_reserve_sz >= memblock_phys_mem_size()) { + mem_usable = memblock_phys_mem_size(); + str = "physical memory"; + goto out; + } + + if (type == HUGE_PAGE_BOOTMEM_ALLOC) { + mem_usable = memblock_phys_mem_size() - memblock_reserved_size(); + str = "memblock usable"; + } else if (type == HUGE_PAGE_FRESH_ALLOC) { + mem_usable = nr_free_pages() << PAGE_SHIFT; + str = "free page"; + } + + if (mem_usable < normal_page_reserve_sz + hsize) + goto out; + + return true; +out: + string_get_size(hsize, 1, STRING_UNITS_2, buf, 32); + pr_info("HugeTLB: allocating(%s) + Normal pages reserved(%lldMB) node%d exceed %s size(%lldMB)\n", + buf, normal_page_reserve_sz >> 20, + nid, str, mem_usable >> 20); + + return false; +} +#endif + /* * Common helper to allocate a fresh hugetlb page. All specific allocators * should use this function to get new hugetlb pages @@ -2196,6 +2264,11 @@ static struct folio *alloc_fresh_hugetlb_folio(struct hstate *h, bool retry = false;
retry: +#ifdef CONFIG_HUGETLB_ALLOC_LIMIT + if (!huge_page_limit_check(HUGE_PAGE_FRESH_ALLOC, huge_page_size(h), nid)) + return NULL; +#endif + if (hstate_is_gigantic(h)) folio = alloc_gigantic_folio(h, gfp_mask, nid, nmask); else @@ -3173,6 +3246,11 @@ int __alloc_bootmem_huge_page(struct hstate *h, int nid) struct huge_bootmem_page *m = NULL; /* initialize for clang */ int nr_nodes, node;
+#ifdef CONFIG_HUGETLB_ALLOC_LIMIT + if (!huge_page_limit_check(HUGE_PAGE_BOOTMEM_ALLOC, huge_page_size(h), nid)) + return 0; +#endif + /* do node specific alloc */ if (nid != NUMA_NO_NODE) { m = memblock_alloc_try_nid_raw(huge_page_size(h), huge_page_size(h),