On 8/26/26 22:13, Zqiang wrote:
In this SRCU_SIZE_SMALL mode, when queue delayed work timer, the cblist is 
always no-empty.
unless invoke start_poll_synchronize_srcu() to begin SRCU garce period,
otherwise invoke call_srcu() or synchronize_srcu*() will insert callback.
Right, every grace period which armed the delay_work timer is started by the real call_srcu(&kvm->srcu, &bus->rcu, __free_bus) in kvm_io_bus_register_dev(). I missed one point: the invoke work which invoked the barrier callbacks is not queued by the nearest end of grace period. It was queued by the timer of a previous end of GP, and it started only after the last GP had ended. Meanwhile the srcu_gp_end() from the last GP armed another timer even though the work was already queued. The timeline is as below:

1. call_srcu(&kvm->srcu, &bus->rcu, __free_bus)
2. One end of GP comes, arms a timer.
3. The timer is fired and an invoke work is queued to rcu_gp_wq. The timer is disabled now.
4. Another call_srcu(&kvm->srcu, &bus->rcu, __free_bus)
5. srcu_barrier() is called and queues barrier callbacks, waits for srcu_invoke_callbacks() to invoke them.
6. The end of GP from step 4 comes, arms another timer.
7. The invoke work queued in step 3 starts, srcu_invoke_callbacks() is called. It starts invoking callbacks without subtracting the cblist len field. It will call rcu_segcblist_add_len(&sdp->srcu_cblist, -len) after the invoking loop is over. When I debugged, there were five __free_bus(the real callbacks) and one barrier callback, so the cblist len field was 6. 8. Barrier callback is invoked, still the cblist len field is not subtracted as srcu_invoke_callbacks()'s invoking loop is not over. 9. srcu_barrier() wakes up by completion and cleanup_srcu_struct() is called before the timer armed in step 6 expires. At this point the cblist is physically empty (head == NULL, all seglen are 0) as all six callbacks have already been invoked. Only the cblist len field is stale(>0).

Thanks
Sunho Park

Reply via email to