Commit 44ff42de1c2df7255108d88e98c2bfe6e7bdbf88

Authored by Kevin Wolf
Committed by Anthony Liguori
1 parent ade40677

qcow2: Refactor update_refcount

This is a preparation patch with no functional changes. It moves the allocation
of new refcounts block to a new function and makes update_cluster_refcount (for
one cluster) call update_refcount (for multiple clusters) instead the other way
round.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing 1 changed file with 56 additions and 30 deletions
block/qcow2.c
... ... @@ -173,7 +173,7 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
173 173 static int update_cluster_refcount(BlockDriverState *bs,
174 174 int64_t cluster_index,
175 175 int addend);
176   -static void update_refcount(BlockDriverState *bs,
  176 +static int update_refcount(BlockDriverState *bs,
177 177 int64_t offset, int64_t length,
178 178 int addend);
179 179 static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
... ... @@ -2508,29 +2508,25 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size)
2508 2508 return -EIO;
2509 2509 }
2510 2510  
2511   -/* addend must be 1 or -1 */
2512   -/* XXX: cache several refcount block clusters ? */
2513   -static int update_cluster_refcount(BlockDriverState *bs,
2514   - int64_t cluster_index,
2515   - int addend)
  2511 +
  2512 +static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
2516 2513 {
2517 2514 BDRVQcowState *s = bs->opaque;
2518 2515 int64_t offset, refcount_block_offset;
2519   - int ret, refcount_table_index, block_index, refcount;
  2516 + int ret, refcount_table_index;
2520 2517 uint64_t data64;
2521 2518  
  2519 + /* Find L1 index and grow refcount table if needed */
2522 2520 refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
2523 2521 if (refcount_table_index >= s->refcount_table_size) {
2524   - if (addend < 0)
2525   - return -EINVAL;
2526 2522 ret = grow_refcount_table(bs, refcount_table_index + 1);
2527 2523 if (ret < 0)
2528 2524 return ret;
2529 2525 }
  2526 +
  2527 + /* Load or allocate the refcount block */
2530 2528 refcount_block_offset = s->refcount_table[refcount_table_index];
2531 2529 if (!refcount_block_offset) {
2532   - if (addend < 0)
2533   - return -EINVAL;
2534 2530 /* create a new refcount block */
2535 2531 /* Note: we cannot update the refcount now to avoid recursion */
2536 2532 offset = alloc_clusters_noref(bs, s->cluster_size);
... ... @@ -2555,25 +2551,28 @@ static int update_cluster_refcount(BlockDriverState *bs,
2555 2551 return -EIO;
2556 2552 }
2557 2553 }
2558   - /* we can update the count and save it */
2559   - block_index = cluster_index &
2560   - ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
2561   - refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
2562   - refcount += addend;
2563   - if (refcount < 0 || refcount > 0xffff)
2564   - return -EINVAL;
2565   - if (refcount == 0 && cluster_index < s->free_cluster_index) {
2566   - s->free_cluster_index = cluster_index;
  2554 +
  2555 + return refcount_block_offset;
  2556 +}
  2557 +
  2558 +/* addend must be 1 or -1 */
  2559 +static int update_cluster_refcount(BlockDriverState *bs,
  2560 + int64_t cluster_index,
  2561 + int addend)
  2562 +{
  2563 + BDRVQcowState *s = bs->opaque;
  2564 + int ret;
  2565 +
  2566 + ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend);
  2567 + if (ret < 0) {
  2568 + return ret;
2567 2569 }
2568   - s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
2569   - if (bdrv_pwrite(s->hd,
2570   - refcount_block_offset + (block_index << REFCOUNT_SHIFT),
2571   - &s->refcount_block_cache[block_index], 2) != 2)
2572   - return -EIO;
2573   - return refcount;
  2570 +
  2571 + return get_refcount(bs, cluster_index);
2574 2572 }
2575 2573  
2576   -static void update_refcount(BlockDriverState *bs,
  2574 +/* XXX: cache several refcount block clusters ? */
  2575 +static int update_refcount(BlockDriverState *bs,
2577 2576 int64_t offset, int64_t length,
2578 2577 int addend)
2579 2578 {
... ... @@ -2585,13 +2584,40 @@ static void update_refcount(BlockDriverState *bs,
2585 2584 offset, length, addend);
2586 2585 #endif
2587 2586 if (length <= 0)
2588   - return;
  2587 + return -EINVAL;
2589 2588 start = offset & ~(s->cluster_size - 1);
2590 2589 last = (offset + length - 1) & ~(s->cluster_size - 1);
2591 2590 for(cluster_offset = start; cluster_offset <= last;
2592   - cluster_offset += s->cluster_size) {
2593   - update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
  2591 + cluster_offset += s->cluster_size)
  2592 + {
  2593 + int64_t refcount_block_offset;
  2594 + int block_index, refcount;
  2595 + int64_t cluster_index = cluster_offset >> s->cluster_bits;
  2596 +
  2597 + /* Load the refcount block and allocate it if needed */
  2598 + refcount_block_offset = alloc_refcount_block(bs, cluster_index);
  2599 + if (refcount_block_offset < 0) {
  2600 + return refcount_block_offset;
  2601 + }
  2602 +
  2603 + /* we can update the count and save it */
  2604 + block_index = cluster_index &
  2605 + ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
  2606 + refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
  2607 + refcount += addend;
  2608 + if (refcount < 0 || refcount > 0xffff)
  2609 + return -EINVAL;
  2610 + if (refcount == 0 && cluster_index < s->free_cluster_index) {
  2611 + s->free_cluster_index = cluster_index;
  2612 + }
  2613 + s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
  2614 + if (bdrv_pwrite(s->hd,
  2615 + refcount_block_offset + (block_index << REFCOUNT_SHIFT),
  2616 + &s->refcount_block_cache[block_index], 2) != 2)
  2617 + return -EIO;
  2618 +
2594 2619 }
  2620 + return 0;
2595 2621 }
2596 2622  
2597 2623 /*
... ...