On 2017-05-31 12:41, Stefan Hajnoczi wrote: > On Fri, May 26, 2017 at 06:55:16PM +0200, Max Reitz wrote: >> @@ -2677,6 +2679,102 @@ static int qcow2_truncate(BlockDriverState *bs, >> int64_t offset, >> } >> break; >> >> + case PREALLOC_MODE_FALLOC: >> + case PREALLOC_MODE_FULL: >> + { >> + int64_t allocation_start, host_offset, guest_offset; >> + int64_t clusters_allocated; >> + int64_t old_file_size, new_file_size; >> + uint64_t nb_new_data_clusters, nb_new_l2_tables; >> + >> + old_file_size = bdrv_getlength(bs->file->bs); >> + if (old_file_size < 0) { >> + error_setg_errno(errp, -old_file_size, >> + "Failed to inquire current file length"); >> + return ret; >> + } >> + >> + nb_new_data_clusters = DIV_ROUND_UP(offset - old_length, >> + s->cluster_size); >> + >> + /* This is an overestimation; we will not actually allocate space >> for >> + * these in the file but just make sure the new refcount structures >> are >> + * able to cover them so we will not have to allocate new refblocks >> + * while entering the data blocks in the potentially new L2 tables. >> + * (We do not actually care where the L2 tables are placed. Maybe >> they >> + * are already allocated or they can be placed somewhere before >> + * @old_file_size. It does not matter because they will be fully >> + * allocated automatically, so they do not need to be covered by >> the >> + * preallocation. All that matters is that we will not have to >> allocate >> + * new refcount structures for them.) */ >> + nb_new_l2_tables = DIV_ROUND_UP(nb_new_data_clusters, >> + s->cluster_size / sizeof(uint64_t)); >> + /* The cluster range may not be aligned to L2 boundaries, so add >> one L2 >> + * table for a potential head/tail */ >> + nb_new_l2_tables++; >> + >> + allocation_start = qcow2_refcount_area(bs, old_file_size, >> + nb_new_data_clusters + >> + nb_new_l2_tables, >> + true, 0, 0); >> + if (allocation_start < 0) { >> + error_setg_errno(errp, -allocation_start, >> + "Failed to resize refcount structures"); >> + return -allocation_start; >> + } >> + >> + clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start, >> + nb_new_data_clusters); >> + if (clusters_allocated < 0) { >> + error_setg_errno(errp, -clusters_allocated, >> + "Failed to allocate data clusters"); >> + return -clusters_allocated; >> + } >> + >> + assert(clusters_allocated == nb_new_data_clusters); >> + >> + /* Allocate the data area */ >> + new_file_size = allocation_start + >> + nb_new_data_clusters * s->cluster_size; >> + ret = bdrv_truncate(bs->file, new_file_size, prealloc, errp); >> + if (ret < 0) { >> + error_prepend(errp, "Failed to resize underlying file: "); >> + qcow2_free_clusters(bs, allocation_start, >> + nb_new_data_clusters * s->cluster_size, >> + QCOW2_DISCARD_OTHER); >> + return ret; >> + } >> + >> + /* Create the necessary L2 entries */ >> + host_offset = allocation_start; >> + guest_offset = old_length; >> + while (nb_new_data_clusters) { >> + int64_t guest_cluster = guest_offset >> s->cluster_bits; >> + int64_t nb_clusters = MIN(nb_new_data_clusters, >> + s->l2_size - guest_cluster % >> s->l2_size); >> + QCowL2Meta allocation = { >> + .offset = guest_offset, >> + .alloc_offset = host_offset, >> + .nb_clusters = nb_clusters, >> + }; >> + qemu_co_queue_init(&allocation.dependent_requests); >> + >> + ret = qcow2_alloc_cluster_link_l2(bs, &allocation); >> + if (ret < 0) { >> + error_setg_errno(errp, -ret, "Failed to update L2 tables"); >> + qcow2_free_clusters(bs, host_offset, >> + nb_new_data_clusters * s->cluster_size, >> + QCOW2_DISCARD_OTHER); >> + return ret; >> + } >> + >> + guest_offset += nb_clusters * s->cluster_size; >> + host_offset += nb_clusters * s->cluster_size; >> + nb_new_data_clusters -= nb_clusters; >> + } >> + break; >> + } > > Flush L1/L2 tables?
Right. It would be good to actually have the area allocated for sure before writing the new size. :-) The same applies to the metadata-only preallocate(), though. So this should probably be added in patch 11. Thanks for spotting this, and thanks for reviewing! Max
signature.asc
Description: OpenPGP digital signature