Jakub Kicinski [off-list ref] writes:
On Wed, 31 May 2023 12:16:50 -0700 Stefan Roesch wrote:
quoted
quoted
This will conflict with:
https://git.kernel.org/netdev/net-next/c/c857946a4e26
:( Not sure what to do about it..
Maybe we can merge a simpler version to unblock io-uring (just add
need_resched() to your loop_end callback and you'll get the same
behavior). Refactor in net-next in parallel. Then once trees converge
do simple a cleanup and call the _rcu version?
Jakub, I can certainly call need_resched() in the loop_end callback, but
isn't there a potential race? need_resched() in the loop_end callback
might not return true, but the need_resched() call in napi_busy_poll
does?
need_resched() is best effort. It gets added to potentially long
execution paths and loops. Extra single round thru the loop won't
make a difference.
I might be missing something, however what can happen at a high-level is:
io_napi_blocking_busy_loop()
rcu_read_lock()
__io_napi_busy_do_busy_loop()
rcu_read_unlock()
in __io_napi_do_busy_loop() we do
__io_napi_do_busy_loop()
list_foreach_entry_rcu()
napi_busy_loop()
and in napi_busy_loop()
napi_busy_loop()
rcu_read_lock()
__napi_busy_poll()
loop_end()
if (need_resched) {
rcu_read_unlock()
schedule()
}
The problem with checking need_resched in loop_end is that need_resched
can be false in loop_end, however the check for need_resched in
napi_busy_loop succeeds. This means that we unlock the rcu read lock and
call schedule. However the code in io_napi_blocking_busy_loop still
believes we hold the read lock.