From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
To: "Paul E . McKenney" <paulmck@kernel.org>
Cc: linux-kernel@vger.kernel.org,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
David Woodhouse <dwmw2@infradead.org>,
Frederic Weisbecker <frederic@kernel.org>,
Neeraj Upadhyay <neeraj.upadhyay@kernel.org>,
Joel Fernandes <joelagnelf@nvidia.com>,
Josh Triplett <josh@joshtriplett.org>,
Boqun Feng <boqun@kernel.org>,
Uladzislau Rezki <urezki@gmail.com>,
Steven Rostedt <rostedt@goodmis.org>,
Lai Jiangshan <jiangshanlai@gmail.com>,
Zqiang <qiang.zhang@linux.dev>,
Davidlohr Bueso <dave@stgolabs.net>,
Kunwu Chan <kunwu.chan@gmail.com>,
Puranjay Mohan <puranjay@kernel.org>,
rcu@vger.kernel.org
Subject: [PATCH 4/4] rcutorture: Test the irqsave forms of atomic SRCU readers
Date: Tue, 10 Nov 2026 14:28:44 -0500 [thread overview]
Message-ID: <20261110192844.44713-5-mathieu.desnoyers@efficios.com> (raw)
In-Reply-To: <20261110192844.44713-1-mathieu.desnoyers@efficios.com>
Nothing tests srcu_read_lock_atomic_irqsave() and
srcu_read_unlock_atomic_irqrestore(). Testing them in the normal readers
has two obstacles. rcutorture_one_extend() ends the readers of a CPU in
any order, but each irqrestore restores the state its own irqsave saw.
It also enables interrupts and bottom halves within readers, which an
irqsave reader forbids.
Add an atomic_irqsave module parameter. With it, half the atomic
readers use the irqsave forms, alternating per CPU. A per-CPU count
tracks these readers: the first one saves the interrupt state, and only
the last one restores it. The others restore the current state, with
interrupts disabled. The parameter also removes the bottom-half and
interrupt reader extensions, and the reader end under ->pi_lock, which
would enable interrupts under a raw spinlock.
An irqsave reader checks that interrupts are still disabled when it
ends.
Add an atomic-srcu-irqsave run of SRCU-P to torture.sh.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
---
kernel/rcu/rcutorture.c | 74 +++++++++++++++++--
.../selftests/rcutorture/bin/torture.sh | 6 ++
2 files changed, 75 insertions(+), 5 deletions(-)
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 3b9c08a094cd..99dde988f974 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -134,6 +134,7 @@ torture_param(int, preempt_interval, MSEC_PER_SEC, "Interval between preemptions
torture_param(int, read_exit_delay, 13, "Delay between read-then-exit episodes (s)");
torture_param(int, read_exit_burst, 16, "# of read-then-exit bursts per episode, zero to disable");
torture_param(int, reader_flavor, SRCU_READ_FLAVOR_NORMAL, "Reader flavors to use, one per bit.");
+torture_param(bool, atomic_irqsave, false, "Half the atomic SRCU readers disable irqs");
torture_param(int, shuffle_interval, 3, "Number of seconds between shuffles");
torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable.");
torture_param(int, stall_cpu, 0, "Stall duration (s), zero to disable.");
@@ -728,6 +729,66 @@ static void srcu_torture_init_forbidden_apis(void)
cur_ops->start_gp_poll = NULL;
}
+/*
+ * With atomic_irqsave, half the atomic SRCU readers disable interrupts instead
+ * of preemption. rcutorture_one_extend() may end the readers of a CPU in any
+ * order, so the first one saves the interrupt state and the last one restores
+ * it. An extension must then neither enable interrupts nor enable bottom
+ * halves within such a reader, and no reader may end under ->pi_lock.
+ */
+#define SRCU_TORTURE_IRQSAVE 0x20 // The reader disabled interrupts.
+
+struct srcu_torture_irqsave {
+ unsigned int count; // Picks the form of the next reader.
+ int depth; // Readers of this CPU that disabled interrupts.
+ unsigned long flags; // Interrupt state before the first one.
+};
+
+static DEFINE_PER_CPU(struct srcu_torture_irqsave, srcu_torture_irqsave);
+
+static void srcu_torture_init_irqsave(void)
+{
+ if (!atomic_irqsave || !(reader_flavor & SRCU_READ_FLAVOR_ATOMIC))
+ return;
+ cur_ops->extendables &= ~(RCUTORTURE_RDR_BH | RCUTORTURE_RDR_RBH |
+ RCUTORTURE_RDR_IRQ);
+ cur_ops->no_pi_lock = 1;
+ VERBOSE_TOROUT_STRING("srcu_torture_init atomic SRCU, irqsave readers");
+}
+
+static int srcu_torture_read_lock_atomic(void)
+{
+ struct srcu_torture_irqsave *stip;
+ unsigned long flags;
+ int idx;
+
+ if (!atomic_irqsave || in_nmi() || !(this_cpu_inc_return(srcu_torture_irqsave.count) & 0x1))
+ return srcu_read_lock_atomic(srcu_ctlp);
+ idx = srcu_read_lock_atomic_irqsave(srcu_ctlp, flags);
+ stip = this_cpu_ptr(&srcu_torture_irqsave);
+ if (!stip->depth++)
+ stip->flags = flags;
+ return idx | SRCU_TORTURE_IRQSAVE;
+}
+
+static void srcu_torture_read_unlock_atomic(int idx)
+{
+ struct srcu_torture_irqsave *stip;
+ unsigned long flags;
+
+ if (!(idx & SRCU_TORTURE_IRQSAVE)) {
+ srcu_read_unlock_atomic(srcu_ctlp, idx);
+ return;
+ }
+ idx &= ~SRCU_TORTURE_IRQSAVE;
+ WARN_ON_ONCE(!irqs_disabled()); // Its section must be interrupts-off.
+ stip = this_cpu_ptr(&srcu_torture_irqsave);
+ local_save_flags(flags); // Disabled: keep it so for the other readers.
+ if (!WARN_ON_ONCE(stip->depth <= 0) && !--stip->depth)
+ flags = stip->flags;
+ srcu_read_unlock_atomic_irqrestore(srcu_ctlp, idx, flags);
+}
+
static void srcu_torture_init(void)
{
rcu_sync_torture_init();
@@ -747,6 +808,7 @@ static void srcu_torture_init(void)
srcu_ctlp = &srcu_ctla;
VERBOSE_TOROUT_STRING("srcu_torture_init atomic SRCU");
srcu_torture_init_forbidden_apis();
+ srcu_torture_init_irqsave();
}
}
@@ -786,9 +848,9 @@ static int srcu_torture_read_lock(void)
ret += idx << 3;
}
if (reader_flavor & SRCU_READ_FLAVOR_ATOMIC) {
- idx = srcu_read_lock_atomic(srcu_ctlp);
- WARN_ON_ONCE(idx & ~0x1);
- ret += idx << 4;
+ idx = srcu_torture_read_lock_atomic();
+ WARN_ON_ONCE(idx & ~(0x1 | SRCU_TORTURE_IRQSAVE));
+ ret += ((idx & 0x1) << 4) | (idx & SRCU_TORTURE_IRQSAVE);
}
return ret;
}
@@ -828,9 +890,10 @@ srcu_read_delay(struct torture_random_state *rrsp, struct rt_read_seg *rtrsp)
static void srcu_torture_read_unlock(int idx)
{
- WARN_ON_ONCE((reader_flavor && (idx & ~reader_flavor)) || (!reader_flavor && (idx & ~0x1)));
+ WARN_ON_ONCE((reader_flavor && (idx & ~(reader_flavor | SRCU_TORTURE_IRQSAVE))) ||
+ (!reader_flavor && (idx & ~0x1)));
if (reader_flavor & SRCU_READ_FLAVOR_ATOMIC)
- srcu_read_unlock_atomic(srcu_ctlp, (idx & 0x10) >> 4);
+ srcu_torture_read_unlock_atomic(((idx & 0x10) >> 4) | (idx & SRCU_TORTURE_IRQSAVE));
if (reader_flavor & SRCU_READ_FLAVOR_FAST_UPDOWN)
srcu_read_unlock_fast_updown(srcu_ctlp,
__srcu_ctr_to_ptr(srcu_ctlp, (idx & 0x8) >> 3));
@@ -1015,6 +1078,7 @@ static void srcud_torture_init(void)
WARN_ON(init_srcu_struct_atomic(&srcu_ctld));
VERBOSE_TOROUT_STRING("srcud_torture_init atomic SRCU");
srcu_torture_init_forbidden_apis();
+ srcu_torture_init_irqsave();
} else {
WARN_ON(init_srcu_struct(&srcu_ctld));
}
diff --git a/tools/testing/selftests/rcutorture/bin/torture.sh b/tools/testing/selftests/rcutorture/bin/torture.sh
index e7b578ec152f..18a03fad1038 100755
--- a/tools/testing/selftests/rcutorture/bin/torture.sh
+++ b/tools/testing/selftests/rcutorture/bin/torture.sh
@@ -519,6 +519,12 @@ then
torture_set "atomic-srcu" tools/testing/selftests/rcutorture/bin/kvm.sh \
--allcpus --duration "$duration_rcutorture" \
--configs "$configs_atomic_srcu" --trust-make
+
+ # Half the readers then use srcu_read_lock_atomic_irqsave().
+ torture_bootargs="rcutorture.reader_flavor=0x10 rcutorture.atomic_irqsave=1"
+ torture_set "atomic-srcu-irqsave" tools/testing/selftests/rcutorture/bin/kvm.sh \
+ --allcpus --duration "$duration_rcutorture" \
+ --configs "SRCU-P" --trust-make
fi
if test "$do_locktorture" = "yes"
--
2.47.3
prev parent reply other threads:[~2026-11-10 19:29 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 19:28 [PATCH 0/4] srcu: NMI-safe atomic SRCU readers, and their irqsave forms Mathieu Desnoyers
2026-11-10 19:28 ` [PATCH 1/4] srcu: Make atomic SRCU readers NMI-safe Mathieu Desnoyers
2026-11-10 19:28 ` [PATCH 2/4] srcu: Add irqsave variants of the atomic SRCU readers Mathieu Desnoyers
2026-11-10 19:28 ` [PATCH 3/4] rcutorture: Run NMI-safe SRCU readers from NMI Mathieu Desnoyers
2026-11-10 19:28 ` Mathieu Desnoyers [this message]
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=20261110192844.44713-5-mathieu.desnoyers@efficios.com \
--to=mathieu.desnoyers@efficios.com \
--cc=boqun@kernel.org \
--cc=dave@stgolabs.net \
--cc=dwmw2@infradead.org \
--cc=frederic@kernel.org \
--cc=jiangshanlai@gmail.com \
--cc=joelagnelf@nvidia.com \
--cc=josh@joshtriplett.org \
--cc=kunwu.chan@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=neeraj.upadhyay@kernel.org \
--cc=paulmck@kernel.org \
--cc=puranjay@kernel.org \
--cc=qiang.zhang@linux.dev \
--cc=rcu@vger.kernel.org \
--cc=rostedt@goodmis.org \
--cc=urezki@gmail.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
all inboxes | Powered by JetHome®