mirror of https://github.com/xemu-project/xemu.git
qcow2: Allow qcow2_get_cluster_offset to return errors
qcow2_get_cluster_offset() looks up a given virtual disk offset and returns the offset of the corresponding cluster in the image file. Errors (e.g. L2 table can't be read) are currenctly indicated by a return value of 0, which is unfortuately the same as for any unallocated cluster. So in effect we can't check for errors. This makes the old return value a by-reference parameter and returns the usual 0/-errno error code. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
c63782cbe8
commit
1c46efaa0a
|
@ -345,7 +345,13 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
|
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
n = nb_sectors;
|
n = nb_sectors;
|
||||||
cluster_offset = qcow2_get_cluster_offset(bs, sector_num << 9, &n);
|
|
||||||
|
ret = qcow2_get_cluster_offset(bs, sector_num << 9, &n,
|
||||||
|
&cluster_offset);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||||
if (!cluster_offset) {
|
if (!cluster_offset) {
|
||||||
if (bs->backing_hd) {
|
if (bs->backing_hd) {
|
||||||
|
@ -412,25 +418,25 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
|
||||||
/*
|
/*
|
||||||
* get_cluster_offset
|
* get_cluster_offset
|
||||||
*
|
*
|
||||||
* For a given offset of the disk image, return cluster offset in
|
* For a given offset of the disk image, find the cluster offset in
|
||||||
* qcow2 file.
|
* qcow2 file. The offset is stored in *cluster_offset.
|
||||||
*
|
*
|
||||||
* on entry, *num is the number of contiguous clusters we'd like to
|
* on entry, *num is the number of contiguous clusters we'd like to
|
||||||
* access following offset.
|
* access following offset.
|
||||||
*
|
*
|
||||||
* on exit, *num is the number of contiguous clusters we can read.
|
* on exit, *num is the number of contiguous clusters we can read.
|
||||||
*
|
*
|
||||||
* Return 1, if the offset is found
|
* Return 0, if the offset is found
|
||||||
* Return 0, otherwise.
|
* Return -errno, otherwise.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int *num)
|
int *num, uint64_t *cluster_offset)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
unsigned int l1_index, l2_index;
|
unsigned int l1_index, l2_index;
|
||||||
uint64_t l2_offset, *l2_table, cluster_offset;
|
uint64_t l2_offset, *l2_table;
|
||||||
int l1_bits, c;
|
int l1_bits, c;
|
||||||
unsigned int index_in_cluster, nb_clusters;
|
unsigned int index_in_cluster, nb_clusters;
|
||||||
uint64_t nb_available, nb_needed;
|
uint64_t nb_available, nb_needed;
|
||||||
|
@ -454,7 +460,7 @@ uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
nb_needed = nb_available;
|
nb_needed = nb_available;
|
||||||
}
|
}
|
||||||
|
|
||||||
cluster_offset = 0;
|
*cluster_offset = 0;
|
||||||
|
|
||||||
/* seek the the l2 offset in the l1 table */
|
/* seek the the l2 offset in the l1 table */
|
||||||
|
|
||||||
|
@ -473,16 +479,17 @@ uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
|
|
||||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
l2_offset &= ~QCOW_OFLAG_COPIED;
|
||||||
l2_table = l2_load(bs, l2_offset);
|
l2_table = l2_load(bs, l2_offset);
|
||||||
if (l2_table == NULL)
|
if (l2_table == NULL) {
|
||||||
return 0;
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
/* find the cluster offset for the given disk offset */
|
/* find the cluster offset for the given disk 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_clusters = size_to_clusters(s, nb_needed << 9);
|
nb_clusters = size_to_clusters(s, nb_needed << 9);
|
||||||
|
|
||||||
if (!cluster_offset) {
|
if (!*cluster_offset) {
|
||||||
/* how many empty clusters ? */
|
/* how many empty clusters ? */
|
||||||
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
|
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -498,7 +505,8 @@ out:
|
||||||
|
|
||||||
*num = nb_available - index_in_cluster;
|
*num = nb_available - index_in_cluster;
|
||||||
|
|
||||||
return cluster_offset & ~QCOW_OFLAG_COPIED;
|
*cluster_offset &=~QCOW_OFLAG_COPIED;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -297,9 +297,15 @@ static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors, int *pnum)
|
int nb_sectors, int *pnum)
|
||||||
{
|
{
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
|
int ret;
|
||||||
|
|
||||||
*pnum = nb_sectors;
|
*pnum = nb_sectors;
|
||||||
cluster_offset = qcow2_get_cluster_offset(bs, sector_num << 9, pnum);
|
/* FIXME We can get errors here, but the bdrv_is_allocated interface can't
|
||||||
|
* pass them on today */
|
||||||
|
ret = qcow2_get_cluster_offset(bs, sector_num << 9, pnum, &cluster_offset);
|
||||||
|
if (ret < 0) {
|
||||||
|
*pnum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return (cluster_offset != 0);
|
return (cluster_offset != 0);
|
||||||
}
|
}
|
||||||
|
@ -409,8 +415,12 @@ static void qcow_aio_read_cb(void *opaque, int ret)
|
||||||
|
|
||||||
/* prepare next AIO request */
|
/* prepare next AIO request */
|
||||||
acb->cur_nr_sectors = acb->remaining_sectors;
|
acb->cur_nr_sectors = acb->remaining_sectors;
|
||||||
acb->cluster_offset = qcow2_get_cluster_offset(bs, acb->sector_num << 9,
|
ret = qcow2_get_cluster_offset(bs, acb->sector_num << 9,
|
||||||
&acb->cur_nr_sectors);
|
&acb->cur_nr_sectors, &acb->cluster_offset);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
|
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
|
||||||
|
|
||||||
if (!acb->cluster_offset) {
|
if (!acb->cluster_offset) {
|
||||||
|
|
|
@ -196,8 +196,8 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
||||||
int nb_sectors, int enc,
|
int nb_sectors, int enc,
|
||||||
const AES_KEY *key);
|
const AES_KEY *key);
|
||||||
|
|
||||||
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int *num);
|
int *num, uint64_t *cluster_offset);
|
||||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int n_start, int n_end, int *num, QCowL2Meta *m);
|
int n_start, int n_end, int *num, QCowL2Meta *m);
|
||||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||||
|
|
Loading…
Reference in New Issue