[PATCH 19/28] Documentation/litmus-tests: Add hazptr drain generation-visibility test
From: Kunwu Chan
Date: Wed Nov 04 2026 - 12:07:41 EST
Prove that the drain engage's smp_mb() publication ordering is
correct: a release hook that observes the new drain address also
observes the new generation counter (herd7: Never).
Signed-off-by: Kunwu Chan <kunwu.chan@xxxxxxxxx>
---
Documentation/litmus-tests/README | 4 ++
.../hazptr-drain-generation-visibility.litmus | 41 +++++++++++++++++++
2 files changed, 45 insertions(+)
create mode 100644 Documentation/litmus-tests/hazptr/hazptr-drain-generation-visibility.litmus
diff --git a/Documentation/litmus-tests/README b/Documentation/litmus-tests/README
index 604c2c0025d9..79b0634ddb13 100644
--- a/Documentation/litmus-tests/README
+++ b/Documentation/litmus-tests/README
@@ -123,3 +123,7 @@ hazptr-drain-resnapshot-slot-race.litmus
hazptr-drain-safety.litmus
Test the engage snapshot race: the engage can miss an in-flight
slow-path acquire, so completion must defer on wildcards.
+
+hazptr-drain-generation-visibility.litmus
+ Test the drain generation ordering: a release hook that observes
+ the new drain address also observes the new generation.
diff --git a/Documentation/litmus-tests/hazptr/hazptr-drain-generation-visibility.litmus b/Documentation/litmus-tests/hazptr/hazptr-drain-generation-visibility.litmus
new file mode 100644
index 000000000000..d5c1ca247d71
--- /dev/null
+++ b/Documentation/litmus-tests/hazptr/hazptr-drain-generation-visibility.litmus
@@ -0,0 +1,41 @@
+C hazptr-drain-generation-visibility
+
+(*
+ * Result: Never
+ *
+ * Drain generation visibility: the engage publishes the
+ * generation counter before the drain address (separated by
+ * smp_mb()). The release hook reads the address with
+ * smp_load_acquire(). If it observes the new address, the
+ * subsequent generation read must also observe the new value,
+ * so the cmpxchg compares against the correct round.
+ *
+ * If this were not the case, a release could read a stale
+ * generation (from the previous drain round) while the address
+ * already belongs to the new round, causing the cmpxchg to
+ * succeed against the wrong round's marker and falsely
+ * decrement the new round's backup_outstanding.
+ *)
+
+{
+ gen = 5;
+ addr = 0;
+}
+
+P0(int *gen, int *addr)
+{
+ WRITE_ONCE(*gen, 6);
+ smp_mb();
+ WRITE_ONCE(*addr, 1);
+}
+
+P1(int *addr, int *gen)
+{
+ int r0;
+ int r1;
+
+ r0 = smp_load_acquire(addr);
+ r1 = READ_ONCE(*gen);
+}
+
+exists (1:r0=1 /\ 1:r1=5)
\ No newline at end of file
--
2.43.0