mirror of https://github.com/xemu-project/xemu.git
qcow2: Make size_to_clusters() return uint64_t
Sadly, some images may have more clusters than what can be represented using a plain int. We should be prepared for that case (in qcow2_check_refcounts() we actually were trying to catch that case, but since size_to_clusters() truncated the returned value, that check never did anything useful). Cc: qemu-stable <qemu-stable@nongnu.org> Signed-off-by: Max Reitz <mreitz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
231f66d2a3
commit
b6d36def6d
|
@ -298,7 +298,7 @@ fail:
|
||||||
* as contiguous. (This allows it, for example, to stop at the first compressed
|
* as contiguous. (This allows it, for example, to stop at the first compressed
|
||||||
* cluster which may require a different handling)
|
* cluster which may require a different handling)
|
||||||
*/
|
*/
|
||||||
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
|
static int count_contiguous_clusters(int nb_clusters, int cluster_size,
|
||||||
uint64_t *l2_table, uint64_t stop_flags)
|
uint64_t *l2_table, uint64_t stop_flags)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -321,7 +321,7 @@ static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
|
static int count_contiguous_free_clusters(int nb_clusters, uint64_t *l2_table)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -495,6 +495,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
if (nb_needed > nb_available) {
|
if (nb_needed > nb_available) {
|
||||||
nb_needed = nb_available;
|
nb_needed = nb_available;
|
||||||
}
|
}
|
||||||
|
assert(nb_needed <= INT_MAX);
|
||||||
|
|
||||||
*cluster_offset = 0;
|
*cluster_offset = 0;
|
||||||
|
|
||||||
|
@ -530,6 +531,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
|
|
||||||
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
|
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
|
||||||
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
||||||
|
|
||||||
|
/* nb_needed <= INT_MAX, thus nb_clusters <= INT_MAX, too */
|
||||||
nb_clusters = size_to_clusters(s, nb_needed << 9);
|
nb_clusters = size_to_clusters(s, nb_needed << 9);
|
||||||
|
|
||||||
ret = qcow2_get_cluster_type(*cluster_offset);
|
ret = qcow2_get_cluster_type(*cluster_offset);
|
||||||
|
@ -960,7 +963,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
|
||||||
int l2_index;
|
int l2_index;
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
uint64_t *l2_table;
|
uint64_t *l2_table;
|
||||||
unsigned int nb_clusters;
|
uint64_t nb_clusters;
|
||||||
unsigned int keep_clusters;
|
unsigned int keep_clusters;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -979,6 +982,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
|
||||||
|
|
||||||
l2_index = offset_to_l2_index(s, guest_offset);
|
l2_index = offset_to_l2_index(s, guest_offset);
|
||||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||||
|
assert(nb_clusters <= INT_MAX);
|
||||||
|
|
||||||
/* Find L2 entry for the first involved cluster */
|
/* Find L2 entry for the first involved cluster */
|
||||||
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
|
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
|
||||||
|
@ -1061,7 +1065,7 @@ out:
|
||||||
* restarted, but the whole request should not be failed.
|
* restarted, but the whole request should not be failed.
|
||||||
*/
|
*/
|
||||||
static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
||||||
uint64_t *host_offset, unsigned int *nb_clusters)
|
uint64_t *host_offset, uint64_t *nb_clusters)
|
||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
|
|
||||||
|
@ -1079,7 +1083,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
||||||
*host_offset = cluster_offset;
|
*host_offset = cluster_offset;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
int ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
|
int64_t ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1115,7 +1119,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
|
||||||
int l2_index;
|
int l2_index;
|
||||||
uint64_t *l2_table;
|
uint64_t *l2_table;
|
||||||
uint64_t entry;
|
uint64_t entry;
|
||||||
unsigned int nb_clusters;
|
uint64_t nb_clusters;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
uint64_t alloc_cluster_offset;
|
uint64_t alloc_cluster_offset;
|
||||||
|
@ -1133,6 +1137,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
|
||||||
|
|
||||||
l2_index = offset_to_l2_index(s, guest_offset);
|
l2_index = offset_to_l2_index(s, guest_offset);
|
||||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||||
|
assert(nb_clusters <= INT_MAX);
|
||||||
|
|
||||||
/* Find L2 entry for the first involved cluster */
|
/* Find L2 entry for the first involved cluster */
|
||||||
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
|
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
|
||||||
|
@ -1426,7 +1431,8 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
||||||
* clusters.
|
* clusters.
|
||||||
*/
|
*/
|
||||||
static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
unsigned int nb_clusters, enum qcow2_discard_type type, bool full_discard)
|
uint64_t nb_clusters, enum qcow2_discard_type type,
|
||||||
|
bool full_discard)
|
||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
uint64_t *l2_table;
|
uint64_t *l2_table;
|
||||||
|
@ -1441,6 +1447,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
|
|
||||||
/* Limit nb_clusters to one L2 table */
|
/* Limit nb_clusters to one L2 table */
|
||||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||||
|
assert(nb_clusters <= INT_MAX);
|
||||||
|
|
||||||
for (i = 0; i < nb_clusters; i++) {
|
for (i = 0; i < nb_clusters; i++) {
|
||||||
uint64_t old_l2_entry;
|
uint64_t old_l2_entry;
|
||||||
|
@ -1503,7 +1510,7 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
uint64_t end_offset;
|
uint64_t end_offset;
|
||||||
unsigned int nb_clusters;
|
uint64_t nb_clusters;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
end_offset = offset + (nb_sectors << BDRV_SECTOR_BITS);
|
end_offset = offset + (nb_sectors << BDRV_SECTOR_BITS);
|
||||||
|
@ -1545,7 +1552,7 @@ fail:
|
||||||
* clusters.
|
* clusters.
|
||||||
*/
|
*/
|
||||||
static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
|
static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
unsigned int nb_clusters)
|
uint64_t nb_clusters)
|
||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
uint64_t *l2_table;
|
uint64_t *l2_table;
|
||||||
|
@ -1560,6 +1567,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
|
|
||||||
/* Limit nb_clusters to one L2 table */
|
/* Limit nb_clusters to one L2 table */
|
||||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||||
|
assert(nb_clusters <= INT_MAX);
|
||||||
|
|
||||||
for (i = 0; i < nb_clusters; i++) {
|
for (i = 0; i < nb_clusters; i++) {
|
||||||
uint64_t old_offset;
|
uint64_t old_offset;
|
||||||
|
@ -1584,7 +1592,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
|
int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
|
||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
unsigned int nb_clusters;
|
uint64_t nb_clusters;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* The zero flag is only supported by version 3 and newer */
|
/* The zero flag is only supported by version 3 and newer */
|
||||||
|
|
|
@ -875,8 +875,8 @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||||
int nb_clusters)
|
int64_t nb_clusters)
|
||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
uint64_t cluster_index, refcount;
|
uint64_t cluster_index, refcount;
|
||||||
|
@ -1259,7 +1259,7 @@ static size_t refcount_array_byte_size(BDRVQcow2State *s, uint64_t entries)
|
||||||
static int realloc_refcount_array(BDRVQcow2State *s, void **array,
|
static int realloc_refcount_array(BDRVQcow2State *s, void **array,
|
||||||
int64_t *size, int64_t new_size)
|
int64_t *size, int64_t new_size)
|
||||||
{
|
{
|
||||||
size_t old_byte_size, new_byte_size;
|
int64_t old_byte_size, new_byte_size;
|
||||||
void *new_ptr;
|
void *new_ptr;
|
||||||
|
|
||||||
/* Round to clusters so the array can be directly written to disk */
|
/* Round to clusters so the array can be directly written to disk */
|
||||||
|
@ -1275,13 +1275,17 @@ static int realloc_refcount_array(BDRVQcow2State *s, void **array,
|
||||||
|
|
||||||
assert(new_byte_size > 0);
|
assert(new_byte_size > 0);
|
||||||
|
|
||||||
|
if (new_byte_size > SIZE_MAX) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
new_ptr = g_try_realloc(*array, new_byte_size);
|
new_ptr = g_try_realloc(*array, new_byte_size);
|
||||||
if (!new_ptr) {
|
if (!new_ptr) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_byte_size > old_byte_size) {
|
if (new_byte_size > old_byte_size) {
|
||||||
memset((void *)((uintptr_t)new_ptr + old_byte_size), 0,
|
memset((char *)new_ptr + old_byte_size, 0,
|
||||||
new_byte_size - old_byte_size);
|
new_byte_size - old_byte_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -415,7 +415,7 @@ static inline int64_t offset_into_cluster(BDRVQcow2State *s, int64_t offset)
|
||||||
return offset & (s->cluster_size - 1);
|
return offset & (s->cluster_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int size_to_clusters(BDRVQcow2State *s, int64_t size)
|
static inline uint64_t size_to_clusters(BDRVQcow2State *s, uint64_t size)
|
||||||
{
|
{
|
||||||
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
|
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
|
||||||
}
|
}
|
||||||
|
@ -509,8 +509,8 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
|
||||||
enum qcow2_discard_type type);
|
enum qcow2_discard_type type);
|
||||||
|
|
||||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
|
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
|
||||||
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||||
int nb_clusters);
|
int64_t nb_clusters);
|
||||||
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
|
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
|
||||||
void qcow2_free_clusters(BlockDriverState *bs,
|
void qcow2_free_clusters(BlockDriverState *bs,
|
||||||
int64_t offset, int64_t size,
|
int64_t offset, int64_t size,
|
||||||
|
|
Loading…
Reference in New Issue