qcow2: More helpers for refcount modification

Add helper functions for getting and setting refcounts in a refcount
array for any possible refcount order, and choose the correct one during
refcount initialization.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Max Reitz 2015-02-10 15:28:51 -05:00 committed by Kevin Wolf
parent 7453c96b78
commit 59c0cb7830
1 changed files with 119 additions and 2 deletions

View File

@ -32,10 +32,49 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
int64_t offset, int64_t length, uint64_t addend,
bool decrease, enum qcow2_discard_type type);
static uint64_t get_refcount_ro0(const void *refcount_array, uint64_t index);
static uint64_t get_refcount_ro1(const void *refcount_array, uint64_t index);
static uint64_t get_refcount_ro2(const void *refcount_array, uint64_t index);
static uint64_t get_refcount_ro3(const void *refcount_array, uint64_t index);
static uint64_t get_refcount_ro4(const void *refcount_array, uint64_t index);
static uint64_t get_refcount_ro5(const void *refcount_array, uint64_t index);
static uint64_t get_refcount_ro6(const void *refcount_array, uint64_t index);
static void set_refcount_ro0(void *refcount_array, uint64_t index,
uint64_t value);
static void set_refcount_ro1(void *refcount_array, uint64_t index,
uint64_t value);
static void set_refcount_ro2(void *refcount_array, uint64_t index,
uint64_t value);
static void set_refcount_ro3(void *refcount_array, uint64_t index,
uint64_t value);
static void set_refcount_ro4(void *refcount_array, uint64_t index,
uint64_t value);
static void set_refcount_ro5(void *refcount_array, uint64_t index,
uint64_t value);
static void set_refcount_ro6(void *refcount_array, uint64_t index,
uint64_t value);
static Qcow2GetRefcountFunc *const get_refcount_funcs[] = {
&get_refcount_ro0,
&get_refcount_ro1,
&get_refcount_ro2,
&get_refcount_ro3,
&get_refcount_ro4,
&get_refcount_ro5,
&get_refcount_ro6
};
static Qcow2SetRefcountFunc *const set_refcount_funcs[] = {
&set_refcount_ro0,
&set_refcount_ro1,
&set_refcount_ro2,
&set_refcount_ro3,
&set_refcount_ro4,
&set_refcount_ro5,
&set_refcount_ro6
};
/*********************************************************/
@ -47,8 +86,10 @@ int qcow2_refcount_init(BlockDriverState *bs)
unsigned int refcount_table_size2, i;
int ret;
s->get_refcount = &get_refcount_ro4;
s->set_refcount = &set_refcount_ro4;
assert(s->refcount_order >= 0 && s->refcount_order <= 6);
s->get_refcount = get_refcount_funcs[s->refcount_order];
s->set_refcount = set_refcount_funcs[s->refcount_order];
assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
@ -80,6 +121,59 @@ void qcow2_refcount_close(BlockDriverState *bs)
}
static uint64_t get_refcount_ro0(const void *refcount_array, uint64_t index)
{
return (((const uint8_t *)refcount_array)[index / 8] >> (index % 8)) & 0x1;
}
static void set_refcount_ro0(void *refcount_array, uint64_t index,
uint64_t value)
{
assert(!(value >> 1));
((uint8_t *)refcount_array)[index / 8] &= ~(0x1 << (index % 8));
((uint8_t *)refcount_array)[index / 8] |= value << (index % 8);
}
static uint64_t get_refcount_ro1(const void *refcount_array, uint64_t index)
{
return (((const uint8_t *)refcount_array)[index / 4] >> (2 * (index % 4)))
& 0x3;
}
static void set_refcount_ro1(void *refcount_array, uint64_t index,
uint64_t value)
{
assert(!(value >> 2));
((uint8_t *)refcount_array)[index / 4] &= ~(0x3 << (2 * (index % 4)));
((uint8_t *)refcount_array)[index / 4] |= value << (2 * (index % 4));
}
static uint64_t get_refcount_ro2(const void *refcount_array, uint64_t index)
{
return (((const uint8_t *)refcount_array)[index / 2] >> (4 * (index % 2)))
& 0xf;
}
static void set_refcount_ro2(void *refcount_array, uint64_t index,
uint64_t value)
{
assert(!(value >> 4));
((uint8_t *)refcount_array)[index / 2] &= ~(0xf << (4 * (index % 2)));
((uint8_t *)refcount_array)[index / 2] |= value << (4 * (index % 2));
}
static uint64_t get_refcount_ro3(const void *refcount_array, uint64_t index)
{
return ((const uint8_t *)refcount_array)[index];
}
static void set_refcount_ro3(void *refcount_array, uint64_t index,
uint64_t value)
{
assert(!(value >> 8));
((uint8_t *)refcount_array)[index] = value;
}
static uint64_t get_refcount_ro4(const void *refcount_array, uint64_t index)
{
return be16_to_cpu(((const uint16_t *)refcount_array)[index]);
@ -92,6 +186,29 @@ static void set_refcount_ro4(void *refcount_array, uint64_t index,
((uint16_t *)refcount_array)[index] = cpu_to_be16(value);
}
static uint64_t get_refcount_ro5(const void *refcount_array, uint64_t index)
{
return be32_to_cpu(((const uint32_t *)refcount_array)[index]);
}
static void set_refcount_ro5(void *refcount_array, uint64_t index,
uint64_t value)
{
assert(!(value >> 32));
((uint32_t *)refcount_array)[index] = cpu_to_be32(value);
}
static uint64_t get_refcount_ro6(const void *refcount_array, uint64_t index)
{
return be64_to_cpu(((const uint64_t *)refcount_array)[index]);
}
static void set_refcount_ro6(void *refcount_array, uint64_t index,
uint64_t value)
{
((uint64_t *)refcount_array)[index] = cpu_to_be64(value);
}
static int load_refcount_block(BlockDriverState *bs,
int64_t refcount_block_offset,