From: Kunwu Chan <[email protected]> Add atomic SRCU operation checks and the associated state to Tiny SRCU.
An atomic SRCU domain does not use the normal SRCU callback and grace-period machinery. In particular, a callback queued with call_srcu() would never be processed. Use WARN_ON_ONCE() to reject call_srcu() and srcu_barrier() on atomic SRCU domains. For synchronize_srcu(), redirect atomic SRCU domains to synchronize_srcu_atomic(). Add srcu_reader_flavor to the Tiny SRCU state for these checks. Tiny SRCU does not currently set the flavor for atomic SRCU domains, but keeping the flavor in the common state allows the operation checks to enforce the restriction once atomic flavor tracking is enabled. Also initialize srcu_atomic_gp_flag, which was previously left uninitialized. Signed-off-by: Kunwu Chan <[email protected]> --- include/linux/srcutiny.h | 1 + kernel/rcu/srcutiny.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/linux/srcutiny.h b/include/linux/srcutiny.h index 47a368f945e3..2b293336525a 100644 --- a/include/linux/srcutiny.h +++ b/include/linux/srcutiny.h @@ -20,6 +20,7 @@ struct srcu_struct { u8 srcu_gp_running; /* GP workqueue running? */ u8 srcu_gp_waiting; /* GP waiting for readers? */ u8 srcu_atomic_gp_flag; /* Serialize atomic GP work.*/ + u8 srcu_reader_flavor; /* Values: SRCU_READ_FLAVOR_.* */ unsigned long srcu_idx; /* Current reader array element in bit 0x2. */ unsigned long srcu_idx_max; /* Furthest future srcu_idx request. */ struct swait_queue_head srcu_wq; diff --git a/kernel/rcu/srcutiny.c b/kernel/rcu/srcutiny.c index 26ea4bfbeaf2..22f7716cbb0e 100644 --- a/kernel/rcu/srcutiny.c +++ b/kernel/rcu/srcutiny.c @@ -41,6 +41,7 @@ static int init_srcu_struct_fields(struct srcu_struct *ssp) ssp->srcu_cb_tail = &ssp->srcu_cb_head; ssp->srcu_gp_running = false; ssp->srcu_gp_waiting = false; + ssp->srcu_atomic_gp_flag = 0; ssp->srcu_idx = 0; ssp->srcu_idx_max = 0; INIT_WORK(&ssp->srcu_work, srcu_drive_gp); @@ -289,6 +290,9 @@ EXPORT_SYMBOL_GPL(srcu_defer_drain); void call_srcu(struct srcu_struct *ssp, struct rcu_head *rhp, rcu_callback_t func) { + if (WARN_ON_ONCE(ssp->srcu_reader_flavor == SRCU_READ_FLAVOR_ATOMIC)) + return; + if (should_rcu_defer()) { /* A re-entrant call_srcu() during the drain would livelock it. */ if (READ_ONCE(srcu_defer_draining) && !in_nmi()) { @@ -319,6 +323,11 @@ void synchronize_srcu(struct srcu_struct *ssp) { struct rcu_synchronize rs; + if (WARN_ON_ONCE(ssp->srcu_reader_flavor == SRCU_READ_FLAVOR_ATOMIC)) { + synchronize_srcu_atomic(ssp); + return; + } + srcu_lock_sync(&ssp->dep_map); RCU_LOCKDEP_WARN(lockdep_is_held(ssp) || @@ -415,6 +424,9 @@ EXPORT_SYMBOL_GPL(synchronize_srcu_atomic); /* Register any deferred callbacks, then wait for all in-flight ones. */ void srcu_barrier(struct srcu_struct *ssp) { + if (WARN_ON_ONCE(ssp->srcu_reader_flavor == SRCU_READ_FLAVOR_ATOMIC)) + return; + __srcu_defer_drain(ssp); synchronize_srcu(ssp); } -- 2.43.0

