Commit 3b88e52b41fe77728b4accb68e14bed98bdc75d3

Authored by Kevin Wolf
Committed by Anthony Liguori
1 parent 22afa7b5

qcow2: Cache refcount blocks during snapshot creation

The really time consuming part of snapshotting is to adjust the reference count
of all clusters. Currently after each adjusted cluster the refcount block is
written to disk.

Don't write each single byte immediately to disk but cache all writes to the
refcount block and write them out once we're done with the block.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing 1 changed file with 40 additions and 0 deletions
block/qcow2-refcount.c
@@ -31,6 +31,26 @@ static int update_refcount(BlockDriverState *bs, @@ -31,6 +31,26 @@ static int update_refcount(BlockDriverState *bs,
31 int64_t offset, int64_t length, 31 int64_t offset, int64_t length,
32 int addend); 32 int addend);
33 33
  34 +
  35 +static int cache_refcount_updates = 0;
  36 +
  37 +static int write_refcount_block(BDRVQcowState *s)
  38 +{
  39 + size_t size = s->cluster_size;
  40 +
  41 + if (s->refcount_block_cache_offset == 0) {
  42 + return 0;
  43 + }
  44 +
  45 + if (bdrv_pwrite(s->hd, s->refcount_block_cache_offset,
  46 + s->refcount_block_cache, size) != size)
  47 + {
  48 + return -EIO;
  49 + }
  50 +
  51 + return 0;
  52 +}
  53 +
34 /*********************************************************/ 54 /*********************************************************/
35 /* refcount handling */ 55 /* refcount handling */
36 56
@@ -68,6 +88,11 @@ static int load_refcount_block(BlockDriverState *bs, @@ -68,6 +88,11 @@ static int load_refcount_block(BlockDriverState *bs,
68 { 88 {
69 BDRVQcowState *s = bs->opaque; 89 BDRVQcowState *s = bs->opaque;
70 int ret; 90 int ret;
  91 +
  92 + if (cache_refcount_updates) {
  93 + write_refcount_block(s);
  94 + }
  95 +
71 ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache, 96 ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache,
72 s->cluster_size); 97 s->cluster_size);
73 if (ret != s->cluster_size) 98 if (ret != s->cluster_size)
@@ -169,6 +194,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) @@ -169,6 +194,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
169 int64_t offset, refcount_block_offset; 194 int64_t offset, refcount_block_offset;
170 int ret, refcount_table_index; 195 int ret, refcount_table_index;
171 uint64_t data64; 196 uint64_t data64;
  197 + int cache = cache_refcount_updates;
172 198
173 /* Find L1 index and grow refcount table if needed */ 199 /* Find L1 index and grow refcount table if needed */
174 refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); 200 refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
@@ -181,6 +207,10 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) @@ -181,6 +207,10 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
181 /* Load or allocate the refcount block */ 207 /* Load or allocate the refcount block */
182 refcount_block_offset = s->refcount_table[refcount_table_index]; 208 refcount_block_offset = s->refcount_table[refcount_table_index];
183 if (!refcount_block_offset) { 209 if (!refcount_block_offset) {
  210 + if (cache_refcount_updates) {
  211 + write_refcount_block(s);
  212 + cache_refcount_updates = 0;
  213 + }
184 /* create a new refcount block */ 214 /* create a new refcount block */
185 /* Note: we cannot update the refcount now to avoid recursion */ 215 /* Note: we cannot update the refcount now to avoid recursion */
186 offset = alloc_clusters_noref(bs, s->cluster_size); 216 offset = alloc_clusters_noref(bs, s->cluster_size);
@@ -199,6 +229,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) @@ -199,6 +229,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
199 refcount_block_offset = offset; 229 refcount_block_offset = offset;
200 s->refcount_block_cache_offset = offset; 230 s->refcount_block_cache_offset = offset;
201 update_refcount(bs, offset, s->cluster_size, 1); 231 update_refcount(bs, offset, s->cluster_size, 1);
  232 + cache_refcount_updates = cache;
202 } else { 233 } else {
203 if (refcount_block_offset != s->refcount_block_cache_offset) { 234 if (refcount_block_offset != s->refcount_block_cache_offset) {
204 if (load_refcount_block(bs, refcount_block_offset) < 0) 235 if (load_refcount_block(bs, refcount_block_offset) < 0)
@@ -215,6 +246,10 @@ static int write_refcount_block_entries(BDRVQcowState *s, @@ -215,6 +246,10 @@ static int write_refcount_block_entries(BDRVQcowState *s,
215 { 246 {
216 size_t size; 247 size_t size;
217 248
  249 + if (cache_refcount_updates) {
  250 + return 0;
  251 + }
  252 +
218 first_index &= ~(REFCOUNTS_PER_SECTOR - 1); 253 first_index &= ~(REFCOUNTS_PER_SECTOR - 1);
219 last_index = (last_index + REFCOUNTS_PER_SECTOR) 254 last_index = (last_index + REFCOUNTS_PER_SECTOR)
220 & ~(REFCOUNTS_PER_SECTOR - 1); 255 & ~(REFCOUNTS_PER_SECTOR - 1);
@@ -471,6 +506,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, @@ -471,6 +506,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
471 int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount; 506 int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount;
472 507
473 qcow2_l2_cache_reset(bs); 508 qcow2_l2_cache_reset(bs);
  509 + cache_refcount_updates = 1;
474 510
475 l2_table = NULL; 511 l2_table = NULL;
476 l1_table = NULL; 512 l1_table = NULL;
@@ -563,11 +599,15 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, @@ -563,11 +599,15 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
563 if (l1_allocated) 599 if (l1_allocated)
564 qemu_free(l1_table); 600 qemu_free(l1_table);
565 qemu_free(l2_table); 601 qemu_free(l2_table);
  602 + cache_refcount_updates = 0;
  603 + write_refcount_block(s);
566 return 0; 604 return 0;
567 fail: 605 fail:
568 if (l1_allocated) 606 if (l1_allocated)
569 qemu_free(l1_table); 607 qemu_free(l1_table);
570 qemu_free(l2_table); 608 qemu_free(l2_table);
  609 + cache_refcount_updates = 0;
  610 + write_refcount_block(s);
571 return -EIO; 611 return -EIO;
572 } 612 }
573 613