kernel/panic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
The verbose 'Tainted: ...' string in print_tainted_seq
can total to 327 characters while the buffer defined in
_print_tainted is 320 bytes. Increase its size to 350
characters to hold all flags, along with some headroom.
Signed-off-by: Rio <rioo.tsukatsukii@gmail.com>
---
kernel/panic.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/kernel/panic.c b/kernel/panic.c
index c78600212b6c..42b03fdd6ffa 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -854,10 +854,12 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
}
}
+/* 350 can accomadate all taint flags in verbose mode, with some headroom */
+#define TAINT_BUF_MAX 350
+
static const char *_print_tainted(bool verbose)
{
- /* FIXME: what should the size be? */
- static char buf[sizeof(taint_flags)];
+ static char buf[TAINT_BUF_MAX];
struct seq_buf s;
BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
--
2.52.0
On Fri, 20 Feb 2026 20:45:00 +0530 Rio <rioo.tsukatsukii@gmail.com> wrote:
> The verbose 'Tainted: ...' string in print_tainted_seq
> can total to 327 characters while the buffer defined in
> _print_tainted is 320 bytes. Increase its size to 350
> characters to hold all flags, along with some headroom.
>
> ...
>
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -854,10 +854,12 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
> }
> }
>
> +/* 350 can accomadate all taint flags in verbose mode, with some headroom */
"accommodate". I'll fix this.
> +#define TAINT_BUF_MAX 350
> +
> static const char *_print_tainted(bool verbose)
> {
> - /* FIXME: what should the size be? */
> - static char buf[sizeof(taint_flags)];
Well that was weird.
> + static char buf[TAINT_BUF_MAX];
Can you think of a way to do this more flexibly? Something which
scales as we add more flags?
Probably not, as it's dependent upon the length of the various
taint_flags.desc strings.
> struct seq_buf s;
>
> BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
How does this look?
--- a/kernel/panic.c~kernel-panic-increase-buffer-size-for-verbose-taint-logging-fix
+++ a/kernel/panic.c
@@ -801,6 +801,8 @@ EXPORT_SYMBOL(panic);
* Documentation/admin-guide/tainted-kernels.rst, including its
* small shell script that prints the TAINT_FLAGS_COUNT bits of
* /proc/sys/kernel/tainted.
+ *
+ * Also, update TAINT_BUF_MAX below.
*/
const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
TAINT_FLAG(PROPRIETARY_MODULE, 'P', 'G'),
@@ -854,7 +856,7 @@ static void print_tainted_seq(struct seq
}
}
-/* 350 can accomadate all taint flags in verbose mode, with some headroom */
+/* 350 can accommodate all taint flags in verbose mode, with some headroom */
#define TAINT_BUF_MAX 350
static const char *_print_tainted(bool verbose)
_
> "accommodate". I'll fix this. Thanks > How does this look? > + * > + * Also, update TAINT_BUF_MAX below. > */ > ... > -/* 350 can accomadate all taint flags in verbose mode, with some headroom */ > +/* 350 can accommodate all taint flags in verbose mode, with some headroom */ > #define TAINT_BUF_MAX 350 Looks good, though it might help future maintainers if we document the current maximum length of the verbose string (excluding the trailing NULL). Happy to send a small follow-up patch if needed.
On Sat, 21 Feb 2026 12:26:03 +0530 Rio <rioo.tsukatsukii@gmail.com> wrote: > > "accommodate". I'll fix this. > > Thanks > > > How does this look? > > > + * > > + * Also, update TAINT_BUF_MAX below. > > */ > > ... > > -/* 350 can accomadate all taint flags in verbose mode, with some headroom */ > > +/* 350 can accommodate all taint flags in verbose mode, with some headroom */ > > #define TAINT_BUF_MAX 350 > > Looks good, though it might help future maintainers if we document the current > maximum length of the verbose string (excluding the trailing NULL). Happy to > send a small follow-up patch if needed. OK, how about this idea. - Allocating static storage is annoying: dynamic allocation is better - Now knowing how large to make the storage is also annoying. So: - define a static buffer, mark it __initdata so it gets released later in boot. Make print_tainted() use that, initially, so print_tainted() is available at initial bootup time. - write a new __init function which adds up all string lengths in taint_flags[] and calculates the precise maximum needed buffer size. Allocate that much memory (kmalloc) and switch print_tainted() over to using that buffer. - When __init data gets released, the initial static buffer and the new __init function get thrown away.
The buffer used to hold the taint string is statically allocated, which
requires updating whenever a new taint flag is added.
Instead, allocate the exact required length at boot once the allocator is
available in an init function. The allocation sums the string lengths in
taint_flags[], along with space for separators and formatting.
print_tainted() is switched to use this dynamically allocated buffer.
If allocation fails, print_tainted() warns about the failure and continues
to use the original static buffer as a fallback.
Signed-off-by: Rio <rioo.tsukatsukii@gmail.com>
---
V1 -> V2: Allocate taint string buffer dynamically during init
v1: https://lore.kernel.org/all/20260220151500.13585-1-rioo.tsukatsukii@gmail.com/
kernel/panic.c | 51 +++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 46 insertions(+), 5 deletions(-)
diff --git a/kernel/panic.c b/kernel/panic.c
index 75368738d32d..5d498ff8a18b 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -802,7 +802,7 @@ EXPORT_SYMBOL(panic);
* small shell script that prints the TAINT_FLAGS_COUNT bits of
* /proc/sys/kernel/tainted.
*
- * Also, update TAINT_BUF_MAX below.
+ * Also, update INIT_TAINT_BUF_MAX below.
*/
const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
TAINT_FLAG(PROPRIETARY_MODULE, 'P', 'G'),
@@ -856,17 +856,58 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
}
}
-/* 350 can accommodate all taint flags in verbose mode, with some headroom */
-#define TAINT_BUF_MAX 350
+/* The initial buffer can accommodate all taint flags in verbose
+ * mode, with some headroom. Once the allocator is available, the
+ * exact size is allocated dynamically; the initial buffer remains
+ * as a fallback if allocation fails.
+ *
+ * The verbose taint string currently requires up to 327 characters.
+ */
+#define INIT_TAINT_BUF_MAX 350
+
+static char init_taint_buf[INIT_TAINT_BUF_MAX];
+static char *taint_buf = init_taint_buf;
+static size_t taint_buf_size = INIT_TAINT_BUF_MAX;
+
+static __init int alloc_taint_buf(void)
+{
+ int i;
+ char *buf;
+ size_t size = 0;
+
+ size += sizeof("Tainted: ") - 1;
+ for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
+ size += 2; /* For ", " */
+ size += 4; /* For "[%c]=" */
+ size += strlen(taint_flags[i].desc);
+ }
+
+ size += 1; /* For NULL terminator */
+
+ buf = kmalloc(size, GFP_KERNEL);
+
+ if (!buf) {
+ /* Allocation may fail; this warning explains possibly
+ * truncated taint strings
+ */
+ pr_warn_once("taint string buffer allocation failed, using fallback buffer\n");
+ return 0;
+ }
+
+ taint_buf = buf;
+ taint_buf_size = size;
+
+ return 0;
+}
+postcore_initcall(alloc_taint_buf);
static const char *_print_tainted(bool verbose)
{
- static char buf[TAINT_BUF_MAX];
struct seq_buf s;
BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
- seq_buf_init(&s, buf, sizeof(buf));
+ seq_buf_init(&s, taint_buf, taint_buf_size);
print_tainted_seq(&s, verbose);
--
2.52.0
On Sun, 22 Feb 2026 19:38:04 +0530 Rio <rioo.tsukatsukii@gmail.com> wrote:
> The buffer used to hold the taint string is statically allocated, which
> requires updating whenever a new taint flag is added.
>
> Instead, allocate the exact required length at boot once the allocator is
> available in an init function. The allocation sums the string lengths in
> taint_flags[], along with space for separators and formatting.
> print_tainted() is switched to use this dynamically allocated buffer.
>
> If allocation fails, print_tainted() warns about the failure and continues
> to use the original static buffer as a fallback.
>
Lovely, thanks.
>
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -802,7 +802,7 @@ EXPORT_SYMBOL(panic);
> * small shell script that prints the TAINT_FLAGS_COUNT bits of
> * /proc/sys/kernel/tainted.
> *
> - * Also, update TAINT_BUF_MAX below.
> + * Also, update INIT_TAINT_BUF_MAX below.
> */
> const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
> TAINT_FLAG(PROPRIETARY_MODULE, 'P', 'G'),
> @@ -856,17 +856,58 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
> }
> }
>
> -/* 350 can accommodate all taint flags in verbose mode, with some headroom */
> -#define TAINT_BUF_MAX 350
> +/* The initial buffer can accommodate all taint flags in verbose
> + * mode, with some headroom. Once the allocator is available, the
> + * exact size is allocated dynamically; the initial buffer remains
> + * as a fallback if allocation fails.
> + *
> + * The verbose taint string currently requires up to 327 characters.
> + */
> +#define INIT_TAINT_BUF_MAX 350
> +
> +static char init_taint_buf[INIT_TAINT_BUF_MAX];
OK, this cannot be __initdata because
> +static char *taint_buf = init_taint_buf;
> +static size_t taint_buf_size = INIT_TAINT_BUF_MAX;
> +
> +static __init int alloc_taint_buf(void)
> +{
> + int i;
> + char *buf;
> + size_t size = 0;
> +
> + size += sizeof("Tainted: ") - 1;
> + for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
> + size += 2; /* For ", " */
> + size += 4; /* For "[%c]=" */
> + size += strlen(taint_flags[i].desc);
> + }
> +
> + size += 1; /* For NULL terminator */
> +
> + buf = kmalloc(size, GFP_KERNEL);
> +
> + if (!buf) {
> + /* Allocation may fail; this warning explains possibly
> + * truncated taint strings
> + */
> + pr_warn_once("taint string buffer allocation failed, using fallback buffer\n");
> + return 0;
We may end up using it after boot time.
> + }
> +
> + taint_buf = buf;
> + taint_buf_size = size;
> +
> + return 0;
> +}
> +postcore_initcall(alloc_taint_buf);
However there's a convention of assuming that __init-time allocations
cannot fail. Because if a kmalloc() were to fail at this time, the
kernel is hopelessly messed up anyway.
So we could simply panic() if that kmalloc failed, then make that
350-byte buffer __initdata.
That saves about $100 per machine with current DRAM prices ;)
This follow-up provides some tradeoffs between v1 and v2 - v1 used a fixed-size static buffer, requiring manual updates whenever new strings are added to taint_flags[]. - v2 uses a fixed-size static buffer only for initial boot. Once kmalloc is available, it allocates a dynamically sized buffer based on the total length of strings in taint_flags[]. - v1 needs an update every time taint_flags[] is updated. - v2 relies on the initial buffer as a fallback mechanism in case kmalloc fails. The initial buffer is currently large enough for all taint strings, but future updates to taint_flags[] may require adjustments. - v1 is more predictable, but requires more manual maintenance. - v2 is more convenient, but introduces subtle edge cases and potential allocation issues.
On Sun, Feb 22, 2026 at 11:25:52AM -0800, Andrew Morton wrote:
> However there's a convention of assuming that __init-time allocations
> cannot fail. Because if a kmalloc() were to fail at this time, the
> kernel is hopelessly messed up anyway.
> So we could simply panic() if that kmalloc failed, then make that
> 350-byte buffer __initdata.
Ah, got it. I made it __initdata, and replaced the warn with panic.
> That saves about $100 per machine with current DRAM prices ;)
Haha, saving every bit counts huh
Signed-off-by: Rio <rioo.tsukatsukii@gmail.com>
---
V2 -> V3: Mark initial buffer as __initdata and panic if allocation
fails
V1 -> V2: Allocate taint string buffer dynamically during init
v2: https://lore.kernel.org/all/20260222140804.22225-1-rioo.tsukatsukii@gmail.com/
v1: https://lore.kernel.org/all/20260220151500.13585-1-rioo.tsukatsukii@gmail.com/
kernel/panic.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/kernel/panic.c b/kernel/panic.c
index 5d498ff8a18b..20feada5319d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -865,8 +865,8 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
*/
#define INIT_TAINT_BUF_MAX 350
-static char init_taint_buf[INIT_TAINT_BUF_MAX];
-static char *taint_buf = init_taint_buf;
+static char init_taint_buf[INIT_TAINT_BUF_MAX] __initdata;
+static char *taint_buf __refdata = init_taint_buf;
static size_t taint_buf_size = INIT_TAINT_BUF_MAX;
static __init int alloc_taint_buf(void)
@@ -887,11 +887,7 @@ static __init int alloc_taint_buf(void)
buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
- /* Allocation may fail; this warning explains possibly
- * truncated taint strings
- */
- pr_warn_once("taint string buffer allocation failed, using fallback buffer\n");
- return 0;
+ panic("Failed to allocate taint string buffer");
}
taint_buf = buf;
--
2.52.0
© 2016 - 2026 Red Hat, Inc.