X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=block%2Fvhdx.c;h=fa9e544a5e22c428af8a11c5a869b2c9dfd1987e;hb=e0d0ddc591a079d2a3da6aa913ba7dd9551fb5ef;hp=f02d2611bef85d885c36fc0e097c13bff78f656d;hpb=69f735179e064ba4e2c30653f681b616b4791aa7;p=mirror_qemu.git diff --git a/block/vhdx.c b/block/vhdx.c index f02d2611be..fa9e544a5e 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -411,8 +411,7 @@ int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, if (ret < 0) { return ret; } - ret = vhdx_update_header(bs, s, generate_data_write_guid, log_guid); - return ret; + return vhdx_update_header(bs, s, generate_data_write_guid, log_guid); } /* opens the specified header block from the VHDX file header section */ @@ -997,8 +996,8 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, uint64_t signature; Error *local_err = NULL; - bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, - false, errp); + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, + BDRV_CHILD_IMAGE, false, errp); if (!bs->file) { return -EINVAL; } @@ -1241,12 +1240,16 @@ exit: /* * Allocate a new payload block at the end of the file. * - * Allocation will happen at 1MB alignment inside the file + * Allocation will happen at 1MB alignment inside the file. + * + * If @need_zero is set on entry but not cleared on return, then truncation + * could not guarantee that the new portion reads as zero, and the caller + * will take care of it instead. * * Returns the file offset start of the new payload block */ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s, - uint64_t *new_offset) + uint64_t *new_offset, bool *need_zero) { int64_t current_len; @@ -1263,8 +1266,19 @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s, return -EINVAL; } + if (*need_zero) { + int ret; + + ret = bdrv_truncate(bs->file, *new_offset + s->block_size, false, + PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, NULL); + if (ret != -ENOTSUP) { + *need_zero = false; + return ret; + } + } + return bdrv_truncate(bs->file, *new_offset + s->block_size, false, - PREALLOC_MODE_OFF, NULL); + PREALLOC_MODE_OFF, 0, NULL); } /* @@ -1356,18 +1370,38 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, /* in this case, we need to preserve zero writes for * data that is not part of this write, so we must pad * the rest of the buffer to zeroes */ - - /* if we are on a posix system with ftruncate() that extends - * a file, then it is zero-filled for us. On Win32, the raw - * layer uses SetFilePointer and SetFileEnd, which does not - * zero fill AFAIK */ - - /* Queue another write of zero buffers if the underlying file - * does not zero-fill on file extension */ - - if (bdrv_has_zero_init_truncate(bs->file->bs) == 0) { - use_zero_buffers = true; - + use_zero_buffers = true; + /* fall through */ + case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */ + case PAYLOAD_BLOCK_UNMAPPED: + case PAYLOAD_BLOCK_UNMAPPED_v095: + case PAYLOAD_BLOCK_UNDEFINED: + bat_prior_offset = sinfo.file_offset; + ret = vhdx_allocate_block(bs, s, &sinfo.file_offset, + &use_zero_buffers); + if (ret < 0) { + goto exit; + } + /* + * once we support differencing files, this may also be + * partially present + */ + /* update block state to the newly specified state */ + vhdx_update_bat_table_entry(bs, s, &sinfo, &bat_entry, + &bat_entry_offset, + PAYLOAD_BLOCK_FULLY_PRESENT); + bat_update = true; + /* + * Since we just allocated a block, file_offset is the + * beginning of the payload block. It needs to be the + * write address, which includes the offset into the + * block, unless the entire block needs to read as + * zeroes but truncation was not able to provide them, + * in which case we need to fill in the rest. + */ + if (!use_zero_buffers) { + sinfo.file_offset += sinfo.block_offset; + } else { /* zero fill the front, if any */ if (sinfo.block_offset) { iov1.iov_len = sinfo.block_offset; @@ -1379,7 +1413,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, } /* our actual data */ - qemu_iovec_concat(&hd_qiov, qiov, bytes_done, + qemu_iovec_concat(&hd_qiov, qiov, bytes_done, sinfo.bytes_avail); /* zero fill the back, if any */ @@ -1394,29 +1428,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, sectors_to_write += iov2.iov_len >> BDRV_SECTOR_BITS; } } - /* fall through */ - case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */ - case PAYLOAD_BLOCK_UNMAPPED: - case PAYLOAD_BLOCK_UNMAPPED_v095: - case PAYLOAD_BLOCK_UNDEFINED: - bat_prior_offset = sinfo.file_offset; - ret = vhdx_allocate_block(bs, s, &sinfo.file_offset); - if (ret < 0) { - goto exit; - } - /* once we support differencing files, this may also be - * partially present */ - /* update block state to the newly specified state */ - vhdx_update_bat_table_entry(bs, s, &sinfo, &bat_entry, - &bat_entry_offset, - PAYLOAD_BLOCK_FULLY_PRESENT); - bat_update = true; - /* since we just allocated a block, file_offset is the - * beginning of the payload block. It needs to be the - * write address, which includes the offset into the block */ - if (!use_zero_buffers) { - sinfo.file_offset += sinfo.block_offset; - } + /* fall through */ case PAYLOAD_BLOCK_FULLY_PRESENT: /* if the file offset address is in the header zone, @@ -1703,13 +1715,13 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, /* All zeroes, so we can just extend the file - the end of the BAT * is the furthest thing we have written yet */ ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF, - errp); + 0, errp); if (ret < 0) { goto exit; } } else if (type == VHDX_TYPE_FIXED) { ret = blk_truncate(blk, data_file_offset + image_size, false, - PREALLOC_MODE_OFF, errp); + PREALLOC_MODE_OFF, 0, errp); if (ret < 0) { goto exit; } @@ -1984,10 +1996,10 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts, return -EIO; } - blk = blk_new(bdrv_get_aio_context(bs), - BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, errp); - if (ret < 0) { + blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); + if (!blk) { + ret = -EPERM; goto delete_and_exit; } blk_set_allow_write_beyond_eof(blk, true); @@ -2046,7 +2058,8 @@ delete_and_exit: return ret; } -static int coroutine_fn vhdx_co_create_opts(const char *filename, +static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv, + const char *filename, QemuOpts *opts, Error **errp) { @@ -2205,20 +2218,20 @@ static QemuOptsList vhdx_create_opts = { .name = VHDX_BLOCK_OPT_BLOCK_SIZE, .type = QEMU_OPT_SIZE, .def_value_str = stringify(0), - .help = "Block Size; min 1MB, max 256MB. " \ + .help = "Block Size; min 1MB, max 256MB. " "0 means auto-calculate based on image size." }, { .name = BLOCK_OPT_SUBFMT, .type = QEMU_OPT_STRING, - .help = "VHDX format type, can be either 'dynamic' or 'fixed'. "\ + .help = "VHDX format type, can be either 'dynamic' or 'fixed'. " "Default is 'dynamic'." }, { .name = VHDX_BLOCK_OPT_ZERO, .type = QEMU_OPT_BOOL, - .help = "Force use of payload blocks of type 'ZERO'. "\ - "Non-standard, but default. Do not set to 'off' when "\ + .help = "Force use of payload blocks of type 'ZERO'. " + "Non-standard, but default. Do not set to 'off' when " "using 'qemu-img convert' with subformat=dynamic." }, { NULL } @@ -2232,7 +2245,7 @@ static BlockDriver bdrv_vhdx = { .bdrv_open = vhdx_open, .bdrv_close = vhdx_close, .bdrv_reopen_prepare = vhdx_reopen_prepare, - .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_child_perm = bdrv_default_perms, .bdrv_co_readv = vhdx_co_readv, .bdrv_co_writev = vhdx_co_writev, .bdrv_co_create = vhdx_co_create, @@ -2241,6 +2254,7 @@ static BlockDriver bdrv_vhdx = { .bdrv_co_check = vhdx_co_check, .bdrv_has_zero_init = vhdx_has_zero_init, + .is_format = true, .create_opts = &vhdx_create_opts, };