block: Fall back to write when fallocate returns EOPNOTSUPP

Filesystems such as tmpfs do not support fallocate with
FALLOC_FL_ZERO_RANGE or FALLOC_FL_PUNCH_HOLE and return EOPNOTSUPP.
When a raw disk image lives on such a filesystem, virtio write zeroes
and discard requests fail with IOERR.

Use the WriteZeroesAt trait from vmm_sys_util through AlignedFile,
which already bundles fallocate with a positional write fallback.
For punch_hole, catch EOPNOTSUPP and fall back to the same trait.

The io_uring engine previously submitted fallocate directly through
the ring, where the async EOPNOTSUPP completion had no retry path.
Route it through the same sync helpers that the other engines
already use.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-07-17 16:13:12 +02:00
committed by Rob Bradford
parent e37f63282c
commit d7a7d73622
5 changed files with 58 additions and 119 deletions

View File

@@ -211,25 +211,6 @@ impl UringDataIo {
)
}
/// Submits a fallocate operation carrying `user_data`.
pub fn submit_fallocate(
&mut self,
fd: RawFd,
offset: u64,
length: u64,
mode: i32,
user_data: u64,
) -> io::Result<()> {
self.submit_kernel_entry(
user_data,
&opcode::Fallocate::new(types::Fd(fd), length)
.offset(offset)
.mode(mode)
.build()
.user_data(user_data),
)
}
/// Injects a completion that did not come from a kernel CQE.
///
/// The notifier is signaled so callers can drain it with
@@ -360,13 +341,6 @@ mod tests {
data_io.submit_nop(7).unwrap_err().kind(),
io::ErrorKind::AlreadyExists
);
assert_eq!(
data_io
.submit_fallocate(fd, 0, 512, 0, 7)
.unwrap_err()
.kind(),
io::ErrorKind::AlreadyExists
);
let completion = wait_for_completion(&mut data_io);
assert_eq!(completion.user_data, 7);