From bc9f0fdc346f14cc423b2a074f534a50d860f61c Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 3 Sep 2018 22:18:34 +0200 Subject: [PATCH] nova: lock pager object state during fault lookup Fixes #2950 --- repos/base-nova/src/core/include/pager.h | 2 -- repos/base-nova/src/core/pager.cc | 41 +++++++++++++++--------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/repos/base-nova/src/core/include/pager.h b/repos/base-nova/src/core/include/pager.h index 4ab1d8f03..1e79a909b 100644 --- a/repos/base-nova/src/core/include/pager.h +++ b/repos/base-nova/src/core/include/pager.h @@ -306,8 +306,6 @@ namespace Genode { */ void unresolved_page_fault_occurred() { - Lock::Guard _state_lock_guard(_state_lock); - _state.thread.unresolved_page_fault = true; } diff --git a/repos/base-nova/src/core/pager.cc b/repos/base-nova/src/core/pager.cc index f1fbba128..b7711a5d8 100644 --- a/repos/base-nova/src/core/pager.cc +++ b/repos/base-nova/src/core/pager.cc @@ -121,6 +121,20 @@ void Pager_object::_page_fault_handler(addr_t pager_obj) if (utcb->msg_words() == 1) _invoke_handler(pager_obj); + /* + * obj->pager() (pager thread) may issue a signal to the remote region + * handler thread which may respond via wake_up() (ep thread) before + * we are done here - we have to lock the whole page lookup procedure + */ + obj->_state_lock.lock(); + + obj->_state.thread.ip = ipc_pager.fault_ip(); + obj->_state.thread.sp = 0; + obj->_state.thread.trapno = PT_SEL_PAGE_FAULT; + + obj->_state.block(); + obj->_state.block_pause_sm(); + /* lookup fault address and decide what to do */ int error = obj->pager(ipc_pager); @@ -135,30 +149,25 @@ void Pager_object::_page_fault_handler(addr_t pager_obj) /* dst pd has not enough kernel quota ? - try to recover */ if (ipc_pager.syscall_result() == Nova::NOVA_PD_OOM) { uint8_t res = obj->handle_oom(); - if (res == Nova::NOVA_PD_OOM) + if (res == Nova::NOVA_PD_OOM) { + obj->_state.unblock_pause_sm(); + obj->_state.unblock(); + obj->_state_lock.unlock(); /* block until revoke is due */ ipc_pager.reply_and_wait_for_fault(obj->sel_sm_block_oom()); - else if (res == Nova::NOVA_OK) + } else if (res == Nova::NOVA_OK) /* succeeded to recover - continue normally */ error = 0; } } /* good case - found a valid region which is mappable */ - if (!error) + if (!error) { + obj->_state.unblock_pause_sm(); + obj->_state.unblock(); + obj->_state_lock.unlock(); ipc_pager.reply_and_wait_for_fault(); - - - obj->_state_lock.lock(); - - obj->_state.thread.ip = ipc_pager.fault_ip(); - obj->_state.thread.sp = 0; - obj->_state.thread.trapno = PT_SEL_PAGE_FAULT; - - obj->_state.block(); - obj->_state.block_pause_sm(); - - obj->_state_lock.unlock(); + } const char * client_thread = obj->client_thread(); const char * client_pd = obj->client_pd(); @@ -173,6 +182,8 @@ void Pager_object::_page_fault_handler(addr_t pager_obj) /* region manager fault - to be handled */ log("page fault, ", fault_info, " reason=", error); + obj->_state_lock.unlock(); + /* block the faulting thread until region manager is done */ ipc_pager.reply_and_wait_for_fault(obj->sel_sm_block_pause()); }