summaryrefslogtreecommitdiff
path: root/lib/tests
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-27 12:08:22 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-27 12:08:22 -1000
commit7d1f84f1b94e79cb95d974ab3ec54cb3a4d64f5b (patch)
tree1055fc0d54d44122acbff64e0752747a03722bf3 /lib/tests
parent83f32c773255720a661aa45d83e36278135f23f5 (diff)
parentb6232ca8d194c60ee603586e42b5ea584d4b7be9 (diff)
Merge tag 'mm-nonmm-stable-2026-10-25-14-57' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull non-MM updates from Andrew Morton: - "ocfs2: exit recovery thread on mount error path" (Joseph Qi): Stop OCFS2 recovery before freeing failed-mount state and replay slots, closing use-after-free and double-free races. Defer suballocator reclaim to break a transaction-lock deadlock with dismount. - "ocfs2: validate suballoc slot and bit of metadata blocks" (Joseph Qi): Validate OCFS2 metadata suballocator slots, bits and directory index block locations. Reject corrupt metadata with filesystem errors instead of BUGs or out-of-bounds accesses. - "ocfs2: deal with legacy signed name hash values" (Joseph Qi): Restore OCFS2 lookups for non-ASCII names stored with legacy signed hashes. Use stored xattr hashes during bucket splits to avoid duplicate entries and spurious ENOSPC failures. - "ocfs2: stabilize dentry names in file and setattr traces" (Cen Zhang): Snapshot OCFS2 names during file and setattr tracing to prevent rename races using freed storage or mismatched names and lengths. Preserve trace formats and the locked release open-count sample. - "panic: fix panic_force_cpu= redirect races and NMI bypass" (Bradley Morgan): Fix panic_force_cpu races and NMI redirection so crash-kernel CPU selection is honored. Preserve variable arguments on failed redirects and use a static message buffer. - "fat: allocate multiple clusters in fallocate" (Matheus Alves de Almeida): Allocate FAT clusters in batches for FALLOC_FL_KEEP_SIZE and batch FAT updates. This removes repeated single-cluster allocation overhead, particularly on synchronous mounts. - "scripts/gdb: fix radix tree lookup and stack depot diagnostic" (Ting-Han Hou): Fix GDB radix-tree lookup and its handling of XArray sibling, retry and zero entries. Also repair the stack-depot diagnostic for an out-of-range pool index. - "hung_task: Improve warning budget handling and task reporting" (Aaron Tomlin): Reset the hung-task warning budget after recovery so later hangs remain visible. Keep the configured limit intact and emit one summary per scan when detailed reports exhaust the budget. - "bootconfig: Reject unexpected data after null character and cleanups" (Masami Hiramatsu): Reject bootconfig data after an embedded null while accepting trailing padding. Validate the full input in the userspace tool, and retain internal tree sanity checks there rather than in the kernel. - "kbuild: GCOV cleanups following the prefer-atomic fix" (Konstantin Khorenko): Use the actual GCOV build flags in the prefer-atomic compiler probe. Move flag setup into scripts/Makefile.gcov and skip the probe when GCOV is disabled. - "ocfs2: xattr bucket validation fixes" (Joseph Qi): Accept valid OCFS2 xattr buckets spanning 512-byte blocks, avoiding false read-only remounts. Reject misaligned buckets and return errors instead of panicking on corrupt defrag metadata. - "ocfs2: fix metadata reservation for xattr value trees" (Joseph Qi): Reserve enough OCFS2 metadata for new and relocated xattr value trees. Fix shortfalls which could cause ENOSPC, dropped entries and leaked clusters on fragmented filesystems; remove duplicate reservations. - "Introduce arch_do_panic" (Mete Durlu): Add arch_do_panic() and move s390 and sparc handling out of generic panic code. The architecture-specific actions now follow the end-of-panic marker. - "checkpatch: userspace improvements" (Petr Vorel): Improve checkpatch's userspace detection and suppress kernel-only checks. Recognize standard inttypes macros and add explicit --userspace and --no-userspace overrides. - "ocfs2: validate dr_fs_generation of dir index root blocks" (Joseph Qi): Check OCFS2 directory index generations and leaf block numbers. Reject stale or misplaced blocks instead of using metadata left by a previously formatted filesystem. - "selftests/membarrier: Skip an unregistered memory barrier test on Musl" (Chris Gellermann): Skip the unregistered membarrier test when libc has already registered the command. Musl does this during thread creation, causing false failures in the multithreaded test. - "init: fix array boundary bugs in boot parameter parsing" (Wilson Felipe Pereira): Fix boot argument boundary cases which leave stale arguments in init's command line or panic when replacing the final environment variable. Clear the last slot and check duplicates before the limit. Summary of the 87 singletons in this merge: The OCFS2 singletons fix deadlocks between xattr updates and inline truncation, and during inode reclaim. Corrupt quota and extent metadata could also crash the kernel or corrupt memory; these paths now check the layout before using it. Other fixes close use-after-free and publication races around cluster reconfiguration, node failure, quota remount errors and shared refcount trees. New files now retain security labels from all stacked LSMs instead of silently dropping all but one. Valid xattr insertions also stop tripping FORTIFY on builds with counted arrays. Elsewhere, a lost wakeup could leave hardware-monitoring reads stuck in unkillable sleep and block further I2C traffic. That is fixed, as are kernel memory leaks in POSIX message-queue notifications and tmpfs casefold setup which could grow until memory is exhausted. A driver removal race which could crash the kernel is fixed too. The hibernation command through reboot() also stops taking the same mutex twice, avoiding a deadlock before suspension. On the boot side, bzip2 decoding now accepts valid full blocks emitted by lbzip2, fixing failures to boot those compressed kernels. Malformed bzip2 streams can no longer overflow the decode buffer, and LZ4 initrds are checked before the decoder can read past their end. FAT rejects geometry which overflows the data-area calculation on 32-bit systems, and rolls back entries when inode setup fails, preventing failed creations from reappearing after remount. The x86 XOR and RAID6 AVX paths also avoid imposing a slowdown on subsequent SSE code. * tag 'mm-nonmm-stable-2026-10-25-14-57' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (134 commits) scripts/gdb: fix stack depot out-of-bounds diagnostic scripts/gdb: fix radix tree lookup pointer handling ocfs2/cluster: remove zero-address nodes from IP tree on teardown ocfs2: snapshot the dentry name while tracing file release ocfs2: snapshot dentry names in file and setattr traces ocfs2/dlm: drain join handlers before releasing module text MAINTAINERS: update Markus's e-mail address mailmap: add entries for Andrew Jones stackdepot: stop preallocating after the final pool ocfs2: drain quorum work before removing the cluster watchdog: force console verbose when reporting lockups profiling: fix sampling step on 64-bit big-endian systems kernel/reboot: avoid potential deadlocks during suspension compat: avoid double rounding in times() ocfs2: pin owning modules for open debugfs files ocfs2/cluster: initialize heartbeat regions before publishing them selftests/proc: proc-pid-vm: fix unused variable warning on non-x86 ocfs2: pin refcount trees before dropping the lookup lock ocfs2: validate the xattr tree root of an indexed xattr block ocfs2/dlm: hold the lookup reference across convert AST enqueue ...
Diffstat (limited to 'lib/tests')
-rw-r--r--lib/tests/Makefile1
-rw-r--r--lib/tests/cmdline_kunit.c39
-rw-r--r--lib/tests/errseq_kunit.c237
3 files changed, 277 insertions, 0 deletions
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 5f6cf654a128..df0537e1b91f 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_BLACKHOLE_DEV_KUNIT_TEST) += blackhole_dev_kunit.o
obj-$(CONFIG_CHECKSUM_KUNIT) += checksum_kunit.o
obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o
obj-$(CONFIG_CPUMASK_KUNIT_TEST) += cpumask_kunit.o
+obj-$(CONFIG_ERRSEQ_KUNIT_TEST) += errseq_kunit.o
obj-$(CONFIG_FFS_KUNIT_TEST) += ffs_kunit.o
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced)
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-overread)
diff --git a/lib/tests/cmdline_kunit.c b/lib/tests/cmdline_kunit.c
index 3f61ff8d3178..12b85f255b65 100644
--- a/lib/tests/cmdline_kunit.c
+++ b/lib/tests/cmdline_kunit.c
@@ -140,6 +140,44 @@ static void cmdline_test_range(struct kunit *test)
} while (++i < ARRAY_SIZE(cmdline_test_range_strings));
}
+static const struct {
+ const char *in;
+ int parsed[4];
+ int validated;
+} cmdline_test_range_overflow_cases[] = {
+ { "1-100", { 3, 1, 2, 3, }, 100, },
+ { "1,5-100,7", { 3, 1, 5, 6, }, 98, },
+ { "1-2147483646", { 3, 1, 2, 3, }, 2147483646, },
+ { "0-2147483647", { 3, 0, 1, 2, }, 0, },
+ { "-5-2147483647", { 3, -5, -4, -3, }, 0, },
+ { "2147483647--5", { 0, 2147483647, }, 0, },
+ { "1,0-2147483647", { 3, 1, 0, 1, }, 1, },
+};
+
+static void cmdline_test_range_overflow(struct kunit *test)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(cmdline_test_range_overflow_cases); i++) {
+ const char *in = cmdline_test_range_overflow_cases[i].in;
+ const int *e = cmdline_test_range_overflow_cases[i].parsed;
+ /* Two guard elements past the array handed to get_options() */
+ int r[ARRAY_SIZE(cmdline_test_range_overflow_cases[0].parsed) + 2];
+ int n;
+
+ memset(r, 0, sizeof(r));
+ get_options(in, ARRAY_SIZE(r) - 2, r);
+ for (j = 0; j < ARRAY_SIZE(r) - 2; j++)
+ KUNIT_EXPECT_EQ_MSG(test, r[j], e[j], "Pattern: %s at %u", in, j);
+ for (; j < ARRAY_SIZE(r); j++)
+ KUNIT_EXPECT_EQ_MSG(test, r[j], 0, "Pattern: %s out of bound at %u", in, j);
+
+ get_options(in, 0, &n);
+ KUNIT_EXPECT_EQ_MSG(test, n, cmdline_test_range_overflow_cases[i].validated,
+ "Pattern: %s (validated)", in);
+ }
+}
+
static void cmdline_test_next_arg_quoted_value(struct kunit *test)
{
char in[] = "foo=\"bar baz\" qux=1";
@@ -258,6 +296,7 @@ static struct kunit_case cmdline_test_cases[] = {
KUNIT_CASE(cmdline_test_lead_int),
KUNIT_CASE(cmdline_test_tail_int),
KUNIT_CASE(cmdline_test_range),
+ KUNIT_CASE(cmdline_test_range_overflow),
KUNIT_CASE(cmdline_test_next_arg_quoted_value),
KUNIT_CASE(cmdline_test_next_arg_bare_quote_regression),
KUNIT_CASE(cmdline_test_next_arg_mixed_tokens),
diff --git a/lib/tests/errseq_kunit.c b/lib/tests/errseq_kunit.c
new file mode 100644
index 000000000000..8f39ebc4a248
--- /dev/null
+++ b/lib/tests/errseq_kunit.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit tests for the errseq_t error-tracking infrastructure.
+ *
+ * These exercise the documented single-threaded semantics of the errseq
+ * API (see Documentation/core-api/errseq.rst and lib/errseq.c): error
+ * recording and overwriting, the "seen" handoff between errseq_sample()
+ * and errseq_check_and_advance(), and the re-reporting of an error that
+ * is recorded again after it has been seen.
+ *
+ * The lockless properties of errseq_t under concurrent updates are
+ * outside the scope of these deterministic tests, as is the WARN path
+ * for invalid error values.
+ */
+#include <kunit/test.h>
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/errseq.h>
+
+/*
+ * A zeroed errseq_t is the "no error has ever occurred" epoch: it
+ * samples as zero and no check against it reports anything.
+ */
+static void errseq_test_zero_epoch_reports_no_error(struct kunit *test)
+{
+ errseq_t eseq = 0;
+ errseq_t since = 0;
+
+ KUNIT_EXPECT_EQ(test, errseq_sample(&eseq), 0);
+ KUNIT_EXPECT_EQ(test, errseq_check(&eseq, 0), 0);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), 0);
+ KUNIT_EXPECT_EQ(test, since, 0);
+}
+
+static void errseq_test_set_records_error(struct kunit *test)
+{
+ errseq_t eseq = 0;
+
+ /* errseq_set() returns the previous value; the epoch is zero. */
+ KUNIT_EXPECT_EQ(test, errseq_set(&eseq, -EIO), 0);
+ KUNIT_EXPECT_EQ(test, errseq_check(&eseq, 0), -EIO);
+}
+
+/* Any error set always overwrites an existing error. */
+static void errseq_test_set_overwrites_error(struct kunit *test)
+{
+ errseq_t eseq = 0;
+
+ errseq_set(&eseq, -EIO);
+ errseq_set(&eseq, -ENOSPC);
+ KUNIT_EXPECT_EQ(test, errseq_check(&eseq, 0), -ENOSPC);
+}
+
+/* Both ends of the valid error range are recorded exactly. */
+static void errseq_test_errno_range_extremes(struct kunit *test)
+{
+ errseq_t lo = 0;
+ errseq_t hi = 0;
+
+ errseq_set(&lo, -1);
+ KUNIT_EXPECT_EQ(test, errseq_check(&lo, 0), -1);
+
+ errseq_set(&hi, -MAX_ERRNO);
+ KUNIT_EXPECT_EQ(test, errseq_check(&hi, 0), -MAX_ERRNO);
+}
+
+/*
+ * An error nobody has seen yet samples as zero, so that a check against
+ * the sample still reports it (see commit b4678df184b3 ("errseq: Always
+ * report a writeback error once")).
+ */
+static void errseq_test_sample_of_unseen_error_is_zero(struct kunit *test)
+{
+ errseq_t eseq = 0;
+
+ errseq_set(&eseq, -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_sample(&eseq), 0);
+}
+
+static void errseq_test_new_sampler_sees_unseen_error(struct kunit *test)
+{
+ errseq_t eseq = 0;
+ errseq_t since;
+
+ errseq_set(&eseq, -EIO);
+ since = errseq_sample(&eseq);
+ KUNIT_EXPECT_EQ(test, errseq_check(&eseq, since), -EIO);
+}
+
+/* A given error is reported exactly once per advancing cursor. */
+static void errseq_test_check_and_advance_reports_once(struct kunit *test)
+{
+ errseq_t eseq = 0;
+ errseq_t since = errseq_sample(&eseq);
+
+ errseq_set(&eseq, -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), 0);
+}
+
+/*
+ * Once an error has been seen, a fresh sample is non-zero and checking
+ * against it reports nothing: handled errors do not reach new samplers.
+ */
+static void errseq_test_sample_after_seen_is_current(struct kunit *test)
+{
+ errseq_t eseq = 0;
+ errseq_t since = 0;
+ errseq_t sample;
+
+ errseq_set(&eseq, -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
+
+ sample = errseq_sample(&eseq);
+ KUNIT_EXPECT_NE(test, sample, 0);
+ KUNIT_EXPECT_EQ(test, errseq_check(&eseq, sample), 0);
+}
+
+static void errseq_test_new_error_after_advance(struct kunit *test)
+{
+ errseq_t eseq = 0;
+ errseq_t since = 0;
+
+ errseq_set(&eseq, -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
+
+ errseq_set(&eseq, -ENOSPC);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -ENOSPC);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), 0);
+}
+
+/*
+ * Recording the same error again after it has been seen must bump the
+ * sequence, so cursors that consumed the first occurrence see the
+ * second one too.
+ */
+static void errseq_test_same_error_reported_again_after_seen(struct kunit *test)
+{
+ errseq_t eseq = 0;
+ errseq_t since = 0;
+ errseq_t seen_cursor;
+
+ errseq_set(&eseq, -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
+
+ seen_cursor = since;
+ errseq_set(&eseq, -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check(&eseq, since), -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
+ /* The repeat must advance the sequence, not just re-toggle "seen". */
+ KUNIT_EXPECT_NE(test, since, seen_cursor);
+}
+
+/*
+ * A cursor that consumed an error must still observe a repeat of that
+ * error even when another cursor has already marked the repeat seen:
+ * recording over a seen value must advance the sequence.
+ */
+static void errseq_test_repeat_error_visible_to_all_cursors(struct kunit *test)
+{
+ errseq_t eseq = 0;
+ errseq_t cursor_a = 0;
+ errseq_t cursor_b = 0;
+
+ errseq_set(&eseq, -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), -EIO);
+
+ errseq_set(&eseq, -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_b), -EIO);
+
+ KUNIT_EXPECT_EQ(test, errseq_check(&eseq, cursor_a), -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), 0);
+}
+
+/* An advance with no new error reports nothing and leaves the cursor put. */
+static void errseq_test_advance_stable_when_unchanged(struct kunit *test)
+{
+ errseq_t eseq = 0;
+ errseq_t since = 0;
+ errseq_t cursor;
+
+ errseq_set(&eseq, -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
+
+ cursor = since;
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), 0);
+ KUNIT_EXPECT_EQ(test, since, cursor);
+}
+
+/*
+ * Cursors are independent: one subscriber consuming an error does not
+ * consume it for another, and each subscriber sees each error once.
+ */
+static void errseq_test_two_subscribers_independent(struct kunit *test)
+{
+ errseq_t eseq = 0;
+ errseq_t cursor_a = errseq_sample(&eseq);
+ errseq_t cursor_b = errseq_sample(&eseq);
+
+ errseq_set(&eseq, -EIO);
+
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check(&eseq, cursor_b), -EIO);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_b), -EIO);
+
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), 0);
+ KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_b), 0);
+}
+
+static struct kunit_case errseq_test_cases[] = {
+ KUNIT_CASE(errseq_test_zero_epoch_reports_no_error),
+ KUNIT_CASE(errseq_test_set_records_error),
+ KUNIT_CASE(errseq_test_set_overwrites_error),
+ KUNIT_CASE(errseq_test_errno_range_extremes),
+ KUNIT_CASE(errseq_test_sample_of_unseen_error_is_zero),
+ KUNIT_CASE(errseq_test_new_sampler_sees_unseen_error),
+ KUNIT_CASE(errseq_test_check_and_advance_reports_once),
+ KUNIT_CASE(errseq_test_sample_after_seen_is_current),
+ KUNIT_CASE(errseq_test_new_error_after_advance),
+ KUNIT_CASE(errseq_test_same_error_reported_again_after_seen),
+ KUNIT_CASE(errseq_test_repeat_error_visible_to_all_cursors),
+ KUNIT_CASE(errseq_test_advance_stable_when_unchanged),
+ KUNIT_CASE(errseq_test_two_subscribers_independent),
+ {}
+};
+
+static struct kunit_suite errseq_test_suite = {
+ .name = "errseq",
+ .test_cases = errseq_test_cases,
+};
+
+kunit_test_suite(errseq_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for the errseq infrastructure");
+MODULE_LICENSE("GPL");