[PATCH V2] hugetlb: Add nohugepages parameter to prevent hugepages creation

From: Guilherme G. Piccoli
Date: Tue Oct 15 2019 - 00:52:19 EST


Currently there are 2 ways for setting HugeTLB hugepages in kernel; either
users pass parameters on kernel command-line or they can write to sysfs
files (which is effectively the sysctl way).

Kdump kernels won't benefit from hugepages - in fact it's quite opposite,
it may be the case hugepages on kdump kernel can lead to OOM if kernel
gets unable to allocate demanded pages due to the fact the preallocated
hugepages are consuming a lot of memory.

This patch proposes a new kernel parameter to prevent the creation of
HugeTLB hugepages - we currently don't have a way to do that. We can
even have kdump scripts removing the kernel command-line options to
set hugepages, but it's not straightforward to prevent sysctl/sysfs
configuration, given it happens in later boot or anytime when the
system is running.

Signed-off-by: Guilherme G. Piccoli <gpiccoli@xxxxxxxxxxxxx>
---
.../admin-guide/kernel-parameters.txt | 4 +++
fs/hugetlbfs/inode.c | 5 ++--
include/linux/hugetlb.h | 7 ++++++
mm/hugetlb.c | 25 +++++++++++++------
4 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index a84a83f8881e..061bec851114 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2982,6 +2982,10 @@

nohugeiomap [KNL,x86,PPC] Disable kernel huge I/O mappings.

+ nohugepages [KNL] Disable HugeTLB hugepages completely, preventing
+ its setting either by kernel parameter or sysfs;
+ useful specially in kdump kernel.
+
nosmt [KNL,S390] Disable symmetric multithreading (SMT).
Equivalent to smt=1.

diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index a478df035651..bbf8827ecccf 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -1451,8 +1451,9 @@ static int __init init_hugetlbfs_fs(void)
int error;
int i;

- if (!hugepages_supported()) {
- pr_info("disabling because there are no supported hugepage sizes\n");
+ if (!hugepages_enabled()) {
+ if (!hugetlb_disable_hugepages)
+ pr_info("disabling because there are no supported hugepage sizes\n");
return -ENOTSUPP;
}

diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 53fc34f930d0..91b3cc7ae891 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -549,6 +549,13 @@ static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
#define hugepages_supported() (HPAGE_SHIFT != 0)
#endif

+extern int hugetlb_disable_hugepages;
+
+static inline bool hugepages_enabled(void)
+{
+ return (hugepages_supported() && (!hugetlb_disable_hugepages));
+}
+
void hugetlb_report_usage(struct seq_file *m, struct mm_struct *mm);

static inline void hugetlb_count_add(long l, struct mm_struct *mm)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index ef37c85423a5..d0151454f13f 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -43,6 +43,8 @@
int hugetlb_max_hstate __read_mostly;
unsigned int default_hstate_idx;
struct hstate hstates[HUGE_MAX_HSTATE];
+int hugetlb_disable_hugepages;
+
/*
* Minimum page order among possible hugepage sizes, set to a proper value
* at boot time.
@@ -1604,7 +1606,7 @@ int dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
struct page *page;
int rc = 0;

- if (!hugepages_supported())
+ if (!hugepages_enabled())
return rc;

for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order) {
@@ -2897,7 +2899,7 @@ static int __init hugetlb_init(void)
{
int i;

- if (!hugepages_supported())
+ if (!hugepages_enabled())
return 0;

if (!size_to_hstate(default_hstate_size)) {
@@ -3022,6 +3024,15 @@ static int __init hugetlb_default_setup(char *s)
}
__setup("default_hugepagesz=", hugetlb_default_setup);

+static int __init nohugepages_setup(char *str)
+{
+ hugetlb_disable_hugepages = 1;
+ pr_info("HugeTLB: hugepages disabled by kernel parameter\n");
+
+ return 0;
+}
+early_param("nohugepages", nohugepages_setup);
+
static unsigned int cpuset_mems_nr(unsigned int *array)
{
int node;
@@ -3042,7 +3053,7 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
unsigned long tmp = h->max_huge_pages;
int ret;

- if (!hugepages_supported())
+ if (!hugepages_enabled())
return -EOPNOTSUPP;

table->data = &tmp;
@@ -3083,7 +3094,7 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
unsigned long tmp;
int ret;

- if (!hugepages_supported())
+ if (!hugepages_enabled())
return -EOPNOTSUPP;

tmp = h->nr_overcommit_huge_pages;
@@ -3113,7 +3124,7 @@ void hugetlb_report_meminfo(struct seq_file *m)
struct hstate *h;
unsigned long total = 0;

- if (!hugepages_supported())
+ if (!hugepages_enabled())
return;

for_each_hstate(h) {
@@ -3141,7 +3152,7 @@ void hugetlb_report_meminfo(struct seq_file *m)
int hugetlb_report_node_meminfo(int nid, char *buf)
{
struct hstate *h = &default_hstate;
- if (!hugepages_supported())
+ if (!hugepages_enabled())
return 0;
return sprintf(buf,
"Node %d HugePages_Total: %5u\n"
@@ -3157,7 +3168,7 @@ void hugetlb_show_meminfo(void)
struct hstate *h;
int nid;

- if (!hugepages_supported())
+ if (!hugepages_enabled())
return;

for_each_node_state(nid, N_MEMORY)
--
2.23.0