[BUG] srcu: false-positive WARN in cleanup_srcu_struct() after 78a38cbf6f20

Sunho Park <[email protected]>
Newsgroups org.kernel.vger.rcu,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
The main crash report [1] which is tested on non-merged commit 6b8c8af514d7
is caused by the single-condition WARN_ON(timer_delete_sync(&sdp->delay_work))
in cleanup_srcu_struct(&kvm->irq_srcu). As discussed in [2], it is a false
positive because irq_srcu does not use call_srcu().

However, the merged WARN_ON(timer_delete_sync(&sdp->delay_work) &&
rcu_segcblist_n_cbs(&sdp->srcu_cblist)) is also triggered in
cleanup_srcu_struct(&kvm->srcu) which is called after srcu_barrier() properly.
Although my syz test command [3] failed to reproduce, it was reproducible
in my QEMU environment built with the .config of the report.

I found out that the return value of rcu_segcblist_n_cbs can be nonzero
even after srcu_barrier() because of the srcu_barrier_cb() that srcu_barrier()
inserts at the end of the queue. The length of cblist is decreased after
srcu_invoke_callbacks() finishes invoking all callbacks in a batch. But
srcu_barrier() may return when all the srcu_barrier_cb() are called, bringing
the counter to zero, even if srcu_invoke_callbacks() has not yet decremented
the length. So checking cblist length before flush_work() is inaccurate.

By the comment of srcu_barrier(), it guarantees that all the previously
registered call_srcu() callbacks are completed. Therefore srcu_barrier()
did what it said, only the length of cblist was not updated. I think there
are two options:

1) Not to check the length of cblist before flush_work()
2) Make srcu_barrier() guarantee the length of cblist is adjusted when it returns

[1] https://lore.kernel.org/all/[email protected]/T
[2] https://lore.kernel.org/rcu/[email protected]/T
[3] https://lore.kernel.org/all/[email protected]

Reported-by: [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.