diff --git a/block/io.c b/block/io.c index 343ff1f233..a69bfc4197 100644 --- a/block/io.c +++ b/block/io.c @@ -301,6 +301,7 @@ void bdrv_drain_all(void) if (bs->job) { block_job_pause(bs->job); } + bdrv_drain_recurse(bs); aio_context_release(aio_context); if (!g_slist_find(aio_ctxs, aio_context)) { diff --git a/blockjob.c b/blockjob.c index a402181835..9fc37ca965 100644 --- a/blockjob.c +++ b/blockjob.c @@ -296,7 +296,9 @@ static int block_job_finish_sync(BlockJob *job, return -EBUSY; } while (!job->completed) { - aio_poll(bdrv_get_aio_context(bs), true); + aio_poll(job->deferred_to_main_loop ? qemu_get_aio_context() : + bdrv_get_aio_context(bs), + true); } ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret; block_job_unref(job); @@ -470,6 +472,7 @@ static void block_job_defer_to_main_loop_bh(void *opaque) aio_context = bdrv_get_aio_context(data->job->bs); aio_context_acquire(aio_context); + data->job->deferred_to_main_loop = false; data->fn(data->job, data->opaque); aio_context_release(aio_context); @@ -489,6 +492,7 @@ void block_job_defer_to_main_loop(BlockJob *job, data->aio_context = bdrv_get_aio_context(job->bs); data->fn = fn; data->opaque = opaque; + job->deferred_to_main_loop = true; qemu_bh_schedule(data->bh); } diff --git a/include/block/blockjob.h b/include/block/blockjob.h index d84ccd8d2c..8bedc4936c 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -130,6 +130,11 @@ struct BlockJob { */ bool ready; + /** + * Set to true when the job has deferred work to the main loop. + */ + bool deferred_to_main_loop; + /** Status that is published by the query-block-jobs QMP API */ BlockDeviceIoStatus iostatus; diff --git a/include/qemu/iov.h b/include/qemu/iov.h index 569b2c2a23..28475516eb 100644 --- a/include/qemu/iov.h +++ b/include/qemu/iov.h @@ -39,10 +39,36 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt); * such "large" value is -1 (sinice size_t is unsigned), * so specifying `-1' as `bytes' means 'up to the end of iovec'. */ -size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt, - size_t offset, const void *buf, size_t bytes); -size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt, - size_t offset, void *buf, size_t bytes); +size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt, + size_t offset, const void *buf, size_t bytes); +size_t iov_to_buf_full(const struct iovec *iov, const unsigned int iov_cnt, + size_t offset, void *buf, size_t bytes); + +static inline size_t +iov_from_buf(const struct iovec *iov, unsigned int iov_cnt, + size_t offset, const void *buf, size_t bytes) +{ + if (__builtin_constant_p(bytes) && iov_cnt && + offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) { + memcpy(iov[0].iov_base + offset, buf, bytes); + return bytes; + } else { + return iov_from_buf_full(iov, iov_cnt, offset, buf, bytes); + } +} + +static inline size_t +iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt, + size_t offset, void *buf, size_t bytes) +{ + if (__builtin_constant_p(bytes) && iov_cnt && + offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) { + memcpy(buf, iov[0].iov_base + offset, bytes); + return bytes; + } else { + return iov_to_buf_full(iov, iov_cnt, offset, buf, bytes); + } +} /** * Set data bytes pointed out by iovec `iov' of size `iov_cnt' elements, diff --git a/util/iov.c b/util/iov.c index e802ee15bc..062f4e50c3 100644 --- a/util/iov.c +++ b/util/iov.c @@ -20,8 +20,8 @@ #include "qemu/iov.h" #include "qemu/sockets.h" -size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt, - size_t offset, const void *buf, size_t bytes) +size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt, + size_t offset, const void *buf, size_t bytes) { size_t done; unsigned int i; @@ -39,8 +39,8 @@ size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt, return done; } -size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt, - size_t offset, void *buf, size_t bytes) +size_t iov_to_buf_full(const struct iovec *iov, const unsigned int iov_cnt, + size_t offset, void *buf, size_t bytes) { size_t done; unsigned int i;