diff --git a/block/io.c b/block/io.c index e8fb4ede4d..6c0bbdcf1e 100644 --- a/block/io.c +++ b/block/io.c @@ -1918,7 +1918,18 @@ bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, assert(!bs->supported_zero_flags); } - if (ret == -ENOTSUP && !(flags & BDRV_REQ_NO_FALLBACK)) { + /* + * TODO The ret == -EINVAL && num < alignment case is a workaround for + * when request_alignment is 1 on files with cache=writeback. The Linux + * ioctl(BLKZEROOUT) requires block alignment and will fail with + * EINVAL. The block layer should align the request to + * write_zeroes_alignment instead of trying the syscall, failing, and + * falling back to a bounce buffer. Doing that is not easy so for now + * we use a bounce buffer: + * https://lore.kernel.org/qemu-devel/20260109120837.2772961-1-f.ebner@proxmox.com/ + */ + if ((ret == -ENOTSUP || (ret == -EINVAL && num < alignment)) && + !(flags & BDRV_REQ_NO_FALLBACK)) { /* Fall back to bounce buffer if write zeroes is unsupported */ BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;