public inbox for linux-doc@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: akpm@linux-foundation.org, david@kernel.org, corbet@lwn.net
Cc: ljs@kernel.org, Liam.Howlett@oracle.com, vbabka@kernel.org,
	rppt@kernel.org, surenb@google.com, mhocko@suse.com,
	skhan@linuxfoundation.org, jackmanb@google.com,
	hannes@cmpxchg.org, ziy@nvidia.com, linux-mm@kvack.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	Sasha Levin <sashal@nvidia.com>,
	Sanif Veeras <sveeras@nvidia.com>,
	"Claude:claude-opus-4-7" <noreply@anthropic.com>
Subject: [RFC 7/7] mm/page_consistency: add KUnit tests for dual-bitmap primitives
Date: Fri, 24 Apr 2026 10:00:56 -0400	[thread overview]
Message-ID: <20260424140056.2094777-8-sashal@kernel.org> (raw)
In-Reply-To: <20260424140056.2094777-1-sashal@kernel.org>

From: Sasha Levin <sashal@nvidia.com>

Add a KUnit test suite that exercises the dual-bitmap algorithm used by
the page consistency checker. The tests verify that the core invariant
is maintained through various operations and that corruption can be
reliably detected.

The test suite covers several scenarios. The initial-state test confirms
that a freshly initialized dual bitmap with zeroed primary and filled
secondary passes validation. The set and clear tests verify that normal
operations maintain the complementary relationship between bitmaps. The
double-set and double-clear tests confirm that attempts to set an
already-set bit or clear an already-clear bit are properly detected and
reported through the return value.

The corruption detection tests are particularly important for validating
the safety guarantees. These tests directly manipulate one bitmap without
updating its complement, simulating what would happen if a memory error
flipped a bit. Both primary and secondary corruption scenarios are
tested, confirming that either type is caught by validation.

The suite also includes boundary condition tests covering the first bit,
last bit, and word boundaries to ensure the bit manipulation logic
handles edge cases correctly.

Based-on-patch-by: Sanif Veeras <sveeras@nvidia.com>
Assisted-by: Claude:claude-opus-4-7 <noreply@anthropic.com>
Signed-off-by: Sasha Levin <sashal@nvidia.com>
---
 mm/Makefile                |   1 +
 mm/page_consistency_test.c | 274 +++++++++++++++++++++++++++++++++++++
 2 files changed, 275 insertions(+)
 create mode 100644 mm/page_consistency_test.c

diff --git a/mm/Makefile b/mm/Makefile
index 2ee360001456..7106aeb79cf5 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_BALLOON) += balloon.o
 obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
 obj-$(CONFIG_PAGE_TABLE_CHECK) += page_table_check.o
 obj-$(CONFIG_DEBUG_PAGE_CONSISTENCY) += page_consistency.o
+obj-$(CONFIG_DEBUG_PAGE_CONSISTENCY_KUNIT_TEST) += page_consistency_test.o
 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
 obj-$(CONFIG_SECRETMEM) += secretmem.o
 obj-$(CONFIG_CMA_SYSFS) += cma_sysfs.o
diff --git a/mm/page_consistency_test.c b/mm/page_consistency_test.c
new file mode 100644
index 000000000000..6cd587f8146f
--- /dev/null
+++ b/mm/page_consistency_test.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit tests for dual-bitmap primitives
+ *
+ * Tests the dual-bitmap consistency checking algorithm used by the page
+ * consistency checker. These tests verify the core invariant maintenance
+ * and corruption detection logic.
+ */
+
+#include <kunit/test.h>
+#include <linux/dual_bitmap.h>
+
+#define TEST_BITMAP_BITS 256
+
+struct dual_bitmap_test_context {
+	struct dual_bitmap db;
+	unsigned long primary[BITS_TO_LONGS(TEST_BITMAP_BITS)];
+	unsigned long secondary[BITS_TO_LONGS(TEST_BITMAP_BITS)];
+};
+
+static int dual_bitmap_test_init(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx;
+
+	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->db.bitmap[DUAL_BITMAP_PRIMARY] = ctx->primary;
+	ctx->db.bitmap[DUAL_BITMAP_SECONDARY] = ctx->secondary;
+	ctx->db.nbits = TEST_BITMAP_BITS;
+
+	/* Initialize: primary all zeros, secondary all ones */
+	dual_bitmap_init(&ctx->db);
+
+	test->priv = ctx;
+	return 0;
+}
+
+static void test_initial_state_consistent(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+	unsigned long violations;
+
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_EQ(test, violations, 0UL);
+}
+
+static void test_set_maintains_consistency(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+	unsigned long violations;
+	bool was_set;
+
+	/* Set bit 42 */
+	was_set = dual_bitmap_set(&ctx->db, 42);
+	KUNIT_EXPECT_FALSE(test, was_set);
+
+	/* Verify consistency */
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_EQ(test, violations, 0UL);
+
+	/* Verify individual bit consistency */
+	KUNIT_EXPECT_TRUE(test, dual_bitmap_consistent(&ctx->db, 42));
+}
+
+static void test_clear_maintains_consistency(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+	unsigned long violations;
+	bool was_set;
+
+	/* First set the bit */
+	dual_bitmap_set(&ctx->db, 100);
+
+	/* Now clear it */
+	was_set = dual_bitmap_clear(&ctx->db, 100);
+	KUNIT_EXPECT_TRUE(test, was_set);
+
+	/* Verify consistency */
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_EQ(test, violations, 0UL);
+}
+
+static void test_double_set_detected(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+	bool was_set;
+
+	/* Set bit 50 */
+	was_set = dual_bitmap_set(&ctx->db, 50);
+	KUNIT_EXPECT_FALSE(test, was_set);
+
+	/* Try to set it again - should report it was already set */
+	was_set = dual_bitmap_set(&ctx->db, 50);
+	KUNIT_EXPECT_TRUE(test, was_set);
+}
+
+static void test_double_clear_detected(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+	bool was_set;
+
+	/* Clear bit 60 which is already clear (never set) */
+	was_set = dual_bitmap_clear(&ctx->db, 60);
+	KUNIT_EXPECT_FALSE(test, was_set);
+}
+
+static void test_corruption_in_primary_detected(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+	unsigned long violations;
+
+	/* Corrupt the primary bitmap directly */
+	set_bit(75, ctx->primary);
+
+	/* Validation should detect the corruption */
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_GT(test, violations, 0UL);
+
+	/* Individual bit check should also fail */
+	KUNIT_EXPECT_FALSE(test, dual_bitmap_consistent(&ctx->db, 75));
+}
+
+static void test_corruption_in_secondary_detected(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+	unsigned long violations;
+
+	/* Corrupt the secondary bitmap directly */
+	clear_bit(80, ctx->secondary);
+
+	/* Validation should detect the corruption */
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_GT(test, violations, 0UL);
+
+	/* Individual bit check should also fail */
+	KUNIT_EXPECT_FALSE(test, dual_bitmap_consistent(&ctx->db, 80));
+}
+
+static void test_multiple_operations(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+	unsigned long violations;
+	unsigned long i;
+
+	/* Set bits 0-63 */
+	for (i = 0; i < 64; i++)
+		dual_bitmap_set(&ctx->db, i);
+
+	/* Clear bits 32-63 */
+	for (i = 32; i < 64; i++)
+		dual_bitmap_clear(&ctx->db, i);
+
+	/* Validate entire bitmap */
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_EQ(test, violations, 0UL);
+
+	/* Verify expected state: bits 0-31 set, rest clear */
+	for (i = 0; i < 32; i++)
+		KUNIT_EXPECT_TRUE(test, test_bit(i, ctx->primary));
+	for (i = 32; i < TEST_BITMAP_BITS; i++)
+		KUNIT_EXPECT_FALSE(test, test_bit(i, ctx->primary));
+}
+
+static void test_boundary_bits(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+	unsigned long violations;
+
+	/* Test first bit */
+	dual_bitmap_set(&ctx->db, 0);
+	KUNIT_EXPECT_TRUE(test, dual_bitmap_consistent(&ctx->db, 0));
+
+	/* Test last bit */
+	dual_bitmap_set(&ctx->db, TEST_BITMAP_BITS - 1);
+	KUNIT_EXPECT_TRUE(test, dual_bitmap_consistent(&ctx->db, TEST_BITMAP_BITS - 1));
+
+	/* Test word boundary (last bit of first word / first bit of second word) */
+	dual_bitmap_set(&ctx->db, BITS_PER_LONG - 1);
+	dual_bitmap_set(&ctx->db, BITS_PER_LONG);
+	KUNIT_EXPECT_TRUE(test, dual_bitmap_consistent(&ctx->db, BITS_PER_LONG - 1));
+	KUNIT_EXPECT_TRUE(test, dual_bitmap_consistent(&ctx->db, BITS_PER_LONG));
+
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_EQ(test, violations, 0UL);
+}
+
+static void test_dual_bitmap_test_func(struct kunit *test)
+{
+	struct dual_bitmap_test_context *ctx = test->priv;
+
+	/* Initially all bits should be clear (not allocated) */
+	KUNIT_EXPECT_FALSE(test, dual_bitmap_test(&ctx->db, 10));
+
+	/* After setting, bit should be set */
+	dual_bitmap_set(&ctx->db, 10);
+	KUNIT_EXPECT_TRUE(test, dual_bitmap_test(&ctx->db, 10));
+
+	/* After clearing, bit should be clear again */
+	dual_bitmap_clear(&ctx->db, 10);
+	KUNIT_EXPECT_FALSE(test, dual_bitmap_test(&ctx->db, 10));
+}
+
+/* Test with non-word-aligned nbits to exercise partial-word handling */
+#define TEST_UNALIGNED_BITS 100  /* not a multiple of BITS_PER_LONG */
+
+struct dual_bitmap_unaligned_context {
+	struct dual_bitmap db;
+	unsigned long primary[BITS_TO_LONGS(TEST_UNALIGNED_BITS)];
+	unsigned long secondary[BITS_TO_LONGS(TEST_UNALIGNED_BITS)];
+};
+
+static void test_non_aligned_nbits(struct kunit *test)
+{
+	struct dual_bitmap_unaligned_context *ctx;
+	unsigned long violations;
+	unsigned long i;
+
+	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+	ctx->db.bitmap[DUAL_BITMAP_PRIMARY] = ctx->primary;
+	ctx->db.bitmap[DUAL_BITMAP_SECONDARY] = ctx->secondary;
+	ctx->db.nbits = TEST_UNALIGNED_BITS;
+
+	dual_bitmap_init(&ctx->db);
+
+	/* Initial state should be consistent */
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_EQ(test, violations, 0UL);
+
+	/* Set and clear bits near the non-aligned boundary */
+	for (i = TEST_UNALIGNED_BITS - 5; i < TEST_UNALIGNED_BITS; i++) {
+		dual_bitmap_set(&ctx->db, i);
+		KUNIT_EXPECT_TRUE(test, dual_bitmap_consistent(&ctx->db, i));
+	}
+
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_EQ(test, violations, 0UL);
+
+	/* Clear them back */
+	for (i = TEST_UNALIGNED_BITS - 5; i < TEST_UNALIGNED_BITS; i++)
+		dual_bitmap_clear(&ctx->db, i);
+
+	violations = dual_bitmap_validate(&ctx->db);
+	KUNIT_EXPECT_EQ(test, violations, 0UL);
+}
+
+static struct kunit_case dual_bitmap_test_cases[] = {
+	KUNIT_CASE(test_initial_state_consistent),
+	KUNIT_CASE(test_set_maintains_consistency),
+	KUNIT_CASE(test_clear_maintains_consistency),
+	KUNIT_CASE(test_double_set_detected),
+	KUNIT_CASE(test_double_clear_detected),
+	KUNIT_CASE(test_corruption_in_primary_detected),
+	KUNIT_CASE(test_corruption_in_secondary_detected),
+	KUNIT_CASE(test_multiple_operations),
+	KUNIT_CASE(test_boundary_bits),
+	KUNIT_CASE(test_dual_bitmap_test_func),
+	KUNIT_CASE(test_non_aligned_nbits),
+	{},
+};
+
+static struct kunit_suite dual_bitmap_test_suite = {
+	.name = "dual_bitmap",
+	.init = dual_bitmap_test_init,
+	.test_cases = dual_bitmap_test_cases,
+};
+
+kunit_test_suites(&dual_bitmap_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit tests for dual-bitmap consistency primitives");
-- 
2.53.0


  parent reply	other threads:[~2026-04-24 14:01 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-24 14:00 [RFC 0/7] mm: dual-bitmap page allocator consistency checker Sasha Levin
2026-04-24 14:00 ` [RFC 1/7] mm: add generic dual-bitmap consistency primitives Sasha Levin
2026-04-24 14:00 ` [RFC 2/7] mm: add page consistency checker header Sasha Levin
2026-04-24 14:00 ` [RFC 3/7] mm: add Kconfig options for page consistency checker Sasha Levin
2026-04-24 14:00 ` [RFC 4/7] mm: add page consistency checker implementation Sasha Levin
2026-04-24 14:25   ` David Hildenbrand (Arm)
2026-04-24 14:49     ` Sasha Levin
2026-04-24 15:06       ` Pasha Tatashin
2026-04-24 18:28         ` David Hildenbrand (Arm)
2026-04-24 23:34           ` Sasha Levin
2026-04-25  5:30             ` David Hildenbrand (Arm)
2026-04-25 16:38               ` Sasha Levin
2026-04-24 18:26       ` David Hildenbrand (Arm)
2026-04-24 14:00 ` [RFC 5/7] mm/page_alloc: integrate page consistency hooks Sasha Levin
2026-04-24 14:00 ` [RFC 6/7] Documentation/mm: add page consistency checker documentation Sasha Levin
2026-04-24 14:00 ` Sasha Levin [this message]
2026-04-24 15:34 ` [RFC 0/7] mm: dual-bitmap page allocator consistency checker Matthew Wilcox
2026-04-24 15:53   ` Sasha Levin
2026-04-24 15:42 ` Vlastimil Babka (SUSE)
2026-04-24 16:25   ` Sasha Levin
2026-04-25  5:51     ` David Hildenbrand (Arm)
2026-04-25 16:09       ` Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260424140056.2094777-8-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=Liam.Howlett@oracle.com \
    --cc=akpm@linux-foundation.org \
    --cc=corbet@lwn.net \
    --cc=david@kernel.org \
    --cc=hannes@cmpxchg.org \
    --cc=jackmanb@google.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=mhocko@suse.com \
    --cc=noreply@anthropic.com \
    --cc=rppt@kernel.org \
    --cc=sashal@nvidia.com \
    --cc=skhan@linuxfoundation.org \
    --cc=surenb@google.com \
    --cc=sveeras@nvidia.com \
    --cc=vbabka@kernel.org \
    --cc=ziy@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox