[PATCH 2/2] hugetlb: report cmdline parameters recorded too late

From: Zhenghui Hao

Date: Thu Sep 17 2026 - 02:28:58 EST


hugetlb command line parameters are recorded by the early_param()
handlers registered through hugetlb_early_param() and consumed later by
hugetlb_parse_params(), which is called from hugetlb_bootmem_alloc().

Since commit d49004c5f0c1 ("arch, mm: consolidate initialization of nodes,
zones and memory map") that consumer runs from mm_core_init_early(),
which is called before the generic parse_early_param() in start_kernel().

On architectures that do not call parse_early_param() from setup_arch(),
such as parisc, the parameters are recorded only after they have been
consumed, so they are dropped without any diagnostics: do_early_param()
stays quiet because the handlers return 0, and obsolete_checksetup()
treats early parameters as already handled.

Warn in that case instead of dropping the parameter silently.
Returning non-zero from the wrapper would also work, but it makes
do_early_param() print "Malformed early option", which points at the
command line instead of at the ordering problem, so print an accurate
message and return 0.

The check cannot produce false positives: the wrappers are reachable
only from do_early_param(), and hugetlb_parse_params() is called exactly
once, so once hugetlb_cmdline_consumed is set, any further recording is
by construction too late to be honored.

Not tested on parisc hardware.

Cc: Mike Rapoport (Microsoft) <rppt@xxxxxxxxxx>
Cc: Helge Deller <deller@xxxxxx>
Signed-off-by: Zhenghui Hao <zhenghui.hao@xxxxxx>
---
mm/hugetlb.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 4f6f58bf3db6..bda8af614a70 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -91,12 +91,24 @@ static char hstate_cmdline_buf[COMMAND_LINE_SIZE] __initdata;
static int hstate_cmdline_index __initdata;
static struct hugetlb_cmdline hugetlb_params[HUGE_MAX_CMDLINE_ARGS] __initdata;
static int hugetlb_param_index __initdata;
+/*
+ * Set once hugetlb_bootmem_alloc() has consumed the recorded parameters.
+ * A parameter recorded after that point can never be honored, so report it
+ * instead of dropping it silently. This happens if an architecture calls
+ * parse_early_param() only after mm_core_init_early().
+ */
+static bool hugetlb_cmdline_consumed __initdata;
static __init int hugetlb_add_param(char *s, int (*setup)(char *val));
static __init void hugetlb_parse_params(void);

#define hugetlb_early_param(str, func) \
static __init int func##args(char *s) \
{ \
+ if (hugetlb_cmdline_consumed) { \
+ pr_warn("HugeTLB: %s=%s recorded too late to be honored, ignoring\n", \
+ str, s ?: ""); \
+ return 0; \
+ } \
return hugetlb_add_param(s, func); \
} \
early_param(str, func##args)
@@ -4491,6 +4503,8 @@ void __init hugetlb_bootmem_alloc(void)
INIT_LIST_HEAD(&huge_boot_pages[i]);

hugetlb_parse_params();
+ /* Anything recorded from here on can no longer be honored. */
+ hugetlb_cmdline_consumed = true;

for_each_hstate(h) {
h->next_nid_to_alloc = first_online_node;
--
2.53.0