diff mbox series

[v4,19/30] qcow2: Add subcluster support to zero_in_l2_slice()

Message ID f1d8c4bcf7c94e0cedbd96f1d7df9ea9905bddb3.1584468723.git.berto@igalia.com (mailing list archive)
State New, archived
Headers show
Series Add subcluster allocation to qcow2 | expand

Commit Message

Alberto Garcia March 17, 2020, 6:16 p.m. UTC
Setting the QCOW_OFLAG_ZERO bit of the L2 entry is forbidden if an
image has subclusters. Instead, the individual 'all zeroes' bits must
be used.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/qcow2-cluster.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

Comments

Vladimir Sementsov-Ogievskiy April 22, 2020, 11:06 a.m. UTC | #1
17.03.2020 21:16, Alberto Garcia wrote:
> Setting the QCOW_OFLAG_ZERO bit of the L2 entry is forbidden if an
> image has subclusters. Instead, the individual 'all zeroes' bits must
> be used.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>

anyway:
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>

still, some comments below

> ---
>   block/qcow2-cluster.c | 14 ++++++++++----
>   1 file changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
> index 6f2643ba53..746006a117 100644
> --- a/block/qcow2-cluster.c
> +++ b/block/qcow2-cluster.c
> @@ -1897,7 +1897,7 @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,

As I see, function is not prepared to handle unaligned offset. Worth add an assertion while being here?

>       assert(nb_clusters <= INT_MAX);
>   
>       for (i = 0; i < nb_clusters; i++) {
> -        uint64_t old_offset;
> +        uint64_t old_offset, l2_entry = 0;

I'd rename s/old_offset/old_l2_entry

>           QCow2ClusterType cluster_type;
>   
>           old_offset = get_l2_entry(s, l2_slice, l2_index + i);

more context:

 >         /*
 >          * Minimize L2 changes if the cluster already reads back as
 >          * zeroes with correct allocation.
 >          */
 >         cluster_type = qcow2_get_cluster_type(bs, old_offset);
 >         if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN ||
 >             (cluster_type == QCOW2_CLUSTER_ZERO_ALLOC && !unmap)) {

Worth assert !has_subclusters(s), or mark image corrupted?

 >             continue;
 >         }


> @@ -1914,12 +1914,18 @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
>   
>           qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
>           if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
> -            set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO);
>               qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
>           } else {
> -            uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);
> -            set_l2_entry(s, l2_slice, l2_index + i, entry | QCOW_OFLAG_ZERO);
> +            l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
>           }
> +
> +        if (has_subclusters(s)) {
> +            set_l2_bitmap(s, l2_slice, l2_index + i, QCOW_L2_BITMAP_ALL_ZEROES);
> +        } else {
> +            l2_entry |= QCOW_OFLAG_ZERO;
> +        }
> +
> +        set_l2_entry(s, l2_slice, l2_index + i, l2_entry);

For subclasters & !unmap case we set the same value.. And we even don't need to get it.

may be

           if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
               qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
               set_l2_entry(s, l2_slice, l2_index + i,
                            has_subclusters(s) ? 0 : QCOW_OFLAG_ZERO);
           } else if (!has_subclusters(s)) {
               uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);
               set_l2_entry(s, l2_slice, l2_index + i, entry | QCOW_OFLAG_ZERO);
           }

           if (has_subclusters(s)) {
               set_l2_bitmap(s, l2_slice, l2_index + i, QCOW_L2_BITMAP_ALL_ZEROES);
           }




>       }
>   
>       qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
>
Alberto Garcia April 22, 2020, 12:53 p.m. UTC | #2
On Wed 22 Apr 2020 01:06:42 PM CEST, Vladimir Sementsov-Ogievskiy wrote:
>> @@ -1897,7 +1897,7 @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
>
> As I see, function is not prepared to handle unaligned offset. Worth
> add an assertion while being here?

The only caller already asserts that, and the length parameter is not
even the number of bytes but the number of clusters, so I don't think
it's so important in this case.

>>       for (i = 0; i < nb_clusters; i++) {
>> -        uint64_t old_offset;
>> +        uint64_t old_offset, l2_entry = 0;
>
> I'd rename s/old_offset/old_l2_entry

I think we can get rid of old_offset altogether. I'll think of a way to
restructure the logics along the lines that you suggest.

Thanks!

Berto
diff mbox series

Patch

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 6f2643ba53..746006a117 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1897,7 +1897,7 @@  static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
     assert(nb_clusters <= INT_MAX);
 
     for (i = 0; i < nb_clusters; i++) {
-        uint64_t old_offset;
+        uint64_t old_offset, l2_entry = 0;
         QCow2ClusterType cluster_type;
 
         old_offset = get_l2_entry(s, l2_slice, l2_index + i);
@@ -1914,12 +1914,18 @@  static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
 
         qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
         if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
-            set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO);
             qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
         } else {
-            uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);
-            set_l2_entry(s, l2_slice, l2_index + i, entry | QCOW_OFLAG_ZERO);
+            l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
         }
+
+        if (has_subclusters(s)) {
+            set_l2_bitmap(s, l2_slice, l2_index + i, QCOW_L2_BITMAP_ALL_ZEROES);
+        } else {
+            l2_entry |= QCOW_OFLAG_ZERO;
+        }
+
+        set_l2_entry(s, l2_slice, l2_index + i, l2_entry);
     }
 
     qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);