From a21b9588ecd2b9530892ba94b05a839e14ddf236 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Wed, 25 Mar 2026 23:32:25 +0100 Subject: [PATCH] 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 --- virtio-devices/src/block.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/virtio-devices/src/block.rs b/virtio-devices/src/block.rs index 47309dd87..a38a378d1 100644 --- a/virtio-devices/src/block.rs +++ b/virtio-devices/src/block.rs @@ -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), - ) + } + } } } }