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,7 +173,7 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
173 static int update_cluster_refcount(BlockDriverState *bs, 173 static int update_cluster_refcount(BlockDriverState *bs,
174 int64_t cluster_index, 174 int64_t cluster_index,
175 int addend); 175 int addend);
176 -static void update_refcount(BlockDriverState *bs, 176 +static int update_refcount(BlockDriverState *bs,
177 int64_t offset, int64_t length, 177 int64_t offset, int64_t length,
178 int addend); 178 int addend);
179 static int64_t alloc_clusters(BlockDriverState *bs, int64_t size); 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,29 +2508,25 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size)
2508 return -EIO; 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 BDRVQcowState *s = bs->opaque; 2514 BDRVQcowState *s = bs->opaque;
2518 int64_t offset, refcount_block_offset; 2515 int64_t offset, refcount_block_offset;
2519 - int ret, refcount_table_index, block_index, refcount; 2516 + int ret, refcount_table_index;
2520 uint64_t data64; 2517 uint64_t data64;
2521 2518
  2519 + /* Find L1 index and grow refcount table if needed */
2522 refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); 2520 refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
2523 if (refcount_table_index >= s->refcount_table_size) { 2521 if (refcount_table_index >= s->refcount_table_size) {
2524 - if (addend < 0)  
2525 - return -EINVAL;  
2526 ret = grow_refcount_table(bs, refcount_table_index + 1); 2522 ret = grow_refcount_table(bs, refcount_table_index + 1);
2527 if (ret < 0) 2523 if (ret < 0)
2528 return ret; 2524 return ret;
2529 } 2525 }
  2526 +
  2527 + /* Load or allocate the refcount block */
2530 refcount_block_offset = s->refcount_table[refcount_table_index]; 2528 refcount_block_offset = s->refcount_table[refcount_table_index];
2531 if (!refcount_block_offset) { 2529 if (!refcount_block_offset) {
2532 - if (addend < 0)  
2533 - return -EINVAL;  
2534 /* create a new refcount block */ 2530 /* create a new refcount block */
2535 /* Note: we cannot update the refcount now to avoid recursion */ 2531 /* Note: we cannot update the refcount now to avoid recursion */
2536 offset = alloc_clusters_noref(bs, s->cluster_size); 2532 offset = alloc_clusters_noref(bs, s->cluster_size);
@@ -2555,25 +2551,28 @@ static int update_cluster_refcount(BlockDriverState *bs, @@ -2555,25 +2551,28 @@ static int update_cluster_refcount(BlockDriverState *bs,
2555 return -EIO; 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 int64_t offset, int64_t length, 2576 int64_t offset, int64_t length,
2578 int addend) 2577 int addend)
2579 { 2578 {
@@ -2585,13 +2584,40 @@ static void update_refcount(BlockDriverState *bs, @@ -2585,13 +2584,40 @@ static void update_refcount(BlockDriverState *bs,
2585 offset, length, addend); 2584 offset, length, addend);
2586 #endif 2585 #endif
2587 if (length <= 0) 2586 if (length <= 0)
2588 - return; 2587 + return -EINVAL;
2589 start = offset & ~(s->cluster_size - 1); 2588 start = offset & ~(s->cluster_size - 1);
2590 last = (offset + length - 1) & ~(s->cluster_size - 1); 2589 last = (offset + length - 1) & ~(s->cluster_size - 1);
2591 for(cluster_offset = start; cluster_offset <= last; 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 /*