Fix a race in release_page().
Since r354156 we may call release_page() without the page's object lock held, specifically following the page copy during a CoW fault. release_page() must therefore unbusy the page only after scheduling the requeue, to avoid racing with a free of the page. Previously, the object lock prevented this race from occurring. Add some assertions that were helpful in tracking this down. Reported by: pho, syzkaller Tested by: pho Reviewed by: alc, jeff, kib Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D22234
This commit is contained in:
parent
8227969cfa
commit
b75fed1661
@ -155,10 +155,14 @@ release_page(struct faultstate *fs)
|
||||
{
|
||||
|
||||
if (fs->m != NULL) {
|
||||
vm_page_xunbusy(fs->m);
|
||||
/*
|
||||
* fs->m's object lock might not be held, so the page must be
|
||||
* kept busy until we are done with it.
|
||||
*/
|
||||
vm_page_lock(fs->m);
|
||||
vm_page_deactivate(fs->m);
|
||||
vm_page_unlock(fs->m);
|
||||
vm_page_xunbusy(fs->m);
|
||||
fs->m = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -3421,7 +3421,7 @@ vm_page_dequeue(vm_page_t m)
|
||||
struct vm_pagequeue *pq, *pq1;
|
||||
uint8_t aflags;
|
||||
|
||||
KASSERT(mtx_owned(vm_page_lockptr(m)) || m->object == NULL,
|
||||
KASSERT(mtx_owned(vm_page_lockptr(m)) || m->ref_count == 0,
|
||||
("page %p is allocated and unlocked", m));
|
||||
|
||||
for (pq = vm_page_pagequeue(m);; pq = pq1) {
|
||||
@ -3475,6 +3475,8 @@ vm_page_enqueue(vm_page_t m, uint8_t queue)
|
||||
vm_page_assert_locked(m);
|
||||
KASSERT(m->queue == PQ_NONE && (m->aflags & PGA_QUEUE_STATE_MASK) == 0,
|
||||
("%s: page %p is already enqueued", __func__, m));
|
||||
KASSERT(m->ref_count > 0,
|
||||
("%s: page %p does not carry any references", __func__, m));
|
||||
|
||||
m->queue = queue;
|
||||
if ((m->aflags & PGA_REQUEUE) == 0)
|
||||
@ -3496,6 +3498,8 @@ vm_page_requeue(vm_page_t m)
|
||||
vm_page_assert_locked(m);
|
||||
KASSERT(vm_page_queue(m) != PQ_NONE,
|
||||
("%s: page %p is not logically enqueued", __func__, m));
|
||||
KASSERT(m->ref_count > 0,
|
||||
("%s: page %p does not carry any references", __func__, m));
|
||||
|
||||
if ((m->aflags & PGA_REQUEUE) == 0)
|
||||
vm_page_aflag_set(m, PGA_REQUEUE);
|
||||
@ -3889,6 +3893,8 @@ vm_page_mvqueue(vm_page_t m, const uint8_t nqueue)
|
||||
vm_page_assert_locked(m);
|
||||
KASSERT((m->oflags & VPO_UNMANAGED) == 0,
|
||||
("vm_page_mvqueue: page %p is unmanaged", m));
|
||||
KASSERT(m->ref_count > 0,
|
||||
("%s: page %p does not carry any references", __func__, m));
|
||||
|
||||
if (vm_page_queue(m) != nqueue) {
|
||||
vm_page_dequeue(m);
|
||||
|
Loading…
x
Reference in New Issue
Block a user