block/fuse: Let PUNCH_HOLE write zeroes

fallocate(2) says about PUNCH_HOLE: "After a successful call, subsequent
reads from this range will return zeros."  As it is, PUNCH_HOLE is
implemented as a call to blk_pdiscard(), which does not guarantee this.

We must call blk_pwrite_zeroes() instead.  The difference to ZERO_RANGE
is that we pass the `BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK` flags to
the call -- the storage is supposed to be unmapped, and a slow fallback
by actually writing zeroes as data is not allowed.

Closes: https://gitlab.com/qemu-project/qemu/-/issues/1507
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230227104725.33511-2-hreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Hanna Czenczek 2023-02-27 11:47:24 +01:00 committed by Kevin Wolf
parent ee59483267
commit 1703eb1c27
1 changed files with 10 additions and 1 deletions

View File

@ -673,7 +673,16 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
do {
int size = MIN(length, BDRV_REQUEST_MAX_BYTES);
ret = blk_pdiscard(exp->common.blk, offset, size);
ret = blk_pwrite_zeroes(exp->common.blk, offset, size,
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK);
if (ret == -ENOTSUP) {
/*
* fallocate() specifies to return EOPNOTSUPP for unsupported
* operations
*/
ret = -EOPNOTSUPP;
}
offset += size;
length -= size;
} while (ret == 0 && length > 0);