From: markj Date: Mon, 16 Sep 2019 15:12:49 +0000 (+0000) Subject: Fix a race in vm_page_dequeue_deferred_free() after r352110. X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=e4864a62627f15259a99fb3877ef424c4e1197ef;p=freebsd.git 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 --- diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index 092e9ee08dd..bbfc5a7a334 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -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; + } + } } /* diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index 0c3f3a9bade..07672d38e59 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -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;