diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 119031470918d919ceec43415c401c85997b92c5..c90868d14ecde11bb73edc09aa2b271d4033ca23 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/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 8e29cb161800faa2deb8f81384056f35b218a746..88afa95a3ff20efc7e2fe29d739604d5a3e50298 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -6917,6 +6917,7 @@ CONFIG_TMPFS_XATTR=y CONFIG_ARCH_SUPPORTS_HUGETLBFS=y CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y +CONFIG_HUGETLB_ALLOC_LIMIT=y CONFIG_ARCH_HAS_GIGANTIC_PAGE=y CONFIG_CONFIGFS_FS=y CONFIG_EFIVAR_FS=y diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index b3e32559ab625b49643c41d894f0ef79dc0ba099..f1895d38dab89efaba3fd6d95491701f6fbdb456 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -8120,6 +8120,7 @@ CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y # CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set +CONFIG_HUGETLB_ALLOC_LIMIT=y CONFIG_ARCH_HAS_GIGANTIC_PAGE=y CONFIG_CONFIGFS_FS=y CONFIG_EFIVAR_FS=y diff --git a/fs/Kconfig b/fs/Kconfig index aa7e03cc1941cb3e6145d95886b99b83b677a69b..7c9d45ba9b0f7407d0a5b144ebd3d6ed026259c6 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 d996a63ebf50c6067de0f71729b8e7d90414e0f3..d370d5c0014c73bbbbc2cae5f193eba535c6912d 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),