On 09/20/2010 10:33 AM, Kevin Wolf wrote:
Am 20.09.2010 16:56, schrieb Anthony Liguori:
+void blkqueue_flush(BlockQueue *bq)
+{
+ qemu_mutex_lock(&bq->flush_lock);
+
+ /* Process any left over requests */
+ while (QTAILQ_FIRST(&bq->queue)) {
+ blkqueue_process_request(bq);
+ }
+
+ qemu_mutex_unlock(&bq->flush_lock);
+}
+
+static void *blkqueue_thread(void *_bq)
+{
+ BlockQueue *bq = _bq;
+#ifndef RUN_TESTS
+ BlockQueueRequest *req;
+#endif
+
+ qemu_mutex_lock(&bq->flush_lock);
+ while (!bq->thread_done) {
+ barrier();
A barrier shouldn't be needed here.
It was needed when I started with an empty thread because gcc would
"optimize" while(!bq->thread_done) into an endless loop. I guess there
is enough code added now that gcc won't try to be clever any more, so I
can remove that.
The qemu_cond_wait() will act as a read barrier.
A less invasive way of doing this (assuming we're okay with it from a
correctness perspective) is to make use of qemu_aio_wait() as a
replacement for qemu_mutex_lock() and shift the pread/pwrite calls to
bdrv_aio_write/bdrv_aio_read.
IOW, blkqueue_pwrite stages a request via bdrv_aio_write().
blkqueue_pread() either returns a cached read or it does a
bdrv_pread(). The blkqueue_flush() call will then do qemu_aio_wait() to
wait for all pending I/Os to complete.
I was actually considering that, but it would have been a bit more
coding to keep track of another queue of in-flight requests, juggling
with some more AIOCBs and implementing an emulation for the missing
bdrv_aio_pwrite. Nothing really dramatic, it just was easier to start
this way.
bdrv_aio_pwritev is definitely useful in other places so it's worth adding.
If we come to the conclusion that bdrv_aio_write is the way to go and
it's worth the work, I'm fine with changing it.
Adding locking to allow bdrv_pwrite/bdrv_pread to be safely called
outside of qemu_mutex is going to carry an awful lot of complexity since
we can do things like layer qcow2 on top of NBD. That means
bdrv_pread() may be repeatedly interacting with the main loop which
means that there's no simple place to start.
I'm not fundamentally opposed to using threads for concurrency. I think
it's going to get super complicated though to do it here.
Regards,
Anthony Liguori
Kevin