On Tue, Sep 18, 2012 at 11:40 AM, Kevin Wolf <kw...@redhat.com> wrote: > Signed-off-by: Kevin Wolf <kw...@redhat.com> > --- > block/qcow2-cluster.c | 29 +++++++++++++++++++++++++++++ > block/qcow2.c | 31 ++++++++++++++++++++++++++++--- > block/qcow2.h | 10 ++++++++++ > 3 files changed, 67 insertions(+), 3 deletions(-) > > diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c > index a89d68d..0f50888 100644 > --- a/block/qcow2-cluster.c > +++ b/block/qcow2-cluster.c > @@ -791,6 +791,34 @@ out: > return i; > } > > +struct KickL2Meta { > + QEMUBH *bh; > + QCowL2Meta *m; > +}; > + > +static void kick_l2meta_bh(void *opaque) > +{ > + struct KickL2Meta *k = opaque; > + QCowL2Meta *m = k->m; > + > + qemu_bh_delete(k->bh); > + free(k);
You use g_malloc() below. > + > + if (m->sleeping) { > + qemu_coroutine_enter(m->co, NULL); > + } > +} > + > +static void kick_l2meta(QCowL2Meta *m) > +{ > + struct KickL2Meta *k = g_malloc(sizeof(*k)); > + > + k->bh = qemu_bh_new(kick_l2meta_bh, k); > + k->m = m; > + > + qemu_bh_schedule(k->bh); > +} > + > /* > * Check if there already is an AIO write request in flight which allocates > * the same cluster. In this case we need to wait until the previous > @@ -823,6 +851,7 @@ static int handle_dependencies(BlockDriverState *bs, > uint64_t guest_offset, > /* Wait for the dependency to complete. We need to recheck > * the free/allocated clusters when we continue. */ > qemu_co_mutex_unlock(&s->lock); > + kick_l2meta(old_alloc); > qemu_co_queue_wait(&old_alloc->dependent_requests); > qemu_co_mutex_lock(&s->lock); > return -EAGAIN; > diff --git a/block/qcow2.c b/block/qcow2.c > index f9881d0..2e220c7 100644 > --- a/block/qcow2.c > +++ b/block/qcow2.c > @@ -765,6 +765,12 @@ static void coroutine_fn process_l2meta(void *opaque) > BDRVQcowState *s = bs->opaque; > int ret; > > + if (!s->in_l2meta_flush) { > + m->sleeping = true; > + co_sleep_ns(rt_clock, 1000000); > + m->sleeping = false; > + } > + > qemu_co_mutex_lock(&s->lock); > > ret = qcow2_alloc_cluster_link_l2(bs, m); > @@ -781,17 +787,37 @@ static void coroutine_fn process_l2meta(void *opaque) > > static inline coroutine_fn void stop_l2meta(BDRVQcowState *s) > { > + QCowL2Meta *m; > + > + s->in_l2meta_flush = true; > +again: > + QLIST_FOREACH(m, &s->cluster_allocs, next_in_flight) { > + if (m->sleeping) { > + qemu_coroutine_enter(m->co, NULL); > + /* next_in_flight link could have become invalid */ > + goto again; > + } > + } > + > qemu_co_rwlock_wrlock(&s->l2meta_flush); > } > > static inline coroutine_fn void resume_l2meta(BDRVQcowState *s) > { > + s->in_l2meta_flush = false; > qemu_co_rwlock_unlock(&s->l2meta_flush); > } > > static bool qcow2_drain(BlockDriverState *bs) > { > BDRVQcowState *s = bs->opaque; > + QCowL2Meta *m; > + > + QLIST_FOREACH(m, &s->cluster_allocs, next_in_flight) { > + if (m->sleeping) { > + qemu_coroutine_enter(m->co, NULL); > + } > + } > > return !QLIST_EMPTY(&s->cluster_allocs); > } > @@ -876,7 +902,6 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState > *bs, > } > > if (l2meta != NULL) { > - Coroutine *co; > ProcessL2Meta p = { > .bs = bs, > .m = l2meta, > @@ -886,8 +911,8 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState > *bs, > qemu_co_rwlock_rdlock(&s->l2meta_flush); > > l2meta->is_written = true; > - co = qemu_coroutine_create(process_l2meta); > - qemu_coroutine_enter(co, &p); > + l2meta->co = qemu_coroutine_create(process_l2meta); > + qemu_coroutine_enter(l2meta->co, &p); > > l2meta = NULL; > qemu_co_mutex_lock(&s->lock); > diff --git a/block/qcow2.h b/block/qcow2.h > index 73dac17..8bf145c 100644 > --- a/block/qcow2.h > +++ b/block/qcow2.h > @@ -169,6 +169,7 @@ typedef struct BDRVQcowState { > * Writers: Anyone who requires l2meta to be flushed > */ > CoRwlock l2meta_flush; > + bool in_l2meta_flush; > > uint32_t crypt_method; /* current crypt method, 0 if no key yet */ > uint32_t crypt_method_header; > @@ -245,6 +246,15 @@ typedef struct QCowL2Meta > bool is_written; > > /** > + * true if the request is sleeping in the COW delay and the coroutine may > + * be reentered in order to cancel the timer. > + */ > + bool sleeping; > + > + /** Coroutine that handles delayed COW and updates L2 entry */ > + Coroutine *co; > + > + /** > * Requests that overlap with this allocation and wait to be restarted > * when the allocating request has completed. > */ > -- > 1.7.6.5 > >