From 611382968069f54914e3cfff30f2a3b92c6219cd Mon Sep 17 00:00:00 2001 From: Rao Lei Date: Fri, 14 Jan 2022 13:09:02 +0800 Subject: [PATCH] net/filter: Optimize filter_send to coroutine This patch is to improve the logic of QEMU main thread sleep code in qemu_chr_write_buffer() where it can be blocked and can't run other coroutines during COLO IO stress test. Our approach is to put filter_send() in a coroutine. In this way, filter_send() will call qemu_coroutine_yield() in qemu_co_sleep_ns(), so that it can be scheduled out and QEMU main thread has opportunity to run other tasks. Signed-off-by: Lei Rao Signed-off-by: Zhang Chen Reviewed-by: Li Zhijian Reviewed-by: Zhang Chen Signed-off-by: Jason Wang --- net/filter-mirror.c | 66 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/net/filter-mirror.c b/net/filter-mirror.c index f20240cc9f..34a63b5dbb 100644 --- a/net/filter-mirror.c +++ b/net/filter-mirror.c @@ -20,6 +20,7 @@ #include "chardev/char-fe.h" #include "qemu/iov.h" #include "qemu/sockets.h" +#include "block/aio-wait.h" #define TYPE_FILTER_MIRROR "filter-mirror" typedef struct MirrorState MirrorState; @@ -42,20 +43,21 @@ struct MirrorState { bool vnet_hdr; }; -static int filter_send(MirrorState *s, - const struct iovec *iov, - int iovcnt) +typedef struct FilterSendCo { + MirrorState *s; + char *buf; + ssize_t size; + bool done; + int ret; +} FilterSendCo; + +static int _filter_send(MirrorState *s, + char *buf, + ssize_t size) { NetFilterState *nf = NETFILTER(s); int ret = 0; - ssize_t size = 0; uint32_t len = 0; - char *buf; - - size = iov_size(iov, iovcnt); - if (!size) { - return 0; - } len = htonl(size); ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len)); @@ -80,10 +82,7 @@ static int filter_send(MirrorState *s, } } - buf = g_malloc(size); - iov_to_buf(iov, iovcnt, 0, buf, size); ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size); - g_free(buf); if (ret != size) { goto err; } @@ -94,6 +93,47 @@ err: return ret < 0 ? ret : -EIO; } +static void coroutine_fn filter_send_co(void *opaque) +{ + FilterSendCo *data = opaque; + + data->ret = _filter_send(data->s, data->buf, data->size); + data->done = true; + g_free(data->buf); + aio_wait_kick(); +} + +static int filter_send(MirrorState *s, + const struct iovec *iov, + int iovcnt) +{ + ssize_t size = iov_size(iov, iovcnt); + char *buf = NULL; + + if (!size) { + return 0; + } + + buf = g_malloc(size); + iov_to_buf(iov, iovcnt, 0, buf, size); + + FilterSendCo data = { + .s = s, + .size = size, + .buf = buf, + .ret = 0, + }; + + Coroutine *co = qemu_coroutine_create(filter_send_co, &data); + qemu_coroutine_enter(co); + + while (!data.done) { + aio_poll(qemu_get_aio_context(), true); + } + + return data.ret; +} + static void redirector_to_filter(NetFilterState *nf, const uint8_t *buf, int len)