diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-02-09 17:56:45 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-02-09 17:56:46 +0000 |
commit | f075c89f0a9cb31daf38892371d2822177505706 (patch) | |
tree | 72296f7ce1446b3809c749a2e15f4eb76f1aa61f | |
parent | 84c0781103dcbe9b5e5433ba16fbeb55d69d6cb7 (diff) | |
parent | 9dcf8ecd9e74804aa1687e5688386001a1f3f89f (diff) |
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
# gpg: Signature made Tue 09 Feb 2016 15:11:25 GMT using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>"
* remotes/stefanha/tags/block-pull-request:
block: add missing call to bdrv_drain_recurse
blockjob: Fix hang in block_job_finish_sync
iov: avoid memcpy for "simple" iov_from_buf/iov_to_buf
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | block/io.c | 1 | ||||
-rw-r--r-- | blockjob.c | 6 | ||||
-rw-r--r-- | include/block/blockjob.h | 5 | ||||
-rw-r--r-- | include/qemu/iov.h | 34 | ||||
-rw-r--r-- | util/iov.c | 8 |
5 files changed, 45 insertions, 9 deletions
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; |