72 lines
2.2 KiB
Diff
72 lines
2.2 KiB
Diff
From cc04f4c32b475ef0bf1485c5b008921ba18ad89c Mon Sep 17 00:00:00 2001
|
|
From: eabdullin <ed.abdullin.1@gmail.com>
|
|
Date: Wed, 13 Sep 2023 11:43:16 +0300
|
|
Subject: [PATCH] [PATCH] aio-posix: fix race between epoll upgrade and
|
|
aio_set_fd_handler()
|
|
|
|
If another thread calls aio_set_fd_handler() while the IOThread event
|
|
loop is upgrading from ppoll(2) to epoll(7) then we might miss new
|
|
AioHandlers. The epollfd will not monitor the new AioHandler's fd,
|
|
resulting in hangs.
|
|
|
|
Take the AioHandler list lock while upgrading to epoll. This prevents
|
|
AioHandlers from changing while epoll is being set up. If we cannot lock
|
|
because we're in a nested event loop, then don't upgrade to epoll (it
|
|
will happen next time we're not in a nested call).
|
|
|
|
The downside to taking the lock is that the aio_set_fd_handler() thread
|
|
has to wait until the epoll upgrade is finished, which involves many
|
|
epoll_ctl(2) system calls. However, this scenario is rare and I couldn't
|
|
think of another solution that is still simple.
|
|
---
|
|
util/fdmon-epoll.c | 25 ++++++++++++++++++-------
|
|
1 file changed, 18 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/util/fdmon-epoll.c b/util/fdmon-epoll.c
|
|
index e11a8a022..1683aa110 100644
|
|
--- a/util/fdmon-epoll.c
|
|
+++ b/util/fdmon-epoll.c
|
|
@@ -127,6 +127,8 @@ static bool fdmon_epoll_try_enable(AioContext *ctx)
|
|
|
|
bool fdmon_epoll_try_upgrade(AioContext *ctx, unsigned npfd)
|
|
{
|
|
+ bool ok;
|
|
+
|
|
if (ctx->epollfd < 0) {
|
|
return false;
|
|
}
|
|
@@ -136,14 +138,23 @@ bool fdmon_epoll_try_upgrade(AioContext *ctx, unsigned npfd)
|
|
return false;
|
|
}
|
|
|
|
- if (npfd >= EPOLL_ENABLE_THRESHOLD) {
|
|
- if (fdmon_epoll_try_enable(ctx)) {
|
|
- return true;
|
|
- } else {
|
|
- fdmon_epoll_disable(ctx);
|
|
- }
|
|
+ if (npfd < EPOLL_ENABLE_THRESHOLD) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /* The list must not change while we add fds to epoll */
|
|
+ if (!qemu_lockcnt_dec_if_lock(&ctx->list_lock)) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ ok = fdmon_epoll_try_enable(ctx);
|
|
+
|
|
+ qemu_lockcnt_inc_and_unlock(&ctx->list_lock);
|
|
+
|
|
+ if (!ok) {
|
|
+ fdmon_epoll_disable(ctx);
|
|
}
|
|
- return false;
|
|
+ return ok;
|
|
}
|
|
|
|
void fdmon_epoll_setup(AioContext *ctx)
|
|
--
|
|
2.39.2 (Apple Git-143)
|
|
|