Fix a race in vm_page_dequeue_deferred_free() after r352110.
This function loaded the page's queue index before setting PGA_DEQUEUE. In this window the page daemon may have deactivated the page, updating its queue index. Make the operation atomic using vm_page_pqstate_cmpset(); the page daemon will not modify the page once it observes that PGA_DEQUEUE is set. Reported and tested by: pho Reviewed by: alc, kib Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D21639
This commit is contained in:
parent
47aef898ea
commit
923da43e7c
@ -3315,13 +3315,18 @@ vm_page_dequeue_deferred_free(vm_page_t m)
|
||||
|
||||
KASSERT(m->ref_count == 0, ("page %p has references", m));
|
||||
|
||||
if ((m->aflags & PGA_DEQUEUE) != 0)
|
||||
return;
|
||||
atomic_thread_fence_acq();
|
||||
if ((queue = m->queue) == PQ_NONE)
|
||||
return;
|
||||
vm_page_aflag_set(m, PGA_DEQUEUE);
|
||||
vm_page_pqbatch_submit(m, queue);
|
||||
for (;;) {
|
||||
if ((m->aflags & PGA_DEQUEUE) != 0)
|
||||
return;
|
||||
atomic_thread_fence_acq();
|
||||
if ((queue = atomic_load_8(&m->queue)) == PQ_NONE)
|
||||
return;
|
||||
if (vm_page_pqstate_cmpset(m, queue, queue, PGA_DEQUEUE,
|
||||
PGA_DEQUEUE)) {
|
||||
vm_page_pqbatch_submit(m, queue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -783,8 +783,6 @@ vm_page_pqstate_cmpset(vm_page_t m, uint32_t oldq, uint32_t newq,
|
||||
{
|
||||
uint32_t *addr, nval, oval, qsmask;
|
||||
|
||||
vm_page_assert_locked(m);
|
||||
|
||||
fflags <<= VM_PAGE_AFLAG_SHIFT;
|
||||
nflags <<= VM_PAGE_AFLAG_SHIFT;
|
||||
newq <<= VM_PAGE_QUEUE_SHIFT;
|
||||
|
Loading…
Reference in New Issue
Block a user