Commit 44ff42de1c2df7255108d88e98c2bfe6e7bdbf88
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 | /* |