From: Stefan Hajnoczi <[email protected]> Since commit 5634622bcb33 ("file-posix: allow BLKZEROOUT with -t writeback"), qemu-img create errors out on a Linux loop block device with a 4 KB sector size:
# dd if=/dev/zero of=blockfile bs=1M count=1024 # losetup --sector-size 4096 /dev/loop0 blockfile # qemu-img create -f raw /dev/loop0 1G Formatting '/dev/loop0', fmt=raw size=1073741824 qemu-img: /dev/loop0: Failed to clear the new image's first sector: Invalid argument Use the pwrite_zeroes_alignment block limit to avoid misaligned fallocate(2) or ioctl(BLKZEROOUT) in the block/file-posix.c block driver. Cc: [email protected] Fixes: 5634622bcb33 ("file-posix: allow BLKZEROOUT with -t writeback") Reported-by: Jean-Louis Dupond <[email protected]> Buglink: https://gitlab.com/qemu-project/qemu/-/issues/3127 Reviewed-by: Vladimir Sementsov-Ogievskiy <[email protected]> Signed-off-by: Stefan Hajnoczi <[email protected]> Message-ID: <[email protected]> Tested-by: Fiona Ebner <[email protected]> Reviewed-by: Fiona Ebner <[email protected]> Reviewed-by: Kevin Wolf <[email protected]> Signed-off-by: Kevin Wolf <[email protected]> --- include/system/block-backend-io.h | 1 + block.c | 3 ++- block/block-backend.c | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/system/block-backend-io.h b/include/system/block-backend-io.h index ba8dfcc7d0..6d5ac476fc 100644 --- a/include/system/block-backend-io.h +++ b/include/system/block-backend-io.h @@ -116,6 +116,7 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, void *opaque, int ret); uint32_t blk_get_request_alignment(BlockBackend *blk); +uint32_t blk_get_pwrite_zeroes_alignment(BlockBackend *blk); uint32_t blk_get_max_transfer(BlockBackend *blk); uint64_t blk_get_max_hw_transfer(BlockBackend *blk); diff --git a/block.c b/block.c index 4f1581cedf..48a17f393c 100644 --- a/block.c +++ b/block.c @@ -606,12 +606,13 @@ create_file_fallback_zero_first_sector(BlockBackend *blk, int64_t current_size, Error **errp) { + uint32_t alignment = blk_get_pwrite_zeroes_alignment(blk); int64_t bytes_to_clear; int ret; GLOBAL_STATE_CODE(); - bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE); + bytes_to_clear = MIN(current_size, MAX(BDRV_SECTOR_SIZE, alignment)); if (bytes_to_clear) { ret = blk_co_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP); if (ret < 0) { diff --git a/block/block-backend.c b/block/block-backend.c index d6df369188..98315d4470 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2305,6 +2305,17 @@ uint32_t blk_get_request_alignment(BlockBackend *blk) return bs ? bs->bl.request_alignment : BDRV_SECTOR_SIZE; } +/* Returns the optimal write zeroes alignment, in bytes; guaranteed nonzero */ +uint32_t blk_get_pwrite_zeroes_alignment(BlockBackend *blk) +{ + BlockDriverState *bs = blk_bs(blk); + IO_CODE(); + if (!bs) { + return BDRV_SECTOR_SIZE; + } + return bs->bl.pwrite_zeroes_alignment ?: bs->bl.request_alignment; +} + /* Returns the maximum hardware transfer length, in bytes; guaranteed nonzero */ uint64_t blk_get_max_hw_transfer(BlockBackend *blk) { -- 2.51.1
