From: David van Moolenbroek Date: Fri, 4 Sep 2015 05:04:17 +0000 (+0200) Subject: Resolve boot-time VM/RS deadlock X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zpipe.c?a=commitdiff_plain;h=37489f8a24b995dfc498de35eba6b007cf912182;p=minix.git Resolve boot-time VM/RS deadlock VM used to call sendrec to send a boot-time RS_INIT reply to RS, but RS could run into a pagefault at the same time, thus spawning a message to VM, resulting in a deadlock. We resolve this situation by making VM acknowledge RS_INIT asynchronously at boot time, while retaining the synchronous sendrec for subsequent RS_INIT responses. Change-Id: I3cb72d7f8d6b9bfdc59a85958ada739c37fa3bde --- diff --git a/minix/include/minix/sef.h b/minix/include/minix/sef.h index dc5a1beed..4613610ce 100644 --- a/minix/include/minix/sef.h +++ b/minix/include/minix/sef.h @@ -73,6 +73,7 @@ int sef_cb_init_identity_state_transfer(int type, sef_init_info_t *info); int sef_cb_init_lu_identity_as_restart(int type, sef_init_info_t *info); int sef_cb_init_lu_generic(int type, sef_init_info_t *info); int sef_cb_init_response_rs_reply(message *m_ptr); +int sef_cb_init_response_rs_asyn_once(message *m_ptr); /* Macros for predefined callback implementations. */ #define SEF_CB_INIT_FRESH_NULL sef_cb_init_null diff --git a/minix/lib/libsys/sef_init.c b/minix/lib/libsys/sef_init.c index 876e35f45..7b229717b 100644 --- a/minix/lib/libsys/sef_init.c +++ b/minix/lib/libsys/sef_init.c @@ -434,3 +434,19 @@ int sef_cb_init_response_rs_reply(message *m_ptr) return r; } +/*===========================================================================* + * sef_cb_init_response_rs_asyn_once * + *===========================================================================*/ +int sef_cb_init_response_rs_asyn_once(message *m_ptr) +{ +/* This response function is used by VM to avoid a boot-time deadlock. */ + int r; + + /* Inform RS that we completed initialization, asynchronously. */ + r = asynsend3(RS_PROC_NR, m_ptr, AMF_NOREPLY); + + /* Use a blocking reply call next time. */ + sef_setcb_init_response(SEF_CB_INIT_RESPONSE_DEFAULT); + + return r; +} diff --git a/minix/servers/rs/main.c b/minix/servers/rs/main.c index ce3f320c2..6fd432bf7 100644 --- a/minix/servers/rs/main.c +++ b/minix/servers/rs/main.c @@ -807,9 +807,13 @@ endpoint_t endpoint; panic("unable to complete init for service: %d", m.m_source); } - /* Send a reply to unblock the service. */ - m.m_type = OK; - reply(m.m_source, rp, &m); + /* Send a reply to unblock the service, except to VM, which sent the reply + * asynchronously. Synchronous replies could lead to deadlocks there. + */ + if (m.m_source != VM_PROC_NR) { + m.m_type = OK; + reply(m.m_source, rp, &m); + } /* Mark the slot as no longer initializing. */ rp->r_flags &= ~RS_INITIALIZING; diff --git a/minix/servers/vm/main.c b/minix/servers/vm/main.c index 29ead3174..38800f498 100644 --- a/minix/servers/vm/main.c +++ b/minix/servers/vm/main.c @@ -200,6 +200,11 @@ static void sef_local_startup(void) sef_setcb_init_fresh(sef_cb_init_fresh); sef_setcb_init_lu(sef_cb_init_lu_restart); sef_setcb_init_restart(sef_cb_init_lu_restart); + /* In order to avoid a deadlock at boot time, send the first RS_INIT + * reply to RS asynchronously. After that, use sendrec as usual. + */ + if (__vm_init_fresh) + sef_setcb_init_response(sef_cb_init_response_rs_asyn_once); /* Register signal callbacks. */ sef_setcb_signal_handler(sef_cb_signal_handler);