Re: [RFC PATCH 85/86] treewide: drivers: remove cond_resched()
From: Ankur Arora
Date: Thu Nov 09 2023 - 19:07:40 EST
Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx> writes:
> Hi Anhur,
>
> On Tue, Nov 07, 2023 at 03:08:21PM -0800, Ankur Arora wrote:
>> There are broadly three sets of uses of cond_resched():
>>
>> 1. Calls to cond_resched() out of the goodness of our heart,
>> otherwise known as avoiding lockup splats.
>
> ...
>
> What about RCU stalls? The calls to cond_resched() in evdev.c and
> mousedev.c were added specifically to allow RCU to run in cases when
> userspace passes a large buffer and the kernel is not fully preemptable.
Hi Dmitry
The short answer is that even if the kernel isn't fully preemptible, it
will always have preempt-count which means that RCU will always know
when a read-side critical section gets over.
Long version: cond_resched_rcu() is defined as:
static inline void cond_resched_rcu(void)
{
#if defined(CONFIG_DEBUG_ATOMIC_SLEEP) || !defined(CONFIG_PREEMPT_RCU)
rcu_read_unlock();
cond_resched();
rcu_read_lock();
#endif
}
So the relevant case is PREEMPT_RCU=n.
Now, currently PREEMPT_RCU=n, also implies PREEMPT_COUNT=n. And so
the rcu_read_lock()/_unlock() reduce to a barrier. And, that's
why we need the explicit cond_resched() there.
The reason we can remove the cond_resched() after patch 43, and 47 is
because rcu_read_lock()/_unlock() will modify the preempt count and so
RCU will have visibility into when RCU read-side critical sections
finish.
That said, this series in this form isn't really going anywhere in the
short-term so none of this is imminent.
On the calls to cond_resched(), if the kernel is fully preemptible
they are a NOP. And then the code would be polling in a tight loop.
Would it make sense to do something like this instead?
if (!cond_resched())
msleep()/usleep()/cpu_relax();
--
ankur