All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] lib/tests: add KUnit tests for errseq
@ 2026-08-12 18:55 ` Thomas Maarseveen
  0 siblings, 0 replies; 4+ messages in thread
From: Thomas Maarseveen via B4 Relay @ 2026-08-12 18:55 UTC (permalink / raw)
  To: Jeff Layton, Andrew Morton
  Cc: David Gow, kunit-dev, linux-kselftest, linux-kernel,
	Thomas Maarseveen

From: Thomas Maarseveen <maarseveent@gmail.com>

The errseq_t infrastructure (lib/errseq.c) underpins writeback error
reporting but has no regression tests. Its semantics are subtle enough
to have needed fixing before: commit b4678df184b3 ("errseq: Always
report a writeback error once") changed how unseen errors reach new
samplers.

Add a KUnit suite covering the documented single-threaded semantics:

 - a zeroed errseq_t is the "no error yet" epoch
 - errors are recorded, overwrite one another, and both ends of the
   valid errno range round-trip exactly
 - an error nobody has seen samples as zero, so a check against a
   fresh sample still reports it
 - errseq_check_and_advance() reports a given error exactly once per
   cursor and leaves the cursor in place when nothing has changed
 - once an error has been seen, a fresh sample is current and a check
   against it reports nothing
 - the same error recorded again after being seen is reported again,
   even to a cursor that consumed the first occurrence while another
   cursor marked the repeat as seen
 - independent cursors each observe each error

The lockless behaviour of errseq_t under concurrent updates and the
WARN path for invalid error values are deliberately out of scope.

Tested with ./tools/testing/kunit/kunit.py run, with a kunitconfig
enabling CONFIG_KUNIT=y and CONFIG_ERRSEQ_KUNIT_TEST=y; all 13 tests
pass under ARCH=um.

Signed-off-by: Thomas Maarseveen <maarseveent@gmail.com>
---
Single patch adding the first KUnit suite for lib/errseq.c.
(Cover not sent for a single-patch series; trailers below drive
the recipients.)
---
 MAINTAINERS              |   1 +
 lib/Kconfig.debug        |  15 +++
 lib/tests/Makefile       |   1 +
 lib/tests/errseq_kunit.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 254 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8014b9f8253edf15231df215d1b14063a54a55ec..70de54372c4f8f12b2431e693cb3b0b5ec5fdfc9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9624,6 +9624,7 @@ M:	Jeff Layton <jlayton@kernel.org>
 S:	Maintained
 F:	include/linux/errseq.h
 F:	lib/errseq.c
+F:	lib/tests/errseq_kunit.c
 
 ESD CAN NETWORK DRIVERS
 M:	Stefan Mätje <stefan.maetje@esd.eu>
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 1244dcac2294ad99fda37fa6767c9e76f16a4d14..3f1a7103328678926dd82620349957fdede32ee4 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2826,6 +2826,21 @@ config SYSCTL_KUNIT_TEST
 
 	  If unsure, say N.
 
+config ERRSEQ_KUNIT_TEST
+	tristate "KUnit test for errseq" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  This builds the errseq KUnit test suite.
+	  It tests the documented semantics of the errseq_t error-tracking
+	  infrastructure (lib/errseq.c), which underpins writeback error
+	  reporting.
+
+	  For more information on KUnit and unit tests in general please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N.
+
 config KFIFO_KUNIT_TEST
 	tristate "KUnit Test for the generic kernel FIFO implementation" if !KUNIT_ALL_TESTS
 	depends on KUNIT
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 4ead57602eac468e1b9b8148593dc8c41ddc5779..a1e69b2c4318ae03f7834ba41414caf986997f02 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -13,6 +13,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/errseq_kunit.c b/lib/tests/errseq_kunit.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f39ebc4a2488e564efe216883008b0d96a75fe6
--- /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");

---
base-commit: 3d6d817622b0a9721e3cc404df3469171582be13
change-id: 20260812-errseq-kunit-1f1328fbcee1

Best regards,
-- 
Thomas Maarseveen <maarseveent@gmail.com>



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH] lib/tests: add KUnit tests for errseq
@ 2026-08-12 18:55 ` Thomas Maarseveen
  0 siblings, 0 replies; 4+ messages in thread
From: Thomas Maarseveen @ 2026-08-12 18:55 UTC (permalink / raw)
  To: Jeff Layton, Andrew Morton
  Cc: David Gow, kunit-dev, linux-kselftest, linux-kernel,
	Thomas Maarseveen

The errseq_t infrastructure (lib/errseq.c) underpins writeback error
reporting but has no regression tests. Its semantics are subtle enough
to have needed fixing before: commit b4678df184b3 ("errseq: Always
report a writeback error once") changed how unseen errors reach new
samplers.

Add a KUnit suite covering the documented single-threaded semantics:

 - a zeroed errseq_t is the "no error yet" epoch
 - errors are recorded, overwrite one another, and both ends of the
   valid errno range round-trip exactly
 - an error nobody has seen samples as zero, so a check against a
   fresh sample still reports it
 - errseq_check_and_advance() reports a given error exactly once per
   cursor and leaves the cursor in place when nothing has changed
 - once an error has been seen, a fresh sample is current and a check
   against it reports nothing
 - the same error recorded again after being seen is reported again,
   even to a cursor that consumed the first occurrence while another
   cursor marked the repeat as seen
 - independent cursors each observe each error

The lockless behaviour of errseq_t under concurrent updates and the
WARN path for invalid error values are deliberately out of scope.

Tested with ./tools/testing/kunit/kunit.py run, with a kunitconfig
enabling CONFIG_KUNIT=y and CONFIG_ERRSEQ_KUNIT_TEST=y; all 13 tests
pass under ARCH=um.

Signed-off-by: Thomas Maarseveen <maarseveent@gmail.com>
---
Single patch adding the first KUnit suite for lib/errseq.c.
(Cover not sent for a single-patch series; trailers below drive
the recipients.)
---
 MAINTAINERS              |   1 +
 lib/Kconfig.debug        |  15 +++
 lib/tests/Makefile       |   1 +
 lib/tests/errseq_kunit.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 254 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8014b9f8253edf15231df215d1b14063a54a55ec..70de54372c4f8f12b2431e693cb3b0b5ec5fdfc9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9624,6 +9624,7 @@ M:	Jeff Layton <jlayton@kernel.org>
 S:	Maintained
 F:	include/linux/errseq.h
 F:	lib/errseq.c
+F:	lib/tests/errseq_kunit.c
 
 ESD CAN NETWORK DRIVERS
 M:	Stefan Mätje <stefan.maetje@esd.eu>
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 1244dcac2294ad99fda37fa6767c9e76f16a4d14..3f1a7103328678926dd82620349957fdede32ee4 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2826,6 +2826,21 @@ config SYSCTL_KUNIT_TEST
 
 	  If unsure, say N.
 
+config ERRSEQ_KUNIT_TEST
+	tristate "KUnit test for errseq" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  This builds the errseq KUnit test suite.
+	  It tests the documented semantics of the errseq_t error-tracking
+	  infrastructure (lib/errseq.c), which underpins writeback error
+	  reporting.
+
+	  For more information on KUnit and unit tests in general please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N.
+
 config KFIFO_KUNIT_TEST
 	tristate "KUnit Test for the generic kernel FIFO implementation" if !KUNIT_ALL_TESTS
 	depends on KUNIT
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 4ead57602eac468e1b9b8148593dc8c41ddc5779..a1e69b2c4318ae03f7834ba41414caf986997f02 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -13,6 +13,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/errseq_kunit.c b/lib/tests/errseq_kunit.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f39ebc4a2488e564efe216883008b0d96a75fe6
--- /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");

---
base-commit: 3d6d817622b0a9721e3cc404df3469171582be13
change-id: 20260812-errseq-kunit-1f1328fbcee1

Best regards,
-- 
Thomas Maarseveen <maarseveent@gmail.com>


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] lib/tests: add KUnit tests for errseq
  2026-08-12 18:55 ` Thomas Maarseveen
  (?)
@ 2026-08-12 19:14 ` Jeff Layton
  -1 siblings, 0 replies; 4+ messages in thread
From: Jeff Layton @ 2026-08-12 19:14 UTC (permalink / raw)
  To: maarseveent, Andrew Morton
  Cc: David Gow, kunit-dev, linux-kselftest, linux-kernel

On Wed, 2026-08-12 at 20:55 +0200, Thomas Maarseveen via B4 Relay
wrote:
> From: Thomas Maarseveen <maarseveent@gmail.com>
> 
> The errseq_t infrastructure (lib/errseq.c) underpins writeback error
> reporting but has no regression tests. Its semantics are subtle enough
> to have needed fixing before: commit b4678df184b3 ("errseq: Always
> report a writeback error once") changed how unseen errors reach new
> samplers.
> 
> Add a KUnit suite covering the documented single-threaded semantics:
> 
>  - a zeroed errseq_t is the "no error yet" epoch
>  - errors are recorded, overwrite one another, and both ends of the
>    valid errno range round-trip exactly
>  - an error nobody has seen samples as zero, so a check against a
>    fresh sample still reports it
>  - errseq_check_and_advance() reports a given error exactly once per
>    cursor and leaves the cursor in place when nothing has changed
>  - once an error has been seen, a fresh sample is current and a check
>    against it reports nothing
>  - the same error recorded again after being seen is reported again,
>    even to a cursor that consumed the first occurrence while another
>    cursor marked the repeat as seen
>  - independent cursors each observe each error
> 
> The lockless behaviour of errseq_t under concurrent updates and the
> WARN path for invalid error values are deliberately out of scope.
> 
> Tested with ./tools/testing/kunit/kunit.py run, with a kunitconfig
> enabling CONFIG_KUNIT=y and CONFIG_ERRSEQ_KUNIT_TEST=y; all 13 tests
> pass under ARCH=um.
> 
> Signed-off-by: Thomas Maarseveen <maarseveent@gmail.com>
> ---
> Single patch adding the first KUnit suite for lib/errseq.c.
> (Cover not sent for a single-patch series; trailers below drive
> the recipients.)
> ---
>  MAINTAINERS              |   1 +
>  lib/Kconfig.debug        |  15 +++
>  lib/tests/Makefile       |   1 +
>  lib/tests/errseq_kunit.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 254 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8014b9f8253edf15231df215d1b14063a54a55ec..70de54372c4f8f12b2431e693cb3b0b5ec5fdfc9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -9624,6 +9624,7 @@ M:	Jeff Layton <jlayton@kernel.org>
>  S:	Maintained
>  F:	include/linux/errseq.h
>  F:	lib/errseq.c
> +F:	lib/tests/errseq_kunit.c
>  
>  ESD CAN NETWORK DRIVERS
>  M:	Stefan Mätje <stefan.maetje@esd.eu>
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 1244dcac2294ad99fda37fa6767c9e76f16a4d14..3f1a7103328678926dd82620349957fdede32ee4 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2826,6 +2826,21 @@ config SYSCTL_KUNIT_TEST
>  
>  	  If unsure, say N.
>  
> +config ERRSEQ_KUNIT_TEST
> +	tristate "KUnit test for errseq" if !KUNIT_ALL_TESTS
> +	depends on KUNIT
> +	default KUNIT_ALL_TESTS
> +	help
> +	  This builds the errseq KUnit test suite.
> +	  It tests the documented semantics of the errseq_t error-tracking
> +	  infrastructure (lib/errseq.c), which underpins writeback error
> +	  reporting.
> +
> +	  For more information on KUnit and unit tests in general please refer
> +	  to the KUnit documentation in Documentation/dev-tools/kunit/.
> +
> +	  If unsure, say N.
> +
>  config KFIFO_KUNIT_TEST
>  	tristate "KUnit Test for the generic kernel FIFO implementation" if !KUNIT_ALL_TESTS
>  	depends on KUNIT
> diff --git a/lib/tests/Makefile b/lib/tests/Makefile
> index 4ead57602eac468e1b9b8148593dc8c41ddc5779..a1e69b2c4318ae03f7834ba41414caf986997f02 100644
> --- a/lib/tests/Makefile
> +++ b/lib/tests/Makefile
> @@ -13,6 +13,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/errseq_kunit.c b/lib/tests/errseq_kunit.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..8f39ebc4a2488e564efe216883008b0d96a75fe6
> --- /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");
> 

Sounds like a good idea.

Acked-by: Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] lib/tests: add KUnit tests for errseq
  2026-08-12 18:55 ` Thomas Maarseveen
  (?)
  (?)
@ 2026-08-12 21:25 ` Andrew Morton
  -1 siblings, 0 replies; 4+ messages in thread
From: Andrew Morton @ 2026-08-12 21:25 UTC (permalink / raw)
  To: maarseveent
  Cc: Thomas Maarseveen via B4 Relay, Jeff Layton, David Gow, kunit-dev,
	linux-kselftest, linux-kernel

On Wed, 12 Aug 2026 20:55:33 +0200 Thomas Maarseveen via B4 Relay <devnull+maarseveent.gmail.com@kernel.org> wrote:

> The errseq_t infrastructure (lib/errseq.c) underpins writeback error
> reporting but has no regression tests. Its semantics are subtle enough
> to have needed fixing before: commit b4678df184b3 ("errseq: Always
> report a writeback error once") changed how unseen errors reach new
> samplers.
> 
> Add a KUnit suite covering the documented single-threaded semantics:

Thanks.  I'll set this aside for additional consideration after
7.3-rc1.


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-12 21:25 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-12 18:55 [PATCH] lib/tests: add KUnit tests for errseq Thomas Maarseveen via B4 Relay
2026-08-12 18:55 ` Thomas Maarseveen
2026-08-12 19:14 ` Jeff Layton
2026-08-12 21:25 ` Andrew Morton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.