On Wed, May 20, 2020 at 02:06:08PM +0200, Sebastian Andrzej Siewior wrote: > On 2020-05-20 12:24:07 [+0200], Peter Zijlstra wrote: > > Would it perhaps make sense to stick the local_lock in struct srcu_data ? > > In that case we would need something for pointer stability before the > lock is acquired. Maybe I need sleep; but I think this will work. &x->foo = x + foo-offset this_cpu_ptr(x) = x + cpu-offset &this_cpu_ptr(x)->foo = (x + cpu-offset) + foo-offset = (x + foo-offset) + cpu-offset = this_cpu_ptr(&x->foo) --- --- a/include/linux/srcutree.h +++ b/include/linux/srcutree.h @@ -13,6 +13,7 @@ #include <linux/rcu_node_tree.h> #include <linux/completion.h> +#include <linux/locallock.h> struct srcu_node; struct srcu_struct; @@ -22,6 +23,8 @@ struct srcu_struct; * to rcu_node. */ struct srcu_data { + struct local_lock llock; + /* Read-side state. */ unsigned long srcu_lock_count[2]; /* Locks per CPU. */ unsigned long srcu_unlock_count[2]; /* Unlocks per CPU. */ --- a/kernel/rcu/srcutree.c +++ b/kernel/rcu/srcutree.c @@ -778,13 +778,13 @@ static bool srcu_might_be_idle(struct sr unsigned long tlast; /* If the local srcu_data structure has callbacks, not idle. */ - local_irq_save(flags); + local_lock_irqsave(&ssp->sda->llock, flags); sdp = this_cpu_ptr(ssp->sda); if (rcu_segcblist_pend_cbs(&sdp->srcu_cblist)) { - local_irq_restore(flags); + local_unlock_irqrestore(&ssp->sda->llock, flags); return false; /* Callbacks already present, so not idle. */ } - local_irq_restore(flags); + local_unlock_irqrestore(&ssp->sda->llock, flags); /* * No local callbacks, so probabalistically probe global state. @@ -864,7 +864,7 @@ static void __call_srcu(struct srcu_stru } rhp->func = func; idx = srcu_read_lock(ssp); - local_irq_save(flags); + local_lock_irqsave(&ssp->sda->llock, flags); sdp = this_cpu_ptr(ssp->sda); spin_lock_rcu_node(sdp); rcu_segcblist_enqueue(&sdp->srcu_cblist, rhp); @@ -880,7 +880,8 @@ static void __call_srcu(struct srcu_stru sdp->srcu_gp_seq_needed_exp = s; needexp = true; } - spin_unlock_irqrestore_rcu_node(sdp, flags); + spin_unlock_rcu_node(sdp); + local_unlock_irqrestore(&ssp->sda->llock, flags); if (needgp) srcu_funnel_gp_start(ssp, sdp, s, do_norm); else if (needexp)