summaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorDenis V. Lunev <den@openvz.org>2026-07-24 13:13:10 +0200
committerKevin Wolf <kwolf@redhat.com>2026-08-03 10:42:29 +0200
commit16f94ef4c6ce3e7ca6b02b796580e2cfc41e9789 (patch)
tree4d454e415bfa89b0d938f2397ca0d46bd9f3143f /block
parent5b0ba385a024ad92c63c175317cd9374de2e6165 (diff)
downloadqemu-16f94ef4c6ce3e7ca6b02b796580e2cfc41e9789.tar.gz
qemu-16f94ef4c6ce3e7ca6b02b796580e2cfc41e9789.zip
block/qapi: take stats->lock when reading BlockAcctStats for query-blockstats
bdrv_query_blk_stats() reads BlockAcctStats's counters, latency histogram, and per-interval TimedAverage stats without stats->lock, while block_account_one_io() updates the same fields under that lock from an iothread. timed_average_min()/max()/avg() make this worse than a stale read: they call check_expirations(), which can reset a window's sum/count/min/max -- a write, not just a read -- so this is a genuine race with a concurrent writer, not merely a slower reader like the scalar counters. Take stats->lock for the whole call, both to close the race and to make the returned snapshot internally consistent (previously each field could reflect a different instant relative to concurrent updates). block_acct_queue_depth() used to take the lock itself on every call; since bdrv_query_blk_stats() is its only caller and now already holds the lock, that would self-deadlock. Make it require the caller to hold stats->lock instead (documented and asserted). Signed-off-by: Denis V. Lunev <den@openvz.org> CC: Kevin Wolf <kwolf@redhat.com> CC: Hanna Reitz <hreitz@redhat.com> CC: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> CC: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com> Message-ID: <20260724111311.4086859-3-den@openvz.org> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block')
-rw-r--r--block/accounting.c3
-rw-r--r--block/qapi.c3
2 files changed, 4 insertions, 2 deletions
diff --git a/block/accounting.c b/block/accounting.c
index 6e06c7609e..038af37017 100644
--- a/block/accounting.c
+++ b/block/accounting.c
@@ -318,10 +318,9 @@ double block_acct_queue_depth(BlockAcctTimedStats *stats,
uint64_t sum, elapsed;
assert(type < BLOCK_MAX_IOTYPE);
+ assert(qemu_mutex_trylock(&stats->stats->lock) == -EBUSY);
- qemu_mutex_lock(&stats->stats->lock);
sum = timed_average_sum(&stats->latency[type], &elapsed);
- qemu_mutex_unlock(&stats->stats->lock);
return (double) sum / elapsed;
}
diff --git a/block/qapi.c b/block/qapi.c
index eabfbfc258..1dfac51091 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -535,6 +535,8 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
BlockAcctTimedStats *ts = NULL;
BlockLatencyHistogram *hgram;
+ qemu_mutex_lock(&stats->lock);
+
ds->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ];
ds->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE];
ds->zone_append_bytes = stats->nr_bytes[BLOCK_ACCT_ZONE_APPEND];
@@ -624,6 +626,7 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
= bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_ZONE_APPEND]);
ds->flush_latency_histogram
= bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_FLUSH]);
+ qemu_mutex_unlock(&stats->lock);
}
static BlockStats * GRAPH_RDLOCK