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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user