qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v4 05/30] qcow2: Process QCOW2_CLUSTER_ZERO_ALLOC clusters in


From: Alberto Garcia
Subject: Re: [PATCH v4 05/30] qcow2: Process QCOW2_CLUSTER_ZERO_ALLOC clusters in handle_copied()
Date: Thu, 09 Apr 2020 18:08:17 +0200
User-agent: Notmuch/0.18.2 (http://notmuchmail.org) Emacs/24.4.1 (i586-pc-linux-gnu)

On Thu 09 Apr 2020 12:59:30 PM CEST, Vladimir Sementsov-Ogievskiy wrote:
>>   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)
>>   {
>>       BDRVQcow2State *s = bs->opaque;
>> -    unsigned cow_start_from = 0;
>> +    int l2_index = offset_to_l2_slice_index(s, guest_offset);
>> +    uint64_t l2_entry;
>> +    unsigned cow_start_from, cow_end_to;
>>       unsigned cow_start_to = offset_into_cluster(s, guest_offset);
>>       unsigned cow_end_from = cow_start_to + bytes;
>> -    unsigned cow_end_to = ROUND_UP(cow_end_from, s->cluster_size);
>>       unsigned nb_clusters = size_to_clusters(s, cow_end_from);
>>       QCowL2Meta *old_m = *m;
>> +    QCow2ClusterType type;
>> +
>> +    assert(nb_clusters <= s->l2_slice_size - l2_index);
>> +
>> +    /* 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) {
>
> Could we also allow full ZERO_ALLOC clusters here?

No, because the L2 entry needs to be modified (in order to remove the
'all zeroes' bit) and we need to create a QCowL2Meta entry for that (see
qcow2_handle_l2meta()).

>> +    /* Get the L2 entry of the first cluster */
>> +    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 of the last cluster */
>> +    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);
>> +    }
>
> These two ifs may be moved into if (keep_old), and drop "&& keep_old"
> from conditions. This also will allow to drop extra calculations, move
> new variables to if (keep_old) {} block and allow to pass
> l2_slice=NULL together with keep_old=false.

In subsequent patches we're going to have more cases than just
QCOW2_CLUSTER_NORMAL so I don't think it makes sense to move the
keep_old check around.

>> @@ -1239,7 +1304,8 @@ static int handle_copied(BlockDriverState *bs, 
>> uint64_t guest_offset,
>>   
>>       l2_index = offset_to_l2_slice_index(s, guest_offset);
>>       nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
>> -    assert(nb_clusters <= INT_MAX);
>> +    /* Limit total byte count to BDRV_REQUEST_MAX_BYTES */
>> +    nb_clusters = MIN(nb_clusters, BDRV_REQUEST_MAX_BYTES >> 
>> s->cluster_bits);
>>   
>>       /* Find L2 entry for the first involved cluster */
>>       ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index);
>> @@ -1249,18 +1315,17 @@ static int handle_copied(BlockDriverState *bs, 
>> uint64_t guest_offset,
>>   
>>       cluster_offset = be64_to_cpu(l2_slice[l2_index]);
>
> It would be good to s/cluster_offset/l2_entry/
>
> And, "cluster_offset & L2E_OFFSET_MASK" is used so many times, so, I'd
> not substitute, but keep both variables: l2_entry and cluster_offset.

Sounds good, I can change that.

>> +    /* Allocate at a given offset in the image file */
>> +    alloc_cluster_offset = *host_offset == INV_OFFSET ? INV_OFFSET :
>> +        start_of_cluster(s, *host_offset);
>> +    ret = do_alloc_cluster_offset(bs, guest_offset, &alloc_cluster_offset,
>> +                                  &nb_clusters);
>> +    if (ret < 0) {
>> +        goto out;
>>       }
>>   
>> -    qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
>
> actually we don't need l2_slice for keep_old=false in
> calculate_l2_meta, so if calculate_l2_meta modified a bit, change of
> function tail is not needed..
>
> Still, may be l2_slice will be used in calculate_l2_meta() in further
> patches? Will see..

We'll need it in a later patch.

>> -fail:
>> -    if (*m && (*m)->nb_clusters > 0) {
>> +out:
>> +    qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
>> +    if (ret < 0 && *m && (*m)->nb_clusters > 0) {
>>           QLIST_REMOVE(*m, next_in_flight);
>>       }
>
> Hmm, unrelated to the patch, but why do we remove meta, which we
> didn't create?

Not sure actually, I would need to check further...

Berto



reply via email to

[Prev in Thread] Current Thread [Next in Thread]