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