When out of biglock, object will be unplugged while its bh is scheduling, using refcnt on bh->object to pin the object.
Signed-off-by: Liu Ping Fan <pingf...@linux.vnet.ibm.com> --Another choice may be -- rcu_read_lock protect aio_bh_poll() qemu_bh_delete(); smp_wmb(); object_unref(obj) reclaim object after grace period, NOTE obj is not accessed from "view", since bh->deleted guarantee that even if bh survive to next gp, bh->deleted will forbid the access to bh->cb --- async.c | 24 ++++++++++++++++++++++-- include/block/aio.h | 6 ++++++ stubs/Makefile.objs | 1 + 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/async.c b/async.c index bea3d7e..0b977b3 100644 --- a/async.c +++ b/async.c @@ -34,6 +34,10 @@ struct QEMUBH { AioContext *ctx; QEMUBHFunc *cb; void *opaque; + /* Object which is referred by bh's callback. It can be dissappear and + * should be pinned when bh is scheduling + */ + Object *obj; QEMUBH *next; bool scheduled; bool idle; @@ -73,11 +77,11 @@ int aio_bh_poll(AioContext *ctx) if (bh->scheduled) { bh->scheduled = 0; if (unlikely(bh->deleted)) { - continue; + goto release_obj; } if (unlikely(bh->canceled)) { bh->canceled = 0; - continue; + goto release_obj; } /* Paired with write barrier in bh schedule to ensure reading for * idle & callbacks coming after bh's scheduling. @@ -87,6 +91,10 @@ int aio_bh_poll(AioContext *ctx) ret = 1; bh->idle = 0; bh->cb(bh->opaque); +release_obj: + if (bh->obj) { + object_unref(bh->obj); + } } } @@ -116,6 +124,9 @@ void qemu_bh_schedule_idle(QEMUBH *bh) if (bh->scheduled) return; bh->idle = 1; + if (bh->obj) { + object_ref(bh->obj); + } /* Make sure that idle & any writes needed by the callback are done * before the locations are read in the aio_bh_poll. */ @@ -128,6 +139,9 @@ void qemu_bh_schedule(QEMUBH *bh) if (bh->scheduled) return; bh->idle = 0; + if (bh->obj) { + object_ref(bh->obj); + } /* Make sure that idle & any writes needed by the callback are done * before the locations are read in the aio_bh_poll. */ @@ -152,6 +166,12 @@ void qemu_bh_delete(QEMUBH *bh) bh->deleted = 1; } +void qemu_bh_set_obj(QEMUBH *bh, Object *obj) +{ + assert(obj); + bh->obj = obj; +} + static gboolean aio_ctx_prepare(GSource *source, gint *timeout) { diff --git a/include/block/aio.h b/include/block/aio.h index cc77771..7da93d3 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -15,6 +15,7 @@ #define QEMU_AIO_H #include "qemu-common.h" +#include "qom/object.h" #include "qemu/queue.h" #include "qemu/event_notifier.h" #include "qemu/thread.h" @@ -175,6 +176,11 @@ void qemu_bh_cancel(QEMUBH *bh); */ void qemu_bh_delete(QEMUBH *bh); +/* @obj which is referred by bh's callback. It can be dissappear and + * should be pinned when bh is scheduling. + */ +void qemu_bh_set_obj(QEMUBH *bh, Object *obj); + /* Return whether there are any pending callbacks from the GSource * attached to the AioContext. * diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 03dff20..fc80562 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -24,3 +24,4 @@ stub-obj-y += vm-stop.o stub-obj-y += vmstate.o stub-obj-$(CONFIG_WIN32) += fd-register.o stub-obj-y += cpus.o +stub-obj-y += object.o -- 1.8.1.4