From: Joel Fernandes <joel@joelfernandes.org>
To: "Zhang, Qiang1" <qiang1.zhang@intel.com>
Cc: "Zhuo, Qiuxu" <qiuxu.zhuo@intel.com>,
"paulmck@kernel.org" <paulmck@kernel.org>,
"frederic@kernel.org" <frederic@kernel.org>,
"quic_neeraju@quicinc.com" <quic_neeraju@quicinc.com>,
"rcu@vger.kernel.org" <rcu@vger.kernel.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] rcu-tasks: Directly invoke rcuwait_wake_up() in call_rcu_tasks_generic()
Date: Fri, 24 Feb 2023 02:25:13 +0000 [thread overview]
Message-ID: <Y/ggCdoMEhMO8vs+@google.com> (raw)
In-Reply-To: <PH0PR11MB58801B94B0374865394E9F8FDAA89@PH0PR11MB5880.namprd11.prod.outlook.com>
On Fri, Feb 24, 2023 at 12:36:05AM +0000, Zhang, Qiang1 wrote:
> On Thu, Feb 23, 2023 at 08:43:05AM +0000, Zhang, Qiang1 wrote:
> > > From: Zqiang <qiang1.zhang@intel.com>
> > > Sent: Thursday, February 23, 2023 2:30 PM
> > > To: paulmck@kernel.org; frederic@kernel.org; quic_neeraju@quicinc.com;
> > > joel@joelfernandes.org
> > > Cc: rcu@vger.kernel.org; linux-kernel@vger.kernel.org
> > > Subject: [PATCH] rcu-tasks: Directly invoke rcuwait_wake_up() in
> > > call_rcu_tasks_generic()
> > >
> > > According to commit '3063b33a347c ("Avoid raw-spinlocked wakeups from
> > > call_rcu_tasks_generic()")', the grace-period kthread is delayed to wakeup
> > > using irq_work_queue() is because if the caller of
> > > call_rcu_tasks_generic() holds a raw spinlock, when the kernel is built with
> > > CONFIG_PROVE_RAW_LOCK_NESTING=y, due to a spinlock will be hold in
> > > wake_up(), so the lockdep splats will happen. but now using
> > > rcuwait_wake_up() to wakeup grace-period kthread instead of wake_up(), in
> > > rcuwait_wake_up() no spinlock will be acquired, so this commit remove using
> > >
> > >There are still spinlock-acquisition and spinlock-release invocations within the call path from rcuwait_wake_up().
> > >
> > >rcuwait_wake_up() -> wake_up_process() -> try_to_wake_up(), then:
> > >
> > > raw_spin_lock_irqsave()
> > > ...
> > > raw_spin_unlock_irqrestore
> >
> > Yes, but this is raw_spinlock acquisition and release(note: spinlock will convert to
> > sleepable lock in Preempt-RT kernel, but raw spinlock is not change).
> >
> > acquire raw_spinlock -> acquire spinlock will trigger lockdep warning.
> >
> >Is this really safe in the long run though? I seem to remember there are
> >weird locking dependencies if RCU is used from within the scheduler [1].
> >
>
>
> I have been running rcutorture with rcutorture.type = tasks-tracing,
> so far no problems have been found.
>
>
> >I prefer to keep it as irq_work_queue() unless you are seeing some benefit.
> >Generally, there has to be a 'win' or other justification for adding more
> >risk.
> >
> >thanks,
> >
> >- Joel
> >[1] http://www.joelfernandes.org/rcu/scheduler/locking/2019/09/02/rcu-schedlocks.html
>
>
> The problem in this link, in an earlier RCU version, rcu_read_unlock_special()
> Invoke wakeup and enter scheduler can lead to deadlock, but my modification is for
> call_rcu_tasks_generic(), even if there is a lock dependency problem, we should pay
> more attention to rcu_read_unlock_trace_special()
Consider ABBA deadlocks as well, not just self-deadlocks (which IIRC is what
the straight-RCU rcu_read_unlock() issues were about).
What prevents the following scenario?
In the scheduler you have code like this:
rq = task_rq_lock(p, &rf);
trace_sched_wait_task(p);
Someone can hook up a BPF program to that tracepoint that then calls
rcu_read_unlock_trace() -> rcu_read_unlock_trace_special(). All of
this while holding the rq and pi scheduler locks.
That's A (rq lock) -> B (rtpcp lock).
In another path, your change adds the following dependency due to doing
wakeup under the rtpcp lock.
That's call_rcu_tasks_generic() -> B (rtpcp lock) -> A (rq lock).
Maybe there is some other state that prevents this case, but it still makes
me queasy specially since there is perhaps no benefit more than deleting a
few lines of code.
Either way, nice observation!
Btw, the way irq_work works is quite interesting, so I guess what it does is
it does a self-IPI and then runs the callback in hard IRQ context, without
holding any locks. Another interesting fact is, there is also a "lazy"
version of the IRQ work API (IRQ_WORK_INIT_LAZY) which seems currently to be
used by printk. This executes the work from the scheduler tick instead of an
IPI handler unless the tick is stopped.
thanks,
- Joel
>
> Thanks
> Zqiang
>
> >
> > > irq_work_queue(), invoke rcuwait_wake_up() directly in
> > > call_rcu_tasks_generic().
> > >
> > > Signed-off-by: Zqiang <qiang1.zhang@intel.com>
> > > ---
> > > kernel/rcu/tasks.h | 16 +---------------
> > > 1 file changed, 1 insertion(+), 15 deletions(-)
> > >
> > > diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h index
> > > baf7ec178155..757b8c6da1ad 100644
> > > --- a/kernel/rcu/tasks.h
> > > +++ b/kernel/rcu/tasks.h
> > > @@ -39,7 +39,6 @@ struct rcu_tasks_percpu {
> > > unsigned long rtp_jiffies;
> > > unsigned long rtp_n_lock_retries;
> > > struct work_struct rtp_work;
> > > - struct irq_work rtp_irq_work;
> > > struct rcu_head barrier_q_head;
> > > struct list_head rtp_blkd_tasks;
> > > int cpu;
> > > @@ -112,12 +111,9 @@ struct rcu_tasks {
> > > char *kname;
> > > };
> > >
> > > -static void call_rcu_tasks_iw_wakeup(struct irq_work *iwp);
> > > -
> > > #define DEFINE_RCU_TASKS(rt_name, gp, call, n)
> > > \
> > > static DEFINE_PER_CPU(struct rcu_tasks_percpu, rt_name ## __percpu) = {
> > > \
> > > .lock = __RAW_SPIN_LOCK_UNLOCKED(rt_name ##
> > > __percpu.cbs_pcpu_lock), \
> > > - .rtp_irq_work = IRQ_WORK_INIT_HARD(call_rcu_tasks_iw_wakeup),
> > > \
> > > };
> > > \
> > > static struct rcu_tasks rt_name =
> > > \
> > > {
> > > \
> > > @@ -273,16 +269,6 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
> > > pr_info("%s: Setting shift to %d and lim to %d.\n", __func__,
> > > data_race(rtp->percpu_enqueue_shift), data_race(rtp-
> > > >percpu_enqueue_lim));
> > > }
> > >
> > > -// IRQ-work handler that does deferred wakeup for call_rcu_tasks_generic().
> > > -static void call_rcu_tasks_iw_wakeup(struct irq_work *iwp) -{
> > > - struct rcu_tasks *rtp;
> > > - struct rcu_tasks_percpu *rtpcp = container_of(iwp, struct
> > > rcu_tasks_percpu, rtp_irq_work);
> > > -
> > > - rtp = rtpcp->rtpp;
> > > - rcuwait_wake_up(&rtp->cbs_wait);
> > > -}
> > > -
> > > // Enqueue a callback for the specified flavor of Tasks RCU.
> > > static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
> > > struct rcu_tasks *rtp)
> > > @@ -334,7 +320,7 @@ static void call_rcu_tasks_generic(struct rcu_head
> > > *rhp, rcu_callback_t func,
> > > rcu_read_unlock();
> > > /* We can't create the thread unless interrupts are enabled. */
> > > if (needwake && READ_ONCE(rtp->kthread_ptr))
> > > - irq_work_queue(&rtpcp->rtp_irq_work);
> > > + rcuwait_wake_up(&rtp->cbs_wait);
> > > }
> > >
> > > // RCU callback function for rcu_barrier_tasks_generic().
> > > --
> > > 2.25.1
> >
next prev parent reply other threads:[~2023-02-24 2:25 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-02-23 6:30 [PATCH] rcu-tasks: Directly invoke rcuwait_wake_up() in call_rcu_tasks_generic() Zqiang
2023-02-23 8:36 ` Zhuo, Qiuxu
2023-02-23 8:43 ` Zhang, Qiang1
2023-02-23 14:36 ` Zhuo, Qiuxu
2023-02-23 16:10 ` Joel Fernandes
2023-02-23 16:57 ` Joel Fernandes
2023-02-23 17:13 ` Paul E. McKenney
2023-02-24 0:36 ` Zhang, Qiang1
2023-02-24 2:25 ` Joel Fernandes [this message]
2023-02-24 2:35 ` Joel Fernandes
2023-02-24 2:36 ` Joel Fernandes
2023-02-24 3:04 ` Zhang, Qiang1
2023-02-24 3:11 ` Joel Fernandes
2023-02-24 3:22 ` Zhang, Qiang1
2023-02-24 4:30 ` Joel Fernandes
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=Y/ggCdoMEhMO8vs+@google.com \
--to=joel@joelfernandes.org \
--cc=frederic@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=paulmck@kernel.org \
--cc=qiang1.zhang@intel.com \
--cc=qiuxu.zhuo@intel.com \
--cc=quic_neeraju@quicinc.com \
--cc=rcu@vger.kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.