diff options
Diffstat (limited to 'block/file-posix.c')
| -rw-r--r-- | block/file-posix.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/block/file-posix.c b/block/file-posix.c index 1cf4ee49eb..d018429672 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1444,9 +1444,22 @@ out: #ifdef CONFIG_XFS static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes) { + int64_t len; struct xfs_flock64 fl; int err; + len = lseek(s->fd, 0, SEEK_END); + if (len < 0) { + return -errno; + } + + if (offset + bytes > len) { + /* XFS_IOC_ZERO_RANGE does not increase the file length */ + if (ftruncate(s->fd, offset + bytes) < 0) { + return -errno; + } + } + memset(&fl, 0, sizeof(fl)); fl.l_whence = SEEK_SET; fl.l_start = offset; @@ -2475,6 +2488,8 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, off_t data = 0, hole = 0; int ret; + assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment)); + ret = fd_open(bs); if (ret < 0) { return ret; @@ -2500,6 +2515,20 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, /* On a data extent, compute bytes to the end of the extent, * possibly including a partial sector at EOF. */ *pnum = MIN(bytes, hole - offset); + + /* + * We are not allowed to return partial sectors, though, so + * round up if necessary. + */ + if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) { + int64_t file_length = raw_getlength(bs); + if (file_length > 0) { + /* Ignore errors, this is just a safeguard */ + assert(hole == file_length); + } + *pnum = ROUND_UP(*pnum, bs->bl.request_alignment); + } + ret = BDRV_BLOCK_DATA; } else { /* On a hole, compute bytes to the beginning of the next extent. */ |