I have no idea how I managed to forgot some style comments I wrote during the review, but, anyway: On 22.12.19 12:36, Alberto Garcia wrote: > When writing to a qcow2 file there are two functions that take a > virtual offset and return a host offset, possibly allocating new > clusters if necessary: > > - handle_copied() looks for normal data clusters that are already > allocated and have a reference count of 1. In those clusters we > can simply write the data and there is no need to perform any > copy-on-write. > > - handle_alloc() looks for clusters that do need copy-on-write, > either because they haven't been allocated yet, because their > reference count is != 1 or because they are ZERO_ALLOC clusters. > > The ZERO_ALLOC case is a bit special because those are clusters that > are already allocated and they could perfectly be dealt with in > handle_copied() (as long as copy-on-write is performed when required). > > In fact, there is extra code specifically for them in handle_alloc() > that tries to reuse the existing allocation if possible and frees them > otherwise. > > This patch changes the handling of ZERO_ALLOC clusters so the > semantics of these two functions are now like this: > > - handle_copied() looks for clusters that are already allocated and > which we can overwrite (NORMAL and ZERO_ALLOC clusters with a > reference count of 1). > > - handle_alloc() looks for clusters for which we need a new > allocation (all other cases). > > One importante difference after this change is that clusters found in s/importante/important/ > handle_copied() may now require copy-on-write, but this will be anyway > necessary once we add support for subclusters. > > Signed-off-by: Alberto Garcia > --- > block/qcow2-cluster.c | 226 +++++++++++++++++++++++------------------- > 1 file changed, 126 insertions(+), 100 deletions(-) > > diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c > index e078bddcc2..9387f15866 100644 > --- a/block/qcow2-cluster.c > +++ b/block/qcow2-cluster.c [...] > @@ -1035,15 +1040,53 @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) > static void calculate_l2_meta(BlockDriverState *bs, > uint64_t host_cluster_offset, > uint64_t guest_offset, unsigned bytes, > - QCowL2Meta **m, bool keep_old) > + uint64_t *l2_slice, QCowL2Meta **m, bool keep_old) > { [...] > + /* Return if there's no COW (all clusters are normal and we keep them) */ > + if (keep_old) { > + int i; > + for (i = 0; i < nb_clusters; i++) { > + l2_entry = be64_to_cpu(l2_slice[l2_index + i]); > + if (qcow2_get_cluster_type(bs, l2_entry) != QCOW2_CLUSTER_NORMAL) { > + break; > + } > + } > + if (i == nb_clusters) { > + return; > + } > + } > + > + /* Get the L2 entry from the first cluster */ s/from/of/ (Otherwise it sounds a bit like this is the same entry for all clusters) > + l2_entry = be64_to_cpu(l2_slice[l2_index]); > + type = qcow2_get_cluster_type(bs, l2_entry); > + > + if (type == QCOW2_CLUSTER_NORMAL && keep_old) { > + cow_start_from = cow_start_to; > + } else { > + cow_start_from = 0; > + } > + > + /* Get the L2 entry from the last cluster */ s/from/of/ > + l2_entry = be64_to_cpu(l2_slice[l2_index + nb_clusters - 1]); > + type = qcow2_get_cluster_type(bs, l2_entry); > + > + if (type == QCOW2_CLUSTER_NORMAL && keep_old) { > + cow_end_to = cow_end_from; > + } else { > + cow_end_to = ROUND_UP(cow_end_from, s->cluster_size); > + } > > *m = g_malloc0(sizeof(**m)); > **m = (QCowL2Meta) { > @@ -1069,18 +1112,20 @@ static void calculate_l2_meta(BlockDriverState *bs, > QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight); > } > > -/* Returns true if writing to a cluster requires COW */ > -static bool cluster_needs_cow(BlockDriverState *bs, uint64_t l2_entry) > +/* Returns true if writing to the cluster pointed to by @l2_entry > + * requires a new allocation (that is, if the cluster is unallocated > + * or has refcount > 1 and therefore cannot be written in-place). */ Not sure why Patchew hasn’t complained, but the current coding style requires /* and */ to be on separate lines for multi-line comments. Max