nova: avoid race in pager_object destruction

Don't skip the cleanup call if a pager object is marked as blocked.

It happens that the pager_object is in destruction but it is also used
concurrently by the pager thread. The pager thread handling code may set the
pager object to blocked but still uses the pointer to the pager object. Avoid
locking at the state of the pager object and make the cleanup call everytime.

Error output looks like this, where the pf_ip is within

  void Pager_object::_page_fault_handler(addr_t pager_obj)

method and the pf_addr is the stale pointer to the already released pager_object.

no RM attachment (READ pf_addr=xxx pf_ip=xxx from 00 <NULL>)
static void Genode::Pager_object::_page_fault_handler(Genode::addr_t): page fault, thread '<NULL>', cpu x, ip=xxx, fault address=xxx

PAGE-FAULT IN CORE (READ pf_addr=b10e0090 pf_ip=132dbc from 00 <NULL>)
This commit is contained in:
Alexander Boettcher 2015-10-12 13:17:34 +02:00 committed by Christian Helmuth
parent c4f8af2665
commit ceb04d3c11
2 changed files with 40 additions and 4 deletions

View File

@ -398,10 +398,6 @@ void Pager_object::cleanup_call()
/* revoke all portals handling the client. */
revoke(Obj_crd(exc_pt_sel_client(), NUM_INITIAL_PT_LOG2));
/* if we are paused or waiting for a page fault nothing is in-flight */
if (_state.blocked())
return;
Utcb *utcb = reinterpret_cast<Utcb *>(Thread_base::myself()->utcb());
utcb->set_msg_word(0);
utcb->mtd = 0;

View File

@ -118,6 +118,46 @@ static void page_fault_handler()
print_page_fault("\nPAGE-FAULT IN CORE", pf_addr, pf_ip,
(pf_type & Ipc_pager::ERR_W) ? Rm_session::WRITE_FAULT : Rm_session::READ_FAULT, 0);
printf("\nstack pointer 0x%lx, qualifiers 0x%lx %s%s%s%s%s\n",
pf_sp, pf_type,
pf_type & Ipc_pager::ERR_I ? "I" : "i",
pf_type & Ipc_pager::ERR_R ? "R" : "r",
pf_type & Ipc_pager::ERR_U ? "U" : "u",
pf_type & Ipc_pager::ERR_W ? "W" : "w",
pf_type & Ipc_pager::ERR_P ? "P" : "p");
if ((Native_config::context_area_virtual_base() <= pf_sp) &&
(pf_sp < Native_config::context_area_virtual_base() +
Native_config::context_area_virtual_size()))
{
addr_t utcb_addr_f = pf_sp / Native_config::context_virtual_size();
utcb_addr_f *= Native_config::context_virtual_size();
utcb_addr_f += Native_config::context_virtual_size();
utcb_addr_f -= 4096;
Nova::Utcb * utcb_fault = reinterpret_cast<Nova::Utcb *>(utcb_addr_f);
unsigned last_items = utcb_fault->msg_items();
printf("faulter utcb %p, last message item count %u\n",
utcb_fault, last_items);
for (unsigned i = 0; i < last_items; i++) {
Nova::Utcb::Item * item = utcb_fault->get_item(i);
if (!item)
break;
Nova::Crd crd(item->crd);
if (crd.is_null())
continue;
printf("%u - type=%x rights=0x%x region=0x%lx+0x%lx "
"hotspot %lx(%lx) - %s\n", i, crd.type(), crd.rights(),
crd.addr(), 1UL << (12 +crd.order()),
crd.hotspot(item->hotspot), item->hotspot,
item->is_del() ? "delegated" : "translated");
}
}
/* dump stack trace */
struct Core_img
{