Revision 44ff42de block/qcow2.c
b/block/qcow2.c | ||
---|---|---|
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 | 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 | 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 | 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 |
/* |
Also available in: Unified diff