Signed-off-by: Kevin Wolf <kw...@redhat.com> --- block/qcow2-cluster.c | 26 ++++++++++++++++---------- block/qcow2.h | 11 +++++++++++ 2 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 4d5c3da..440fdbf 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -825,29 +825,29 @@ static void kick_l2meta(QCowL2Meta *m) * request has completed and updated the L2 table accordingly. */ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, - unsigned int *nb_clusters) + uint64_t bytes, unsigned int *nb_clusters) { BDRVQcowState *s = bs->opaque; QCowL2Meta *old_alloc; QLIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) { - uint64_t start = guest_offset >> s->cluster_bits; - uint64_t end = start + *nb_clusters; - uint64_t old_start = old_alloc->offset >> s->cluster_bits; - uint64_t old_end = old_start + old_alloc->nb_clusters; + uint64_t start = guest_offset; + uint64_t end = start + bytes; + uint64_t old_start = l2meta_cow_start(old_alloc); + uint64_t old_end = l2meta_cow_end(old_alloc); - if (end < old_start || start > old_end) { + if (end <= old_start || start >= old_end) { /* No intersection */ } else { if (start < old_start) { /* Stop at the start of a running allocation */ - *nb_clusters = old_start - start; + bytes = old_start - start; } else { - *nb_clusters = 0; + bytes = 0; } - if (*nb_clusters == 0) { + if (bytes == 0) { /* Wait for the dependency to complete. We need to recheck * the free/allocated clusters when we continue. */ qemu_co_mutex_unlock(&s->lock); @@ -859,6 +859,9 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, } } + *nb_clusters = size_to_clusters(s, guest_offset + bytes) + - (guest_offset >> s->cluster_bits); + if (!*nb_clusters) { abort(); } @@ -952,6 +955,7 @@ again: l2_index = offset_to_l2_index(s, offset); nb_clusters = MIN(size_to_clusters(s, n_end << BDRV_SECTOR_BITS), s->l2_size - l2_index); + n_end = MIN(n_end, nb_clusters * s->cluster_sectors); /* * Now start gathering as many contiguous clusters as possible: @@ -976,7 +980,9 @@ again: * 3. If the request still hasn't completed, allocate new clusters, * considering any cluster_offset of steps 1c or 2. */ - ret = handle_dependencies(bs, offset, &nb_clusters); + ret = handle_dependencies(bs, offset, + (n_end - n_start) * BDRV_SECTOR_SIZE, + &nb_clusters); if (ret == -EAGAIN) { goto again; } else if (ret < 0) { diff --git a/block/qcow2.h b/block/qcow2.h index eb94463..06ca195 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -343,6 +343,17 @@ static inline uint64_t l2meta_req_end(QCowL2Meta *m) return m->offset + (m->nb_available << BDRV_SECTOR_BITS); } +static inline uint64_t l2meta_cow_start(QCowL2Meta *m) +{ + return m->offset + m->cow_start.offset; +} + +static inline uint64_t l2meta_cow_end(QCowL2Meta *m) +{ + return m->offset + m->cow_end.offset + + (m->cow_end.nb_sectors << BDRV_SECTOR_BITS); +} + // FIXME Need qcow2_ prefix to global functions /* qcow2.c functions */ -- 1.7.6.5