block: qcow: Implement punch_hole and write_zeroes for QcowSync
Implement punch_hole and write_zeroes for QcowSync backend by delegating to QcowFile::punch_hole which triggers cluster deallocation. write_zeroes delegates to punch_hole as unallocated clusters read as zeros in QCOW2. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
parent
81c075b317
commit
6c94975c80
1 changed files with 61 additions and 8 deletions
|
|
@ -9,6 +9,7 @@ use std::os::fd::AsRawFd;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
use vmm_sys_util::write_zeroes::PunchHole;
|
||||||
|
|
||||||
use crate::async_io::{
|
use crate::async_io::{
|
||||||
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
|
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
|
||||||
|
|
@ -151,15 +152,67 @@ impl AsyncIo for QcowSync {
|
||||||
self.completion_list.pop_front()
|
self.completion_list.pop_front()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn punch_hole(&mut self, _offset: u64, _length: u64, _user_data: u64) -> AsyncIoResult<()> {
|
fn punch_hole(&mut self, offset: u64, length: u64, user_data: u64) -> AsyncIoResult<()> {
|
||||||
Err(AsyncIoError::PunchHole(std::io::Error::other(
|
// For QCOW2, punch_hole calls deallocate_cluster
|
||||||
"punch_hole not supported for QCOW sync backend",
|
let result = self
|
||||||
)))
|
.qcow_file
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.punch_hole(offset, length)
|
||||||
|
.map(|_| 0i32)
|
||||||
|
.map_err(AsyncIoError::PunchHole);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(res) => {
|
||||||
|
self.completion_list.push_back((user_data, res));
|
||||||
|
self.eventfd.write(1).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// CRITICAL: Always signal completion even on error to avoid hangs
|
||||||
|
let errno = if let AsyncIoError::PunchHole(io_err) = &e {
|
||||||
|
let err = io_err.raw_os_error().unwrap_or(libc::EIO);
|
||||||
|
-err
|
||||||
|
} else {
|
||||||
|
-libc::EIO
|
||||||
|
};
|
||||||
|
self.completion_list.push_back((user_data, errno));
|
||||||
|
self.eventfd.write(1).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_zeroes(&mut self, _offset: u64, _length: u64, _user_data: u64) -> AsyncIoResult<()> {
|
fn write_zeroes(&mut self, offset: u64, length: u64, user_data: u64) -> AsyncIoResult<()> {
|
||||||
Err(AsyncIoError::WriteZeroes(std::io::Error::other(
|
// For QCOW2, write_zeroes is implemented by deallocating clusters via punch_hole.
|
||||||
"write_zeroes not supported for QCOW sync backend",
|
// This is more efficient than writing actual zeros and reduces disk usage.
|
||||||
)))
|
// Unallocated clusters inherently read as zero in the QCOW2 format.
|
||||||
|
let result = self
|
||||||
|
.qcow_file
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.punch_hole(offset, length)
|
||||||
|
.map(|_| 0i32)
|
||||||
|
.map_err(AsyncIoError::WriteZeroes);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(res) => {
|
||||||
|
self.completion_list.push_back((user_data, res));
|
||||||
|
self.eventfd.write(1).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// Always signal completion even on error to avoid hangs
|
||||||
|
let errno = if let AsyncIoError::WriteZeroes(io_err) = &e {
|
||||||
|
let err = io_err.raw_os_error().unwrap_or(libc::EIO);
|
||||||
|
-err
|
||||||
|
} else {
|
||||||
|
-libc::EIO
|
||||||
|
};
|
||||||
|
self.completion_list.push_back((user_data, errno));
|
||||||
|
self.eventfd.write(1).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue