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