mirror of
https://gitlab.com/qemu-project/qemu.git
synced 2026-10-28 14:04:39 +08:00
cache_clean_timer_del_and_wait() cancels the cache-cleaner coroutine
by setting s->cache_clean_interval = 0 and calling qemu_co_sleep_wake()
to cut short its qemu_co_sleep_ns_wakeable(). qemu_co_sleep_wake() is
fire-and-forget: it reads w->to_wake and silently returns when it is
NULL. A sleeper that is between two iterations -- has just released
s->lock but has not yet set w->to_wake inside qemu_co_sleep() -- loses
the wake:
iothread0 timer coroutine main thread (qcow2 close)
------------------------- -------------------------
while-body (holding s->lock):
read interval = 600
wait_ns = 600 * NS
release s->lock
take s->lock
interval = 0
qemu_co_sleep_wake(w):
w->to_wake == NULL -> skip
return
qemu_co_queue_wait(exit, s->lock):
release s->lock
yield
qemu_co_sleep_ns_wakeable:
aio_timer_init(+600 s)
qemu_co_sleep:
cas scheduled NULL -> "qsns"
w->to_wake = co
yield [sleeps 600 s]
cache_clean_timer_del_and_wait() then blocks on cache_clean_timer_exit
until the original 600 s expiry fires, and qcow2_close() holds BQL the
whole time so the VM stalls behind it.
block_copy_kick() has the same shape. Fix the primitive once instead
of working around it in each caller.
Use a tri-state for QemuCoSleep::to_wake:
NULL - idle
co - sleeper parked
PENDING - wake delivered, no sleeper yet (sticky)
qemu_co_sleep_wake() xchgs PENDING into to_wake: a real sleeper is
woken, NULL/PENDING is left untouched so the wake stays sticky.
qemu_co_sleep() cmpxchg-publishes itself as the sleeper; if a wake
was delivered before it got there or races the publish, the cmpxchg
observes PENDING and returns without yielding. On normal resume
qemu_co_sleep() clears the PENDING the waker left behind so the next
sleep starts clean.
A double-fire (real wake plus timer callback) is harmless: the first
xchg returns the coroutine and wakes it; the second returns PENDING
and is a no-op. Cancellation latency through qemu_co_sleep_wake() is
now bounded by aio_co_wake() rather than by the sleep duration.
Fixes: f86dde9a15 ("qcow2: Fix cache_clean_timer")
Signed-off-by: Denis V. Lunev <den@openvz.org>
Cc: Hanna Czenczek <hreitz@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260610115850.2410566-2-den@openvz.org>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit e554413bd2)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>