[sheepdog] [PATCH stable-0.7] event: refresh event info after unregistering

Hitoshi Mitake mitake.hitoshi at gmail.com
Tue Sep 3 17:45:41 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>
Signed-off-by: Liu Yuan <namei.unix at gmail.com>
---
 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 d949d68..7d3421e 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -137,6 +137,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)
@@ -186,6 +192,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);
@@ -202,10 +209,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 77c09fb..a3e67a0 100644
--- a/shepherd/shepherd.c
+++ b/shepherd/shepherd.c
@@ -184,8 +184,6 @@ del:
 	list_del(&s->join_wait_list);
 	free(s);
 
-	event_force_refresh();
-
 	if (--nr_removed)
 		goto remove;
 
-- 
1.8.1.2




More information about the sheepdog mailing list