From 94368c622e1571ca9f169ea4cfcb2c4b8969ffb2 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 19 Feb 2026 11:22:28 +0100 Subject: [PATCH] block: Add BackingFilesDisabled error for actionable user guidance When a QCOW2 image has a backing file but backing_files=on is not set, the error was MaxNestingDepthExceeded which gives no indication that this is a policy decision or how to resolve it. Add a BackingFilesDisabled error variant whose message indicates that backing file support is disabled and references the backing_files option. The translation from MaxNestingDepthExceeded to BackingFilesDisabled happens at the QcowDiskSync boundary where the policy decision is made, preserving the original error for genuine recursive depth exhaustion. Signed-off-by: Anatol Belski --- block/src/qcow/mod.rs | 2 ++ block/src/qcow_sync.rs | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/block/src/qcow/mod.rs b/block/src/qcow/mod.rs index 65027bfaf..fd932406c 100644 --- a/block/src/qcow/mod.rs +++ b/block/src/qcow/mod.rs @@ -44,6 +44,8 @@ pub enum Error { BackingFileIo(#[source] io::Error), #[error("Backing file open error")] BackingFileOpen(#[source] Box), + #[error("Backing file support is disabled")] + BackingFilesDisabled, #[error("Backing file name is too long: {0} bytes over")] BackingFileTooLong(usize), #[error("Image is marked corrupt and cannot be opened for writing")] diff --git a/block/src/qcow_sync.rs b/block/src/qcow_sync.rs index 4c7486f22..d4dfc9b78 100644 --- a/block/src/qcow_sync.rs +++ b/block/src/qcow_sync.rs @@ -14,7 +14,7 @@ use vmm_sys_util::write_zeroes::PunchHole; use crate::async_io::{ AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult, }; -use crate::qcow::{MAX_NESTING_DEPTH, QcowFile, RawFile, Result as QcowResult}; +use crate::qcow::{Error as QcowError, MAX_NESTING_DEPTH, QcowFile, RawFile, Result as QcowResult}; use crate::{AsyncAdaptor, BlockBackend}; pub struct QcowDiskSync { @@ -32,12 +32,17 @@ pub struct QcowDiskSync { impl QcowDiskSync { pub fn new(file: File, direct_io: bool, backing_files: bool, sparse: bool) -> QcowResult { let max_nesting_depth = if backing_files { MAX_NESTING_DEPTH } else { 0 }; + let qcow_file = QcowFile::from_with_nesting_depth( + RawFile::new(file, direct_io), + max_nesting_depth, + sparse, + ) + .map_err(|e| match e { + QcowError::MaxNestingDepthExceeded if !backing_files => QcowError::BackingFilesDisabled, + other => other, + })?; Ok(QcowDiskSync { - qcow_file: Arc::new(Mutex::new(QcowFile::from_with_nesting_depth( - RawFile::new(file, direct_io), - max_nesting_depth, - sparse, - )?)), + qcow_file: Arc::new(Mutex::new(qcow_file)), }) } }