[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