On 05/05/2017 03:51 PM, Max Reitz wrote:
> On 04.05.2017 05:07, Eric Blake wrote:
>> Treat plain zero clusters differently from allocated ones, so that
>> we can simplify the logic of checking whether an offset is present.
>> Do this by splitting QCOW2_CLUSTER_ZERO into two new enums,
>> QCOW2_CLUSTER_ZERO_PLAIN and QCOW2_CLUSTER_ZERO_ALLOC.
>>
>> I tried to arrange the enum so that we could use
>> 'ret <= QCOW2_CLUSTER_ZERO_PLAIN' for all unallocated types, and
>> 'ret >= QCOW2_CLUSTER_ZERO_ALLOC' for allocated types, although
>> I didn't actually end up taking advantage of the layout.
>>
>> In many cases, this leads to simpler code, by properly combining
>> cases (sometimes, both zero types pair together, other times,
>> plain zero is more like unallocated while allocated zero is more
>> like normal).
>>
>> Signed-off-by: Eric Blake <ebl...@redhat.com>
>>

>> @@ -558,52 +557,32 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, 
>> uint64_t offset,
>>      assert(nb_clusters <= INT_MAX);
>>
>>      ret = qcow2_get_cluster_type(*cluster_offset);
>> +    if (s->qcow_version < 3 && (ret == QCOW2_CLUSTER_ZERO_PLAIN ||
>> +                                ret == QCOW2_CLUSTER_ZERO_ALLOC)) {
>> +        qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"
>> +                                " in pre-v3 image (L2 offset: %#" PRIx64
>> +                                ", L2 index: %#x)", l2_offset, l2_index);
>> +        ret = -EIO;
>> +        goto fail;
>> +    }
...
>> +    case QCOW2_CLUSTER_ZERO_PLAIN:
>>      case QCOW2_CLUSTER_UNALLOCATED:
>>          /* how many empty clusters ? */
>>          c = count_contiguous_clusters_unallocated(nb_clusters,
>> -                                                  &l2_table[l2_index],
>> -                                                  
>> QCOW2_CLUSTER_UNALLOCATED);
>> +                                                  &l2_table[l2_index], ret);
> 
> Nit pick: Using ret here is a bit weird (because it's such a meaningless
> name). It would be good if we had a separate cluster_type variable.

qcow2_get_cluster_offset() returns the cluster type on success, and
-errno on failure.  So 'ret' actually makes some sense: it really is the
value we are about to return.  But it may also work to have a separate
variable up front, then assign ret = cluster_type at the end; I'll play
with it and see which one looks better.

> 
>>          *cluster_offset = 0;
>>          break;
>> +    case QCOW2_CLUSTER_ZERO_ALLOC:
>>      case QCOW2_CLUSTER_NORMAL:
>>          /* how many allocated clusters ? */
>>          c = count_contiguous_clusters(nb_clusters, s->cluster_size,
>> -                &l2_table[l2_index], QCOW_OFLAG_ZERO);
>> +                                      &l2_table[l2_index], QCOW_OFLAG_ZERO);
>>          *cluster_offset &= L2E_OFFSET_MASK;
>>          if (offset_into_cluster(s, *cluster_offset)) {
>>              qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset 
>> %#"
> 
> Well, preallocated zero clusters are not exactly data clusters... Not
> that any user cared, but s/Data cluster/Cluster allocation/ would be
> more correct.

Good idea.

> 
> By the way, allow me to state just how much I love this hunk: Very much.
> Looks great! It gets a place on my list of favorite hunks of this year
> at least.
> 
> [...]
> 
>> @@ -1760,7 +1740,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState 
>> *bs, uint64_t *l1_table,
>>              int cluster_type = qcow2_get_cluster_type(l2_entry);>           
>>    bool preallocated = offset != 0;
> 
> I could get behind removing this variable and replacing all
> "if (!preallocated)" instances by
> "if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN)". Up to you, though.

Makes sense.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to