A single lseek(SEEK_DATA) is sufficient to tell us if a raw file is completely sparse, in which case it reads as all zeroes. Not done here, but possible extension for the future: when working with block devices instead of files, there may be various ways with ioctl or similar to quickly probe if a given block device is known to be completely unmapped where unmapped regions read as zero. But for now, block devices remain without a .bdrv_known_zeroes, because most block devices have random content without an explicit pre-zeroing pass.
Signed-off-by: Eric Blake <ebl...@redhat.com> --- block/file-posix.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/block/file-posix.c b/block/file-posix.c index ff9e39ab882f..b4d73dd0363b 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2541,6 +2541,19 @@ static int find_allocation(BlockDriverState *bs, off_t start, #endif } +static int raw_known_zeroes(BlockDriverState *bs) +{ + /* This callback is only installed for files, not block devices. */ + int r = BDRV_ZERO_CREATE | BDRV_ZERO_TRUNCATE; + off_t data, hole; + + if (find_allocation(bs, 0, &data, &hole) == -ENXIO) { + r |= BDRV_ZERO_OPEN; + } + + return r; +} + /* * Returns the allocation status of the specified offset. * @@ -3071,7 +3084,7 @@ BlockDriver bdrv_file = { .bdrv_close = raw_close, .bdrv_co_create = raw_co_create, .bdrv_co_create_opts = raw_co_create_opts, - .bdrv_known_zeroes = bdrv_known_zeroes_truncate, + .bdrv_known_zeroes = raw_known_zeroes, .bdrv_co_block_status = raw_co_block_status, .bdrv_co_invalidate_cache = raw_co_invalidate_cache, .bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes, -- 2.24.1