[sheepdog] [PATCH] event: refresh event info after unregistering
MORITA Kazutaka
morita.kazutaka at gmail.com
Thu Aug 22 05:37:35 CEST 2013
From: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
The current code causes a segfault with the following scenario:
1. Both worker_thread_request_done() event and client_handler() event
become ready with epoll_wait() in do_event_loop().
2. do_event_loop() calls worker_thread_request_done(), and it calls
clear_client_info(). This can happen when the client connection
is already closed (e.g. in put_request(), tx_main()).
3. clear_client_info() calls unregister_event(), and it frees the
client_handler() event.
3. do_event_loop() tries to call client_handler() but the event is
already freed and no longer valid.
To fix the problem, this patch calls event_force_refresh() in
unregister_event() and make do_event_loop() call epoll_wait() again.
Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
lib/event.c | 11 ++++++++---
shepherd/shepherd.c | 2 --
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/lib/event.c b/lib/event.c
index 55f94a2..f3af3e8 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -136,6 +136,12 @@ void unregister_event(int fd)
list_del(&ei->ei_list);
free(ei);
+
+ /*
+ * Although ei is no longer valid pointer, ei->handler() might be about
+ * to be called in do_event_loop(). Refreshing the event loop is safe.
+ */
+ event_force_refresh();
}
int modify_event(int fd, unsigned int new_events)
@@ -185,6 +191,7 @@ static void do_event_loop(int timeout, bool sort_with_prio)
int i, nr;
refresh:
+ event_loop_refresh = false;
nr = epoll_wait(efd, events, nr_events, timeout);
if (sort_with_prio)
xqsort(events, nr, epoll_event_cmp);
@@ -201,10 +208,8 @@ refresh:
ei = (struct event_info *)events[i].data.ptr;
ei->handler(ei->fd, events[i].events, ei->data);
- if (event_loop_refresh) {
- event_loop_refresh = false;
+ if (event_loop_refresh)
goto refresh;
- }
}
}
}
diff --git a/shepherd/shepherd.c b/shepherd/shepherd.c
index 33670d5..fd59229 100644
--- a/shepherd/shepherd.c
+++ b/shepherd/shepherd.c
@@ -183,8 +183,6 @@ del:
list_del(&s->join_wait_list);
free(s);
- event_force_refresh();
-
if (--nr_removed)
goto remove;
--
1.7.9.5
More information about the sheepdog
mailing list