virtio-devices: block: Use logical_size() for advisory lock range

Use logical_size() instead of physical_size() for the byte-range
advisory lock. physical_size() returns st_blocks*512 which is the
actual host allocation and can be smaller than the guest visible
extent on sparse files, leaving part of the range unprotected.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-03-25 23:32:25 +01:00
committed by Rob Bradford
parent 8b6eb83f2a
commit a21b9588ec

View File

@@ -8,6 +8,7 @@
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use std::cmp::max;
use std::collections::{BTreeMap, HashMap, VecDeque};
use std::num::Wrapping;
use std::ops::Deref;
@@ -887,10 +888,16 @@ impl Block {
match self.lock_granularity_choice {
LockGranularityChoice::Full => LockGranularity::WholeFile,
LockGranularityChoice::ByteRange => {
// Byte-range lock covering [0, size)
self.disk_image.physical_size().map_or_else(
// use a safe fallback
|e| {
// Byte range lock covering [0, max(logical, physical))
// logical > physical for sparse files, physical > logical
// for small dense files due to filesystem block rounding.
let logical = self.disk_image.logical_size();
let physical = self.disk_image.physical_size();
match (logical, physical) {
(Ok(l), Ok(p)) => LockGranularity::ByteRange(0, max(l, p)),
(Ok(l), Err(_)) => LockGranularity::ByteRange(0, l),
(Err(_), Ok(p)) => LockGranularity::ByteRange(0, p),
(Err(e), Err(_)) => {
let fallback = LockGranularity::WholeFile;
warn!(
"Can't get disk size for id={},path={}, falling back to {:?}: error: {e}",
@@ -899,9 +906,8 @@ impl Block {
fallback
);
fallback
},
|size| LockGranularity::ByteRange(0, size),
)
}
}
}
}
}