All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size
@ 2018-01-26 14:59 Alberto Garcia
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 01/39] qcow2: Fix documentation of get_cluster_table() Alberto Garcia
                   ` (38 more replies)
  0 siblings, 39 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

this is the new revision of the patch series to allow configuring the
entry size of the qcow2 L2 cache. Follow this link for the full
description from the first version:

   https://lists.gnu.org/archive/html/qemu-block/2017-10/msg00458.html

And here are some numbers showing the performance improvements:

   https://lists.gnu.org/archive/html/qemu-block/2017-12/msg00507.html

There are more patches in this revision but that's because I split the
hairiest ones as Eric suggested. Those should be much easier to review
now. There's also a few new test cases.

Regards,

Berto

Changes:

v3:
- Rebased on top of 1867d97b372d452184c65e8fcc273cfc45937541
- Patch 2: Use QEMU_IS_ALIGNED() instead of doing the bit operations
           manually [Eric]
- Patch 13: Clarify that l2_slice_size means size in entries, not
            bytes [Eric].
- Patch 16-17: The previous code has been splitted into patches 16 and
               17 for clarity.
- Patch 17: Use slice_size2 for storing the size of the slice in bytes
            (keeping the existing convention used in l1_size2 or
            refcount_table_size2)
- Patch 17: Flush the cache only once [Anton, Eric]
- Patch 17: Call l2_load() after qcow2_free_clusters() [Anton]
- Patch 18 [new]: Refactor the l2_load() call in get_cluster_table()
           [Anton]
- Patch 19: Fix typo [Eric]
- Patch 26-27: The previous code has been splitted into patches 26 and
               27 for clarity.
- Patch 27: Use slice_size2 for storing the size of the slice in bytes
- Patch 28-30: The previous code has been splitted into patches 28, 29
               and 30 for clarity.
- Patch 30: Use slice_size2 for storing the size of the slice in bytes
- Patch 30: Replace bdrv_read/write() with bdrv_pread/pwrite() [Eric]
- Patch 30: Initialize l2_dirty inside the inner loop [Anton]
- Patch 36: Fix maybe-uninitialized warning of l2_cache_entry_size
            [Anton]
- Patch 36: Make MIN_L2_CACHE_SIZE the minimum number of cache
            entries, not clusters [Anton]
- Patch 36: Add l2-cache-entry-size to BlockdevOptionsQcow2 [Eric]
- Patch 37-39: New iotests.

v2: https://lists.gnu.org/archive/html/qemu-block/2017-12/msg00507.html
- Rebased after the v2.11.0 release.
- Patch 2: Adjust the unaligned access check introduce by Max in 4efb1f7c612
- Patch 18: Prevent overflow when computing bytes_available in
  qcow2_get_cluster_offset()
- Patch 31: Fix typo in error message in read_cache_sizes()
- Patch 32 [new]: Add test for l2-cache-entry-size'

v1: https://lists.gnu.org/archive/html/qemu-block/2017-10/msg00458.html
- Initial version

Here's the ouput of git backport-diff against v2:

Key:
[----] : patches are identical
[####] : number of functional differences between upstream/downstream patch
[down] : patch is downstream-only
The flags [FC] indicate (F)unctional and (C)ontextual differences, respectively

001/39:[----] [--] 'qcow2: Fix documentation of get_cluster_table()'
002/39:[0002] [FC] 'qcow2: Add table size field to Qcow2Cache'
003/39:[----] [--] 'qcow2: Remove BDS parameter from qcow2_cache_get_table_addr()'
004/39:[----] [--] 'qcow2: Remove BDS parameter from qcow2_cache_get_table_idx()'
005/39:[----] [--] 'qcow2: Remove BDS parameter from qcow2_cache_table_release()'
006/39:[----] [--] 'qcow2: Remove BDS parameter from qcow2_cache_entry_mark_dirty()'
007/39:[----] [--] 'qcow2: Remove BDS parameter from qcow2_cache_put()'
008/39:[----] [--] 'qcow2: Remove BDS parameter from qcow2_cache_destroy()'
009/39:[----] [--] 'qcow2: Remove BDS parameter from qcow2_cache_clean_unused()'
010/39:[----] [--] 'qcow2: Remove BDS parameter from qcow2_cache_discard()'
011/39:[----] [--] 'qcow2: Remove BDS parameter from qcow2_cache_is_table_offset()'
012/39:[----] [--] 'qcow2: Add offset_to_l1_index()'
013/39:[0002] [FC] 'qcow2: Add l2_slice_size field to BDRVQcow2State'
014/39:[----] [--] 'qcow2: Add offset_to_l2_slice_index()'
015/39:[----] [--] 'qcow2: Update l2_load() to support L2 slices'
016/39:[down] 'qcow2: Prepare l2_allocate() for adding L2 slice support'
017/39:[0088] [FC] 'qcow2: Update l2_allocate() to support L2 slices'
018/39:[down] 'qcow2: Refactor get_cluster_table()'
019/39:[0016] [FC] 'qcow2: Update get_cluster_table() to support L2 slices'
020/39:[----] [--] 'qcow2: Update qcow2_get_cluster_offset() to support L2 slices'
021/39:[----] [--] 'qcow2: Update qcow2_alloc_cluster_link_l2() to support L2 slices'
022/39:[----] [--] 'qcow2: Update handle_copied() to support L2 slices'
023/39:[----] [--] 'qcow2: Update handle_alloc() to support L2 slices'
024/39:[----] [--] 'qcow2: Update discard_single_l2() to support L2 slices'
025/39:[----] [--] 'qcow2: Update zero_single_l2() to support L2 slices'
026/39:[down] 'qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support'
027/39:[0147] [FC] 'qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices'
028/39:[down] 'qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1()'
029/39:[down] 'qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support'
030/39:[0211] [FC] 'qcow2: Update expand_zero_clusters_in_l1() to support L2 slices'
031/39:[----] [--] 'qcow2: Update qcow2_truncate() to support L2 slices'
032/39:[----] [--] 'qcow2: Rename l2_table in qcow2_alloc_compressed_cluster_offset()'
033/39:[----] [--] 'qcow2: Rename l2_table in count_contiguous_clusters()'
034/39:[----] [--] 'qcow2: Rename l2_table in count_contiguous_clusters_unallocated()'
035/39:[----] [--] 'qcow2: Rename l2_table in count_cow_clusters()'
036/39:[0015] [FC] 'qcow2: Allow configuring the L2 slice size'
037/39:[down] 'iotests: Test valid values of l2-cache-entry-size'
038/39:[down] 'iotests: Test downgrading an image using a small L2 slice size'
039/39:[down] 'iotests: Add l2-cache-entry-size to iotest 137'

Alberto Garcia (39):
  qcow2: Fix documentation of get_cluster_table()
  qcow2: Add table size field to Qcow2Cache
  qcow2: Remove BDS parameter from qcow2_cache_get_table_addr()
  qcow2: Remove BDS parameter from qcow2_cache_get_table_idx()
  qcow2: Remove BDS parameter from qcow2_cache_table_release()
  qcow2: Remove BDS parameter from qcow2_cache_entry_mark_dirty()
  qcow2: Remove BDS parameter from qcow2_cache_put()
  qcow2: Remove BDS parameter from qcow2_cache_destroy()
  qcow2: Remove BDS parameter from qcow2_cache_clean_unused()
  qcow2: Remove BDS parameter from qcow2_cache_discard()
  qcow2: Remove BDS parameter from qcow2_cache_is_table_offset()
  qcow2: Add offset_to_l1_index()
  qcow2: Add l2_slice_size field to BDRVQcow2State
  qcow2: Add offset_to_l2_slice_index()
  qcow2: Update l2_load() to support L2 slices
  qcow2: Prepare l2_allocate() for adding L2 slice support
  qcow2: Update l2_allocate() to support L2 slices
  qcow2: Refactor get_cluster_table()
  qcow2: Update get_cluster_table() to support L2 slices
  qcow2: Update qcow2_get_cluster_offset() to support L2 slices
  qcow2: Update qcow2_alloc_cluster_link_l2() to support L2 slices
  qcow2: Update handle_copied() to support L2 slices
  qcow2: Update handle_alloc() to support L2 slices
  qcow2: Update discard_single_l2() to support L2 slices
  qcow2: Update zero_single_l2() to support L2 slices
  qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice
    support
  qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices
  qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1()
  qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice
    support
  qcow2: Update expand_zero_clusters_in_l1() to support L2 slices
  qcow2: Update qcow2_truncate() to support L2 slices
  qcow2: Rename l2_table in qcow2_alloc_compressed_cluster_offset()
  qcow2: Rename l2_table in count_contiguous_clusters()
  qcow2: Rename l2_table in count_contiguous_clusters_unallocated()
  qcow2: Rename l2_table in count_cow_clusters()
  qcow2: Allow configuring the L2 slice size
  iotests: Test valid values of l2-cache-entry-size
  iotests: Test downgrading an image using a small L2 slice size
  iotests: Add l2-cache-entry-size to iotest 137

 block/qcow2-cache.c        |  80 ++++----
 block/qcow2-cluster.c      | 492 ++++++++++++++++++++++++---------------------
 block/qcow2-refcount.c     | 199 +++++++++---------
 block/qcow2.c              |  60 ++++--
 block/qcow2.h              |  31 ++-
 qapi/block-core.json       |   6 +
 tests/qemu-iotests/061     |  16 ++
 tests/qemu-iotests/061.out |  61 ++++++
 tests/qemu-iotests/103     |  17 ++
 tests/qemu-iotests/103.out |   3 +
 tests/qemu-iotests/137     |   5 +
 tests/qemu-iotests/137.out |   2 +
 12 files changed, 575 insertions(+), 397 deletions(-)

-- 
2.11.0

^ permalink raw reply	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 01/39] qcow2: Fix documentation of get_cluster_table()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:16   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 02/39] qcow2: Add table size field to Qcow2Cache Alberto Garcia
                   ` (37 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function has not been returning the offset of the L2 table since
commit 3948d1d4876065160583e79533bf604481063833

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index a3fec27bf9..8163983d28 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -648,8 +648,7 @@ fail:
  * for a given disk offset, load (and allocate if needed)
  * the l2 table.
  *
- * the l2 table offset in the qcow2 file and the cluster index
- * in the l2 table are given to the caller.
+ * the cluster index in the l2 table is given to the caller.
  *
  * Returns 0 on success, -errno in failure case
  */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 02/39] qcow2: Add table size field to Qcow2Cache
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 01/39] qcow2: Fix documentation of get_cluster_table() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:25   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 03/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_addr() Alberto Garcia
                   ` (36 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

The table size in the qcow2 cache is currently equal to the cluster
size. This doesn't allow us to use the cache memory efficiently,
particularly with large cluster sizes, so we need to be able to have
smaller cache tables that are independent from the cluster size. This
patch adds a new field to Qcow2Cache that we can use instead of the
cluster size.

The current table size is still being initialized to the cluster size,
so there are no semantic changes yet, but this patch will allow us to
prepare the rest of the code and simplify a few function calls.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c | 29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index c48ffebd8f..38c03770b4 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -39,6 +39,7 @@ struct Qcow2Cache {
     Qcow2CachedTable       *entries;
     struct Qcow2Cache      *depends;
     int                     size;
+    int                     table_size;
     bool                    depends_on_flush;
     void                   *table_array;
     uint64_t                lru_counter;
@@ -48,17 +49,15 @@ struct Qcow2Cache {
 static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
                     Qcow2Cache *c, int table)
 {
-    BDRVQcow2State *s = bs->opaque;
-    return (uint8_t *) c->table_array + (size_t) table * s->cluster_size;
+    return (uint8_t *) c->table_array + (size_t) table * c->table_size;
 }
 
 static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
                   Qcow2Cache *c, void *table)
 {
-    BDRVQcow2State *s = bs->opaque;
     ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
-    int idx = table_offset / s->cluster_size;
-    assert(idx >= 0 && idx < c->size && table_offset % s->cluster_size == 0);
+    int idx = table_offset / c->table_size;
+    assert(idx >= 0 && idx < c->size && table_offset % c->table_size == 0);
     return idx;
 }
 
@@ -79,10 +78,9 @@ static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
 {
 /* Using MADV_DONTNEED to discard memory is a Linux-specific feature */
 #ifdef CONFIG_LINUX
-    BDRVQcow2State *s = bs->opaque;
     void *t = qcow2_cache_get_table_addr(bs, c, i);
     int align = getpagesize();
-    size_t mem_size = (size_t) s->cluster_size * num_tables;
+    size_t mem_size = (size_t) c->table_size * num_tables;
     size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
     size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align);
     if (mem_size > offset && length > 0) {
@@ -132,9 +130,10 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
 
     c = g_new0(Qcow2Cache, 1);
     c->size = num_tables;
+    c->table_size = s->cluster_size;
     c->entries = g_try_new0(Qcow2CachedTable, num_tables);
     c->table_array = qemu_try_blockalign(bs->file->bs,
-                                         (size_t) num_tables * s->cluster_size);
+                                         (size_t) num_tables * c->table_size);
 
     if (!c->entries || !c->table_array) {
         qemu_vfree(c->table_array);
@@ -203,13 +202,13 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
 
     if (c == s->refcount_block_cache) {
         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK,
-                c->entries[i].offset, s->cluster_size);
+                c->entries[i].offset, c->table_size);
     } else if (c == s->l2_table_cache) {
         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
-                c->entries[i].offset, s->cluster_size);
+                c->entries[i].offset, c->table_size);
     } else {
         ret = qcow2_pre_write_overlap_check(bs, 0,
-                c->entries[i].offset, s->cluster_size);
+                c->entries[i].offset, c->table_size);
     }
 
     if (ret < 0) {
@@ -223,7 +222,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
     }
 
     ret = bdrv_pwrite(bs->file, c->entries[i].offset,
-                      qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
+                      qcow2_cache_get_table_addr(bs, c, i), c->table_size);
     if (ret < 0) {
         return ret;
     }
@@ -331,7 +330,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
     trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
                           offset, read_from_disk);
 
-    if (offset_into_cluster(s, offset)) {
+    if (!QEMU_IS_ALIGNED(offset, c->table_size)) {
         qcow2_signal_corruption(bs, true, -1, -1, "Cannot get entry from %s "
                                 "cache: Offset %#" PRIx64 " is unaligned",
                                 qcow2_cache_get_name(s, c), offset);
@@ -339,7 +338,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
     }
 
     /* Check if the table is already cached */
-    i = lookup_index = (offset / s->cluster_size * 4) % c->size;
+    i = lookup_index = (offset / c->table_size * 4) % c->size;
     do {
         const Qcow2CachedTable *t = &c->entries[i];
         if (t->offset == offset) {
@@ -380,7 +379,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
 
         ret = bdrv_pread(bs->file, offset,
                          qcow2_cache_get_table_addr(bs, c, i),
-                         s->cluster_size);
+                         c->table_size);
         if (ret < 0) {
             return ret;
         }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 03/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_addr()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 01/39] qcow2: Fix documentation of get_cluster_table() Alberto Garcia
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 02/39] qcow2: Add table size field to Qcow2Cache Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:26   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 04/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_idx() Alberto Garcia
                   ` (35 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function was only using the BlockDriverState parameter to get the
cache table size (since it was equal to the cluster size). This is no
longer necessary so this parameter can be removed.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 38c03770b4..a481ef499a 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -46,8 +46,7 @@ struct Qcow2Cache {
     uint64_t                cache_clean_lru_counter;
 };
 
-static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
-                    Qcow2Cache *c, int table)
+static inline void *qcow2_cache_get_table_addr(Qcow2Cache *c, int table)
 {
     return (uint8_t *) c->table_array + (size_t) table * c->table_size;
 }
@@ -78,7 +77,7 @@ static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
 {
 /* Using MADV_DONTNEED to discard memory is a Linux-specific feature */
 #ifdef CONFIG_LINUX
-    void *t = qcow2_cache_get_table_addr(bs, c, i);
+    void *t = qcow2_cache_get_table_addr(c, i);
     int align = getpagesize();
     size_t mem_size = (size_t) c->table_size * num_tables;
     size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
@@ -222,7 +221,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
     }
 
     ret = bdrv_pwrite(bs->file, c->entries[i].offset,
-                      qcow2_cache_get_table_addr(bs, c, i), c->table_size);
+                      qcow2_cache_get_table_addr(c, i), c->table_size);
     if (ret < 0) {
         return ret;
     }
@@ -378,7 +377,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
         }
 
         ret = bdrv_pread(bs->file, offset,
-                         qcow2_cache_get_table_addr(bs, c, i),
+                         qcow2_cache_get_table_addr(c, i),
                          c->table_size);
         if (ret < 0) {
             return ret;
@@ -390,7 +389,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
     /* And return the right table */
 found:
     c->entries[i].ref++;
-    *table = qcow2_cache_get_table_addr(bs, c, i);
+    *table = qcow2_cache_get_table_addr(c, i);
 
     trace_qcow2_cache_get_done(qemu_coroutine_self(),
                                c == s->l2_table_cache, i);
@@ -439,7 +438,7 @@ void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
 
     for (i = 0; i < c->size; i++) {
         if (c->entries[i].offset == offset) {
-            return qcow2_cache_get_table_addr(bs, c, i);
+            return qcow2_cache_get_table_addr(c, i);
         }
     }
     return NULL;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 04/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_idx()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (2 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 03/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_addr() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:27   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 05/39] qcow2: Remove BDS parameter from qcow2_cache_table_release() Alberto Garcia
                   ` (34 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function was only using the BlockDriverState parameter to get the
cache table size (since it was equal to the cluster size). This is no
longer necessary so this parameter can be removed.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index a481ef499a..3749d55595 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -51,8 +51,7 @@ static inline void *qcow2_cache_get_table_addr(Qcow2Cache *c, int table)
     return (uint8_t *) c->table_array + (size_t) table * c->table_size;
 }
 
-static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
-                  Qcow2Cache *c, void *table)
+static inline int qcow2_cache_get_table_idx(Qcow2Cache *c, void *table)
 {
     ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
     int idx = table_offset / c->table_size;
@@ -411,7 +410,7 @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
 
 void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
 {
-    int i = qcow2_cache_get_table_idx(bs, c, *table);
+    int i = qcow2_cache_get_table_idx(c, *table);
 
     c->entries[i].ref--;
     *table = NULL;
@@ -426,7 +425,7 @@ void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
 void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
      void *table)
 {
-    int i = qcow2_cache_get_table_idx(bs, c, table);
+    int i = qcow2_cache_get_table_idx(c, table);
     assert(c->entries[i].offset != 0);
     c->entries[i].dirty = true;
 }
@@ -446,7 +445,7 @@ void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
 
 void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table)
 {
-    int i = qcow2_cache_get_table_idx(bs, c, table);
+    int i = qcow2_cache_get_table_idx(c, table);
 
     assert(c->entries[i].ref == 0);
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 05/39] qcow2: Remove BDS parameter from qcow2_cache_table_release()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (3 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 04/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_idx() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:28   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 06/39] qcow2: Remove BDS parameter from qcow2_cache_entry_mark_dirty() Alberto Garcia
                   ` (33 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function was only using the BlockDriverState parameter to get the
cache table size (since it was equal to the cluster size). This is no
longer necessary so this parameter can be removed.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 3749d55595..5ff2cbf5c5 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -71,8 +71,7 @@ static inline const char *qcow2_cache_get_name(BDRVQcow2State *s, Qcow2Cache *c)
     }
 }
 
-static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
-                                      int i, int num_tables)
+static void qcow2_cache_table_release(Qcow2Cache *c, int i, int num_tables)
 {
 /* Using MADV_DONTNEED to discard memory is a Linux-specific feature */
 #ifdef CONFIG_LINUX
@@ -114,7 +113,7 @@ void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
         }
 
         if (to_clean > 0) {
-            qcow2_cache_table_release(bs, c, i - to_clean, to_clean);
+            qcow2_cache_table_release(c, i - to_clean, to_clean);
         }
     }
 
@@ -306,7 +305,7 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
         c->entries[i].lru_counter = 0;
     }
 
-    qcow2_cache_table_release(bs, c, 0, c->size);
+    qcow2_cache_table_release(c, 0, c->size);
 
     c->lru_counter = 0;
 
@@ -453,5 +452,5 @@ void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table)
     c->entries[i].lru_counter = 0;
     c->entries[i].dirty = false;
 
-    qcow2_cache_table_release(bs, c, i, 1);
+    qcow2_cache_table_release(c, i, 1);
 }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 06/39] qcow2: Remove BDS parameter from qcow2_cache_entry_mark_dirty()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (4 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 05/39] qcow2: Remove BDS parameter from qcow2_cache_table_release() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:30   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 07/39] qcow2: Remove BDS parameter from qcow2_cache_put() Alberto Garcia
                   ` (32 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function was only using the BlockDriverState parameter to pass it
to qcow2_cache_get_table_idx(). This is no longer necessary so this
parameter can be removed.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c    |  3 +--
 block/qcow2-cluster.c  | 12 ++++++------
 block/qcow2-refcount.c | 14 ++++++--------
 block/qcow2.h          |  3 +--
 4 files changed, 14 insertions(+), 18 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 5ff2cbf5c5..07603e6b15 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -421,8 +421,7 @@ void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
     assert(c->entries[i].ref >= 0);
 }
 
-void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
-     void *table)
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
 {
     int i = qcow2_cache_get_table_idx(c, table);
     assert(c->entries[i].offset != 0);
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 8163983d28..1f279a9151 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -325,7 +325,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
     BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
 
     trace_qcow2_l2_allocate_write_l2(bs, l1_index);
-    qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
     ret = qcow2_cache_flush(bs, s->l2_table_cache);
     if (ret < 0) {
         goto fail;
@@ -766,7 +766,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
     /* compressed clusters never have the copied flag */
 
     BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
-    qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
     l2_table[l2_index] = cpu_to_be64(cluster_offset);
     qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
 
@@ -938,7 +938,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
     if (ret < 0) {
         goto err;
     }
-    qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
 
     assert(l2_index + m->nb_clusters <= s->l2_size);
     for (i = 0; i < m->nb_clusters; i++) {
@@ -1679,7 +1679,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
         }
 
         /* First remove L2 entries */
-        qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
         if (!full_discard && s->qcow_version >= 3) {
             l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
         } else {
@@ -1775,7 +1775,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
             continue;
         }
 
-        qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
         if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
             l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
             qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
@@ -1984,7 +1984,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
 
         if (is_active_l1) {
             if (l2_dirty) {
-                qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+                qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
                 qcow2_cache_depends_on_flush(s->l2_table_cache);
             }
             qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 92701ab7af..5434e7d4c8 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -421,7 +421,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
 
     /* Now the new refcount block needs to be written to disk */
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
-    qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, *refcount_block);
+    qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *refcount_block);
     ret = qcow2_cache_flush(bs, s->refcount_block_cache);
     if (ret < 0) {
         goto fail;
@@ -623,7 +623,7 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
                 goto fail;
             }
             memset(refblock_data, 0, s->cluster_size);
-            qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
+            qcow2_cache_entry_mark_dirty(s->refcount_block_cache,
                                          refblock_data);
 
             new_table[i] = block_offset;
@@ -656,7 +656,7 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
                 s->set_refcount(refblock_data, j, 1);
             }
 
-            qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
+            qcow2_cache_entry_mark_dirty(s->refcount_block_cache,
                                          refblock_data);
         }
 
@@ -845,8 +845,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
         }
         old_table_index = table_index;
 
-        qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
-                                     refcount_block);
+        qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refcount_block);
 
         /* we can update the count and save it */
         block_index = cluster_index & (s->refcount_block_size - 1);
@@ -1316,8 +1315,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                             s->refcount_block_cache);
                     }
                     l2_table[j] = cpu_to_be64(entry);
-                    qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache,
-                                                 l2_table);
+                    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
                 }
             }
 
@@ -3180,7 +3178,7 @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
     }
     s->set_refcount(refblock, block_index, 0);
 
-    qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, refblock);
+    qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refblock);
 
     qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
 
diff --git a/block/qcow2.h b/block/qcow2.h
index 46c8cf44ec..ad332ed380 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -639,8 +639,7 @@ int qcow2_read_snapshots(BlockDriverState *bs);
 Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
 int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
 
-void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
-     void *table);
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
 int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
 int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c);
 int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 07/39] qcow2: Remove BDS parameter from qcow2_cache_put()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (5 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 06/39] qcow2: Remove BDS parameter from qcow2_cache_entry_mark_dirty() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:33   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 08/39] qcow2: Remove BDS parameter from qcow2_cache_destroy() Alberto Garcia
                   ` (31 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function was only using the BlockDriverState parameter to pass it
to qcow2_cache_get_table_idx(). This is no longer necessary so this
parameter can be removed.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c    |  2 +-
 block/qcow2-cluster.c  | 28 ++++++++++++++--------------
 block/qcow2-refcount.c | 30 +++++++++++++++---------------
 block/qcow2.h          |  2 +-
 4 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 07603e6b15..3b55f39afb 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -407,7 +407,7 @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
     return qcow2_cache_do_get(bs, c, offset, table, false);
 }
 
-void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
+void qcow2_cache_put(Qcow2Cache *c, void **table)
 {
     int i = qcow2_cache_get_table_idx(c, *table);
 
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 1f279a9151..4a7b46038b 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -318,7 +318,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
 
         memcpy(l2_table, old_table, s->cluster_size);
 
-        qcow2_cache_put(bs, s->l2_table_cache, (void **) &old_table);
+        qcow2_cache_put(s->l2_table_cache, (void **) &old_table);
     }
 
     /* write the l2 table to the file */
@@ -346,7 +346,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
 fail:
     trace_qcow2_l2_allocate_done(bs, l1_index, ret);
     if (l2_table != NULL) {
-        qcow2_cache_put(bs, s->l2_table_cache, (void**) table);
+        qcow2_cache_put(s->l2_table_cache, (void **) table);
     }
     s->l1_table[l1_index] = old_l2_offset;
     if (l2_offset > 0) {
@@ -620,7 +620,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
         abort();
     }
 
-    qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
 
     bytes_available = (int64_t)c * s->cluster_size;
 
@@ -638,7 +638,7 @@ out:
     return type;
 
 fail:
-    qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **)&l2_table);
     return ret;
 }
 
@@ -745,13 +745,13 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
      * allocated. */
     cluster_offset = be64_to_cpu(l2_table[l2_index]);
     if (cluster_offset & L2E_OFFSET_MASK) {
-        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+        qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
         return 0;
     }
 
     cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
     if (cluster_offset < 0) {
-        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+        qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
         return 0;
     }
 
@@ -768,7 +768,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
     BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
     qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
     l2_table[l2_index] = cpu_to_be64(cluster_offset);
-    qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
 
     return cluster_offset;
 }
@@ -957,7 +957,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
      }
 
 
-    qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
 
     /*
      * If this was a COW, we need to decrease the refcount of the old cluster.
@@ -1175,7 +1175,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
 
     /* Cleanup */
 out:
-    qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
 
     /* Only return a host offset if we actually made progress. Otherwise we
      * would make requirements for handle_alloc() that it can't fulfill */
@@ -1334,7 +1334,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
         keep_old_clusters = true;
     }
 
-    qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
 
     if (!alloc_cluster_offset) {
         /* Allocate, if necessary at a given offset in the image file */
@@ -1690,7 +1690,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
         qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
     }
 
-    qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
 
     return nb_clusters;
 }
@@ -1784,7 +1784,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
         }
     }
 
-    qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
 
     return nb_clusters;
 }
@@ -1987,7 +1987,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
                 qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
                 qcow2_cache_depends_on_flush(s->l2_table_cache);
             }
-            qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+            qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
         } else {
             if (l2_dirty) {
                 ret = qcow2_pre_write_overlap_check(bs,
@@ -2018,7 +2018,7 @@ fail:
         if (!is_active_l1) {
             qemu_vfree(l2_table);
         } else {
-            qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+            qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
         }
     }
     return ret;
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 5434e7d4c8..65af05dd23 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -277,7 +277,7 @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
     block_index = cluster_index & (s->refcount_block_size - 1);
     *refcount = s->get_refcount(refcount_block, block_index);
 
-    qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
+    qcow2_cache_put(s->refcount_block_cache, &refcount_block);
 
     return 0;
 }
@@ -449,7 +449,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
         return -EAGAIN;
     }
 
-    qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
+    qcow2_cache_put(s->refcount_block_cache, refcount_block);
 
     /*
      * If we come here, we need to grow the refcount table. Again, a new
@@ -501,7 +501,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
 
 fail:
     if (*refcount_block != NULL) {
-        qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
+        qcow2_cache_put(s->refcount_block_cache, refcount_block);
     }
     return ret;
 }
@@ -660,7 +660,7 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
                                          refblock_data);
         }
 
-        qcow2_cache_put(bs, s->refcount_block_cache, &refblock_data);
+        qcow2_cache_put(s->refcount_block_cache, &refblock_data);
     }
 
     assert(block_offset == table_offset);
@@ -836,7 +836,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
         /* Load the refcount block and allocate it if needed */
         if (table_index != old_table_index) {
             if (refcount_block) {
-                qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
+                qcow2_cache_put(s->refcount_block_cache, &refcount_block);
             }
             ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
             if (ret < 0) {
@@ -874,7 +874,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
             table = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
                                                 offset);
             if (table != NULL) {
-                qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
+                qcow2_cache_put(s->refcount_block_cache, &refcount_block);
                 qcow2_cache_discard(bs, s->refcount_block_cache, table);
             }
 
@@ -897,7 +897,7 @@ fail:
 
     /* Write last changed block to disk */
     if (refcount_block) {
-        qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
+        qcow2_cache_put(s->refcount_block_cache, &refcount_block);
     }
 
     /*
@@ -1319,7 +1319,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                 }
             }
 
-            qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+            qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
 
             if (addend != 0) {
                 ret = qcow2_update_cluster_refcount(bs, l2_offset >>
@@ -1347,7 +1347,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
     ret = bdrv_flush(bs);
 fail:
     if (l2_table) {
-        qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+        qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
     }
 
     s->cache_discards = false;
@@ -2847,7 +2847,7 @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
                                     new_reftable_size, new_refblock,
                                     new_refblock_empty, allocated, errp);
                     if (ret < 0) {
-                        qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+                        qcow2_cache_put(s->refcount_block_cache, &refblock);
                         return ret;
                     }
 
@@ -2860,7 +2860,7 @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
                 if (new_refcount_bits < 64 && refcount >> new_refcount_bits) {
                     uint64_t offset;
 
-                    qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+                    qcow2_cache_put(s->refcount_block_cache, &refblock);
 
                     offset = ((reftable_index << s->refcount_block_bits)
                               + refblock_index) << s->cluster_bits;
@@ -2881,7 +2881,7 @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
                 new_refblock_empty = new_refblock_empty && refcount == 0;
             }
 
-            qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+            qcow2_cache_put(s->refcount_block_cache, &refblock);
         } else {
             /* No refblock means every refcount is 0 */
             for (refblock_index = 0; refblock_index < s->refcount_block_size;
@@ -3173,14 +3173,14 @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
                                 offset_to_reftable_index(s, discard_block_offs),
                                 discard_block_offs,
                                 s->get_refcount(refblock, block_index));
-        qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+        qcow2_cache_put(s->refcount_block_cache, &refblock);
         return -EINVAL;
     }
     s->set_refcount(refblock, block_index, 0);
 
     qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refblock);
 
-    qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+    qcow2_cache_put(s->refcount_block_cache, &refblock);
 
     if (cluster_index < s->free_cluster_index) {
         s->free_cluster_index = cluster_index;
@@ -3233,7 +3233,7 @@ int qcow2_shrink_reftable(BlockDriverState *bs)
         } else {
             unused_block = buffer_is_zero(refblock, s->cluster_size);
         }
-        qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+        qcow2_cache_put(s->refcount_block_cache, &refblock);
 
         reftable_tmp[i] = unused_block ? 0 : cpu_to_be64(s->refcount_table[i]);
     }
diff --git a/block/qcow2.h b/block/qcow2.h
index ad332ed380..96626d151f 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -653,7 +653,7 @@ int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
     void **table);
 int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
     void **table);
-void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
+void qcow2_cache_put(Qcow2Cache *c, void **table);
 void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
                                   uint64_t offset);
 void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 08/39] qcow2: Remove BDS parameter from qcow2_cache_destroy()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (6 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 07/39] qcow2: Remove BDS parameter from qcow2_cache_put() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:35   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 09/39] qcow2: Remove BDS parameter from qcow2_cache_clean_unused() Alberto Garcia
                   ` (30 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function was never using the BlockDriverState parameter so it can
be safely removed.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c |  2 +-
 block/qcow2.c       | 16 ++++++++--------
 block/qcow2.h       |  2 +-
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 3b55f39afb..6f17a28635 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -142,7 +142,7 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
     return c;
 }
 
-int qcow2_cache_destroy(BlockDriverState *bs, Qcow2Cache *c)
+int qcow2_cache_destroy(Qcow2Cache *c)
 {
     int i;
 
diff --git a/block/qcow2.c b/block/qcow2.c
index 1f80961e1b..8e64c12605 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1042,10 +1042,10 @@ static void qcow2_update_options_commit(BlockDriverState *bs,
     int i;
 
     if (s->l2_table_cache) {
-        qcow2_cache_destroy(bs, s->l2_table_cache);
+        qcow2_cache_destroy(s->l2_table_cache);
     }
     if (s->refcount_block_cache) {
-        qcow2_cache_destroy(bs, s->refcount_block_cache);
+        qcow2_cache_destroy(s->refcount_block_cache);
     }
     s->l2_table_cache = r->l2_table_cache;
     s->refcount_block_cache = r->refcount_block_cache;
@@ -1071,10 +1071,10 @@ static void qcow2_update_options_abort(BlockDriverState *bs,
                                        Qcow2ReopenState *r)
 {
     if (r->l2_table_cache) {
-        qcow2_cache_destroy(bs, r->l2_table_cache);
+        qcow2_cache_destroy(r->l2_table_cache);
     }
     if (r->refcount_block_cache) {
-        qcow2_cache_destroy(bs, r->refcount_block_cache);
+        qcow2_cache_destroy(r->refcount_block_cache);
     }
     qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
 }
@@ -1512,10 +1512,10 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
     s->l1_table = NULL;
     cache_clean_timer_del(bs);
     if (s->l2_table_cache) {
-        qcow2_cache_destroy(bs, s->l2_table_cache);
+        qcow2_cache_destroy(s->l2_table_cache);
     }
     if (s->refcount_block_cache) {
-        qcow2_cache_destroy(bs, s->refcount_block_cache);
+        qcow2_cache_destroy(s->refcount_block_cache);
     }
     qcrypto_block_free(s->crypto);
     qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
@@ -2063,8 +2063,8 @@ static void qcow2_close(BlockDriverState *bs)
     }
 
     cache_clean_timer_del(bs);
-    qcow2_cache_destroy(bs, s->l2_table_cache);
-    qcow2_cache_destroy(bs, s->refcount_block_cache);
+    qcow2_cache_destroy(s->l2_table_cache);
+    qcow2_cache_destroy(s->refcount_block_cache);
 
     qcrypto_block_free(s->crypto);
     s->crypto = NULL;
diff --git a/block/qcow2.h b/block/qcow2.h
index 96626d151f..e0c429aef2 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -637,7 +637,7 @@ int qcow2_read_snapshots(BlockDriverState *bs);
 
 /* qcow2-cache.c functions */
 Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
-int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
+int qcow2_cache_destroy(Qcow2Cache *c);
 
 void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
 int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 09/39] qcow2: Remove BDS parameter from qcow2_cache_clean_unused()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (7 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 08/39] qcow2: Remove BDS parameter from qcow2_cache_destroy() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:37   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 10/39] qcow2: Remove BDS parameter from qcow2_cache_discard() Alberto Garcia
                   ` (29 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function was only using the BlockDriverState parameter to pass it
to qcow2_cache_table_release(). This is no longer necessary so this
parameter can be removed.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c | 2 +-
 block/qcow2.c       | 4 ++--
 block/qcow2.h       | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 6f17a28635..03b3e03c6c 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -93,7 +93,7 @@ static inline bool can_clean_entry(Qcow2Cache *c, int i)
         t->lru_counter <= c->cache_clean_lru_counter;
 }
 
-void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
+void qcow2_cache_clean_unused(Qcow2Cache *c)
 {
     int i = 0;
     while (i < c->size) {
diff --git a/block/qcow2.c b/block/qcow2.c
index 8e64c12605..e2d4bf7ad5 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -704,8 +704,8 @@ static void cache_clean_timer_cb(void *opaque)
 {
     BlockDriverState *bs = opaque;
     BDRVQcow2State *s = bs->opaque;
-    qcow2_cache_clean_unused(bs, s->l2_table_cache);
-    qcow2_cache_clean_unused(bs, s->refcount_block_cache);
+    qcow2_cache_clean_unused(s->l2_table_cache);
+    qcow2_cache_clean_unused(s->refcount_block_cache);
     timer_mod(s->cache_clean_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
               (int64_t) s->cache_clean_interval * 1000);
 }
diff --git a/block/qcow2.h b/block/qcow2.h
index e0c429aef2..7e2781ffa4 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -646,7 +646,7 @@ int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
     Qcow2Cache *dependency);
 void qcow2_cache_depends_on_flush(Qcow2Cache *c);
 
-void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c);
+void qcow2_cache_clean_unused(Qcow2Cache *c);
 int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c);
 
 int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 10/39] qcow2: Remove BDS parameter from qcow2_cache_discard()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (8 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 09/39] qcow2: Remove BDS parameter from qcow2_cache_clean_unused() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:38   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 11/39] qcow2: Remove BDS parameter from qcow2_cache_is_table_offset() Alberto Garcia
                   ` (28 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function was only using the BlockDriverState parameter to pass it
to qcow2_cache_get_table_idx() and qcow2_cache_table_release(). This
is no longer necessary so this parameter can be removed.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c    | 2 +-
 block/qcow2-refcount.c | 6 +++---
 block/qcow2.h          | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 03b3e03c6c..8d0b65e671 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -441,7 +441,7 @@ void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
     return NULL;
 }
 
-void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table)
+void qcow2_cache_discard(Qcow2Cache *c, void *table)
 {
     int i = qcow2_cache_get_table_idx(c, table);
 
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 65af05dd23..361b39d5cc 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -875,12 +875,12 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
                                                 offset);
             if (table != NULL) {
                 qcow2_cache_put(s->refcount_block_cache, &refcount_block);
-                qcow2_cache_discard(bs, s->refcount_block_cache, table);
+                qcow2_cache_discard(s->refcount_block_cache, table);
             }
 
             table = qcow2_cache_is_table_offset(bs, s->l2_table_cache, offset);
             if (table != NULL) {
-                qcow2_cache_discard(bs, s->l2_table_cache, table);
+                qcow2_cache_discard(s->l2_table_cache, table);
             }
 
             if (s->discard_passthrough[type]) {
@@ -3190,7 +3190,7 @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
                                            discard_block_offs);
     if (refblock) {
         /* discard refblock from the cache if refblock is cached */
-        qcow2_cache_discard(bs, s->refcount_block_cache, refblock);
+        qcow2_cache_discard(s->refcount_block_cache, refblock);
     }
     update_refcount_discard(bs, discard_block_offs, s->cluster_size);
 
diff --git a/block/qcow2.h b/block/qcow2.h
index 7e2781ffa4..f6552fe9c3 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -656,7 +656,7 @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
 void qcow2_cache_put(Qcow2Cache *c, void **table);
 void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
                                   uint64_t offset);
-void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table);
+void qcow2_cache_discard(Qcow2Cache *c, void *table);
 
 /* qcow2-bitmap.c functions */
 int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 11/39] qcow2: Remove BDS parameter from qcow2_cache_is_table_offset()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (9 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 10/39] qcow2: Remove BDS parameter from qcow2_cache_discard() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:39   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 12/39] qcow2: Add offset_to_l1_index() Alberto Garcia
                   ` (27 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function was only using the BlockDriverState parameter to pass it
to qcow2_cache_get_table_addr(). This is no longer necessary so this
parameter can be removed.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cache.c    | 3 +--
 block/qcow2-refcount.c | 6 +++---
 block/qcow2.h          | 3 +--
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 8d0b65e671..b1aa42477e 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -428,8 +428,7 @@ void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
     c->entries[i].dirty = true;
 }
 
-void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
-                                  uint64_t offset)
+void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset)
 {
     int i;
 
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 361b39d5cc..9df380d52c 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -871,14 +871,14 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
         if (refcount == 0) {
             void *table;
 
-            table = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
+            table = qcow2_cache_is_table_offset(s->refcount_block_cache,
                                                 offset);
             if (table != NULL) {
                 qcow2_cache_put(s->refcount_block_cache, &refcount_block);
                 qcow2_cache_discard(s->refcount_block_cache, table);
             }
 
-            table = qcow2_cache_is_table_offset(bs, s->l2_table_cache, offset);
+            table = qcow2_cache_is_table_offset(s->l2_table_cache, offset);
             if (table != NULL) {
                 qcow2_cache_discard(s->l2_table_cache, table);
             }
@@ -3186,7 +3186,7 @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
         s->free_cluster_index = cluster_index;
     }
 
-    refblock = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
+    refblock = qcow2_cache_is_table_offset(s->refcount_block_cache,
                                            discard_block_offs);
     if (refblock) {
         /* discard refblock from the cache if refblock is cached */
diff --git a/block/qcow2.h b/block/qcow2.h
index f6552fe9c3..cb8dd784fa 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -654,8 +654,7 @@ int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
 int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
     void **table);
 void qcow2_cache_put(Qcow2Cache *c, void **table);
-void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
-                                  uint64_t offset);
+void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset);
 void qcow2_cache_discard(Qcow2Cache *c, void *table);
 
 /* qcow2-bitmap.c functions */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 12/39] qcow2: Add offset_to_l1_index()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (10 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 11/39] qcow2: Remove BDS parameter from qcow2_cache_is_table_offset() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:43   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 13/39] qcow2: Add l2_slice_size field to BDRVQcow2State Alberto Garcia
                   ` (26 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

Similar to offset_to_l2_index(), this function returns the index in
the L1 table for a given guest offset. This is only used in a couple
of places and it's not a particularly complex calculation, but it
makes the code a bit more readable.

Although in the qcow2_get_cluster_offset() case the old code was
taking advantage of the l1_bits variable, we're going to get rid of
the other uses of l1_bits in a later patch anyway, so it doesn't make
sense to keep it just for this.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 4 ++--
 block/qcow2.h         | 5 +++++
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 4a7b46038b..6369a74efe 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -541,7 +541,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
 
     /* seek to the l2 offset in the l1 table */
 
-    l1_index = offset >> l1_bits;
+    l1_index = offset_to_l1_index(s, offset);
     if (l1_index >= s->l1_size) {
         type = QCOW2_CLUSTER_UNALLOCATED;
         goto out;
@@ -664,7 +664,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
 
     /* seek to the l2 offset in the l1 table */
 
-    l1_index = offset >> (s->l2_bits + s->cluster_bits);
+    l1_index = offset_to_l1_index(s, offset);
     if (l1_index >= s->l1_size) {
         ret = qcow2_grow_l1_table(bs, l1_index + 1, false);
         if (ret < 0) {
diff --git a/block/qcow2.h b/block/qcow2.h
index cb8dd784fa..0559afbc63 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -463,6 +463,11 @@ static inline int64_t size_to_l1(BDRVQcow2State *s, int64_t size)
     return (size + (1ULL << shift) - 1) >> shift;
 }
 
+static inline int offset_to_l1_index(BDRVQcow2State *s, uint64_t offset)
+{
+    return offset >> (s->l2_bits + s->cluster_bits);
+}
+
 static inline int offset_to_l2_index(BDRVQcow2State *s, int64_t offset)
 {
     return (offset >> s->cluster_bits) & (s->l2_size - 1);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 13/39] qcow2: Add l2_slice_size field to BDRVQcow2State
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (11 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 12/39] qcow2: Add offset_to_l1_index() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:48   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 14/39] qcow2: Add offset_to_l2_slice_index() Alberto Garcia
                   ` (25 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

The BDRVQcow2State structure contains an l2_size field, which stores
the number of 64-bit entries in an L2 table.

For efficiency reasons we want to be able to load slices instead of
full L2 tables, so we need to know how many entries an L2 slice can
hold.

An L2 slice is the portion of an L2 table that is loaded by the qcow2
cache. At the moment that cache can only load complete tables,
therefore an L2 slice has the same size as an L2 table (one cluster)
and l2_size == l2_slice_size.

Later we'll allow smaller slices, but until then we have to use this
new l2_slice_size field to make the rest of the code ready for that.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2.c | 3 +++
 block/qcow2.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/block/qcow2.c b/block/qcow2.c
index e2d4bf7ad5..78f067cae7 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -805,6 +805,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
 typedef struct Qcow2ReopenState {
     Qcow2Cache *l2_table_cache;
     Qcow2Cache *refcount_block_cache;
+    int l2_slice_size; /* Number of entries in a slice of the L2 table */
     bool use_lazy_refcounts;
     int overlap_check;
     bool discard_passthrough[QCOW2_DISCARD_MAX];
@@ -886,6 +887,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
         }
     }
 
+    r->l2_slice_size = s->cluster_size / sizeof(uint64_t);
     r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
     r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
     if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
@@ -1049,6 +1051,7 @@ static void qcow2_update_options_commit(BlockDriverState *bs,
     }
     s->l2_table_cache = r->l2_table_cache;
     s->refcount_block_cache = r->refcount_block_cache;
+    s->l2_slice_size = r->l2_slice_size;
 
     s->overlap_check = r->overlap_check;
     s->use_lazy_refcounts = r->use_lazy_refcounts;
diff --git a/block/qcow2.h b/block/qcow2.h
index 0559afbc63..e0aee88811 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -251,6 +251,7 @@ typedef struct BDRVQcow2State {
     int cluster_bits;
     int cluster_size;
     int cluster_sectors;
+    int l2_slice_size;
     int l2_bits;
     int l2_size;
     int l1_size;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 14/39] qcow2: Add offset_to_l2_slice_index()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (12 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 13/39] qcow2: Add l2_slice_size field to BDRVQcow2State Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:49   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 15/39] qcow2: Update l2_load() to support L2 slices Alberto Garcia
                   ` (24 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

Similar to offset_to_l2_index(), this function takes a guest offset
and returns the index in the L2 slice that contains its L2 entry.

An L2 slice has currently the same size as an L2 table (one cluster),
so both functions return the same value for now.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/block/qcow2.h b/block/qcow2.h
index e0aee88811..87b5c4063e 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -474,6 +474,11 @@ static inline int offset_to_l2_index(BDRVQcow2State *s, int64_t offset)
     return (offset >> s->cluster_bits) & (s->l2_size - 1);
 }
 
+static inline int offset_to_l2_slice_index(BDRVQcow2State *s, int64_t offset)
+{
+    return (offset >> s->cluster_bits) & (s->l2_slice_size - 1);
+}
+
 static inline int64_t align_offset(int64_t offset, int n)
 {
     offset = (offset + n - 1) & ~(n - 1);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 15/39] qcow2: Update l2_load() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (13 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 14/39] qcow2: Add offset_to_l2_slice_index() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 19:56   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 16/39] qcow2: Prepare l2_allocate() for adding L2 slice support Alberto Garcia
                   ` (23 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

Each entry in the qcow2 L2 cache stores a full L2 table (which uses a
complete cluster in the qcow2 image). A cluster is usually too large
to be used efficiently as the size for a cache entry, so we want to
decouple both values by allowing smaller cache entries. Therefore the
qcow2 L2 cache will no longer return full L2 tables but slices
instead.

This patch updates l2_load() so it can handle L2 slices correctly.
Apart from the offset of the L2 table (which we already had) we also
need the guest offset in order to calculate which one of the slices
we need.

An L2 slice has currently the same size as an L2 table (one cluster),
so for now this function will load exactly the same data as before.

This patch also removes a stale comment about the return value being
a pointer to the L2 table. This function returns an error code since
55c17e9821c474d5fcdebdc82ed2fc096777d611.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 6369a74efe..8d92d623d8 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -196,20 +196,26 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
 /*
  * l2_load
  *
- * Loads a L2 table into memory. If the table is in the cache, the cache
- * is used; otherwise the L2 table is loaded from the image file.
+ * @bs: The BlockDriverState
+ * @offset: A guest offset, used to calculate what slice of the L2
+ *          table to load.
+ * @l2_offset: Offset to the L2 table in the image file.
+ * @l2_slice: Location to store the pointer to the L2 slice.
  *
- * Returns a pointer to the L2 table on success, or NULL if the read from
- * the image file failed.
+ * Loads a L2 slice into memory (L2 slices are the parts of L2 tables
+ * that are loaded by the qcow2 cache). If the slice is in the cache,
+ * the cache is used; otherwise the L2 slice is loaded from the image
+ * file.
  */
-
-static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
-    uint64_t **l2_table)
+static int l2_load(BlockDriverState *bs, uint64_t offset,
+                   uint64_t l2_offset, uint64_t **l2_slice)
 {
     BDRVQcow2State *s = bs->opaque;
+    int start_of_slice = sizeof(uint64_t) *
+        (offset_to_l2_index(s, offset) - offset_to_l2_slice_index(s, offset));
 
-    return qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
-                           (void **)l2_table);
+    return qcow2_cache_get(bs, s->l2_table_cache, l2_offset + start_of_slice,
+                           (void **)l2_slice);
 }
 
 /*
@@ -562,7 +568,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
 
     /* load the l2 table in memory */
 
-    ret = l2_load(bs, l2_offset, &l2_table);
+    ret = l2_load(bs, offset, l2_offset, &l2_table);
     if (ret < 0) {
         return ret;
     }
@@ -685,7 +691,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
 
     if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
         /* load the l2 table in memory */
-        ret = l2_load(bs, l2_offset, &l2_table);
+        ret = l2_load(bs, offset, l2_offset, &l2_table);
         if (ret < 0) {
             return ret;
         }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 16/39] qcow2: Prepare l2_allocate() for adding L2 slice support
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (14 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 15/39] qcow2: Update l2_load() to support L2 slices Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-26 16:24   ` Eric Blake
  2018-01-31 19:57   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices Alberto Garcia
                   ` (22 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

Adding support for L2 slices to l2_allocate() needs (among other
things) an extra loop that iterates over all slices of a new L2 table.

Putting all changes in one patch would make it hard to read because
all semantic changes would be mixed with pure indentation changes.

To make things easier this patch simply creates a new block and
changes the indentation of all lines of code inside it. Thus, all
modifications in this patch are cosmetic. There are no semantic
changes and no variables are renamed yet. The next patch will take
care of that.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-cluster.c | 55 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 30 insertions(+), 25 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 8d92d623d8..57349928a9 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -300,38 +300,43 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
     /* allocate a new entry in the l2 cache */
 
     trace_qcow2_l2_allocate_get_empty(bs, l1_index);
-    ret = qcow2_cache_get_empty(bs, s->l2_table_cache, l2_offset, (void**) table);
-    if (ret < 0) {
-        goto fail;
-    }
-
-    l2_table = *table;
-
-    if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
-        /* if there was no old l2 table, clear the new table */
-        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
-    } else {
-        uint64_t* old_table;
-
-        /* if there was an old l2 table, read it from the disk */
-        BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
-        ret = qcow2_cache_get(bs, s->l2_table_cache,
-            old_l2_offset & L1E_OFFSET_MASK,
-            (void**) &old_table);
+    {
+        ret = qcow2_cache_get_empty(bs, s->l2_table_cache,
+                                    l2_offset,
+                                    (void **) table);
         if (ret < 0) {
             goto fail;
         }
 
-        memcpy(l2_table, old_table, s->cluster_size);
+        l2_table = *table;
 
-        qcow2_cache_put(s->l2_table_cache, (void **) &old_table);
+        if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
+            /* if there was no old l2 table, clear the new table */
+            memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
+        } else {
+            uint64_t *old_table;
+
+            /* if there was an old l2 table, read it from the disk */
+            BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
+            ret = qcow2_cache_get(bs, s->l2_table_cache,
+                                  old_l2_offset & L1E_OFFSET_MASK,
+                                  (void **) &old_table);
+            if (ret < 0) {
+                goto fail;
+            }
+
+            memcpy(l2_table, old_table, s->cluster_size);
+
+            qcow2_cache_put(s->l2_table_cache, (void **) &old_table);
+        }
+
+        /* write the l2 table to the file */
+        BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
+
+        trace_qcow2_l2_allocate_write_l2(bs, l1_index);
+        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
     }
 
-    /* write the l2 table to the file */
-    BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
-
-    trace_qcow2_l2_allocate_write_l2(bs, l1_index);
-    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
     ret = qcow2_cache_flush(bs, s->l2_table_cache);
     if (ret < 0) {
         goto fail;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (15 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 16/39] qcow2: Prepare l2_allocate() for adding L2 slice support Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-26 16:30   ` Eric Blake
  2018-01-31 20:07   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table() Alberto Garcia
                   ` (21 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This patch updates l2_allocate() to support the qcow2 cache returning
L2 slices instead of full L2 tables.

The old code simply gets an L2 table from the cache and initializes it
with zeroes or with the contents of an existing table. With a cache
that returns slices instead of tables the idea remains the same, but
the code must now iterate over all the slices that are contained in an
L2 table.

Since now we're operating with slices the function can no longer
return the newly-allocated table, so it's up to the caller to retrieve
the appropriate L2 slice after calling l2_allocate() (note that with
this patch the caller is still loading full L2 tables, but we'll deal
with that in a separate patch).

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-cluster.c | 56 +++++++++++++++++++++++++++++++--------------------
 1 file changed, 34 insertions(+), 22 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 57349928a9..2a53c1dc5f 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -264,11 +264,12 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
  *
  */
 
-static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
+static int l2_allocate(BlockDriverState *bs, int l1_index)
 {
     BDRVQcow2State *s = bs->opaque;
     uint64_t old_l2_offset;
-    uint64_t *l2_table = NULL;
+    uint64_t *l2_slice = NULL;
+    unsigned slice, slice_size2, n_slices;
     int64_t l2_offset;
     int ret;
 
@@ -299,42 +300,45 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
 
     /* allocate a new entry in the l2 cache */
 
+    slice_size2 = s->l2_slice_size * sizeof(uint64_t);
+    n_slices = s->cluster_size / slice_size2;
+
     trace_qcow2_l2_allocate_get_empty(bs, l1_index);
-    {
+    for (slice = 0; slice < n_slices; slice++) {
         ret = qcow2_cache_get_empty(bs, s->l2_table_cache,
-                                    l2_offset,
-                                    (void **) table);
+                                    l2_offset + slice * slice_size2,
+                                    (void **) &l2_slice);
         if (ret < 0) {
             goto fail;
         }
 
-        l2_table = *table;
-
         if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
-            /* if there was no old l2 table, clear the new table */
-            memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
+            /* if there was no old l2 table, clear the new slice */
+            memset(l2_slice, 0, slice_size2);
         } else {
-            uint64_t *old_table;
+            uint64_t *old_slice;
+            uint64_t old_l2_slice_offset =
+                (old_l2_offset & L1E_OFFSET_MASK) + slice * slice_size2;
 
-            /* if there was an old l2 table, read it from the disk */
+            /* if there was an old l2 table, read an slice from the disk */
             BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
-            ret = qcow2_cache_get(bs, s->l2_table_cache,
-                                  old_l2_offset & L1E_OFFSET_MASK,
-                                  (void **) &old_table);
+            ret = qcow2_cache_get(bs, s->l2_table_cache, old_l2_slice_offset,
+                                  (void **) &old_slice);
             if (ret < 0) {
                 goto fail;
             }
 
-            memcpy(l2_table, old_table, s->cluster_size);
+            memcpy(l2_slice, old_slice, slice_size2);
 
-            qcow2_cache_put(s->l2_table_cache, (void **) &old_table);
+            qcow2_cache_put(s->l2_table_cache, (void **) &old_slice);
         }
 
-        /* write the l2 table to the file */
+        /* write the l2 slice to the file */
         BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
 
         trace_qcow2_l2_allocate_write_l2(bs, l1_index);
-        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
+        qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
     }
 
     ret = qcow2_cache_flush(bs, s->l2_table_cache);
@@ -350,14 +354,13 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
         goto fail;
     }
 
-    *table = l2_table;
     trace_qcow2_l2_allocate_done(bs, l1_index, 0);
     return 0;
 
 fail:
     trace_qcow2_l2_allocate_done(bs, l1_index, ret);
-    if (l2_table != NULL) {
-        qcow2_cache_put(s->l2_table_cache, (void **) table);
+    if (l2_slice != NULL) {
+        qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
     }
     s->l1_table[l1_index] = old_l2_offset;
     if (l2_offset > 0) {
@@ -702,7 +705,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
         }
     } else {
         /* First allocate a new L2 table (and do COW if needed) */
-        ret = l2_allocate(bs, l1_index, &l2_table);
+        ret = l2_allocate(bs, l1_index);
         if (ret < 0) {
             return ret;
         }
@@ -712,6 +715,15 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
             qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t),
                                 QCOW2_DISCARD_OTHER);
         }
+
+        /* Get the offset of the newly-allocated l2 table */
+        l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
+        assert(offset_into_cluster(s, l2_offset) == 0);
+        /* Load the l2 table in memory */
+        ret = l2_load(bs, offset, l2_offset, &l2_table);
+        if (ret < 0) {
+            return ret;
+        }
     }
 
     /* find the cluster offset for the given disk offset */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (16 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-26 16:37   ` Eric Blake
  2018-01-31 20:11   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 19/39] qcow2: Update get_cluster_table() to support L2 slices Alberto Garcia
                   ` (20 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

After the previous patch we're now always using l2_load() in
get_cluster_table() regardless of whether a new L2 table has to be
allocated or not.

This patch refactors that part of the code to use one single l2_load()
call.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-cluster.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 2a53c1dc5f..0c0cab85e8 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -695,15 +695,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
         return -EIO;
     }
 
-    /* seek the l2 table of the given l2 offset */
-
-    if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
-        /* load the l2 table in memory */
-        ret = l2_load(bs, offset, l2_offset, &l2_table);
-        if (ret < 0) {
-            return ret;
-        }
-    } else {
+    if (!(s->l1_table[l1_index] & QCOW_OFLAG_COPIED)) {
         /* First allocate a new L2 table (and do COW if needed) */
         ret = l2_allocate(bs, l1_index);
         if (ret < 0) {
@@ -719,11 +711,12 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
         /* Get the offset of the newly-allocated l2 table */
         l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
         assert(offset_into_cluster(s, l2_offset) == 0);
-        /* Load the l2 table in memory */
-        ret = l2_load(bs, offset, l2_offset, &l2_table);
-        if (ret < 0) {
-            return ret;
-        }
+    }
+
+    /* load the l2 table in memory */
+    ret = l2_load(bs, offset, l2_offset, &l2_table);
+    if (ret < 0) {
+        return ret;
     }
 
     /* find the cluster offset for the given disk offset */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 19/39] qcow2: Update get_cluster_table() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (17 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-26 16:39   ` Eric Blake
  2018-01-31 20:14   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 20/39] qcow2: Update qcow2_get_cluster_offset() " Alberto Garcia
                   ` (19 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This patch updates get_cluster_table() to return L2 slices instead of
full L2 tables.

The code itself needs almost no changes, it only needs to call
offset_to_l2_slice_index() instead of offset_to_l2_index(). This patch
also renames all the relevant variables and the documentation.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-cluster.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 0c0cab85e8..416d48fa77 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -660,20 +660,20 @@ fail:
  * get_cluster_table
  *
  * for a given disk offset, load (and allocate if needed)
- * the l2 table.
+ * the appropriate slice of its l2 table.
  *
- * the cluster index in the l2 table is given to the caller.
+ * the cluster index in the l2 slice is given to the caller.
  *
  * Returns 0 on success, -errno in failure case
  */
 static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
-                             uint64_t **new_l2_table,
+                             uint64_t **new_l2_slice,
                              int *new_l2_index)
 {
     BDRVQcow2State *s = bs->opaque;
     unsigned int l2_index;
     uint64_t l1_index, l2_offset;
-    uint64_t *l2_table = NULL;
+    uint64_t *l2_slice = NULL;
     int ret;
 
     /* seek to the l2 offset in the l1 table */
@@ -713,17 +713,17 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
         assert(offset_into_cluster(s, l2_offset) == 0);
     }
 
-    /* load the l2 table in memory */
-    ret = l2_load(bs, offset, l2_offset, &l2_table);
+    /* load the l2 slice in memory */
+    ret = l2_load(bs, offset, l2_offset, &l2_slice);
     if (ret < 0) {
         return ret;
     }
 
     /* find the cluster offset for the given disk offset */
 
-    l2_index = offset_to_l2_index(s, offset);
+    l2_index = offset_to_l2_slice_index(s, offset);
 
-    *new_l2_table = l2_table;
+    *new_l2_slice = l2_slice;
     *new_l2_index = l2_index;
 
     return 0;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 20/39] qcow2: Update qcow2_get_cluster_offset() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (18 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 19/39] qcow2: Update get_cluster_table() to support L2 slices Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-31 20:24   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 21/39] qcow2: Update qcow2_alloc_cluster_link_l2() " Alberto Garcia
                   ` (18 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

qcow2_get_cluster_offset() checks how many contiguous bytes are
available at a given offset. The returned number of bytes is limited
by the amount that can be addressed without having to load more than
one L2 table.

Since we'll be loading L2 slices instead of full tables this patch
changes the limit accordingly using the size of the L2 slice for the
calculations instead of the full table size.

One consequence of this is that with small L2 slices operations such
as 'qemu-img map' will need to iterate in more steps because each
qcow2_get_cluster_offset() call will potentially return a smaller
number. However the code is already prepared for that so this doesn't
break semantics.

The l2_table variable is also renamed to l2_slice to reflect this, and
offset_to_l2_index() is replaced with offset_to_l2_slice_index().

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 416d48fa77..128a82dc5a 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -530,8 +530,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
 {
     BDRVQcow2State *s = bs->opaque;
     unsigned int l2_index;
-    uint64_t l1_index, l2_offset, *l2_table;
-    int l1_bits, c;
+    uint64_t l1_index, l2_offset, *l2_slice;
+    int c;
     unsigned int offset_in_cluster;
     uint64_t bytes_available, bytes_needed, nb_clusters;
     QCow2ClusterType type;
@@ -540,12 +540,12 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
     offset_in_cluster = offset_into_cluster(s, offset);
     bytes_needed = (uint64_t) *bytes + offset_in_cluster;
 
-    l1_bits = s->l2_bits + s->cluster_bits;
-
     /* compute how many bytes there are between the start of the cluster
-     * containing offset and the end of the l1 entry */
-    bytes_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1))
-                    + offset_in_cluster;
+     * containing offset and the end of the l2 slice that contains
+     * the entry pointing to it */
+    bytes_available =
+        ((uint64_t) (s->l2_slice_size - offset_to_l2_slice_index(s, offset)))
+        << s->cluster_bits;
 
     if (bytes_needed > bytes_available) {
         bytes_needed = bytes_available;
@@ -574,17 +574,17 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
         return -EIO;
     }
 
-    /* load the l2 table in memory */
+    /* load the l2 slice in memory */
 
-    ret = l2_load(bs, offset, l2_offset, &l2_table);
+    ret = l2_load(bs, offset, l2_offset, &l2_slice);
     if (ret < 0) {
         return ret;
     }
 
     /* find the cluster offset for the given disk offset */
 
-    l2_index = offset_to_l2_index(s, offset);
-    *cluster_offset = be64_to_cpu(l2_table[l2_index]);
+    l2_index = offset_to_l2_slice_index(s, offset);
+    *cluster_offset = be64_to_cpu(l2_slice[l2_index]);
 
     nb_clusters = size_to_clusters(s, bytes_needed);
     /* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned
@@ -611,14 +611,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
     case QCOW2_CLUSTER_UNALLOCATED:
         /* how many empty clusters ? */
         c = count_contiguous_clusters_unallocated(nb_clusters,
-                                                  &l2_table[l2_index], type);
+                                                  &l2_slice[l2_index], type);
         *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_slice[l2_index], QCOW_OFLAG_ZERO);
         *cluster_offset &= L2E_OFFSET_MASK;
         if (offset_into_cluster(s, *cluster_offset)) {
             qcow2_signal_corruption(bs, true, -1, -1,
@@ -634,7 +634,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
         abort();
     }
 
-    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
 
     bytes_available = (int64_t)c * s->cluster_size;
 
@@ -652,7 +652,7 @@ out:
     return type;
 
 fail:
-    qcow2_cache_put(s->l2_table_cache, (void **)&l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **)&l2_slice);
     return ret;
 }
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 21/39] qcow2: Update qcow2_alloc_cluster_link_l2() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (19 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 20/39] qcow2: Update qcow2_get_cluster_offset() " Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-02-01 18:44   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 22/39] qcow2: Update handle_copied() " Alberto Garcia
                   ` (17 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

There's a loop in this function that iterates over the L2 entries in a
table, so now we need to assert that it remains within the limits of
an L2 slice.

Apart from that, this function doesn't need any additional changes, so
this patch simply updates the variable name from l2_table to l2_slice.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 128a82dc5a..abc9e3ed6a 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -923,7 +923,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
 {
     BDRVQcow2State *s = bs->opaque;
     int i, j = 0, l2_index, ret;
-    uint64_t *old_cluster, *l2_table;
+    uint64_t *old_cluster, *l2_slice;
     uint64_t cluster_offset = m->alloc_offset;
 
     trace_qcow2_cluster_link_l2(qemu_coroutine_self(), m->nb_clusters);
@@ -950,13 +950,13 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
                                    s->refcount_block_cache);
     }
 
-    ret = get_cluster_table(bs, m->offset, &l2_table, &l2_index);
+    ret = get_cluster_table(bs, m->offset, &l2_slice, &l2_index);
     if (ret < 0) {
         goto err;
     }
-    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
 
-    assert(l2_index + m->nb_clusters <= s->l2_size);
+    assert(l2_index + m->nb_clusters <= s->l2_slice_size);
     for (i = 0; i < m->nb_clusters; i++) {
         /* if two concurrent writes happen to the same unallocated cluster
          * each write allocates separate cluster and writes data concurrently.
@@ -964,16 +964,16 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
          * cluster the second one has to do RMW (which is done above by
          * perform_cow()), update l2 table with its cluster pointer and free
          * old cluster. This is what this loop does */
-        if (l2_table[l2_index + i] != 0) {
-            old_cluster[j++] = l2_table[l2_index + i];
+        if (l2_slice[l2_index + i] != 0) {
+            old_cluster[j++] = l2_slice[l2_index + i];
         }
 
-        l2_table[l2_index + i] = cpu_to_be64((cluster_offset +
+        l2_slice[l2_index + i] = cpu_to_be64((cluster_offset +
                     (i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
      }
 
 
-    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
 
     /*
      * If this was a COW, we need to decrease the refcount of the old cluster.
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 22/39] qcow2: Update handle_copied() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (20 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 21/39] qcow2: Update qcow2_alloc_cluster_link_l2() " Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-02-01 18:54   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 23/39] qcow2: Update handle_alloc() " Alberto Garcia
                   ` (16 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

handle_copied() loads an L2 table and limits the number of checked
clusters to the amount that fits inside that table. Since we'll be
loading L2 slices instead of full tables we need to update that limit.

Apart from that, this function doesn't need any additional changes, so
this patch simply updates the variable name from l2_table to l2_slice.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index abc9e3ed6a..ac23776b2a 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1120,7 +1120,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
     BDRVQcow2State *s = bs->opaque;
     int l2_index;
     uint64_t cluster_offset;
-    uint64_t *l2_table;
+    uint64_t *l2_slice;
     uint64_t nb_clusters;
     unsigned int keep_clusters;
     int ret;
@@ -1132,23 +1132,23 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
                                 == offset_into_cluster(s, *host_offset));
 
     /*
-     * Calculate the number of clusters to look for. We stop at L2 table
+     * Calculate the number of clusters to look for. We stop at L2 slice
      * boundaries to keep things simple.
      */
     nb_clusters =
         size_to_clusters(s, offset_into_cluster(s, guest_offset) + *bytes);
 
-    l2_index = offset_to_l2_index(s, guest_offset);
-    nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+    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);
 
     /* Find L2 entry for the first involved cluster */
-    ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
+    ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index);
     if (ret < 0) {
         return ret;
     }
 
-    cluster_offset = be64_to_cpu(l2_table[l2_index]);
+    cluster_offset = be64_to_cpu(l2_slice[l2_index]);
 
     /* Check how many clusters are already allocated and don't need COW */
     if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
@@ -1176,7 +1176,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
         /* We keep all QCOW_OFLAG_COPIED clusters */
         keep_clusters =
             count_contiguous_clusters(nb_clusters, s->cluster_size,
-                                      &l2_table[l2_index],
+                                      &l2_slice[l2_index],
                                       QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
         assert(keep_clusters <= nb_clusters);
 
@@ -1191,7 +1191,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
 
     /* Cleanup */
 out:
-    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
 
     /* Only return a host offset if we actually made progress. Otherwise we
      * would make requirements for handle_alloc() that it can't fulfill */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 23/39] qcow2: Update handle_alloc() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (21 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 22/39] qcow2: Update handle_copied() " Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-02-01 18:56   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 24/39] qcow2: Update discard_single_l2() " Alberto Garcia
                   ` (15 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

handle_alloc() loads an L2 table and limits the number of checked
clusters to the amount that fits inside that table. Since we'll be
loading L2 slices instead of full tables we need to update that limit.

Apart from that, this function doesn't need any additional changes, so
this patch simply updates the variable name from l2_table to l2_slice.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index ac23776b2a..aa374f9928 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1275,7 +1275,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
 {
     BDRVQcow2State *s = bs->opaque;
     int l2_index;
-    uint64_t *l2_table;
+    uint64_t *l2_slice;
     uint64_t entry;
     uint64_t nb_clusters;
     int ret;
@@ -1288,29 +1288,29 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
     assert(*bytes > 0);
 
     /*
-     * Calculate the number of clusters to look for. We stop at L2 table
+     * Calculate the number of clusters to look for. We stop at L2 slice
      * boundaries to keep things simple.
      */
     nb_clusters =
         size_to_clusters(s, offset_into_cluster(s, guest_offset) + *bytes);
 
-    l2_index = offset_to_l2_index(s, guest_offset);
-    nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+    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);
 
     /* Find L2 entry for the first involved cluster */
-    ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
+    ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index);
     if (ret < 0) {
         return ret;
     }
 
-    entry = be64_to_cpu(l2_table[l2_index]);
+    entry = be64_to_cpu(l2_slice[l2_index]);
 
     /* For the moment, overwrite compressed clusters one by one */
     if (entry & QCOW_OFLAG_COMPRESSED) {
         nb_clusters = 1;
     } else {
-        nb_clusters = count_cow_clusters(s, nb_clusters, l2_table, l2_index);
+        nb_clusters = count_cow_clusters(s, nb_clusters, l2_slice, l2_index);
     }
 
     /* This function is only called when there were no non-COW clusters, so if
@@ -1339,7 +1339,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
          * nb_clusters already to a range of COW clusters */
         preallocated_nb_clusters =
             count_contiguous_clusters(nb_clusters, s->cluster_size,
-                                      &l2_table[l2_index], QCOW_OFLAG_COPIED);
+                                      &l2_slice[l2_index], QCOW_OFLAG_COPIED);
         assert(preallocated_nb_clusters > 0);
 
         nb_clusters = preallocated_nb_clusters;
@@ -1350,7 +1350,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
         keep_old_clusters = true;
     }
 
-    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
 
     if (!alloc_cluster_offset) {
         /* Allocate, if necessary at a given offset in the image file */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 24/39] qcow2: Update discard_single_l2() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (22 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 23/39] qcow2: Update handle_alloc() " Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-02-01 19:07   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 25/39] qcow2: Update zero_single_l2() " Alberto Garcia
                   ` (14 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

discard_single_l2() limits the number of clusters to be discarded to
the amount that fits inside an L2 table. Since we'll be loading L2
slices instead of full tables we need to update that limit.

Apart from that, this function doesn't need any additional changes, so
this patch simply updates the variable name from l2_table to l2_slice.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index aa374f9928..fd1bf5d093 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1632,7 +1632,7 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
 
 /*
  * This discards as many clusters of nb_clusters as possible at once (i.e.
- * all clusters in the same L2 table) and returns the number of discarded
+ * all clusters in the same L2 slice) and returns the number of discarded
  * clusters.
  */
 static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
@@ -1640,24 +1640,24 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
                              bool full_discard)
 {
     BDRVQcow2State *s = bs->opaque;
-    uint64_t *l2_table;
+    uint64_t *l2_slice;
     int l2_index;
     int ret;
     int i;
 
-    ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+    ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
     if (ret < 0) {
         return ret;
     }
 
-    /* Limit nb_clusters to one L2 table */
-    nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+    /* Limit nb_clusters to one L2 slice */
+    nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
     assert(nb_clusters <= INT_MAX);
 
     for (i = 0; i < nb_clusters; i++) {
         uint64_t old_l2_entry;
 
-        old_l2_entry = be64_to_cpu(l2_table[l2_index + i]);
+        old_l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
 
         /*
          * If full_discard is false, make sure that a discarded area reads back
@@ -1695,18 +1695,18 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
         }
 
         /* First remove L2 entries */
-        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
         if (!full_discard && s->qcow_version >= 3) {
-            l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
+            l2_slice[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
         } else {
-            l2_table[l2_index + i] = cpu_to_be64(0);
+            l2_slice[l2_index + i] = cpu_to_be64(0);
         }
 
         /* Then decrease the refcount */
         qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
     }
 
-    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
 
     return nb_clusters;
 }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 25/39] qcow2: Update zero_single_l2() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (23 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 24/39] qcow2: Update discard_single_l2() " Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-02-01 19:08   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 26/39] qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support Alberto Garcia
                   ` (13 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

zero_single_l2() limits the number of clusters to be zeroed to the
amount that fits inside an L2 table. Since we'll be loading L2 slices
instead of full tables we need to update that limit.

Apart from that, this function doesn't need any additional changes, so
this patch simply updates the variable name from l2_table to l2_slice.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index fd1bf5d093..e13f8f2f14 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1753,33 +1753,33 @@ fail:
 
 /*
  * This zeroes as many clusters of nb_clusters as possible at once (i.e.
- * all clusters in the same L2 table) and returns the number of zeroed
+ * all clusters in the same L2 slice) and returns the number of zeroed
  * clusters.
  */
 static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
                           uint64_t nb_clusters, int flags)
 {
     BDRVQcow2State *s = bs->opaque;
-    uint64_t *l2_table;
+    uint64_t *l2_slice;
     int l2_index;
     int ret;
     int i;
     bool unmap = !!(flags & BDRV_REQ_MAY_UNMAP);
 
-    ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+    ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
     if (ret < 0) {
         return ret;
     }
 
-    /* Limit nb_clusters to one L2 table */
-    nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+    /* Limit nb_clusters to one L2 slice */
+    nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
     assert(nb_clusters <= INT_MAX);
 
     for (i = 0; i < nb_clusters; i++) {
         uint64_t old_offset;
         QCow2ClusterType cluster_type;
 
-        old_offset = be64_to_cpu(l2_table[l2_index + i]);
+        old_offset = be64_to_cpu(l2_slice[l2_index + i]);
 
         /*
          * Minimize L2 changes if the cluster already reads back as
@@ -1791,16 +1791,16 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
             continue;
         }
 
-        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
         if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
-            l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
+            l2_slice[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
             qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
         } else {
-            l2_table[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
+            l2_slice[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
         }
     }
 
-    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
 
     return nb_clusters;
 }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 26/39] qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (24 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 25/39] qcow2: Update zero_single_l2() " Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-26 19:38   ` Eric Blake
  2018-02-01 19:21   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 27/39] qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices Alberto Garcia
                   ` (12 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

Adding support for L2 slices to qcow2_update_snapshot_refcount() needs
(among other things) an extra loop that iterates over all slices of
each L2 table.

Putting all changes in one patch would make it hard to read because
all semantic changes would be mixed with pure indentation changes.

To make things easier this patch simply creates a new block and
changes the indentation of all lines of code inside it. Thus, all
modifications in this patch are cosmetic. There are no semantic
changes and no variables are renamed yet. The next patch will take
care of that.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-refcount.c | 140 ++++++++++++++++++++++++++-----------------------
 1 file changed, 73 insertions(+), 67 deletions(-)

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 9df380d52c..dfa28301c4 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1236,91 +1236,97 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                 goto fail;
             }
 
-            ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
-                (void**) &l2_table);
-            if (ret < 0) {
-                goto fail;
-            }
+            {
+                ret = qcow2_cache_get(bs, s->l2_table_cache,
+                                      l2_offset,
+                                      (void **) &l2_table);
+                if (ret < 0) {
+                    goto fail;
+                }
 
-            for (j = 0; j < s->l2_size; j++) {
-                uint64_t cluster_index;
-                uint64_t offset;
+                for (j = 0; j < s->l2_size; j++) {
+                    uint64_t cluster_index;
+                    uint64_t offset;
 
-                entry = be64_to_cpu(l2_table[j]);
-                old_entry = entry;
-                entry &= ~QCOW_OFLAG_COPIED;
-                offset = entry & L2E_OFFSET_MASK;
+                    entry = be64_to_cpu(l2_table[j]);
+                    old_entry = entry;
+                    entry &= ~QCOW_OFLAG_COPIED;
+                    offset = entry & L2E_OFFSET_MASK;
 
-                switch (qcow2_get_cluster_type(entry)) {
-                case QCOW2_CLUSTER_COMPRESSED:
-                    nb_csectors = ((entry >> s->csize_shift) &
-                                   s->csize_mask) + 1;
-                    if (addend != 0) {
-                        ret = update_refcount(bs,
-                                (entry & s->cluster_offset_mask) & ~511,
+                    switch (qcow2_get_cluster_type(entry)) {
+                    case QCOW2_CLUSTER_COMPRESSED:
+                        nb_csectors = ((entry >> s->csize_shift) &
+                                       s->csize_mask) + 1;
+                        if (addend != 0) {
+                            ret = update_refcount(
+                                bs, (entry & s->cluster_offset_mask) & ~511,
                                 nb_csectors * 512, abs(addend), addend < 0,
                                 QCOW2_DISCARD_SNAPSHOT);
-                        if (ret < 0) {
+                            if (ret < 0) {
+                                goto fail;
+                            }
+                        }
+                        /* compressed clusters are never modified */
+                        refcount = 2;
+                        break;
+
+                    case QCOW2_CLUSTER_NORMAL:
+                    case QCOW2_CLUSTER_ZERO_ALLOC:
+                        if (offset_into_cluster(s, offset)) {
+                            qcow2_signal_corruption(
+                                bs, true, -1, -1, "Cluster "
+                                "allocation offset %#" PRIx64
+                                " unaligned (L2 offset: %#"
+                                PRIx64 ", L2 index: %#x)",
+                                offset, l2_offset, j);
+                            ret = -EIO;
                             goto fail;
                         }
-                    }
-                    /* compressed clusters are never modified */
-                    refcount = 2;
-                    break;
-
-                case QCOW2_CLUSTER_NORMAL:
-                case QCOW2_CLUSTER_ZERO_ALLOC:
-                    if (offset_into_cluster(s, offset)) {
-                        qcow2_signal_corruption(bs, true, -1, -1, "Cluster "
-                                                "allocation offset %#" PRIx64
-                                                " unaligned (L2 offset: %#"
-                                                PRIx64 ", L2 index: %#x)",
-                                                offset, l2_offset, j);
-                        ret = -EIO;
-                        goto fail;
-                    }
 
-                    cluster_index = offset >> s->cluster_bits;
-                    assert(cluster_index);
-                    if (addend != 0) {
-                        ret = qcow2_update_cluster_refcount(bs,
-                                    cluster_index, abs(addend), addend < 0,
-                                    QCOW2_DISCARD_SNAPSHOT);
+                        cluster_index = offset >> s->cluster_bits;
+                        assert(cluster_index);
+                        if (addend != 0) {
+                            ret = qcow2_update_cluster_refcount(
+                                bs, cluster_index, abs(addend), addend < 0,
+                                QCOW2_DISCARD_SNAPSHOT);
+                            if (ret < 0) {
+                                goto fail;
+                            }
+                        }
+
+                        ret = qcow2_get_refcount(bs, cluster_index, &refcount);
                         if (ret < 0) {
                             goto fail;
                         }
-                    }
+                        break;
 
-                    ret = qcow2_get_refcount(bs, cluster_index, &refcount);
-                    if (ret < 0) {
-                        goto fail;
-                    }
-                    break;
+                    case QCOW2_CLUSTER_ZERO_PLAIN:
+                    case QCOW2_CLUSTER_UNALLOCATED:
+                        refcount = 0;
+                        break;
 
-                case QCOW2_CLUSTER_ZERO_PLAIN:
-                case QCOW2_CLUSTER_UNALLOCATED:
-                    refcount = 0;
-                    break;
-
-                default:
-                    abort();
-                }
+                    default:
+                        abort();
+                    }
 
-                if (refcount == 1) {
-                    entry |= QCOW_OFLAG_COPIED;
-                }
-                if (entry != old_entry) {
-                    if (addend > 0) {
-                        qcow2_cache_set_dependency(bs, s->l2_table_cache,
-                            s->refcount_block_cache);
+                    if (refcount == 1) {
+                        entry |= QCOW_OFLAG_COPIED;
+                    }
+                    if (entry != old_entry) {
+                        if (addend > 0) {
+                            qcow2_cache_set_dependency(bs, s->l2_table_cache,
+                                                       s->refcount_block_cache);
+                        }
+                        l2_table[j] = cpu_to_be64(entry);
+                        qcow2_cache_entry_mark_dirty(s->l2_table_cache,
+                                                     l2_table);
                     }
-                    l2_table[j] = cpu_to_be64(entry);
-                    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
                 }
+
+                qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+
             }
 
-            qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
-
             if (addend != 0) {
                 ret = qcow2_update_cluster_refcount(bs, l2_offset >>
                                                         s->cluster_bits,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 27/39] qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (25 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 26/39] qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-26 19:39   ` Eric Blake
  2018-02-01 19:26   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 28/39] qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1() Alberto Garcia
                   ` (11 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

qcow2_update_snapshot_refcount() increases the refcount of all
clusters of a given snapshot. In order to do that it needs to load all
its L2 tables and iterate over their entries. Since we'll be loading
L2 slices instead of full tables we need to add an extra loop that
iterates over all slices of each L2 table.

This function doesn't need any additional changes so apart from that
this patch simply updates the variable name from l2_table to l2_slice.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-refcount.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index dfa28301c4..60b521cb89 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1183,17 +1183,20 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
     int64_t l1_table_offset, int l1_size, int addend)
 {
     BDRVQcow2State *s = bs->opaque;
-    uint64_t *l1_table, *l2_table, l2_offset, entry, l1_size2, refcount;
+    uint64_t *l1_table, *l2_slice, l2_offset, entry, l1_size2, refcount;
     bool l1_allocated = false;
     int64_t old_entry, old_l2_offset;
+    unsigned slice, slice_size2, n_slices;
     int i, j, l1_modified = 0, nb_csectors;
     int ret;
 
     assert(addend >= -1 && addend <= 1);
 
-    l2_table = NULL;
+    l2_slice = NULL;
     l1_table = NULL;
     l1_size2 = l1_size * sizeof(uint64_t);
+    slice_size2 = s->l2_slice_size * sizeof(uint64_t);
+    n_slices = s->cluster_size / slice_size2;
 
     s->cache_discards = true;
 
@@ -1236,19 +1239,19 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                 goto fail;
             }
 
-            {
+            for (slice = 0; slice < n_slices; slice++) {
                 ret = qcow2_cache_get(bs, s->l2_table_cache,
-                                      l2_offset,
-                                      (void **) &l2_table);
+                                      l2_offset + slice * slice_size2,
+                                      (void **) &l2_slice);
                 if (ret < 0) {
                     goto fail;
                 }
 
-                for (j = 0; j < s->l2_size; j++) {
+                for (j = 0; j < s->l2_slice_size; j++) {
                     uint64_t cluster_index;
                     uint64_t offset;
 
-                    entry = be64_to_cpu(l2_table[j]);
+                    entry = be64_to_cpu(l2_slice[j]);
                     old_entry = entry;
                     entry &= ~QCOW_OFLAG_COPIED;
                     offset = entry & L2E_OFFSET_MASK;
@@ -1273,12 +1276,13 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                     case QCOW2_CLUSTER_NORMAL:
                     case QCOW2_CLUSTER_ZERO_ALLOC:
                         if (offset_into_cluster(s, offset)) {
+                            int l2_index = slice * s->l2_slice_size + j;
                             qcow2_signal_corruption(
                                 bs, true, -1, -1, "Cluster "
                                 "allocation offset %#" PRIx64
                                 " unaligned (L2 offset: %#"
                                 PRIx64 ", L2 index: %#x)",
-                                offset, l2_offset, j);
+                                offset, l2_offset, l2_index);
                             ret = -EIO;
                             goto fail;
                         }
@@ -1317,14 +1321,13 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                             qcow2_cache_set_dependency(bs, s->l2_table_cache,
                                                        s->refcount_block_cache);
                         }
-                        l2_table[j] = cpu_to_be64(entry);
+                        l2_slice[j] = cpu_to_be64(entry);
                         qcow2_cache_entry_mark_dirty(s->l2_table_cache,
-                                                     l2_table);
+                                                     l2_slice);
                     }
                 }
 
-                qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
-
+                qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
             }
 
             if (addend != 0) {
@@ -1352,8 +1355,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
 
     ret = bdrv_flush(bs);
 fail:
-    if (l2_table) {
-        qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+    if (l2_slice) {
+        qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
     }
 
     s->cache_discards = false;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 28/39] qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (26 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 27/39] qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-26 19:41   ` Eric Blake
  2018-02-01 19:29   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 29/39] qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support Alberto Garcia
                   ` (10 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

At the moment it doesn't really make a difference whether we call
qcow2_get_refcount() before of after reading the L2 table, but if we
want to support L2 slices we'll need to read the refcount first.

This patch simply changes the order of those two operations to prepare
for that. The patch with the actual semantic changes will be easier to
read because of this.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-cluster.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index e13f8f2f14..1338485184 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1899,6 +1899,12 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
             goto fail;
         }
 
+        ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,
+                                 &l2_refcount);
+        if (ret < 0) {
+            goto fail;
+        }
+
         if (is_active_l1) {
             /* get active L2 tables from cache */
             ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
@@ -1912,12 +1918,6 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
             goto fail;
         }
 
-        ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,
-                                 &l2_refcount);
-        if (ret < 0) {
-            goto fail;
-        }
-
         for (j = 0; j < s->l2_size; j++) {
             uint64_t l2_entry = be64_to_cpu(l2_table[j]);
             int64_t offset = l2_entry & L2E_OFFSET_MASK;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 29/39] qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (27 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 28/39] qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1() Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-26 19:42   ` Eric Blake
  2018-02-01 19:34   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 30/39] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices Alberto Garcia
                   ` (9 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

Adding support for L2 slices to expand_zero_clusters_in_l1() needs
(among other things) an extra loop that iterates over all slices of
each L2 table.

Putting all changes in one patch would make it hard to read because
all semantic changes would be mixed with pure indentation changes.

To make things easier this patch simply creates a new block and
changes the indentation of all lines of code inside it. Thus, all
modifications in this patch are cosmetic. There are no semantic
changes and no variables are renamed yet. The next patch will take
care of that.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-cluster.c | 187 ++++++++++++++++++++++++++------------------------
 1 file changed, 96 insertions(+), 91 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 1338485184..6042ec69e3 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1905,118 +1905,123 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
             goto fail;
         }
 
-        if (is_active_l1) {
-            /* get active L2 tables from cache */
-            ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
-                    (void **)&l2_table);
-        } else {
-            /* load inactive L2 tables from disk */
-            ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
-                            (void *)l2_table, s->cluster_sectors);
-        }
-        if (ret < 0) {
-            goto fail;
-        }
-
-        for (j = 0; j < s->l2_size; j++) {
-            uint64_t l2_entry = be64_to_cpu(l2_table[j]);
-            int64_t offset = l2_entry & L2E_OFFSET_MASK;
-            QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry);
-
-            if (cluster_type != QCOW2_CLUSTER_ZERO_PLAIN &&
-                cluster_type != QCOW2_CLUSTER_ZERO_ALLOC) {
-                continue;
+        {
+            if (is_active_l1) {
+                /* get active L2 tables from cache */
+                ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
+                                      (void **)&l2_table);
+            } else {
+                /* load inactive L2 tables from disk */
+                ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
+                                (void *)l2_table, s->cluster_sectors);
             }
+            if (ret < 0) {
+                goto fail;
+            }
+
+            for (j = 0; j < s->l2_size; j++) {
+                uint64_t l2_entry = be64_to_cpu(l2_table[j]);
+                int64_t offset = l2_entry & L2E_OFFSET_MASK;
+                QCow2ClusterType cluster_type =
+                    qcow2_get_cluster_type(l2_entry);
 
-            if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
-                if (!bs->backing) {
-                    /* not backed; therefore we can simply deallocate the
-                     * cluster */
-                    l2_table[j] = 0;
-                    l2_dirty = true;
+                if (cluster_type != QCOW2_CLUSTER_ZERO_PLAIN &&
+                    cluster_type != QCOW2_CLUSTER_ZERO_ALLOC) {
                     continue;
                 }
 
-                offset = qcow2_alloc_clusters(bs, s->cluster_size);
-                if (offset < 0) {
-                    ret = offset;
-                    goto fail;
-                }
+                if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
+                    if (!bs->backing) {
+                        /* not backed; therefore we can simply deallocate the
+                         * cluster */
+                        l2_table[j] = 0;
+                        l2_dirty = true;
+                        continue;
+                    }
 
-                if (l2_refcount > 1) {
-                    /* For shared L2 tables, set the refcount accordingly (it is
-                     * already 1 and needs to be l2_refcount) */
-                    ret = qcow2_update_cluster_refcount(bs,
-                            offset >> s->cluster_bits,
+                    offset = qcow2_alloc_clusters(bs, s->cluster_size);
+                    if (offset < 0) {
+                        ret = offset;
+                        goto fail;
+                    }
+
+                    if (l2_refcount > 1) {
+                        /* For shared L2 tables, set the refcount accordingly
+                         * (it is already 1 and needs to be l2_refcount) */
+                        ret = qcow2_update_cluster_refcount(
+                            bs, offset >> s->cluster_bits,
                             refcount_diff(1, l2_refcount), false,
                             QCOW2_DISCARD_OTHER);
-                    if (ret < 0) {
+                        if (ret < 0) {
+                            qcow2_free_clusters(bs, offset, s->cluster_size,
+                                                QCOW2_DISCARD_OTHER);
+                            goto fail;
+                        }
+                    }
+                }
+
+                if (offset_into_cluster(s, offset)) {
+                    qcow2_signal_corruption(
+                        bs, true, -1, -1,
+                        "Cluster allocation offset "
+                        "%#" PRIx64 " unaligned (L2 offset: %#"
+                        PRIx64 ", L2 index: %#x)", offset,
+                        l2_offset, j);
+                    if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
                         qcow2_free_clusters(bs, offset, s->cluster_size,
-                                            QCOW2_DISCARD_OTHER);
-                        goto fail;
+                                            QCOW2_DISCARD_ALWAYS);
                     }
+                    ret = -EIO;
+                    goto fail;
                 }
-            }
 
-            if (offset_into_cluster(s, offset)) {
-                qcow2_signal_corruption(bs, true, -1, -1,
-                                        "Cluster allocation offset "
-                                        "%#" PRIx64 " unaligned (L2 offset: %#"
-                                        PRIx64 ", L2 index: %#x)", offset,
-                                        l2_offset, j);
-                if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
-                    qcow2_free_clusters(bs, offset, s->cluster_size,
-                                        QCOW2_DISCARD_ALWAYS);
+                ret = qcow2_pre_write_overlap_check(bs, 0, offset,
+                                                    s->cluster_size);
+                if (ret < 0) {
+                    if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
+                        qcow2_free_clusters(bs, offset, s->cluster_size,
+                                            QCOW2_DISCARD_ALWAYS);
+                    }
+                    goto fail;
                 }
-                ret = -EIO;
-                goto fail;
-            }
 
-            ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size);
-            if (ret < 0) {
-                if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
-                    qcow2_free_clusters(bs, offset, s->cluster_size,
-                                        QCOW2_DISCARD_ALWAYS);
+                ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0);
+                if (ret < 0) {
+                    if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
+                        qcow2_free_clusters(bs, offset, s->cluster_size,
+                                            QCOW2_DISCARD_ALWAYS);
+                    }
+                    goto fail;
                 }
-                goto fail;
-            }
 
-            ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0);
-            if (ret < 0) {
-                if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
-                    qcow2_free_clusters(bs, offset, s->cluster_size,
-                                        QCOW2_DISCARD_ALWAYS);
+                if (l2_refcount == 1) {
+                    l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
+                } else {
+                    l2_table[j] = cpu_to_be64(offset);
                 }
-                goto fail;
+                l2_dirty = true;
             }
 
-            if (l2_refcount == 1) {
-                l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
+            if (is_active_l1) {
+                if (l2_dirty) {
+                    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+                    qcow2_cache_depends_on_flush(s->l2_table_cache);
+                }
+                qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
             } else {
-                l2_table[j] = cpu_to_be64(offset);
-            }
-            l2_dirty = true;
-        }
+                if (l2_dirty) {
+                    ret = qcow2_pre_write_overlap_check(
+                        bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2,
+                        l2_offset, s->cluster_size);
+                    if (ret < 0) {
+                        goto fail;
+                    }
 
-        if (is_active_l1) {
-            if (l2_dirty) {
-                qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
-                qcow2_cache_depends_on_flush(s->l2_table_cache);
-            }
-            qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
-        } else {
-            if (l2_dirty) {
-                ret = qcow2_pre_write_overlap_check(bs,
-                        QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, l2_offset,
-                        s->cluster_size);
-                if (ret < 0) {
-                    goto fail;
-                }
-
-                ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
-                                 (void *)l2_table, s->cluster_sectors);
-                if (ret < 0) {
-                    goto fail;
+                    ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
+                                     (void *)l2_table, s->cluster_sectors);
+                    if (ret < 0) {
+                        goto fail;
+                    }
                 }
             }
         }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 30/39] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (28 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 29/39] qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-01-26 19:46   ` Eric Blake
  2018-02-01 19:44   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 31/39] qcow2: Update qcow2_truncate() " Alberto Garcia
                   ` (8 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

expand_zero_clusters_in_l1() expands zero clusters as a necessary step
to downgrade qcow2 images to a version that doesn't support metadata
zero clusters. This function takes an L1 table (which may or may not
be active) and iterates over all its L2 tables looking for zero
clusters.

Since we'll be loading L2 slices instead of full tables we need to add
an extra loop that iterates over all slices of each L2 table, and we
should also use the slice size when allocating the buffer used when
the L1 table is not active.

This function doesn't need any additional changes so apart from that
this patch simply updates the variable name from l2_table to l2_slice.

Finally, and since we have to touch the bdrv_read() / bdrv_write()
calls anyway, this patch takes the opportunity to replace them with
the byte-based bdrv_pread() / bdrv_pwrite().

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-cluster.c | 52 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 29 insertions(+), 23 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 6042ec69e3..659830ad4d 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1864,22 +1864,25 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
 {
     BDRVQcow2State *s = bs->opaque;
     bool is_active_l1 = (l1_table == s->l1_table);
-    uint64_t *l2_table = NULL;
+    uint64_t *l2_slice = NULL;
+    unsigned slice, slice_size2, n_slices;
     int ret;
     int i, j;
 
+    slice_size2 = s->l2_slice_size * sizeof(uint64_t);
+    n_slices = s->cluster_size / slice_size2;
+
     if (!is_active_l1) {
         /* inactive L2 tables require a buffer to be stored in when loading
          * them from disk */
-        l2_table = qemu_try_blockalign(bs->file->bs, s->cluster_size);
-        if (l2_table == NULL) {
+        l2_slice = qemu_try_blockalign(bs->file->bs, slice_size2);
+        if (l2_slice == NULL) {
             return -ENOMEM;
         }
     }
 
     for (i = 0; i < l1_size; i++) {
         uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK;
-        bool l2_dirty = false;
         uint64_t l2_refcount;
 
         if (!l2_offset) {
@@ -1905,22 +1908,24 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
             goto fail;
         }
 
-        {
+        for (slice = 0; slice < n_slices; slice++) {
+            uint64_t slice_offset = l2_offset + slice * slice_size2;
+            bool l2_dirty = false;
             if (is_active_l1) {
                 /* get active L2 tables from cache */
-                ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
-                                      (void **)&l2_table);
+                ret = qcow2_cache_get(bs, s->l2_table_cache, slice_offset,
+                                      (void **)&l2_slice);
             } else {
                 /* load inactive L2 tables from disk */
-                ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
-                                (void *)l2_table, s->cluster_sectors);
+                ret = bdrv_pread(bs->file, slice_offset,
+                                 (void *)l2_slice, slice_size2);
             }
             if (ret < 0) {
                 goto fail;
             }
 
-            for (j = 0; j < s->l2_size; j++) {
-                uint64_t l2_entry = be64_to_cpu(l2_table[j]);
+            for (j = 0; j < s->l2_slice_size; j++) {
+                uint64_t l2_entry = be64_to_cpu(l2_slice[j]);
                 int64_t offset = l2_entry & L2E_OFFSET_MASK;
                 QCow2ClusterType cluster_type =
                     qcow2_get_cluster_type(l2_entry);
@@ -1934,7 +1939,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
                     if (!bs->backing) {
                         /* not backed; therefore we can simply deallocate the
                          * cluster */
-                        l2_table[j] = 0;
+                        l2_slice[j] = 0;
                         l2_dirty = true;
                         continue;
                     }
@@ -1961,12 +1966,13 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
                 }
 
                 if (offset_into_cluster(s, offset)) {
+                    int l2_index = slice * s->l2_slice_size + j;
                     qcow2_signal_corruption(
                         bs, true, -1, -1,
                         "Cluster allocation offset "
                         "%#" PRIx64 " unaligned (L2 offset: %#"
                         PRIx64 ", L2 index: %#x)", offset,
-                        l2_offset, j);
+                        l2_offset, l2_index);
                     if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
                         qcow2_free_clusters(bs, offset, s->cluster_size,
                                             QCOW2_DISCARD_ALWAYS);
@@ -1995,30 +2001,30 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
                 }
 
                 if (l2_refcount == 1) {
-                    l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
+                    l2_slice[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
                 } else {
-                    l2_table[j] = cpu_to_be64(offset);
+                    l2_slice[j] = cpu_to_be64(offset);
                 }
                 l2_dirty = true;
             }
 
             if (is_active_l1) {
                 if (l2_dirty) {
-                    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+                    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
                     qcow2_cache_depends_on_flush(s->l2_table_cache);
                 }
-                qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+                qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
             } else {
                 if (l2_dirty) {
                     ret = qcow2_pre_write_overlap_check(
                         bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2,
-                        l2_offset, s->cluster_size);
+                        slice_offset, slice_size2);
                     if (ret < 0) {
                         goto fail;
                     }
 
-                    ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
-                                     (void *)l2_table, s->cluster_sectors);
+                    ret = bdrv_pwrite(bs->file, slice_offset,
+                                      (void *)l2_slice, slice_size2);
                     if (ret < 0) {
                         goto fail;
                     }
@@ -2035,11 +2041,11 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
     ret = 0;
 
 fail:
-    if (l2_table) {
+    if (l2_slice) {
         if (!is_active_l1) {
-            qemu_vfree(l2_table);
+            qemu_vfree(l2_slice);
         } else {
-            qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+            qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
         }
     }
     return ret;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 31/39] qcow2: Update qcow2_truncate() to support L2 slices
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (29 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 30/39] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-02-01 19:46   ` Max Reitz
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 32/39] qcow2: Rename l2_table in qcow2_alloc_compressed_cluster_offset() Alberto Garcia
                   ` (7 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

The qcow2_truncate() code is mostly independent from whether
we're using L2 slices or full L2 tables, but in full and
falloc preallocation modes new L2 tables are allocated using
qcow2_alloc_cluster_link_l2().  Therefore the code needs to be
modified to ensure that all nb_clusters that are processed in each
call can be allocated with just one L2 slice.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index 78f067cae7..529becfa30 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3261,8 +3261,9 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
         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);
+            int64_t nb_clusters = MIN(
+                nb_new_data_clusters,
+                s->l2_slice_size - guest_cluster % s->l2_slice_size);
             QCowL2Meta allocation = {
                 .offset       = guest_offset,
                 .alloc_offset = host_offset,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 32/39] qcow2: Rename l2_table in qcow2_alloc_compressed_cluster_offset()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (30 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 31/39] qcow2: Update qcow2_truncate() " Alberto Garcia
@ 2018-01-26 14:59 ` Alberto Garcia
  2018-02-01 19:48   ` Max Reitz
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 33/39] qcow2: Rename l2_table in count_contiguous_clusters() Alberto Garcia
                   ` (6 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 14:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function doesn't need any changes to support L2 slices, but since
it's now dealing with slices instead of full tables, the l2_table
variable is renamed for clarity.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 659830ad4d..2d46927dc5 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -748,26 +748,26 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 {
     BDRVQcow2State *s = bs->opaque;
     int l2_index, ret;
-    uint64_t *l2_table;
+    uint64_t *l2_slice;
     int64_t cluster_offset;
     int nb_csectors;
 
-    ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+    ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
     if (ret < 0) {
         return 0;
     }
 
     /* Compression can't overwrite anything. Fail if the cluster was already
      * allocated. */
-    cluster_offset = be64_to_cpu(l2_table[l2_index]);
+    cluster_offset = be64_to_cpu(l2_slice[l2_index]);
     if (cluster_offset & L2E_OFFSET_MASK) {
-        qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+        qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
         return 0;
     }
 
     cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
     if (cluster_offset < 0) {
-        qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+        qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
         return 0;
     }
 
@@ -782,9 +782,9 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
     /* compressed clusters never have the copied flag */
 
     BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
-    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
-    l2_table[l2_index] = cpu_to_be64(cluster_offset);
-    qcow2_cache_put(s->l2_table_cache, (void **) &l2_table);
+    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
+    l2_slice[l2_index] = cpu_to_be64(cluster_offset);
+    qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
 
     return cluster_offset;
 }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 33/39] qcow2: Rename l2_table in count_contiguous_clusters()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (31 preceding siblings ...)
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 32/39] qcow2: Rename l2_table in qcow2_alloc_compressed_cluster_offset() Alberto Garcia
@ 2018-01-26 15:00 ` Alberto Garcia
  2018-02-01 19:49   ` Max Reitz
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 34/39] qcow2: Rename l2_table in count_contiguous_clusters_unallocated() Alberto Garcia
                   ` (5 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 15:00 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function doesn't need any changes to support L2 slices, but since
it's now dealing with slices intead of full tables, the l2_table
variable is renamed for clarity.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 2d46927dc5..60c38a71f1 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -371,19 +371,19 @@ fail:
 }
 
 /*
- * Checks how many clusters in a given L2 table are contiguous in the image
+ * Checks how many clusters in a given L2 slice are contiguous in the image
  * file. As soon as one of the flags in the bitmask stop_flags changes compared
  * to the first cluster, the search is stopped and the cluster is not counted
  * as contiguous. (This allows it, for example, to stop at the first compressed
  * cluster which may require a different handling)
  */
 static int count_contiguous_clusters(int nb_clusters, int cluster_size,
-        uint64_t *l2_table, uint64_t stop_flags)
+        uint64_t *l2_slice, uint64_t stop_flags)
 {
     int i;
     QCow2ClusterType first_cluster_type;
     uint64_t mask = stop_flags | L2E_OFFSET_MASK | QCOW_OFLAG_COMPRESSED;
-    uint64_t first_entry = be64_to_cpu(l2_table[0]);
+    uint64_t first_entry = be64_to_cpu(l2_slice[0]);
     uint64_t offset = first_entry & mask;
 
     if (!offset) {
@@ -396,7 +396,7 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
            first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);
 
     for (i = 0; i < nb_clusters; i++) {
-        uint64_t l2_entry = be64_to_cpu(l2_table[i]) & mask;
+        uint64_t l2_entry = be64_to_cpu(l2_slice[i]) & mask;
         if (offset + (uint64_t) i * cluster_size != l2_entry) {
             break;
         }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 34/39] qcow2: Rename l2_table in count_contiguous_clusters_unallocated()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (32 preceding siblings ...)
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 33/39] qcow2: Rename l2_table in count_contiguous_clusters() Alberto Garcia
@ 2018-01-26 15:00 ` Alberto Garcia
  2018-02-01 19:49   ` Max Reitz
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 35/39] qcow2: Rename l2_table in count_cow_clusters() Alberto Garcia
                   ` (4 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 15:00 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function doesn't need any changes to support L2 slices, but since
it's now dealing with slices intead of full tables, the l2_table
variable is renamed for clarity.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 60c38a71f1..5422c202fb 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -407,10 +407,10 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
 
 /*
  * Checks how many consecutive unallocated clusters in a given L2
- * table have the same cluster type.
+ * slice have the same cluster type.
  */
 static int count_contiguous_clusters_unallocated(int nb_clusters,
-                                                 uint64_t *l2_table,
+                                                 uint64_t *l2_slice,
                                                  QCow2ClusterType wanted_type)
 {
     int i;
@@ -418,7 +418,7 @@ static int count_contiguous_clusters_unallocated(int nb_clusters,
     assert(wanted_type == QCOW2_CLUSTER_ZERO_PLAIN ||
            wanted_type == QCOW2_CLUSTER_UNALLOCATED);
     for (i = 0; i < nb_clusters; i++) {
-        uint64_t entry = be64_to_cpu(l2_table[i]);
+        uint64_t entry = be64_to_cpu(l2_slice[i]);
         QCow2ClusterType type = qcow2_get_cluster_type(entry);
 
         if (type != wanted_type) {
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 35/39] qcow2: Rename l2_table in count_cow_clusters()
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (33 preceding siblings ...)
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 34/39] qcow2: Rename l2_table in count_contiguous_clusters_unallocated() Alberto Garcia
@ 2018-01-26 15:00 ` Alberto Garcia
  2018-02-01 19:50   ` Max Reitz
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 36/39] qcow2: Allow configuring the L2 slice size Alberto Garcia
                   ` (3 subsequent siblings)
  38 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 15:00 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This function doesn't need any changes to support L2 slices, but since
it's now dealing with slices intead of full tables, the l2_table
variable is renamed for clarity.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2-cluster.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 5422c202fb..efa56a1608 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1000,12 +1000,12 @@ err:
  * which must copy from the backing file)
  */
 static int count_cow_clusters(BDRVQcow2State *s, int nb_clusters,
-    uint64_t *l2_table, int l2_index)
+    uint64_t *l2_slice, int l2_index)
 {
     int i;
 
     for (i = 0; i < nb_clusters; i++) {
-        uint64_t l2_entry = be64_to_cpu(l2_table[l2_index + i]);
+        uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
         QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry);
 
         switch(cluster_type) {
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 36/39] qcow2: Allow configuring the L2 slice size
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (34 preceding siblings ...)
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 35/39] qcow2: Rename l2_table in count_cow_clusters() Alberto Garcia
@ 2018-01-26 15:00 ` Alberto Garcia
  2018-01-31 19:20   ` Eric Blake
  2018-02-01 20:04   ` Max Reitz
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 37/39] iotests: Test valid values of l2-cache-entry-size Alberto Garcia
                   ` (2 subsequent siblings)
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 15:00 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

Now that the code is ready to handle L2 slices we can finally add an
option to allow configuring their size.

An L2 slice is the portion of an L2 table that is read by the qcow2
cache. Until now the cache was always reading full L2 tables, and
since the L2 table size is equal to the cluster size this was not very
efficient with large clusters. Here's a more detailed explanation of
why it makes sense to have smaller cache entries in order to load L2
data:

   https://lists.gnu.org/archive/html/qemu-block/2017-09/msg00635.html

This patch introduces a new command-line option to the qcow2 driver
named l2-cache-entry-size (cf. l2-cache-size). The cache entry size
has the same restrictions as the cluster size: it must be a power of
two and it has the same range of allowed values, with the additional
requirement that it must not be larger than the cluster size.

The L2 cache entry size (L2 slice size) remains equal to the cluster
size for now by default, so this feature must be explicitly enabled.
Although my tests show that 4KB slices consistently improve
performance and give the best results, let's wait and make more tests
with different cluster sizes before deciding on an optimal default.

Now that the cache entry size is not necessarily equal to the cluster
size we need to reflect that in the MIN_L2_CACHE_SIZE documentation.
That minimum value is a requirement of the COW algorithm: we need to
read two L2 slices (and not two L2 tables) in order to do COW, see
l2_allocate() for the actual code.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2-cache.c  | 10 ++++++++--
 block/qcow2.c        | 34 +++++++++++++++++++++++++++-------
 block/qcow2.h        |  6 ++++--
 qapi/block-core.json |  6 ++++++
 4 files changed, 45 insertions(+), 11 deletions(-)

diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index b1aa42477e..d9dafa31e5 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -120,14 +120,20 @@ void qcow2_cache_clean_unused(Qcow2Cache *c)
     c->cache_clean_lru_counter = c->lru_counter;
 }
 
-Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
+                               unsigned table_size)
 {
     BDRVQcow2State *s = bs->opaque;
     Qcow2Cache *c;
 
+    assert(num_tables > 0);
+    assert(is_power_of_2(table_size));
+    assert(table_size >= (1 << MIN_CLUSTER_BITS));
+    assert(table_size <= s->cluster_size);
+
     c = g_new0(Qcow2Cache, 1);
     c->size = num_tables;
-    c->table_size = s->cluster_size;
+    c->table_size = table_size;
     c->entries = g_try_new0(Qcow2CachedTable, num_tables);
     c->table_array = qemu_try_blockalign(bs->file->bs,
                                          (size_t) num_tables * c->table_size);
diff --git a/block/qcow2.c b/block/qcow2.c
index 529becfa30..98762433a0 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -674,6 +674,11 @@ static QemuOptsList qcow2_runtime_opts = {
             .help = "Maximum L2 table cache size",
         },
         {
+            .name = QCOW2_OPT_L2_CACHE_ENTRY_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Size of each entry in the L2 cache",
+        },
+        {
             .name = QCOW2_OPT_REFCOUNT_CACHE_SIZE,
             .type = QEMU_OPT_SIZE,
             .help = "Maximum refcount block cache size",
@@ -745,6 +750,7 @@ static void qcow2_attach_aio_context(BlockDriverState *bs,
 
 static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
                              uint64_t *l2_cache_size,
+                             uint64_t *l2_cache_entry_size,
                              uint64_t *refcount_cache_size, Error **errp)
 {
     BDRVQcow2State *s = bs->opaque;
@@ -760,6 +766,9 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
     *refcount_cache_size = qemu_opt_get_size(opts,
                                              QCOW2_OPT_REFCOUNT_CACHE_SIZE, 0);
 
+    *l2_cache_entry_size = qemu_opt_get_size(
+        opts, QCOW2_OPT_L2_CACHE_ENTRY_SIZE, s->cluster_size);
+
     if (combined_cache_size_set) {
         if (l2_cache_size_set && refcount_cache_size_set) {
             error_setg(errp, QCOW2_OPT_CACHE_SIZE ", " QCOW2_OPT_L2_CACHE_SIZE
@@ -800,6 +809,15 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
                                  / DEFAULT_L2_REFCOUNT_SIZE_RATIO;
         }
     }
+
+    if (*l2_cache_entry_size < (1 << MIN_CLUSTER_BITS) ||
+        *l2_cache_entry_size > s->cluster_size ||
+        !is_power_of_2(*l2_cache_entry_size)) {
+        error_setg(errp, "L2 cache entry size must be a power of two "
+                   "between %d and the cluster size (%d)",
+                   1 << MIN_CLUSTER_BITS, s->cluster_size);
+        return;
+    }
 }
 
 typedef struct Qcow2ReopenState {
@@ -822,7 +840,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
     QemuOpts *opts = NULL;
     const char *opt_overlap_check, *opt_overlap_check_template;
     int overlap_check_template = 0;
-    uint64_t l2_cache_size, refcount_cache_size;
+    uint64_t l2_cache_size, l2_cache_entry_size, refcount_cache_size;
     int i;
     const char *encryptfmt;
     QDict *encryptopts = NULL;
@@ -841,15 +859,15 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
     }
 
     /* get L2 table/refcount block cache size from command line options */
-    read_cache_sizes(bs, opts, &l2_cache_size, &refcount_cache_size,
-                     &local_err);
+    read_cache_sizes(bs, opts, &l2_cache_size, &l2_cache_entry_size,
+                     &refcount_cache_size, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         ret = -EINVAL;
         goto fail;
     }
 
-    l2_cache_size /= s->cluster_size;
+    l2_cache_size /= l2_cache_entry_size;
     if (l2_cache_size < MIN_L2_CACHE_SIZE) {
         l2_cache_size = MIN_L2_CACHE_SIZE;
     }
@@ -887,9 +905,11 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
         }
     }
 
-    r->l2_slice_size = s->cluster_size / sizeof(uint64_t);
-    r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
-    r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
+    r->l2_slice_size = l2_cache_entry_size / sizeof(uint64_t);
+    r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size,
+                                           l2_cache_entry_size);
+    r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size,
+                                                 s->cluster_size);
     if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
         error_setg(errp, "Could not allocate metadata caches");
         ret = -ENOMEM;
diff --git a/block/qcow2.h b/block/qcow2.h
index 87b5c4063e..d20753f140 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -68,7 +68,7 @@
 #define MAX_CLUSTER_BITS 21
 
 /* Must be at least 2 to cover COW */
-#define MIN_L2_CACHE_SIZE 2 /* clusters */
+#define MIN_L2_CACHE_SIZE 2 /* cache entries */
 
 /* Must be at least 4 to cover all cases of refcount table growth */
 #define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */
@@ -100,6 +100,7 @@
 #define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2"
 #define QCOW2_OPT_CACHE_SIZE "cache-size"
 #define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size"
+#define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size"
 #define QCOW2_OPT_REFCOUNT_CACHE_SIZE "refcount-cache-size"
 #define QCOW2_OPT_CACHE_CLEAN_INTERVAL "cache-clean-interval"
 
@@ -647,7 +648,8 @@ void qcow2_free_snapshots(BlockDriverState *bs);
 int qcow2_read_snapshots(BlockDriverState *bs);
 
 /* qcow2-cache.c functions */
-Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
+                               unsigned table_size);
 int qcow2_cache_destroy(Qcow2Cache *c);
 
 void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 8225308904..8556123cf4 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2507,6 +2507,11 @@
 # @l2-cache-size:         the maximum size of the L2 table cache in
 #                         bytes (since 2.2)
 #
+# @l2-cache-entry-size:   the size of each entry in the L2 cache in
+#                         bytes. It must be a power of two between 512
+#                         and the cluster size. The default value is
+#                         the cluster size (since 2.12)
+#
 # @refcount-cache-size:   the maximum size of the refcount block cache
 #                         in bytes (since 2.2)
 #
@@ -2528,6 +2533,7 @@
             '*overlap-check': 'Qcow2OverlapChecks',
             '*cache-size': 'int',
             '*l2-cache-size': 'int',
+            '*l2-cache-entry-size': 'int',
             '*refcount-cache-size': 'int',
             '*cache-clean-interval': 'int',
             '*encrypt': 'BlockdevQcow2Encryption' } }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 37/39] iotests: Test valid values of l2-cache-entry-size
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (35 preceding siblings ...)
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 36/39] qcow2: Allow configuring the L2 slice size Alberto Garcia
@ 2018-01-26 15:00 ` Alberto Garcia
  2018-01-31 19:21   ` Eric Blake
  2018-02-01 20:05   ` Max Reitz
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 38/39] iotests: Test downgrading an image using a small L2 slice size Alberto Garcia
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 39/39] iotests: Add l2-cache-entry-size to iotest 137 Alberto Garcia
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 15:00 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

The l2-cache-entry-size setting can only contain values that are
powers of two between 512 and the cluster size.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 tests/qemu-iotests/103     | 17 +++++++++++++++++
 tests/qemu-iotests/103.out |  3 +++
 2 files changed, 20 insertions(+)

diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
index d0cfab8844..7a2ca22803 100755
--- a/tests/qemu-iotests/103
+++ b/tests/qemu-iotests/103
@@ -66,6 +66,14 @@ $QEMU_IO -c "open -o cache-size=1M,refcount-cache-size=2M $TEST_IMG" 2>&1 \
 $QEMU_IO -c "open -o cache-size=0,l2-cache-size=0,refcount-cache-size=0 $TEST_IMG" \
     2>&1 | _filter_testdir | _filter_imgfmt
 
+# Invalid cache entry sizes
+$QEMU_IO -c "open -o l2-cache-entry-size=256 $TEST_IMG" \
+    2>&1 | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "open -o l2-cache-entry-size=300 $TEST_IMG" \
+    2>&1 | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "open -o l2-cache-entry-size=128k $TEST_IMG" \
+    2>&1 | _filter_testdir | _filter_imgfmt
+
 echo
 echo '=== Testing valid option combinations ==='
 echo
@@ -94,6 +102,15 @@ $QEMU_IO -c "open -o l2-cache-size=1M,refcount-cache-size=0.25M $TEST_IMG" \
          -c 'read -P 42 0 64k' \
     | _filter_qemu_io
 
+# Valid cache entry sizes
+$QEMU_IO -c "open -o l2-cache-entry-size=512 $TEST_IMG" \
+    2>&1 | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "open -o l2-cache-entry-size=16k $TEST_IMG" \
+    2>&1 | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "open -o l2-cache-entry-size=64k $TEST_IMG" \
+    2>&1 | _filter_testdir | _filter_imgfmt
+
+
 echo
 echo '=== Testing minimal L2 cache and COW ==='
 echo
diff --git a/tests/qemu-iotests/103.out b/tests/qemu-iotests/103.out
index b7aaadf89a..bd45d3875a 100644
--- a/tests/qemu-iotests/103.out
+++ b/tests/qemu-iotests/103.out
@@ -9,6 +9,9 @@ can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cach
 can't open device TEST_DIR/t.IMGFMT: l2-cache-size may not exceed cache-size
 can't open device TEST_DIR/t.IMGFMT: refcount-cache-size may not exceed cache-size
 can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set the same time
+can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
+can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
+can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
 
 === Testing valid option combinations ===
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 38/39] iotests: Test downgrading an image using a small L2 slice size
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (36 preceding siblings ...)
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 37/39] iotests: Test valid values of l2-cache-entry-size Alberto Garcia
@ 2018-01-26 15:00 ` Alberto Garcia
  2018-01-31 19:23   ` Eric Blake
  2018-02-01 20:11   ` Max Reitz
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 39/39] iotests: Add l2-cache-entry-size to iotest 137 Alberto Garcia
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 15:00 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

expand_zero_clusters_in_l1() is used when downgrading qcow2 images
from v3 to v2 (compat=0.10). This is one of the functions that needed
more changes to support L2 slices, so this patch extends iotest 061 to
test downgrading a qcow2 image using a smaller slice size.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 tests/qemu-iotests/061     | 16 ++++++++++++
 tests/qemu-iotests/061.out | 61 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
index f5678b10c9..911b6f2894 100755
--- a/tests/qemu-iotests/061
+++ b/tests/qemu-iotests/061
@@ -54,6 +54,22 @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
 _check_test_img
 
 echo
+echo "=== Testing version downgrade with zero expansion and 4K cache entries ==="
+echo
+IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
+$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "write -z 32M 128k" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
+$PYTHON qcow2.py "$TEST_IMG" dump-header
+$QEMU_IMG amend -o "compat=0.10" --image-opts \
+          driver=qcow2,file.filename=$TEST_IMG,l2-cache-entry-size=4096
+$PYTHON qcow2.py "$TEST_IMG" dump-header
+$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "read -P 0 32M 128k" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
+_check_test_img
+
+echo
 echo "=== Testing dirty version downgrade ==="
 echo
 IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
index 942485de99..e857ef9a7d 100644
--- a/tests/qemu-iotests/061.out
+++ b/tests/qemu-iotests/061.out
@@ -52,6 +52,67 @@ read 131072/131072 bytes at offset 0
 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 No errors were found on the image.
 
+=== Testing version downgrade with zero expansion and 4K cache entries ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+wrote 131072/131072 bytes at offset 0
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 131072/131072 bytes at offset 33554432
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+128 KiB (0x20000) bytes     allocated at offset 0 bytes (0x0)
+31.875 MiB (0x1fe0000) bytes not allocated at offset 128 KiB (0x20000)
+128 KiB (0x20000) bytes     allocated at offset 32 MiB (0x2000000)
+31.875 MiB (0x1fe0000) bytes not allocated at offset 32.125 MiB (0x2020000)
+magic                     0x514649fb
+version                   3
+backing_file_offset       0x0
+backing_file_size         0x0
+cluster_bits              16
+size                      67108864
+crypt_method              0
+l1_size                   1
+l1_table_offset           0x30000
+refcount_table_offset     0x10000
+refcount_table_clusters   1
+nb_snapshots              0
+snapshot_offset           0x0
+incompatible_features     0x0
+compatible_features       0x1
+autoclear_features        0x0
+refcount_order            4
+header_length             104
+
+Header extension:
+magic                     0x6803f857
+length                    144
+data                      <binary>
+
+magic                     0x514649fb
+version                   2
+backing_file_offset       0x0
+backing_file_size         0x0
+cluster_bits              16
+size                      67108864
+crypt_method              0
+l1_size                   1
+l1_table_offset           0x30000
+refcount_table_offset     0x10000
+refcount_table_clusters   1
+nb_snapshots              0
+snapshot_offset           0x0
+incompatible_features     0x0
+compatible_features       0x0
+autoclear_features        0x0
+refcount_order            4
+header_length             72
+
+read 131072/131072 bytes at offset 0
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 33554432
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+64 MiB (0x4000000) bytes not allocated at offset 0 bytes (0x0)
+No errors were found on the image.
+
 === Testing dirty version downgrade ===
 
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* [Qemu-devel] [PATCH v3 39/39] iotests: Add l2-cache-entry-size to iotest 137
  2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
                   ` (37 preceding siblings ...)
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 38/39] iotests: Test downgrading an image using a small L2 slice size Alberto Garcia
@ 2018-01-26 15:00 ` Alberto Garcia
  2018-01-31 19:23   ` Eric Blake
  2018-02-01 20:12   ` Max Reitz
  38 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-26 15:00 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Max Reitz, Kevin Wolf, Eric Blake,
	Anton Nefedov, Denis V . Lunev

This test tries reopening a qcow2 image with valid and invalid
options. This patch adds l2-cache-entry-size to the set.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 tests/qemu-iotests/137     | 5 +++++
 tests/qemu-iotests/137.out | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
index 5a01250005..87965625d8 100755
--- a/tests/qemu-iotests/137
+++ b/tests/qemu-iotests/137
@@ -83,6 +83,9 @@ $QEMU_IO \
     -c "reopen -o overlap-check.inactive-l2=off" \
     -c "reopen -o cache-size=1M" \
     -c "reopen -o l2-cache-size=512k" \
+    -c "reopen -o l2-cache-entry-size=512" \
+    -c "reopen -o l2-cache-entry-size=4k" \
+    -c "reopen -o l2-cache-entry-size=64k" \
     -c "reopen -o refcount-cache-size=128k" \
     -c "reopen -o cache-clean-interval=5" \
     -c "reopen -o cache-clean-interval=0" \
@@ -107,6 +110,8 @@ $QEMU_IO \
     -c "reopen -o cache-size=1M,l2-cache-size=2M" \
     -c "reopen -o cache-size=1M,refcount-cache-size=2M" \
     -c "reopen -o l2-cache-size=256T" \
+    -c "reopen -o l2-cache-entry-size=33k" \
+    -c "reopen -o l2-cache-entry-size=128k" \
     -c "reopen -o refcount-cache-size=256T" \
     -c "reopen -o overlap-check=constant,overlap-check.template=all" \
     -c "reopen -o overlap-check=blubb" \
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
index 05efd74d17..e28e1eadba 100644
--- a/tests/qemu-iotests/137.out
+++ b/tests/qemu-iotests/137.out
@@ -20,6 +20,8 @@ cache-size, l2-cache-size and refcount-cache-size may not be set the same time
 l2-cache-size may not exceed cache-size
 refcount-cache-size may not exceed cache-size
 L2 cache size too big
+L2 cache entry size must be a power of two between 512 and the cluster size (65536)
+L2 cache entry size must be a power of two between 512 and the cluster size (65536)
 L2 cache size too big
 Conflicting values for qcow2 options 'overlap-check' ('constant') and 'overlap-check.template' ('all')
 Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 16/39] qcow2: Prepare l2_allocate() for adding L2 slice support
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 16/39] qcow2: Prepare l2_allocate() for adding L2 slice support Alberto Garcia
@ 2018-01-26 16:24   ` Eric Blake
  2018-01-31 19:57   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-26 16:24 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1182 bytes --]

On 01/26/2018 08:59 AM, Alberto Garcia wrote:
> Adding support for L2 slices to l2_allocate() needs (among other
> things) an extra loop that iterates over all slices of a new L2 table.
> 
> Putting all changes in one patch would make it hard to read because
> all semantic changes would be mixed with pure indentation changes.
> 
> To make things easier this patch simply creates a new block and
> changes the indentation of all lines of code inside it. Thus, all
> modifications in this patch are cosmetic. There are no semantic
> changes and no variables are renamed yet. The next patch will take
> care of that.

Thanks for the split - it does make reviewing easier.

> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 55 ++++++++++++++++++++++++++++-----------------------
>  1 file changed, 30 insertions(+), 25 deletions(-)

More lines than before, because of the added {}.  But diff ignoring
whitespace makes this one easy to validate.

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices Alberto Garcia
@ 2018-01-26 16:30   ` Eric Blake
  2018-01-31 20:07   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-26 16:30 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1351 bytes --]

On 01/26/2018 08:59 AM, Alberto Garcia wrote:
> This patch updates l2_allocate() to support the qcow2 cache returning
> L2 slices instead of full L2 tables.
> 
> The old code simply gets an L2 table from the cache and initializes it
> with zeroes or with the contents of an existing table. With a cache
> that returns slices instead of tables the idea remains the same, but
> the code must now iterate over all the slices that are contained in an
> L2 table.
> 
> Since now we're operating with slices the function can no longer
> return the newly-allocated table, so it's up to the caller to retrieve
> the appropriate L2 slice after calling l2_allocate() (note that with
> this patch the caller is still loading full L2 tables, but we'll deal
> with that in a separate patch).
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 56 +++++++++++++++++++++++++++++++--------------------
>  1 file changed, 34 insertions(+), 22 deletions(-)
> 

>  
> -            /* if there was an old l2 table, read it from the disk */
> +            /* if there was an old l2 table, read an slice from the disk */

s/an /a /

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table() Alberto Garcia
@ 2018-01-26 16:37   ` Eric Blake
  2018-01-31 20:11   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-26 16:37 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 641 bytes --]

On 01/26/2018 08:59 AM, Alberto Garcia wrote:
> After the previous patch we're now always using l2_load() in
> get_cluster_table() regardless of whether a new L2 table has to be
> allocated or not.
> 
> This patch refactors that part of the code to use one single l2_load()
> call.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 21 +++++++--------------
>  1 file changed, 7 insertions(+), 14 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 19/39] qcow2: Update get_cluster_table() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 19/39] qcow2: Update get_cluster_table() to support L2 slices Alberto Garcia
@ 2018-01-26 16:39   ` Eric Blake
  2018-01-31 20:14   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-26 16:39 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 695 bytes --]

On 01/26/2018 08:59 AM, Alberto Garcia wrote:
> This patch updates get_cluster_table() to return L2 slices instead of
> full L2 tables.
> 
> The code itself needs almost no changes, it only needs to call
> offset_to_l2_slice_index() instead of offset_to_l2_index(). This patch
> also renames all the relevant variables and the documentation.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 26/39] qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 26/39] qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support Alberto Garcia
@ 2018-01-26 19:38   ` Eric Blake
  2018-02-01 19:21   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-26 19:38 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1032 bytes --]

On 01/26/2018 08:59 AM, Alberto Garcia wrote:
> Adding support for L2 slices to qcow2_update_snapshot_refcount() needs
> (among other things) an extra loop that iterates over all slices of
> each L2 table.
> 
> Putting all changes in one patch would make it hard to read because
> all semantic changes would be mixed with pure indentation changes.
> 
> To make things easier this patch simply creates a new block and
> changes the indentation of all lines of code inside it. Thus, all
> modifications in this patch are cosmetic. There are no semantic
> changes and no variables are renamed yet. The next patch will take
> care of that.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-refcount.c | 140 ++++++++++++++++++++++++++-----------------------
>  1 file changed, 73 insertions(+), 67 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 27/39] qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 27/39] qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices Alberto Garcia
@ 2018-01-26 19:39   ` Eric Blake
  2018-02-01 19:26   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-26 19:39 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 889 bytes --]

On 01/26/2018 08:59 AM, Alberto Garcia wrote:
> qcow2_update_snapshot_refcount() increases the refcount of all
> clusters of a given snapshot. In order to do that it needs to load all
> its L2 tables and iterate over their entries. Since we'll be loading
> L2 slices instead of full tables we need to add an extra loop that
> iterates over all slices of each L2 table.
> 
> This function doesn't need any additional changes so apart from that
> this patch simply updates the variable name from l2_table to l2_slice.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-refcount.c | 31 +++++++++++++++++--------------
>  1 file changed, 17 insertions(+), 14 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 28/39] qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 28/39] qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1() Alberto Garcia
@ 2018-01-26 19:41   ` Eric Blake
  2018-02-01 19:29   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-26 19:41 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 771 bytes --]

On 01/26/2018 08:59 AM, Alberto Garcia wrote:
> At the moment it doesn't really make a difference whether we call
> qcow2_get_refcount() before of after reading the L2 table, but if we
> want to support L2 slices we'll need to read the refcount first.
> 
> This patch simply changes the order of those two operations to prepare
> for that. The patch with the actual semantic changes will be easier to
> read because of this.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 29/39] qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 29/39] qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support Alberto Garcia
@ 2018-01-26 19:42   ` Eric Blake
  2018-02-01 19:34   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-26 19:42 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1024 bytes --]

On 01/26/2018 08:59 AM, Alberto Garcia wrote:
> Adding support for L2 slices to expand_zero_clusters_in_l1() needs
> (among other things) an extra loop that iterates over all slices of
> each L2 table.
> 
> Putting all changes in one patch would make it hard to read because
> all semantic changes would be mixed with pure indentation changes.
> 
> To make things easier this patch simply creates a new block and
> changes the indentation of all lines of code inside it. Thus, all
> modifications in this patch are cosmetic. There are no semantic
> changes and no variables are renamed yet. The next patch will take
> care of that.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 187 ++++++++++++++++++++++++++------------------------
>  1 file changed, 96 insertions(+), 91 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 30/39] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 30/39] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices Alberto Garcia
@ 2018-01-26 19:46   ` Eric Blake
  2018-01-29 12:06     ` Alberto Garcia
  2018-02-01 19:44   ` Max Reitz
  1 sibling, 1 reply; 108+ messages in thread
From: Eric Blake @ 2018-01-26 19:46 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 3024 bytes --]

On 01/26/2018 08:59 AM, Alberto Garcia wrote:
> expand_zero_clusters_in_l1() expands zero clusters as a necessary step
> to downgrade qcow2 images to a version that doesn't support metadata
> zero clusters. This function takes an L1 table (which may or may not
> be active) and iterates over all its L2 tables looking for zero
> clusters.
> 
> Since we'll be loading L2 slices instead of full tables we need to add
> an extra loop that iterates over all slices of each L2 table, and we
> should also use the slice size when allocating the buffer used when
> the L1 table is not active.
> 
> This function doesn't need any additional changes so apart from that
> this patch simply updates the variable name from l2_table to l2_slice.
> 
> Finally, and since we have to touch the bdrv_read() / bdrv_write()
> calls anyway, this patch takes the opportunity to replace them with
> the byte-based bdrv_pread() / bdrv_pwrite().

This last paragraph could perhaps be split to a separate patch, but
that's more churn so I'm also fine leaving it here.

> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 52 ++++++++++++++++++++++++++++-----------------------
>  1 file changed, 29 insertions(+), 23 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

> @@ -1905,22 +1908,24 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
>              goto fail;
>          }
>  
> -        {
> +        for (slice = 0; slice < n_slices; slice++) {
> +            uint64_t slice_offset = l2_offset + slice * slice_size2;
> +            bool l2_dirty = false;
>              if (is_active_l1) {
>                  /* get active L2 tables from cache */
> -                ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
> -                                      (void **)&l2_table);
> +                ret = qcow2_cache_get(bs, s->l2_table_cache, slice_offset,
> +                                      (void **)&l2_slice);

The (void **) cast is probably still necessary (anything can go to
void*, but C gets pickier when going to void**), but...

>              } else {
>                  /* load inactive L2 tables from disk */
> -                ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
> -                                (void *)l2_table, s->cluster_sectors);
> +                ret = bdrv_pread(bs->file, slice_offset,
> +                                 (void *)l2_slice, slice_size2);

...do we still need this cast to void*?


>  
> -                    ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
> -                                     (void *)l2_table, s->cluster_sectors);
> +                    ret = bdrv_pwrite(bs->file, slice_offset,
> +                                      (void *)l2_slice, slice_size2);

and again here

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 30/39] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices
  2018-01-26 19:46   ` Eric Blake
@ 2018-01-29 12:06     ` Alberto Garcia
  0 siblings, 0 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-01-29 12:06 UTC (permalink / raw)
  To: Eric Blake, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

On Fri 26 Jan 2018 08:46:19 PM CET, Eric Blake wrote:
>> -                ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
>> -                                      (void **)&l2_table);
>> +                ret = qcow2_cache_get(bs, s->l2_table_cache, slice_offset,
>> +                                      (void **)&l2_slice);
>
> The (void **) cast is probably still necessary (anything can go to
> void*, but C gets pickier when going to void**), but...
>
>>              } else {
>>                  /* load inactive L2 tables from disk */
>> -                ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
>> -                                (void *)l2_table, s->cluster_sectors);
>> +                ret = bdrv_pread(bs->file, slice_offset,
>> +                                 (void *)l2_slice, slice_size2);
>
> ...do we still need this cast to void*?
>
>
>>  
>> -                    ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
>> -                                     (void *)l2_table, s->cluster_sectors);
>> +                    ret = bdrv_pwrite(bs->file, slice_offset,
>> +                                      (void *)l2_slice, slice_size2);
>
> and again here

Good idea, I'll remove the void * casts.

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/39] qcow2: Fix documentation of get_cluster_table()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 01/39] qcow2: Fix documentation of get_cluster_table() Alberto Garcia
@ 2018-01-31 19:16   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:16 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 411 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function has not been returning the offset of the L2 table since
> commit 3948d1d4876065160583e79533bf604481063833
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 36/39] qcow2: Allow configuring the L2 slice size
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 36/39] qcow2: Allow configuring the L2 slice size Alberto Garcia
@ 2018-01-31 19:20   ` Eric Blake
  2018-02-01 20:04   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-31 19:20 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1890 bytes --]

On 01/26/2018 09:00 AM, Alberto Garcia wrote:
> Now that the code is ready to handle L2 slices we can finally add an
> option to allow configuring their size.
> 
> An L2 slice is the portion of an L2 table that is read by the qcow2
> cache. Until now the cache was always reading full L2 tables, and
> since the L2 table size is equal to the cluster size this was not very
> efficient with large clusters. Here's a more detailed explanation of
> why it makes sense to have smaller cache entries in order to load L2
> data:
> 
>    https://lists.gnu.org/archive/html/qemu-block/2017-09/msg00635.html
> 
> This patch introduces a new command-line option to the qcow2 driver
> named l2-cache-entry-size (cf. l2-cache-size). The cache entry size
> has the same restrictions as the cluster size: it must be a power of
> two and it has the same range of allowed values, with the additional
> requirement that it must not be larger than the cluster size.
> 
> The L2 cache entry size (L2 slice size) remains equal to the cluster
> size for now by default, so this feature must be explicitly enabled.
> Although my tests show that 4KB slices consistently improve
> performance and give the best results, let's wait and make more tests
> with different cluster sizes before deciding on an optimal default.
> 
> Now that the cache entry size is not necessarily equal to the cluster
> size we need to reflect that in the MIN_L2_CACHE_SIZE documentation.
> That minimum value is a requirement of the COW algorithm: we need to
> read two L2 slices (and not two L2 tables) in order to do COW, see
> l2_allocate() for the actual code.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 37/39] iotests: Test valid values of l2-cache-entry-size
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 37/39] iotests: Test valid values of l2-cache-entry-size Alberto Garcia
@ 2018-01-31 19:21   ` Eric Blake
  2018-02-01 20:05   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-31 19:21 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 544 bytes --]

On 01/26/2018 09:00 AM, Alberto Garcia wrote:
> The l2-cache-entry-size setting can only contain values that are
> powers of two between 512 and the cluster size.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  tests/qemu-iotests/103     | 17 +++++++++++++++++
>  tests/qemu-iotests/103.out |  3 +++
>  2 files changed, 20 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 38/39] iotests: Test downgrading an image using a small L2 slice size
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 38/39] iotests: Test downgrading an image using a small L2 slice size Alberto Garcia
@ 2018-01-31 19:23   ` Eric Blake
  2018-02-01 20:11   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-31 19:23 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 742 bytes --]

On 01/26/2018 09:00 AM, Alberto Garcia wrote:
> expand_zero_clusters_in_l1() is used when downgrading qcow2 images
> from v3 to v2 (compat=0.10). This is one of the functions that needed
> more changes to support L2 slices, so this patch extends iotest 061 to
> test downgrading a qcow2 image using a smaller slice size.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  tests/qemu-iotests/061     | 16 ++++++++++++
>  tests/qemu-iotests/061.out | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 77 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 39/39] iotests: Add l2-cache-entry-size to iotest 137
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 39/39] iotests: Add l2-cache-entry-size to iotest 137 Alberto Garcia
@ 2018-01-31 19:23   ` Eric Blake
  2018-02-01 20:12   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Eric Blake @ 2018-01-31 19:23 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Max Reitz, Kevin Wolf, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 535 bytes --]

On 01/26/2018 09:00 AM, Alberto Garcia wrote:
> This test tries reopening a qcow2 image with valid and invalid
> options. This patch adds l2-cache-entry-size to the set.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  tests/qemu-iotests/137     | 5 +++++
>  tests/qemu-iotests/137.out | 2 ++
>  2 files changed, 7 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 02/39] qcow2: Add table size field to Qcow2Cache
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 02/39] qcow2: Add table size field to Qcow2Cache Alberto Garcia
@ 2018-01-31 19:25   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:25 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 905 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> The table size in the qcow2 cache is currently equal to the cluster
> size. This doesn't allow us to use the cache memory efficiently,
> particularly with large cluster sizes, so we need to be able to have
> smaller cache tables that are independent from the cluster size. This
> patch adds a new field to Qcow2Cache that we can use instead of the
> cluster size.
> 
> The current table size is still being initialized to the cluster size,
> so there are no semantic changes yet, but this patch will allow us to
> prepare the rest of the code and simplify a few function calls.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c | 29 ++++++++++++++---------------
>  1 file changed, 14 insertions(+), 15 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_addr()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 03/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_addr() Alberto Garcia
@ 2018-01-31 19:26   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:26 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 498 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function was only using the BlockDriverState parameter to get the
> cache table size (since it was equal to the cluster size). This is no
> longer necessary so this parameter can be removed.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c | 13 ++++++-------
>  1 file changed, 6 insertions(+), 7 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 04/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_idx()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 04/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_idx() Alberto Garcia
@ 2018-01-31 19:27   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:27 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 493 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function was only using the BlockDriverState parameter to get the
> cache table size (since it was equal to the cluster size). This is no
> longer necessary so this parameter can be removed.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 05/39] qcow2: Remove BDS parameter from qcow2_cache_table_release()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 05/39] qcow2: Remove BDS parameter from qcow2_cache_table_release() Alberto Garcia
@ 2018-01-31 19:28   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:28 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 493 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function was only using the BlockDriverState parameter to get the
> cache table size (since it was equal to the cluster size). This is no
> longer necessary so this parameter can be removed.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 06/39] qcow2: Remove BDS parameter from qcow2_cache_entry_mark_dirty()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 06/39] qcow2: Remove BDS parameter from qcow2_cache_entry_mark_dirty() Alberto Garcia
@ 2018-01-31 19:30   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:30 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 595 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function was only using the BlockDriverState parameter to pass it
> to qcow2_cache_get_table_idx(). This is no longer necessary so this
> parameter can be removed.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c    |  3 +--
>  block/qcow2-cluster.c  | 12 ++++++------
>  block/qcow2-refcount.c | 14 ++++++--------
>  block/qcow2.h          |  3 +--
>  4 files changed, 14 insertions(+), 18 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/39] qcow2: Remove BDS parameter from qcow2_cache_put()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 07/39] qcow2: Remove BDS parameter from qcow2_cache_put() Alberto Garcia
@ 2018-01-31 19:33   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:33 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 625 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function was only using the BlockDriverState parameter to pass it
> to qcow2_cache_get_table_idx(). This is no longer necessary so this
> parameter can be removed.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c    |  2 +-
>  block/qcow2-cluster.c  | 28 ++++++++++++++--------------
>  block/qcow2-refcount.c | 30 +++++++++++++++---------------
>  block/qcow2.h          |  2 +-
>  4 files changed, 31 insertions(+), 31 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 08/39] qcow2: Remove BDS parameter from qcow2_cache_destroy()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 08/39] qcow2: Remove BDS parameter from qcow2_cache_destroy() Alberto Garcia
@ 2018-01-31 19:35   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:35 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 463 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function was never using the BlockDriverState parameter so it can
> be safely removed.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c |  2 +-
>  block/qcow2.c       | 16 ++++++++--------
>  block/qcow2.h       |  2 +-
>  3 files changed, 10 insertions(+), 10 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/39] qcow2: Remove BDS parameter from qcow2_cache_clean_unused()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 09/39] qcow2: Remove BDS parameter from qcow2_cache_clean_unused() Alberto Garcia
@ 2018-01-31 19:37   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:37 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 524 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function was only using the BlockDriverState parameter to pass it
> to qcow2_cache_table_release(). This is no longer necessary so this
> parameter can be removed.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c | 2 +-
>  block/qcow2.c       | 4 ++--
>  block/qcow2.h       | 2 +-
>  3 files changed, 4 insertions(+), 4 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/39] qcow2: Remove BDS parameter from qcow2_cache_discard()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 10/39] qcow2: Remove BDS parameter from qcow2_cache_discard() Alberto Garcia
@ 2018-01-31 19:38   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:38 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 567 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function was only using the BlockDriverState parameter to pass it
> to qcow2_cache_get_table_idx() and qcow2_cache_table_release(). This
> is no longer necessary so this parameter can be removed.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c    | 2 +-
>  block/qcow2-refcount.c | 6 +++---
>  block/qcow2.h          | 2 +-
>  3 files changed, 5 insertions(+), 5 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 11/39] qcow2: Remove BDS parameter from qcow2_cache_is_table_offset()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 11/39] qcow2: Remove BDS parameter from qcow2_cache_is_table_offset() Alberto Garcia
@ 2018-01-31 19:39   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:39 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 678 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function was only using the BlockDriverState parameter to pass it
> to qcow2_cache_get_table_addr(). This is no longer necessary so this
> parameter can be removed.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cache.c    | 3 +--
>  block/qcow2-refcount.c | 6 +++---
>  block/qcow2.h          | 3 +--
>  3 files changed, 5 insertions(+), 7 deletions(-)

I was hoping you'd smuggle something funny into one of the commit
messages of these patches to test whether we'd actually read them. :(

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 12/39] qcow2: Add offset_to_l1_index()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 12/39] qcow2: Add offset_to_l1_index() Alberto Garcia
@ 2018-01-31 19:43   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:43 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 828 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> Similar to offset_to_l2_index(), this function returns the index in
> the L1 table for a given guest offset. This is only used in a couple
> of places and it's not a particularly complex calculation, but it
> makes the code a bit more readable.
> 
> Although in the qcow2_get_cluster_offset() case the old code was
> taking advantage of the l1_bits variable, we're going to get rid of
> the other uses of l1_bits in a later patch anyway, so it doesn't make
> sense to keep it just for this.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 4 ++--
>  block/qcow2.h         | 5 +++++
>  2 files changed, 7 insertions(+), 2 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 13/39] qcow2: Add l2_slice_size field to BDRVQcow2State
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 13/39] qcow2: Add l2_slice_size field to BDRVQcow2State Alberto Garcia
@ 2018-01-31 19:48   ` Max Reitz
  2018-02-01  9:51     ` Alberto Garcia
  0 siblings, 1 reply; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:48 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 2659 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> The BDRVQcow2State structure contains an l2_size field, which stores
> the number of 64-bit entries in an L2 table.
> 
> For efficiency reasons we want to be able to load slices instead of
> full L2 tables, so we need to know how many entries an L2 slice can
> hold.
> 
> An L2 slice is the portion of an L2 table that is loaded by the qcow2
> cache. At the moment that cache can only load complete tables,
> therefore an L2 slice has the same size as an L2 table (one cluster)
> and l2_size == l2_slice_size.
> 
> Later we'll allow smaller slices, but until then we have to use this
> new l2_slice_size field to make the rest of the code ready for that.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2.c | 3 +++
>  block/qcow2.h | 1 +
>  2 files changed, 4 insertions(+)

Am I missing something or does this patch miss setting l2_slice_size in
qcow2_do_open()?

Max

> diff --git a/block/qcow2.c b/block/qcow2.c
> index e2d4bf7ad5..78f067cae7 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -805,6 +805,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
>  typedef struct Qcow2ReopenState {
>      Qcow2Cache *l2_table_cache;
>      Qcow2Cache *refcount_block_cache;
> +    int l2_slice_size; /* Number of entries in a slice of the L2 table */
>      bool use_lazy_refcounts;
>      int overlap_check;
>      bool discard_passthrough[QCOW2_DISCARD_MAX];
> @@ -886,6 +887,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
>          }
>      }
>  
> +    r->l2_slice_size = s->cluster_size / sizeof(uint64_t);
>      r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
>      r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
>      if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
> @@ -1049,6 +1051,7 @@ static void qcow2_update_options_commit(BlockDriverState *bs,
>      }
>      s->l2_table_cache = r->l2_table_cache;
>      s->refcount_block_cache = r->refcount_block_cache;
> +    s->l2_slice_size = r->l2_slice_size;
>  
>      s->overlap_check = r->overlap_check;
>      s->use_lazy_refcounts = r->use_lazy_refcounts;
> diff --git a/block/qcow2.h b/block/qcow2.h
> index 0559afbc63..e0aee88811 100644
> --- a/block/qcow2.h
> +++ b/block/qcow2.h
> @@ -251,6 +251,7 @@ typedef struct BDRVQcow2State {
>      int cluster_bits;
>      int cluster_size;
>      int cluster_sectors;
> +    int l2_slice_size;
>      int l2_bits;
>      int l2_size;
>      int l1_size;
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 14/39] qcow2: Add offset_to_l2_slice_index()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 14/39] qcow2: Add offset_to_l2_slice_index() Alberto Garcia
@ 2018-01-31 19:49   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:49 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 535 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> Similar to offset_to_l2_index(), this function takes a guest offset
> and returns the index in the L2 slice that contains its L2 entry.
> 
> An L2 slice has currently the same size as an L2 table (one cluster),
> so both functions return the same value for now.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2.h | 5 +++++
>  1 file changed, 5 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 15/39] qcow2: Update l2_load() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 15/39] qcow2: Update l2_load() to support L2 slices Alberto Garcia
@ 2018-01-31 19:56   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:56 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1253 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> Each entry in the qcow2 L2 cache stores a full L2 table (which uses a
> complete cluster in the qcow2 image). A cluster is usually too large
> to be used efficiently as the size for a cache entry, so we want to
> decouple both values by allowing smaller cache entries. Therefore the
> qcow2 L2 cache will no longer return full L2 tables but slices
> instead.
> 
> This patch updates l2_load() so it can handle L2 slices correctly.
> Apart from the offset of the L2 table (which we already had) we also
> need the guest offset in order to calculate which one of the slices
> we need.
> 
> An L2 slice has currently the same size as an L2 table (one cluster),
> so for now this function will load exactly the same data as before.
> 
> This patch also removes a stale comment about the return value being
> a pointer to the L2 table. This function returns an error code since
> 55c17e9821c474d5fcdebdc82ed2fc096777d611.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 28 +++++++++++++++++-----------
>  1 file changed, 17 insertions(+), 11 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 16/39] qcow2: Prepare l2_allocate() for adding L2 slice support
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 16/39] qcow2: Prepare l2_allocate() for adding L2 slice support Alberto Garcia
  2018-01-26 16:24   ` Eric Blake
@ 2018-01-31 19:57   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 19:57 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 873 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> Adding support for L2 slices to l2_allocate() needs (among other
> things) an extra loop that iterates over all slices of a new L2 table.
> 
> Putting all changes in one patch would make it hard to read because
> all semantic changes would be mixed with pure indentation changes.
> 
> To make things easier this patch simply creates a new block and
> changes the indentation of all lines of code inside it. Thus, all
> modifications in this patch are cosmetic. There are no semantic
> changes and no variables are renamed yet. The next patch will take
> care of that.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 55 ++++++++++++++++++++++++++++-----------------------
>  1 file changed, 30 insertions(+), 25 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices Alberto Garcia
  2018-01-26 16:30   ` Eric Blake
@ 2018-01-31 20:07   ` Max Reitz
  2018-02-01 13:13     ` Alberto Garcia
  1 sibling, 1 reply; 108+ messages in thread
From: Max Reitz @ 2018-01-31 20:07 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 2474 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This patch updates l2_allocate() to support the qcow2 cache returning
> L2 slices instead of full L2 tables.
> 
> The old code simply gets an L2 table from the cache and initializes it
> with zeroes or with the contents of an existing table. With a cache
> that returns slices instead of tables the idea remains the same, but
> the code must now iterate over all the slices that are contained in an
> L2 table.
> 
> Since now we're operating with slices the function can no longer
> return the newly-allocated table, so it's up to the caller to retrieve
> the appropriate L2 slice after calling l2_allocate() (note that with
> this patch the caller is still loading full L2 tables, but we'll deal
> with that in a separate patch).
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 56 +++++++++++++++++++++++++++++++--------------------
>  1 file changed, 34 insertions(+), 22 deletions(-)
> 
> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
> index 57349928a9..2a53c1dc5f 100644
> --- a/block/qcow2-cluster.c
> +++ b/block/qcow2-cluster.c
> @@ -264,11 +264,12 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
>   *
>   */
>  
> -static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
> +static int l2_allocate(BlockDriverState *bs, int l1_index)
>  {
>      BDRVQcow2State *s = bs->opaque;
>      uint64_t old_l2_offset;
> -    uint64_t *l2_table = NULL;
> +    uint64_t *l2_slice = NULL;
> +    unsigned slice, slice_size2, n_slices;

I'd personally prefer size_t, but oh well.

(And also maybe slice_size_bytes or slice_bytes instead of the
not-so-intuitive slice_size2.  I know we're using *_size2 in other
places, but that's bad enough as it is.)

Overall (with that fixed or not, and with the spelling fixed as pointed
out by Eric);

Reviewed-by: Max Reitz <mreitz@redhat.com>

However, I'm wondering whether this is the best approach.  The old L2
table is probably not going to be used after this function, so we're
basically polluting the cache here.  That was bad enough so far, but now
that actually means wasting multiple cache entries on it.

Sure, the code is simpler this way.  But maybe it would still be better
to manually copy the data over from the old offset...  (As long as it's
not much more complicated.)

Max

>      int64_t l2_offset;
>      int ret;
>  


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table() Alberto Garcia
  2018-01-26 16:37   ` Eric Blake
@ 2018-01-31 20:11   ` Max Reitz
  2018-02-01 10:40     ` Alberto Garcia
  1 sibling, 1 reply; 108+ messages in thread
From: Max Reitz @ 2018-01-31 20:11 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 2205 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> After the previous patch we're now always using l2_load() in
> get_cluster_table() regardless of whether a new L2 table has to be
> allocated or not.
> 
> This patch refactors that part of the code to use one single l2_load()
> call.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 21 +++++++--------------
>  1 file changed, 7 insertions(+), 14 deletions(-)
> 
> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
> index 2a53c1dc5f..0c0cab85e8 100644
> --- a/block/qcow2-cluster.c
> +++ b/block/qcow2-cluster.c
> @@ -695,15 +695,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
>          return -EIO;
>      }
>  
> -    /* seek the l2 table of the given l2 offset */
> -
> -    if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
> -        /* load the l2 table in memory */
> -        ret = l2_load(bs, offset, l2_offset, &l2_table);
> -        if (ret < 0) {
> -            return ret;
> -        }
> -    } else {
> +    if (!(s->l1_table[l1_index] & QCOW_OFLAG_COPIED)) {
>          /* First allocate a new L2 table (and do COW if needed) */
>          ret = l2_allocate(bs, l1_index);
>          if (ret < 0) {
> @@ -719,11 +711,12 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
>          /* Get the offset of the newly-allocated l2 table */
>          l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
>          assert(offset_into_cluster(s, l2_offset) == 0);
> -        /* Load the l2 table in memory */
> -        ret = l2_load(bs, offset, l2_offset, &l2_table);
> -        if (ret < 0) {
> -            return ret;
> -        }
> +    }
> +
> +    /* load the l2 table in memory */
> +    ret = l2_load(bs, offset, l2_offset, &l2_table);
> +    if (ret < 0) {
> +        return ret;
>      }

I'd pull the l2_offset assignment (and alignment check) down below the
QCOW_OFLAG_COPIED check, saving us another two lines (!!1!) which we
could then spend on an

assert(s->l1_table[l1_index] & QCOW_OFLAG_COPIED);

Max

>  
>      /* find the cluster offset for the given disk offset */
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 19/39] qcow2: Update get_cluster_table() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 19/39] qcow2: Update get_cluster_table() to support L2 slices Alberto Garcia
  2018-01-26 16:39   ` Eric Blake
@ 2018-01-31 20:14   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 20:14 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 557 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This patch updates get_cluster_table() to return L2 slices instead of
> full L2 tables.
> 
> The code itself needs almost no changes, it only needs to call
> offset_to_l2_slice_index() instead of offset_to_l2_index(). This patch
> also renames all the relevant variables and the documentation.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 20/39] qcow2: Update qcow2_get_cluster_offset() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 20/39] qcow2: Update qcow2_get_cluster_offset() " Alberto Garcia
@ 2018-01-31 20:24   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-01-31 20:24 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1194 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> qcow2_get_cluster_offset() checks how many contiguous bytes are
> available at a given offset. The returned number of bytes is limited
> by the amount that can be addressed without having to load more than
> one L2 table.
> 
> Since we'll be loading L2 slices instead of full tables this patch
> changes the limit accordingly using the size of the L2 slice for the
> calculations instead of the full table size.
> 
> One consequence of this is that with small L2 slices operations such
> as 'qemu-img map' will need to iterate in more steps because each
> qcow2_get_cluster_offset() call will potentially return a smaller
> number. However the code is already prepared for that so this doesn't
> break semantics.
> 
> The l2_table variable is also renamed to l2_slice to reflect this, and
> offset_to_l2_index() is replaced with offset_to_l2_slice_index().
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 30 +++++++++++++++---------------
>  1 file changed, 15 insertions(+), 15 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 13/39] qcow2: Add l2_slice_size field to BDRVQcow2State
  2018-01-31 19:48   ` Max Reitz
@ 2018-02-01  9:51     ` Alberto Garcia
  2018-02-01 18:09       ` Max Reitz
  0 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-02-01  9:51 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

On Wed 31 Jan 2018 08:48:08 PM CET, Max Reitz wrote:
> On 2018-01-26 15:59, Alberto Garcia wrote:
>> The BDRVQcow2State structure contains an l2_size field, which stores
>> the number of 64-bit entries in an L2 table.
>> 
>> For efficiency reasons we want to be able to load slices instead of
>> full L2 tables, so we need to know how many entries an L2 slice can
>> hold.
>> 
>> An L2 slice is the portion of an L2 table that is loaded by the qcow2
>> cache. At the moment that cache can only load complete tables,
>> therefore an L2 slice has the same size as an L2 table (one cluster)
>> and l2_size == l2_slice_size.
>> 
>> Later we'll allow smaller slices, but until then we have to use this
>> new l2_slice_size field to make the rest of the code ready for that.
>> 
>> Signed-off-by: Alberto Garcia <berto@igalia.com>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> ---
>>  block/qcow2.c | 3 +++
>>  block/qcow2.h | 1 +
>>  2 files changed, 4 insertions(+)
>
> Am I missing something or does this patch miss setting l2_slice_size
> in qcow2_do_open()?

qcow2_do_open() calls qcow2_update_options() which is what reads
l2-cache-entry-size and sets s->l2_slice_size.

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table()
  2018-01-31 20:11   ` Max Reitz
@ 2018-02-01 10:40     ` Alberto Garcia
  2018-02-01 18:10       ` Max Reitz
  0 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-02-01 10:40 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

On Wed 31 Jan 2018 09:11:48 PM CET, Max Reitz wrote:
> On 2018-01-26 15:59, Alberto Garcia wrote:
>> After the previous patch we're now always using l2_load() in
>> get_cluster_table() regardless of whether a new L2 table has to be
>> allocated or not.
>> 
>> This patch refactors that part of the code to use one single l2_load()
>> call.
>> 
>> Signed-off-by: Alberto Garcia <berto@igalia.com>
>> ---
>>  block/qcow2-cluster.c | 21 +++++++--------------
>>  1 file changed, 7 insertions(+), 14 deletions(-)
>> 
>> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
>> index 2a53c1dc5f..0c0cab85e8 100644
>> --- a/block/qcow2-cluster.c
>> +++ b/block/qcow2-cluster.c
>> @@ -695,15 +695,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
>>          return -EIO;
>>      }
>>  
>> -    /* seek the l2 table of the given l2 offset */
>> -
>> -    if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
>> -        /* load the l2 table in memory */
>> -        ret = l2_load(bs, offset, l2_offset, &l2_table);
>> -        if (ret < 0) {
>> -            return ret;
>> -        }
>> -    } else {
>> +    if (!(s->l1_table[l1_index] & QCOW_OFLAG_COPIED)) {
>>          /* First allocate a new L2 table (and do COW if needed) */
>>          ret = l2_allocate(bs, l1_index);
>>          if (ret < 0) {
>> @@ -719,11 +711,12 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
>>          /* Get the offset of the newly-allocated l2 table */
>>          l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
>>          assert(offset_into_cluster(s, l2_offset) == 0);
>> -        /* Load the l2 table in memory */
>> -        ret = l2_load(bs, offset, l2_offset, &l2_table);
>> -        if (ret < 0) {
>> -            return ret;
>> -        }
>> +    }
>> +
>> +    /* load the l2 table in memory */
>> +    ret = l2_load(bs, offset, l2_offset, &l2_table);
>> +    if (ret < 0) {
>> +        return ret;
>>      }
>
> I'd pull the l2_offset assignment (and alignment check) down below the
> QCOW_OFLAG_COPIED check, saving us another two lines (!!1!) which we
> could then spend on an
>
> assert(s->l1_table[l1_index] & QCOW_OFLAG_COPIED);

I'm not sure if I'm following you. We need to set l2_offset before and
after allocating a new L2 table.

Before, because we need the offset of the old table (if there was one)
in order to decrease its refcount.

And after, because we need the offset of the new table in order to load
it.

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-01-31 20:07   ` Max Reitz
@ 2018-02-01 13:13     ` Alberto Garcia
  2018-02-01 15:23       ` Anton Nefedov
  2018-02-01 18:15       ` Max Reitz
  0 siblings, 2 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-02-01 13:13 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

On Wed 31 Jan 2018 09:07:48 PM CET, Max Reitz wrote:
> On 2018-01-26 15:59, Alberto Garcia wrote:
>> This patch updates l2_allocate() to support the qcow2 cache returning
>> L2 slices instead of full L2 tables.
>> 
>> The old code simply gets an L2 table from the cache and initializes it
>> with zeroes or with the contents of an existing table. With a cache
>> that returns slices instead of tables the idea remains the same, but
>> the code must now iterate over all the slices that are contained in an
>> L2 table.
>> 
>> Since now we're operating with slices the function can no longer
>> return the newly-allocated table, so it's up to the caller to retrieve
>> the appropriate L2 slice after calling l2_allocate() (note that with
>> this patch the caller is still loading full L2 tables, but we'll deal
>> with that in a separate patch).
>> 
>> Signed-off-by: Alberto Garcia <berto@igalia.com>
>> ---
>>  block/qcow2-cluster.c | 56 +++++++++++++++++++++++++++++++--------------------
>>  1 file changed, 34 insertions(+), 22 deletions(-)
>> 
>> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
>> index 57349928a9..2a53c1dc5f 100644
>> --- a/block/qcow2-cluster.c
>> +++ b/block/qcow2-cluster.c
>> @@ -264,11 +264,12 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
>>   *
>>   */
>>  
>> -static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
>> +static int l2_allocate(BlockDriverState *bs, int l1_index)
>>  {
>>      BDRVQcow2State *s = bs->opaque;
>>      uint64_t old_l2_offset;
>> -    uint64_t *l2_table = NULL;
>> +    uint64_t *l2_slice = NULL;
>> +    unsigned slice, slice_size2, n_slices;
>
> I'd personally prefer size_t, but oh well.

I don't see any reason not to use int / unsigned. The size of a slice is
always <= cluster_size (an int), and both slice and n_slices are smaller
than that.

> However, I'm wondering whether this is the best approach.  The old L2
> table is probably not going to be used after this function, so we're
> basically polluting the cache here.  That was bad enough so far, but
> now that actually means wasting multiple cache entries on it.
>
> Sure, the code is simpler this way.  But maybe it would still be
> better to manually copy the data over from the old offset...  (As long
> as it's not much more complicated.)

You mean bypassing the cache altogether?

    qcow2_cache_flush(bs, s->l2_table_cache);
    new_table = g_malloc(s->cluster_size);
    if (old_l2_offset & L1E_OFFSET_MASK) {
        bdrv_pread(bs->file, old_l2_offset, new_table, s->cluster_size);
    } else {
        memset(new_table, 0, s->cluster_size);
    }
    bdrv_pwrite(bs->file, new_l2_offset, new_table, s->cluster_size);
    g_free(new_table);

??

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-02-01 13:13     ` Alberto Garcia
@ 2018-02-01 15:23       ` Anton Nefedov
  2018-02-01 15:43         ` Alberto Garcia
  2018-02-01 18:15       ` Max Reitz
  1 sibling, 1 reply; 108+ messages in thread
From: Anton Nefedov @ 2018-02-01 15:23 UTC (permalink / raw)
  To: Alberto Garcia, Max Reitz, qemu-devel
  Cc: Kevin Wolf, Denis V . Lunev, qemu-block



On 1/2/2018 4:13 PM, Alberto Garcia wrote:
> On Wed 31 Jan 2018 09:07:48 PM CET, Max Reitz wrote:
>> On 2018-01-26 15:59, Alberto Garcia wrote:
>>> This patch updates l2_allocate() to support the qcow2 cache returning
>>> L2 slices instead of full L2 tables.
>>>
>>> The old code simply gets an L2 table from the cache and initializes it
>>> with zeroes or with the contents of an existing table. With a cache
>>> that returns slices instead of tables the idea remains the same, but
>>> the code must now iterate over all the slices that are contained in an
>>> L2 table.
>>>
>>> Since now we're operating with slices the function can no longer
>>> return the newly-allocated table, so it's up to the caller to retrieve
>>> the appropriate L2 slice after calling l2_allocate() (note that with
>>> this patch the caller is still loading full L2 tables, but we'll deal
>>> with that in a separate patch).
>>>
>>> Signed-off-by: Alberto Garcia <berto@igalia.com>
>>> ---
>>>   block/qcow2-cluster.c | 56 +++++++++++++++++++++++++++++++--------------------
>>>   1 file changed, 34 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
>>> index 57349928a9..2a53c1dc5f 100644
>>> --- a/block/qcow2-cluster.c
>>> +++ b/block/qcow2-cluster.c
>>> @@ -264,11 +264,12 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
>>>    *
>>>    */
>>>   
>>> -static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
>>> +static int l2_allocate(BlockDriverState *bs, int l1_index)
>>>   {
>>>       BDRVQcow2State *s = bs->opaque;
>>>       uint64_t old_l2_offset;
>>> -    uint64_t *l2_table = NULL;
>>> +    uint64_t *l2_slice = NULL;
>>> +    unsigned slice, slice_size2, n_slices;
>>
>> I'd personally prefer size_t, but oh well.
> 
> I don't see any reason not to use int / unsigned. The size of a slice is
> always <= cluster_size (an int), and both slice and n_slices are smaller
> than that.
> 
>> However, I'm wondering whether this is the best approach.  The old L2
>> table is probably not going to be used after this function, so we're
>> basically polluting the cache here.  That was bad enough so far, but
>> now that actually means wasting multiple cache entries on it.
>>
>> Sure, the code is simpler this way.  But maybe it would still be
>> better to manually copy the data over from the old offset...  (As long
>> as it's not much more complicated.)
> 
> You mean bypassing the cache altogether?
> 
>      qcow2_cache_flush(bs, s->l2_table_cache);
>      new_table = g_malloc(s->cluster_size);
>      if (old_l2_offset & L1E_OFFSET_MASK) {
>          bdrv_pread(bs->file, old_l2_offset, new_table, s->cluster_size);
>      } else {
>          memset(new_table, 0, s->cluster_size);
>      }
>      bdrv_pwrite(bs->file, new_l2_offset, new_table, s->cluster_size);
>      g_free(new_table);
> 
> ??
> 
> Berto
> 

(I know it's a draft so you probably just skipped that but just in case)
It seems ok to bypass the cache read - perhaps even a flush is
not necessary: old_l2_offset must be read-only and flushed at this
point; I believe new_l2_offset might be cached too, so it
needs to be updated.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-02-01 15:23       ` Anton Nefedov
@ 2018-02-01 15:43         ` Alberto Garcia
  2018-02-01 18:22           ` Max Reitz
  0 siblings, 1 reply; 108+ messages in thread
From: Alberto Garcia @ 2018-02-01 15:43 UTC (permalink / raw)
  To: Anton Nefedov, Max Reitz, qemu-devel
  Cc: Kevin Wolf, Denis V . Lunev, qemu-block

On Thu 01 Feb 2018 04:23:09 PM CET, Anton Nefedov wrote:
>>> However, I'm wondering whether this is the best approach.  The old
>>> L2 table is probably not going to be used after this function, so
>>> we're basically polluting the cache here.  That was bad enough so
>>> far, but now that actually means wasting multiple cache entries on
>>> it.
>>>
>>> Sure, the code is simpler this way.  But maybe it would still be
>>> better to manually copy the data over from the old offset...  (As
>>> long as it's not much more complicated.)
>> 
>> You mean bypassing the cache altogether?
>> 
>>      qcow2_cache_flush(bs, s->l2_table_cache);
>>      new_table = g_malloc(s->cluster_size);
>>      if (old_l2_offset & L1E_OFFSET_MASK) {
>>          bdrv_pread(bs->file, old_l2_offset, new_table, s->cluster_size);
>>      } else {
>>          memset(new_table, 0, s->cluster_size);
>>      }
>>      bdrv_pwrite(bs->file, new_l2_offset, new_table, s->cluster_size);
>>      g_free(new_table);
>> 
>> ??
>
> (I know it's a draft so you probably just skipped that but just in
> case) It seems ok to bypass the cache read - perhaps even a flush is
> not necessary: old_l2_offset must be read-only and flushed at this
> point; I believe new_l2_offset might be cached too, so it needs to be
> updated.

One problem I see with this is that while we wouldn't pollute the cache
we'd always be reading the table twice from disk in all cases:

 1) Read old table
 2) Write new table
 3) Read new table (after l2_allocate(), using the cache this time)

We can of course improve it by reading the old table from disk but
directly in the cache -so we'd spare step (3)-, but we'd still have to
read at least once from disk.

With the old code (especially if slice_size == cluster_size) we don't
need to read anything if the L2 table is already cached:

 1) Get empty table from the cache
 2) memcpy() the old data
 3) Get new table from the cache (after l2_allocate()).

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 13/39] qcow2: Add l2_slice_size field to BDRVQcow2State
  2018-02-01  9:51     ` Alberto Garcia
@ 2018-02-01 18:09       ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 18:09 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1361 bytes --]

On 2018-02-01 10:51, Alberto Garcia wrote:
> On Wed 31 Jan 2018 08:48:08 PM CET, Max Reitz wrote:
>> On 2018-01-26 15:59, Alberto Garcia wrote:
>>> The BDRVQcow2State structure contains an l2_size field, which stores
>>> the number of 64-bit entries in an L2 table.
>>>
>>> For efficiency reasons we want to be able to load slices instead of
>>> full L2 tables, so we need to know how many entries an L2 slice can
>>> hold.
>>>
>>> An L2 slice is the portion of an L2 table that is loaded by the qcow2
>>> cache. At the moment that cache can only load complete tables,
>>> therefore an L2 slice has the same size as an L2 table (one cluster)
>>> and l2_size == l2_slice_size.
>>>
>>> Later we'll allow smaller slices, but until then we have to use this
>>> new l2_slice_size field to make the rest of the code ready for that.
>>>
>>> Signed-off-by: Alberto Garcia <berto@igalia.com>
>>> Reviewed-by: Eric Blake <eblake@redhat.com>
>>> ---
>>>  block/qcow2.c | 3 +++
>>>  block/qcow2.h | 1 +
>>>  2 files changed, 4 insertions(+)
>>
>> Am I missing something or does this patch miss setting l2_slice_size
>> in qcow2_do_open()?
> 
> qcow2_do_open() calls qcow2_update_options() which is what reads
> l2-cache-entry-size and sets s->l2_slice_size.

So I was missing something, good.

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table()
  2018-02-01 10:40     ` Alberto Garcia
@ 2018-02-01 18:10       ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 18:10 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 2791 bytes --]

On 2018-02-01 11:40, Alberto Garcia wrote:
> On Wed 31 Jan 2018 09:11:48 PM CET, Max Reitz wrote:
>> On 2018-01-26 15:59, Alberto Garcia wrote:
>>> After the previous patch we're now always using l2_load() in
>>> get_cluster_table() regardless of whether a new L2 table has to be
>>> allocated or not.
>>>
>>> This patch refactors that part of the code to use one single l2_load()
>>> call.
>>>
>>> Signed-off-by: Alberto Garcia <berto@igalia.com>
>>> ---
>>>  block/qcow2-cluster.c | 21 +++++++--------------
>>>  1 file changed, 7 insertions(+), 14 deletions(-)
>>>
>>> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
>>> index 2a53c1dc5f..0c0cab85e8 100644
>>> --- a/block/qcow2-cluster.c
>>> +++ b/block/qcow2-cluster.c
>>> @@ -695,15 +695,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
>>>          return -EIO;
>>>      }
>>>  
>>> -    /* seek the l2 table of the given l2 offset */
>>> -
>>> -    if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
>>> -        /* load the l2 table in memory */
>>> -        ret = l2_load(bs, offset, l2_offset, &l2_table);
>>> -        if (ret < 0) {
>>> -            return ret;
>>> -        }
>>> -    } else {
>>> +    if (!(s->l1_table[l1_index] & QCOW_OFLAG_COPIED)) {
>>>          /* First allocate a new L2 table (and do COW if needed) */
>>>          ret = l2_allocate(bs, l1_index);
>>>          if (ret < 0) {
>>> @@ -719,11 +711,12 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
>>>          /* Get the offset of the newly-allocated l2 table */
>>>          l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
>>>          assert(offset_into_cluster(s, l2_offset) == 0);
>>> -        /* Load the l2 table in memory */
>>> -        ret = l2_load(bs, offset, l2_offset, &l2_table);
>>> -        if (ret < 0) {
>>> -            return ret;
>>> -        }
>>> +    }
>>> +
>>> +    /* load the l2 table in memory */
>>> +    ret = l2_load(bs, offset, l2_offset, &l2_table);
>>> +    if (ret < 0) {
>>> +        return ret;
>>>      }
>>
>> I'd pull the l2_offset assignment (and alignment check) down below the
>> QCOW_OFLAG_COPIED check, saving us another two lines (!!1!) which we
>> could then spend on an
>>
>> assert(s->l1_table[l1_index] & QCOW_OFLAG_COPIED);
> 
> I'm not sure if I'm following you. We need to set l2_offset before and
> after allocating a new L2 table.
> 
> Before, because we need the offset of the old table (if there was one)
> in order to decrease its refcount.
> 
> And after, because we need the offset of the new table in order to load
> it.

Ah, right, yeah... Well, too bad.  Then I probably can't ask for the
assert() that badly.

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-02-01 13:13     ` Alberto Garcia
  2018-02-01 15:23       ` Anton Nefedov
@ 2018-02-01 18:15       ` Max Reitz
  2018-02-02  9:41         ` Alberto Garcia
  1 sibling, 1 reply; 108+ messages in thread
From: Max Reitz @ 2018-02-01 18:15 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 3282 bytes --]

On 2018-02-01 14:13, Alberto Garcia wrote:
> On Wed 31 Jan 2018 09:07:48 PM CET, Max Reitz wrote:
>> On 2018-01-26 15:59, Alberto Garcia wrote:
>>> This patch updates l2_allocate() to support the qcow2 cache returning
>>> L2 slices instead of full L2 tables.
>>>
>>> The old code simply gets an L2 table from the cache and initializes it
>>> with zeroes or with the contents of an existing table. With a cache
>>> that returns slices instead of tables the idea remains the same, but
>>> the code must now iterate over all the slices that are contained in an
>>> L2 table.
>>>
>>> Since now we're operating with slices the function can no longer
>>> return the newly-allocated table, so it's up to the caller to retrieve
>>> the appropriate L2 slice after calling l2_allocate() (note that with
>>> this patch the caller is still loading full L2 tables, but we'll deal
>>> with that in a separate patch).
>>>
>>> Signed-off-by: Alberto Garcia <berto@igalia.com>
>>> ---
>>>  block/qcow2-cluster.c | 56 +++++++++++++++++++++++++++++++--------------------
>>>  1 file changed, 34 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
>>> index 57349928a9..2a53c1dc5f 100644
>>> --- a/block/qcow2-cluster.c
>>> +++ b/block/qcow2-cluster.c
>>> @@ -264,11 +264,12 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
>>>   *
>>>   */
>>>  
>>> -static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
>>> +static int l2_allocate(BlockDriverState *bs, int l1_index)
>>>  {
>>>      BDRVQcow2State *s = bs->opaque;
>>>      uint64_t old_l2_offset;
>>> -    uint64_t *l2_table = NULL;
>>> +    uint64_t *l2_slice = NULL;
>>> +    unsigned slice, slice_size2, n_slices;
>>
>> I'd personally prefer size_t, but oh well.
> 
> I don't see any reason not to use int / unsigned. The size of a slice is
> always <= cluster_size (an int), and both slice and n_slices are smaller
> than that.

Well, what's the reason to use unsigned? :-)

The type of the expression used to set slice_size2 simply is size_t.

>> However, I'm wondering whether this is the best approach.  The old L2
>> table is probably not going to be used after this function, so we're
>> basically polluting the cache here.  That was bad enough so far, but
>> now that actually means wasting multiple cache entries on it.
>>
>> Sure, the code is simpler this way.  But maybe it would still be
>> better to manually copy the data over from the old offset...  (As long
>> as it's not much more complicated.)
> 
> You mean bypassing the cache altogether?

Yes.

>     qcow2_cache_flush(bs, s->l2_table_cache);
>     new_table = g_malloc(s->cluster_size);
>     if (old_l2_offset & L1E_OFFSET_MASK) {
>         bdrv_pread(bs->file, old_l2_offset, new_table, s->cluster_size);
>     } else {
>         memset(new_table, 0, s->cluster_size);
>     }
>     bdrv_pwrite(bs->file, new_l2_offset, new_table, s->cluster_size);
>     g_free(new_table);
> 
> ??

Well, we wouldn't need to flush the whole table but only the parts of
the L2 table that we are about to copy.  And in theory we can omit even
that, because that old L2 table is not COPIED, so it can't be dirty anyway.

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-02-01 15:43         ` Alberto Garcia
@ 2018-02-01 18:22           ` Max Reitz
  2018-02-02  8:08             ` Alberto Garcia
  0 siblings, 1 reply; 108+ messages in thread
From: Max Reitz @ 2018-02-01 18:22 UTC (permalink / raw)
  To: Alberto Garcia, Anton Nefedov, qemu-devel
  Cc: Kevin Wolf, Denis V . Lunev, qemu-block

[-- Attachment #1: Type: text/plain, Size: 2661 bytes --]

On 2018-02-01 16:43, Alberto Garcia wrote:
> On Thu 01 Feb 2018 04:23:09 PM CET, Anton Nefedov wrote:
>>>> However, I'm wondering whether this is the best approach.  The old
>>>> L2 table is probably not going to be used after this function, so
>>>> we're basically polluting the cache here.  That was bad enough so
>>>> far, but now that actually means wasting multiple cache entries on
>>>> it.
>>>>
>>>> Sure, the code is simpler this way.  But maybe it would still be
>>>> better to manually copy the data over from the old offset...  (As
>>>> long as it's not much more complicated.)
>>>
>>> You mean bypassing the cache altogether?
>>>
>>>      qcow2_cache_flush(bs, s->l2_table_cache);
>>>      new_table = g_malloc(s->cluster_size);
>>>      if (old_l2_offset & L1E_OFFSET_MASK) {
>>>          bdrv_pread(bs->file, old_l2_offset, new_table, s->cluster_size);
>>>      } else {
>>>          memset(new_table, 0, s->cluster_size);
>>>      }
>>>      bdrv_pwrite(bs->file, new_l2_offset, new_table, s->cluster_size);
>>>      g_free(new_table);
>>>
>>> ??
>>
>> (I know it's a draft so you probably just skipped that but just in
>> case) It seems ok to bypass the cache read - perhaps even a flush is
>> not necessary: old_l2_offset must be read-only and flushed at this
>> point; I believe new_l2_offset might be cached too, so it needs to be
>> updated.
> 
> One problem I see with this is that while we wouldn't pollute the cache
> we'd always be reading the table twice from disk in all cases:
> 
>  1) Read old table
>  2) Write new table
>  3) Read new table (after l2_allocate(), using the cache this time)
> 
> We can of course improve it by reading the old table from disk but
> directly in the cache -so we'd spare step (3)-, but we'd still have to
> read at least once from disk.
> 
> With the old code (especially if slice_size == cluster_size) we don't
> need to read anything if the L2 table is already cached:
> 
>  1) Get empty table from the cache
>  2) memcpy() the old data
>  3) Get new table from the cache (after l2_allocate()).

Well, then scratch the bdrv_pwrite() for the new table and keep using
the cache for that (because that actually sounds useful).

On second thought, though, it's rather probable the old L2 table is
already in the cache...  Before the guest does a write to a location, it
is reasonable to assume it has read from there before.

So I guess we could think about adding a parameter to qcow2_cache_put()
or something to reset the LRU counter because we probably won't need
that entry anymore.  But not something for this series, of course.

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 21/39] qcow2: Update qcow2_alloc_cluster_link_l2() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 21/39] qcow2: Update qcow2_alloc_cluster_link_l2() " Alberto Garcia
@ 2018-02-01 18:44   ` Max Reitz
  2018-02-02  9:43     ` Alberto Garcia
  0 siblings, 1 reply; 108+ messages in thread
From: Max Reitz @ 2018-02-01 18:44 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 890 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> There's a loop in this function that iterates over the L2 entries in a
> table, so now we need to assert that it remains within the limits of
> an L2 slice.
> 
> Apart from that, this function doesn't need any additional changes, so
> this patch simply updates the variable name from l2_table to l2_slice.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)

Hm, well, strictly speaking this patch should not be at this point in
this series -- e.g. handle_alloc() so far only limits its nb_clusters to
the L2 size, not the L2 slice size.

But that's nit picking because the slice size equals the L2 size anyway
(for now), so

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 22/39] qcow2: Update handle_copied() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 22/39] qcow2: Update handle_copied() " Alberto Garcia
@ 2018-02-01 18:54   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 18:54 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 668 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> handle_copied() loads an L2 table and limits the number of checked
> clusters to the amount that fits inside that table. Since we'll be
> loading L2 slices instead of full tables we need to update that limit.
> 
> Apart from that, this function doesn't need any additional changes, so
> this patch simply updates the variable name from l2_table to l2_slice.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 23/39] qcow2: Update handle_alloc() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 23/39] qcow2: Update handle_alloc() " Alberto Garcia
@ 2018-02-01 18:56   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 18:56 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 669 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> handle_alloc() loads an L2 table and limits the number of checked
> clusters to the amount that fits inside that table. Since we'll be
> loading L2 slices instead of full tables we need to update that limit.
> 
> Apart from that, this function doesn't need any additional changes, so
> this patch simply updates the variable name from l2_table to l2_slice.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 18 +++++++++---------
>  1 file changed, 9 insertions(+), 9 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 24/39] qcow2: Update discard_single_l2() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 24/39] qcow2: Update discard_single_l2() " Alberto Garcia
@ 2018-02-01 19:07   ` Max Reitz
  2018-02-02  9:46     ` Alberto Garcia
  0 siblings, 1 reply; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:07 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 818 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> discard_single_l2() limits the number of clusters to be discarded to
> the amount that fits inside an L2 table. Since we'll be loading L2
> slices instead of full tables we need to update that limit.

Hmmmm, maybe rename the function to discard_l2_slice() or
discard_in_l2_slice() or discard_all_in_l2_slice() or
discard_single_l2_slice()?

> Apart from that, this function doesn't need any additional changes, so
> this patch simply updates the variable name from l2_table to l2_slice.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 20 ++++++++++----------
>  1 file changed, 10 insertions(+), 10 deletions(-)

Anyway:

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 25/39] qcow2: Update zero_single_l2() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 25/39] qcow2: Update zero_single_l2() " Alberto Garcia
@ 2018-02-01 19:08   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:08 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 736 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> zero_single_l2() limits the number of clusters to be zeroed to the
> amount that fits inside an L2 table. Since we'll be loading L2 slices
> instead of full tables we need to update that limit.

Same as last patch, maybe we should rename the function now.

> Apart from that, this function doesn't need any additional changes, so
> this patch simply updates the variable name from l2_table to l2_slice.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 20 ++++++++++----------
>  1 file changed, 10 insertions(+), 10 deletions(-)

Also again:

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 26/39] qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 26/39] qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support Alberto Garcia
  2018-01-26 19:38   ` Eric Blake
@ 2018-02-01 19:21   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:21 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 894 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> Adding support for L2 slices to qcow2_update_snapshot_refcount() needs
> (among other things) an extra loop that iterates over all slices of
> each L2 table.
> 
> Putting all changes in one patch would make it hard to read because
> all semantic changes would be mixed with pure indentation changes.
> 
> To make things easier this patch simply creates a new block and
> changes the indentation of all lines of code inside it. Thus, all
> modifications in this patch are cosmetic. There are no semantic
> changes and no variables are renamed yet. The next patch will take
> care of that.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-refcount.c | 140 ++++++++++++++++++++++++++-----------------------
>  1 file changed, 73 insertions(+), 67 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 27/39] qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 27/39] qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices Alberto Garcia
  2018-01-26 19:39   ` Eric Blake
@ 2018-02-01 19:26   ` Max Reitz
  2018-02-02  9:56     ` Alberto Garcia
  1 sibling, 1 reply; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:26 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 2817 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> qcow2_update_snapshot_refcount() increases the refcount of all
> clusters of a given snapshot. In order to do that it needs to load all
> its L2 tables and iterate over their entries. Since we'll be loading
> L2 slices instead of full tables we need to add an extra loop that
> iterates over all slices of each L2 table.
> 
> This function doesn't need any additional changes so apart from that
> this patch simply updates the variable name from l2_table to l2_slice.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-refcount.c | 31 +++++++++++++++++--------------
>  1 file changed, 17 insertions(+), 14 deletions(-)
> 
> diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
> index dfa28301c4..60b521cb89 100644
> --- a/block/qcow2-refcount.c
> +++ b/block/qcow2-refcount.c
> @@ -1183,17 +1183,20 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
>      int64_t l1_table_offset, int l1_size, int addend)
>  {
>      BDRVQcow2State *s = bs->opaque;
> -    uint64_t *l1_table, *l2_table, l2_offset, entry, l1_size2, refcount;
> +    uint64_t *l1_table, *l2_slice, l2_offset, entry, l1_size2, refcount;
>      bool l1_allocated = false;
>      int64_t old_entry, old_l2_offset;
> +    unsigned slice, slice_size2, n_slices;

Hm, well. Hm.

>      int i, j, l1_modified = 0, nb_csectors;
>      int ret;
>  
>      assert(addend >= -1 && addend <= 1);
>  
> -    l2_table = NULL;
> +    l2_slice = NULL;
>      l1_table = NULL;
>      l1_size2 = l1_size * sizeof(uint64_t);
> +    slice_size2 = s->l2_slice_size * sizeof(uint64_t);
> +    n_slices = s->cluster_size / slice_size2;
>  
>      s->cache_discards = true;
>  

[...]

> @@ -1273,12 +1276,13 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
>                      case QCOW2_CLUSTER_NORMAL:
>                      case QCOW2_CLUSTER_ZERO_ALLOC:
>                          if (offset_into_cluster(s, offset)) {
> +                            int l2_index = slice * s->l2_slice_size + j;
>                              qcow2_signal_corruption(
>                                  bs, true, -1, -1, "Cluster "
>                                  "allocation offset %#" PRIx64
>                                  " unaligned (L2 offset: %#"
>                                  PRIx64 ", L2 index: %#x)",
> -                                offset, l2_offset, j);
> +                                offset, l2_offset, l2_index);

This makes it a bit weird that in other patches l2_index is now
generally the L2 slice index...

Oh well.

Reviewed-by: Max Reitz <mreitz@redhat.com>

>                              ret = -EIO;
>                              goto fail;
>                          }


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 28/39] qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 28/39] qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1() Alberto Garcia
  2018-01-26 19:41   ` Eric Blake
@ 2018-02-01 19:29   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:29 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 637 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> At the moment it doesn't really make a difference whether we call
> qcow2_get_refcount() before of after reading the L2 table, but if we
> want to support L2 slices we'll need to read the refcount first.
> 
> This patch simply changes the order of those two operations to prepare
> for that. The patch with the actual semantic changes will be easier to
> read because of this.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 29/39] qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 29/39] qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support Alberto Garcia
  2018-01-26 19:42   ` Eric Blake
@ 2018-02-01 19:34   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:34 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 890 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> Adding support for L2 slices to expand_zero_clusters_in_l1() needs
> (among other things) an extra loop that iterates over all slices of
> each L2 table.
> 
> Putting all changes in one patch would make it hard to read because
> all semantic changes would be mixed with pure indentation changes.
> 
> To make things easier this patch simply creates a new block and
> changes the indentation of all lines of code inside it. Thus, all
> modifications in this patch are cosmetic. There are no semantic
> changes and no variables are renamed yet. The next patch will take
> care of that.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 187 ++++++++++++++++++++++++++------------------------
>  1 file changed, 96 insertions(+), 91 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 30/39] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 30/39] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices Alberto Garcia
  2018-01-26 19:46   ` Eric Blake
@ 2018-02-01 19:44   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:44 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1251 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> expand_zero_clusters_in_l1() expands zero clusters as a necessary step
> to downgrade qcow2 images to a version that doesn't support metadata
> zero clusters. This function takes an L1 table (which may or may not
> be active) and iterates over all its L2 tables looking for zero
> clusters.
> 
> Since we'll be loading L2 slices instead of full tables we need to add
> an extra loop that iterates over all slices of each L2 table, and we
> should also use the slice size when allocating the buffer used when
> the L1 table is not active.
> 
> This function doesn't need any additional changes so apart from that
> this patch simply updates the variable name from l2_table to l2_slice.
> 
> Finally, and since we have to touch the bdrv_read() / bdrv_write()
> calls anyway, this patch takes the opportunity to replace them with
> the byte-based bdrv_pread() / bdrv_pwrite().
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cluster.c | 52 ++++++++++++++++++++++++++++-----------------------
>  1 file changed, 29 insertions(+), 23 deletions(-)

Aside from the void * casts (and slice_size2 *cough* *cough*):

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 31/39] qcow2: Update qcow2_truncate() to support L2 slices
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 31/39] qcow2: Update qcow2_truncate() " Alberto Garcia
@ 2018-02-01 19:46   ` Max Reitz
  2018-02-02 10:10     ` Alberto Garcia
  0 siblings, 1 reply; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:46 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1660 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> The qcow2_truncate() code is mostly independent from whether
> we're using L2 slices or full L2 tables, but in full and
> falloc preallocation modes new L2 tables are allocated using
> qcow2_alloc_cluster_link_l2().  Therefore the code needs to be
> modified to ensure that all nb_clusters that are processed in each
> call can be allocated with just one L2 slice.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/block/qcow2.c b/block/qcow2.c
> index 78f067cae7..529becfa30 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -3261,8 +3261,9 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
>          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);
> +            int64_t nb_clusters = MIN(
> +                nb_new_data_clusters,
> +                s->l2_slice_size - guest_cluster % s->l2_slice_size);

An alternative would be the
"s->l2_slice_size - offset_to_l2_slice_index(s, guest_offset)" we
basically have elsewhere, but that's longer and doesn't really matter:

Reviewed-by: Max Reitz <mreitz@redhat.com>

>              QCowL2Meta allocation = {
>                  .offset       = guest_offset,
>                  .alloc_offset = host_offset,
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 32/39] qcow2: Rename l2_table in qcow2_alloc_compressed_cluster_offset()
  2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 32/39] qcow2: Rename l2_table in qcow2_alloc_compressed_cluster_offset() Alberto Garcia
@ 2018-02-01 19:48   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:48 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 481 bytes --]

On 2018-01-26 15:59, Alberto Garcia wrote:
> This function doesn't need any changes to support L2 slices, but since
> it's now dealing with slices instead of full tables, the l2_table
> variable is renamed for clarity.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 33/39] qcow2: Rename l2_table in count_contiguous_clusters()
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 33/39] qcow2: Rename l2_table in count_contiguous_clusters() Alberto Garcia
@ 2018-02-01 19:49   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:49 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 471 bytes --]

On 2018-01-26 16:00, Alberto Garcia wrote:
> This function doesn't need any changes to support L2 slices, but since
> it's now dealing with slices intead of full tables, the l2_table
> variable is renamed for clarity.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 34/39] qcow2: Rename l2_table in count_contiguous_clusters_unallocated()
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 34/39] qcow2: Rename l2_table in count_contiguous_clusters_unallocated() Alberto Garcia
@ 2018-02-01 19:49   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:49 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 469 bytes --]

On 2018-01-26 16:00, Alberto Garcia wrote:
> This function doesn't need any changes to support L2 slices, but since
> it's now dealing with slices intead of full tables, the l2_table
> variable is renamed for clarity.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 35/39] qcow2: Rename l2_table in count_cow_clusters()
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 35/39] qcow2: Rename l2_table in count_cow_clusters() Alberto Garcia
@ 2018-02-01 19:50   ` Max Reitz
  0 siblings, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 19:50 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 467 bytes --]

On 2018-01-26 16:00, Alberto Garcia wrote:
> This function doesn't need any changes to support L2 slices, but since
> it's now dealing with slices intead of full tables, the l2_table
> variable is renamed for clarity.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  block/qcow2-cluster.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 36/39] qcow2: Allow configuring the L2 slice size
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 36/39] qcow2: Allow configuring the L2 slice size Alberto Garcia
  2018-01-31 19:20   ` Eric Blake
@ 2018-02-01 20:04   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 20:04 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 1993 bytes --]

On 2018-01-26 16:00, Alberto Garcia wrote:
> Now that the code is ready to handle L2 slices we can finally add an
> option to allow configuring their size.
> 
> An L2 slice is the portion of an L2 table that is read by the qcow2
> cache. Until now the cache was always reading full L2 tables, and
> since the L2 table size is equal to the cluster size this was not very
> efficient with large clusters. Here's a more detailed explanation of
> why it makes sense to have smaller cache entries in order to load L2
> data:
> 
>    https://lists.gnu.org/archive/html/qemu-block/2017-09/msg00635.html
> 
> This patch introduces a new command-line option to the qcow2 driver
> named l2-cache-entry-size (cf. l2-cache-size). The cache entry size
> has the same restrictions as the cluster size: it must be a power of
> two and it has the same range of allowed values, with the additional
> requirement that it must not be larger than the cluster size.
> 
> The L2 cache entry size (L2 slice size) remains equal to the cluster
> size for now by default, so this feature must be explicitly enabled.
> Although my tests show that 4KB slices consistently improve
> performance and give the best results, let's wait and make more tests
> with different cluster sizes before deciding on an optimal default.
> 
> Now that the cache entry size is not necessarily equal to the cluster
> size we need to reflect that in the MIN_L2_CACHE_SIZE documentation.
> That minimum value is a requirement of the COW algorithm: we need to
> read two L2 slices (and not two L2 tables) in order to do COW, see
> l2_allocate() for the actual code.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  block/qcow2-cache.c  | 10 ++++++++--
>  block/qcow2.c        | 34 +++++++++++++++++++++++++++-------
>  block/qcow2.h        |  6 ++++--
>  qapi/block-core.json |  6 ++++++
>  4 files changed, 45 insertions(+), 11 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 37/39] iotests: Test valid values of l2-cache-entry-size
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 37/39] iotests: Test valid values of l2-cache-entry-size Alberto Garcia
  2018-01-31 19:21   ` Eric Blake
@ 2018-02-01 20:05   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 20:05 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 406 bytes --]

On 2018-01-26 16:00, Alberto Garcia wrote:
> The l2-cache-entry-size setting can only contain values that are
> powers of two between 512 and the cluster size.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  tests/qemu-iotests/103     | 17 +++++++++++++++++
>  tests/qemu-iotests/103.out |  3 +++
>  2 files changed, 20 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 38/39] iotests: Test downgrading an image using a small L2 slice size
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 38/39] iotests: Test downgrading an image using a small L2 slice size Alberto Garcia
  2018-01-31 19:23   ` Eric Blake
@ 2018-02-01 20:11   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 20:11 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 747 bytes --]

On 2018-01-26 16:00, Alberto Garcia wrote:
> expand_zero_clusters_in_l1() is used when downgrading qcow2 images
> from v3 to v2 (compat=0.10). This is one of the functions that needed
> more changes to support L2 slices, so this patch extends iotest 061 to
> test downgrading a qcow2 image using a smaller slice size.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  tests/qemu-iotests/061     | 16 ++++++++++++
>  tests/qemu-iotests/061.out | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 77 insertions(+)

Well, it would be better if we could just specify this option for all of
the qcow2 tests, but I can see that that's not really feasible...

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 39/39] iotests: Add l2-cache-entry-size to iotest 137
  2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 39/39] iotests: Add l2-cache-entry-size to iotest 137 Alberto Garcia
  2018-01-31 19:23   ` Eric Blake
@ 2018-02-01 20:12   ` Max Reitz
  1 sibling, 0 replies; 108+ messages in thread
From: Max Reitz @ 2018-02-01 20:12 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

[-- Attachment #1: Type: text/plain, Size: 397 bytes --]

On 2018-01-26 16:00, Alberto Garcia wrote:
> This test tries reopening a qcow2 image with valid and invalid
> options. This patch adds l2-cache-entry-size to the set.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> ---
>  tests/qemu-iotests/137     | 5 +++++
>  tests/qemu-iotests/137.out | 2 ++
>  2 files changed, 7 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 512 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-02-01 18:22           ` Max Reitz
@ 2018-02-02  8:08             ` Alberto Garcia
  0 siblings, 0 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-02-02  8:08 UTC (permalink / raw)
  To: Max Reitz, Anton Nefedov, qemu-devel
  Cc: Kevin Wolf, Denis V . Lunev, qemu-block

On Thu 01 Feb 2018 07:22:16 PM CET, Max Reitz wrote:
> On 2018-02-01 16:43, Alberto Garcia wrote:
>> On Thu 01 Feb 2018 04:23:09 PM CET, Anton Nefedov wrote:
>>>>> However, I'm wondering whether this is the best approach.  The old
>>>>> L2 table is probably not going to be used after this function, so
>>>>> we're basically polluting the cache here.  That was bad enough so
>>>>> far, but now that actually means wasting multiple cache entries on
>>>>> it.
>>>>>
>>>>> Sure, the code is simpler this way.  But maybe it would still be
>>>>> better to manually copy the data over from the old offset...  (As
>>>>> long as it's not much more complicated.)
>>>>
>>>> You mean bypassing the cache altogether?
>>>>
>>>>      qcow2_cache_flush(bs, s->l2_table_cache);
>>>>      new_table = g_malloc(s->cluster_size);
>>>>      if (old_l2_offset & L1E_OFFSET_MASK) {
>>>>          bdrv_pread(bs->file, old_l2_offset, new_table, s->cluster_size);
>>>>      } else {
>>>>          memset(new_table, 0, s->cluster_size);
>>>>      }
>>>>      bdrv_pwrite(bs->file, new_l2_offset, new_table, s->cluster_size);
>>>>      g_free(new_table);
>>>>
>>>> ??
>>>
>>> (I know it's a draft so you probably just skipped that but just in
>>> case) It seems ok to bypass the cache read - perhaps even a flush is
>>> not necessary: old_l2_offset must be read-only and flushed at this
>>> point; I believe new_l2_offset might be cached too, so it needs to be
>>> updated.
>> 
>> One problem I see with this is that while we wouldn't pollute the cache
>> we'd always be reading the table twice from disk in all cases:
>> 
>>  1) Read old table
>>  2) Write new table
>>  3) Read new table (after l2_allocate(), using the cache this time)
>> 
>> We can of course improve it by reading the old table from disk but
>> directly in the cache -so we'd spare step (3)-, but we'd still have to
>> read at least once from disk.
>> 
>> With the old code (especially if slice_size == cluster_size) we don't
>> need to read anything if the L2 table is already cached:
>> 
>>  1) Get empty table from the cache
>>  2) memcpy() the old data
>>  3) Get new table from the cache (after l2_allocate()).
>
> Well, then scratch the bdrv_pwrite() for the new table and keep using
> the cache for that (because that actually sounds useful).
>
> On second thought, though, it's rather probable the old L2 table is
> already in the cache...  Before the guest does a write to a location,
> it is reasonable to assume it has read from there before.
>
> So I guess we could think about adding a parameter to qcow2_cache_put()
> or something to reset the LRU counter because we probably won't need
> that entry anymore.  But not something for this series, of course.

That actually doesn't sound like a bad idea, there are maybe more cases
in which we know we're unlikely to need a cache entry soon, but as you
say let's take a look at it after this series.

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices
  2018-02-01 18:15       ` Max Reitz
@ 2018-02-02  9:41         ` Alberto Garcia
  0 siblings, 0 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-02-02  9:41 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

On Thu 01 Feb 2018 07:15:23 PM CET, Max Reitz <mreitz@redhat.com> wrote:
>>>> -static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
>>>> +static int l2_allocate(BlockDriverState *bs, int l1_index)
>>>>  {
>>>>      BDRVQcow2State *s = bs->opaque;
>>>>      uint64_t old_l2_offset;
>>>> -    uint64_t *l2_table = NULL;
>>>> +    uint64_t *l2_slice = NULL;
>>>> +    unsigned slice, slice_size2, n_slices;
>>>
>>> I'd personally prefer size_t, but oh well.
>> 
>> I don't see any reason not to use int / unsigned. The size of a slice
>> is always <= cluster_size (an int), and both slice and n_slices are
>> smaller than that.
>
> Well, what's the reason to use unsigned? :-)
> The type of the expression used to set slice_size2 simply is size_t.

I tend to choose the type of a variable based on what it's going to
hold, and use int (signed or not) whenever possible.

In this case a normal integer can certainly hold all possible values of
slice_size2. And unsigned because it's never going to be negative. It
could also be signed, it's not going to be any different in practice,
it's just more explicit.

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 21/39] qcow2: Update qcow2_alloc_cluster_link_l2() to support L2 slices
  2018-02-01 18:44   ` Max Reitz
@ 2018-02-02  9:43     ` Alberto Garcia
  0 siblings, 0 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-02-02  9:43 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

On Thu 01 Feb 2018 07:44:56 PM CET, Max Reitz <mreitz@redhat.com> wrote:
> On 2018-01-26 15:59, Alberto Garcia wrote:
>> There's a loop in this function that iterates over the L2 entries in a
>> table, so now we need to assert that it remains within the limits of
>> an L2 slice.
>> 
>> Apart from that, this function doesn't need any additional changes, so
>> this patch simply updates the variable name from l2_table to l2_slice.
>> 
>> Signed-off-by: Alberto Garcia <berto@igalia.com>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> ---
>>  block/qcow2-cluster.c | 16 ++++++++--------
>>  1 file changed, 8 insertions(+), 8 deletions(-)
>
> Hm, well, strictly speaking this patch should not be at this point in
> this series -- e.g. handle_alloc() so far only limits its nb_clusters to
> the L2 size, not the L2 slice size.

Yeah, I didn't try to be too strict with this because you can only
change the slice size after everything else is ready.

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 24/39] qcow2: Update discard_single_l2() to support L2 slices
  2018-02-01 19:07   ` Max Reitz
@ 2018-02-02  9:46     ` Alberto Garcia
  0 siblings, 0 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-02-02  9:46 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

On Thu 01 Feb 2018 08:07:15 PM CET, Max Reitz <mreitz@redhat.com> wrote:
> On 2018-01-26 15:59, Alberto Garcia wrote:
>> discard_single_l2() limits the number of clusters to be discarded to
>> the amount that fits inside an L2 table. Since we'll be loading L2
>> slices instead of full tables we need to update that limit.
>
> Hmmmm, maybe rename the function to discard_l2_slice() or
> discard_in_l2_slice() or discard_all_in_l2_slice() or
> discard_single_l2_slice()?

Good idea, I think I that will change that (also the related comment in
qcow2_cluster_discard()).

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 27/39] qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices
  2018-02-01 19:26   ` Max Reitz
@ 2018-02-02  9:56     ` Alberto Garcia
  0 siblings, 0 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-02-02  9:56 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

On Thu 01 Feb 2018 08:26:26 PM CET, Max Reitz <mreitz@redhat.com> wrote:
>> @@ -1273,12 +1276,13 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
>>                      case QCOW2_CLUSTER_NORMAL:
>>                      case QCOW2_CLUSTER_ZERO_ALLOC:
>>                          if (offset_into_cluster(s, offset)) {
>> +                            int l2_index = slice * s->l2_slice_size + j;
>>                              qcow2_signal_corruption(
>>                                  bs, true, -1, -1, "Cluster "
>>                                  "allocation offset %#" PRIx64
>>                                  " unaligned (L2 offset: %#"
>>                                  PRIx64 ", L2 index: %#x)",
>> -                                offset, l2_offset, j);
>> +                                offset, l2_offset, l2_index);
>
> This makes it a bit weird that in other patches l2_index is now
> generally the L2 slice index...

You're right, I can call it l2_table_index, I think this is the only
case where it does not refer to the slice index.

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: [Qemu-devel] [PATCH v3 31/39] qcow2: Update qcow2_truncate() to support L2 slices
  2018-02-01 19:46   ` Max Reitz
@ 2018-02-02 10:10     ` Alberto Garcia
  0 siblings, 0 replies; 108+ messages in thread
From: Alberto Garcia @ 2018-02-02 10:10 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: qemu-block, Kevin Wolf, Eric Blake, Anton Nefedov, Denis V . Lunev

On Thu 01 Feb 2018 08:46:46 PM CET, Max Reitz <mreitz@redhat.com> wrote:
>> @@ -3261,8 +3261,9 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
>>          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);
>> +            int64_t nb_clusters = MIN(
>> +                nb_new_data_clusters,
>> +                s->l2_slice_size - guest_cluster % s->l2_slice_size);
>
> An alternative would be the
> "s->l2_slice_size - offset_to_l2_slice_index(s, guest_offset)" we
> basically have elsewhere, but that's longer and doesn't really matter:

It's a bit longer but it looks better and we can get rid of
guest_cluster, so I think I'll change it.

Berto

^ permalink raw reply	[flat|nested] 108+ messages in thread

end of thread, other threads:[~2018-02-02 15:35 UTC | newest]

Thread overview: 108+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-26 14:59 [Qemu-devel] [PATCH v3 00/39] Allow configuring the qcow2 L2 cache entry size Alberto Garcia
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 01/39] qcow2: Fix documentation of get_cluster_table() Alberto Garcia
2018-01-31 19:16   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 02/39] qcow2: Add table size field to Qcow2Cache Alberto Garcia
2018-01-31 19:25   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 03/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_addr() Alberto Garcia
2018-01-31 19:26   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 04/39] qcow2: Remove BDS parameter from qcow2_cache_get_table_idx() Alberto Garcia
2018-01-31 19:27   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 05/39] qcow2: Remove BDS parameter from qcow2_cache_table_release() Alberto Garcia
2018-01-31 19:28   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 06/39] qcow2: Remove BDS parameter from qcow2_cache_entry_mark_dirty() Alberto Garcia
2018-01-31 19:30   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 07/39] qcow2: Remove BDS parameter from qcow2_cache_put() Alberto Garcia
2018-01-31 19:33   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 08/39] qcow2: Remove BDS parameter from qcow2_cache_destroy() Alberto Garcia
2018-01-31 19:35   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 09/39] qcow2: Remove BDS parameter from qcow2_cache_clean_unused() Alberto Garcia
2018-01-31 19:37   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 10/39] qcow2: Remove BDS parameter from qcow2_cache_discard() Alberto Garcia
2018-01-31 19:38   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 11/39] qcow2: Remove BDS parameter from qcow2_cache_is_table_offset() Alberto Garcia
2018-01-31 19:39   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 12/39] qcow2: Add offset_to_l1_index() Alberto Garcia
2018-01-31 19:43   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 13/39] qcow2: Add l2_slice_size field to BDRVQcow2State Alberto Garcia
2018-01-31 19:48   ` Max Reitz
2018-02-01  9:51     ` Alberto Garcia
2018-02-01 18:09       ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 14/39] qcow2: Add offset_to_l2_slice_index() Alberto Garcia
2018-01-31 19:49   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 15/39] qcow2: Update l2_load() to support L2 slices Alberto Garcia
2018-01-31 19:56   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 16/39] qcow2: Prepare l2_allocate() for adding L2 slice support Alberto Garcia
2018-01-26 16:24   ` Eric Blake
2018-01-31 19:57   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 17/39] qcow2: Update l2_allocate() to support L2 slices Alberto Garcia
2018-01-26 16:30   ` Eric Blake
2018-01-31 20:07   ` Max Reitz
2018-02-01 13:13     ` Alberto Garcia
2018-02-01 15:23       ` Anton Nefedov
2018-02-01 15:43         ` Alberto Garcia
2018-02-01 18:22           ` Max Reitz
2018-02-02  8:08             ` Alberto Garcia
2018-02-01 18:15       ` Max Reitz
2018-02-02  9:41         ` Alberto Garcia
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 18/39] qcow2: Refactor get_cluster_table() Alberto Garcia
2018-01-26 16:37   ` Eric Blake
2018-01-31 20:11   ` Max Reitz
2018-02-01 10:40     ` Alberto Garcia
2018-02-01 18:10       ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 19/39] qcow2: Update get_cluster_table() to support L2 slices Alberto Garcia
2018-01-26 16:39   ` Eric Blake
2018-01-31 20:14   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 20/39] qcow2: Update qcow2_get_cluster_offset() " Alberto Garcia
2018-01-31 20:24   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 21/39] qcow2: Update qcow2_alloc_cluster_link_l2() " Alberto Garcia
2018-02-01 18:44   ` Max Reitz
2018-02-02  9:43     ` Alberto Garcia
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 22/39] qcow2: Update handle_copied() " Alberto Garcia
2018-02-01 18:54   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 23/39] qcow2: Update handle_alloc() " Alberto Garcia
2018-02-01 18:56   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 24/39] qcow2: Update discard_single_l2() " Alberto Garcia
2018-02-01 19:07   ` Max Reitz
2018-02-02  9:46     ` Alberto Garcia
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 25/39] qcow2: Update zero_single_l2() " Alberto Garcia
2018-02-01 19:08   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 26/39] qcow2: Prepare qcow2_update_snapshot_refcount() for adding L2 slice support Alberto Garcia
2018-01-26 19:38   ` Eric Blake
2018-02-01 19:21   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 27/39] qcow2: Update qcow2_update_snapshot_refcount() to support L2 slices Alberto Garcia
2018-01-26 19:39   ` Eric Blake
2018-02-01 19:26   ` Max Reitz
2018-02-02  9:56     ` Alberto Garcia
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 28/39] qcow2: Read refcount before L2 table in expand_zero_clusters_in_l1() Alberto Garcia
2018-01-26 19:41   ` Eric Blake
2018-02-01 19:29   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 29/39] qcow2: Prepare expand_zero_clusters_in_l1() for adding L2 slice support Alberto Garcia
2018-01-26 19:42   ` Eric Blake
2018-02-01 19:34   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 30/39] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices Alberto Garcia
2018-01-26 19:46   ` Eric Blake
2018-01-29 12:06     ` Alberto Garcia
2018-02-01 19:44   ` Max Reitz
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 31/39] qcow2: Update qcow2_truncate() " Alberto Garcia
2018-02-01 19:46   ` Max Reitz
2018-02-02 10:10     ` Alberto Garcia
2018-01-26 14:59 ` [Qemu-devel] [PATCH v3 32/39] qcow2: Rename l2_table in qcow2_alloc_compressed_cluster_offset() Alberto Garcia
2018-02-01 19:48   ` Max Reitz
2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 33/39] qcow2: Rename l2_table in count_contiguous_clusters() Alberto Garcia
2018-02-01 19:49   ` Max Reitz
2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 34/39] qcow2: Rename l2_table in count_contiguous_clusters_unallocated() Alberto Garcia
2018-02-01 19:49   ` Max Reitz
2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 35/39] qcow2: Rename l2_table in count_cow_clusters() Alberto Garcia
2018-02-01 19:50   ` Max Reitz
2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 36/39] qcow2: Allow configuring the L2 slice size Alberto Garcia
2018-01-31 19:20   ` Eric Blake
2018-02-01 20:04   ` Max Reitz
2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 37/39] iotests: Test valid values of l2-cache-entry-size Alberto Garcia
2018-01-31 19:21   ` Eric Blake
2018-02-01 20:05   ` Max Reitz
2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 38/39] iotests: Test downgrading an image using a small L2 slice size Alberto Garcia
2018-01-31 19:23   ` Eric Blake
2018-02-01 20:11   ` Max Reitz
2018-01-26 15:00 ` [Qemu-devel] [PATCH v3 39/39] iotests: Add l2-cache-entry-size to iotest 137 Alberto Garcia
2018-01-31 19:23   ` Eric Blake
2018-02-01 20:12   ` Max Reitz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.