sim-card
/
qemu
Archived
10
0
Fork 0

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>
This commit is contained in:
Kevin Wolf 2009-05-26 14:36:02 +02:00 committed by Anthony Liguori
parent ade406775d
commit 44ff42de1c
1 changed files with 57 additions and 31 deletions

View File

@ -173,7 +173,7 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
static int update_cluster_refcount(BlockDriverState *bs,
int64_t cluster_index,
int addend);
static void update_refcount(BlockDriverState *bs,
static int update_refcount(BlockDriverState *bs,
int64_t offset, int64_t length,
int addend);
static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
@ -2508,29 +2508,25 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size)
return -EIO;
}
/* addend must be 1 or -1 */
/* XXX: cache several refcount block clusters ? */
static int update_cluster_refcount(BlockDriverState *bs,
int64_t cluster_index,
int addend)
static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
{
BDRVQcowState *s = bs->opaque;
int64_t offset, refcount_block_offset;
int ret, refcount_table_index, block_index, refcount;
int ret, refcount_table_index;
uint64_t data64;
/* Find L1 index and grow refcount table if needed */
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
if (refcount_table_index >= s->refcount_table_size) {
if (addend < 0)
return -EINVAL;
ret = grow_refcount_table(bs, refcount_table_index + 1);
if (ret < 0)
return ret;
}
/* Load or allocate the refcount block */
refcount_block_offset = s->refcount_table[refcount_table_index];
if (!refcount_block_offset) {
if (addend < 0)
return -EINVAL;
/* create a new refcount block */
/* Note: we cannot update the refcount now to avoid recursion */
offset = alloc_clusters_noref(bs, s->cluster_size);
@ -2555,25 +2551,28 @@ static int update_cluster_refcount(BlockDriverState *bs,
return -EIO;
}
}
/* we can update the count and save it */
block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
refcount += addend;
if (refcount < 0 || refcount > 0xffff)
return -EINVAL;
if (refcount == 0 && cluster_index < s->free_cluster_index) {
s->free_cluster_index = cluster_index;
}
s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
if (bdrv_pwrite(s->hd,
refcount_block_offset + (block_index << REFCOUNT_SHIFT),
&s->refcount_block_cache[block_index], 2) != 2)
return -EIO;
return refcount;
return refcount_block_offset;
}
static void update_refcount(BlockDriverState *bs,
/* addend must be 1 or -1 */
static int update_cluster_refcount(BlockDriverState *bs,
int64_t cluster_index,
int addend)
{
BDRVQcowState *s = bs->opaque;
int ret;
ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend);
if (ret < 0) {
return ret;
}
return get_refcount(bs, cluster_index);
}
/* XXX: cache several refcount block clusters ? */
static int update_refcount(BlockDriverState *bs,
int64_t offset, int64_t length,
int addend)
{
@ -2585,13 +2584,40 @@ static void update_refcount(BlockDriverState *bs,
offset, length, addend);
#endif
if (length <= 0)
return;
return -EINVAL;
start = offset & ~(s->cluster_size - 1);
last = (offset + length - 1) & ~(s->cluster_size - 1);
for(cluster_offset = start; cluster_offset <= last;
cluster_offset += s->cluster_size) {
update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
cluster_offset += s->cluster_size)
{
int64_t refcount_block_offset;
int block_index, refcount;
int64_t cluster_index = cluster_offset >> s->cluster_bits;
/* Load the refcount block and allocate it if needed */
refcount_block_offset = alloc_refcount_block(bs, cluster_index);
if (refcount_block_offset < 0) {
return refcount_block_offset;
}
/* we can update the count and save it */
block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
refcount += addend;
if (refcount < 0 || refcount > 0xffff)
return -EINVAL;
if (refcount == 0 && cluster_index < s->free_cluster_index) {
s->free_cluster_index = cluster_index;
}
s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
if (bdrv_pwrite(s->hd,
refcount_block_offset + (block_index << REFCOUNT_SHIFT),
&s->refcount_block_cache[block_index], 2) != 2)
return -EIO;
}
return 0;
}
/*