From bce0f49d8a8959391de761dca22e2dae4c01182d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 8 Jun 2010 11:12:45 -0300 Subject: [PATCH 03/13] qcow2: Allow qcow2_get_cluster_offset to return errors RH-Author: Kevin Wolf Message-id: <1275995574-17666-3-git-send-email-kwolf@redhat.com> Patchwork-id: 9767 O-Subject: [RHEL-6 qemu-kvm PATCH v2 02/11] qcow2: Allow qcow2_get_cluster_offset to return errors Bugzilla: 598507 RH-Acked-by: Christoph Hellwig RH-Acked-by: Jes Sorensen RH-Acked-by: Juan Quintela Bugzilla: 598507 Upstream status: Submitted 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 (cherry picked from commit 49fc34e6e6ebb0e479c1b7cdc8d40a4a627ebf71) --- block/qcow2-cluster.c | 36 ++++++++++++++++++++++-------------- block/qcow2.c | 16 +++++++++++++--- block/qcow2.h | 4 ++-- 3 files changed, 37 insertions(+), 19 deletions(-) Signed-off-by: Eduardo Habkost --- block/qcow2-cluster.c | 36 ++++++++++++++++++++++-------------- block/qcow2.c | 16 +++++++++++++--- block/qcow2.h | 4 ++-- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index c11680d..36a3fea 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -342,7 +342,13 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, while (nb_sectors > 0) { 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); if (!cluster_offset) { if (bs->backing_hd) { @@ -409,25 +415,25 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect, /* * get_cluster_offset * - * For a given offset of the disk image, return cluster offset in - * qcow2 file. + * For a given offset of the disk image, find the cluster offset in + * qcow2 file. The offset is stored in *cluster_offset. * * on entry, *num is the number of contiguous clusters we'd like to * access following offset. * * on exit, *num is the number of contiguous clusters we can read. * - * Return 1, if the offset is found - * Return 0, otherwise. + * Return 0, if the offset is found + * Return -errno, otherwise. * */ -uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, - int *num) +int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, + int *num, uint64_t *cluster_offset) { BDRVQcowState *s = bs->opaque; unsigned int l1_index, l2_index; - uint64_t l2_offset, *l2_table, cluster_offset; + uint64_t l2_offset, *l2_table; int l1_bits, c; unsigned int index_in_cluster, nb_clusters; uint64_t nb_available, nb_needed; @@ -451,7 +457,7 @@ uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, nb_needed = nb_available; } - cluster_offset = 0; + *cluster_offset = 0; /* seek the the l2 offset in the l1 table */ @@ -470,16 +476,17 @@ uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, l2_offset &= ~QCOW_OFLAG_COPIED; l2_table = l2_load(bs, l2_offset); - if (l2_table == NULL) - return 0; + if (l2_table == NULL) { + return -EIO; + } /* find the cluster offset for the given disk offset */ 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); - if (!cluster_offset) { + if (!*cluster_offset) { /* how many empty clusters ? */ c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]); } else { @@ -495,7 +502,8 @@ out: *num = nb_available - index_in_cluster; - return cluster_offset & ~QCOW_OFLAG_COPIED; + *cluster_offset &=~QCOW_OFLAG_COPIED; + return 0; } /* diff --git a/block/qcow2.c b/block/qcow2.c index c1a54f1..6ecbae6 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -299,9 +299,15 @@ static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { uint64_t cluster_offset; + int ret; *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); } @@ -411,8 +417,12 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* prepare next AIO request */ acb->cur_nr_sectors = acb->remaining_sectors; - acb->cluster_offset = qcow2_get_cluster_offset(bs, acb->sector_num << 9, - &acb->cur_nr_sectors); + ret = qcow2_get_cluster_offset(bs, acb->sector_num << 9, + &acb->cur_nr_sectors, &acb->cluster_offset); + if (ret < 0) { + goto done; + } + index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); if (!acb->cluster_offset) { diff --git a/block/qcow2.h b/block/qcow2.h index 5bd08db..3ee72d5 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -190,8 +190,8 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, int nb_sectors, int enc, const AES_KEY *key); -uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, - int *num); +int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, + int *num, uint64_t *cluster_offset); int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, int n_start, int n_end, int *num, QCowL2Meta *m); uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, -- 1.7.0.3