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
This commit is contained in:
David van Moolenbroek 2015-09-04 07:04:17 +02:00
parent 0e78c0166c
commit 37489f8a24
4 changed files with 29 additions and 3 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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);