Fix a long standing bug that was made worse in r355765. When we are cowing a
page that was previously mapped read-only it exists in pmap until pmap_enter() returns. However, we held no reference to the original page after the copy was complete. This allowed vm_object_scan_all_shadowed() to collapse an object that still had pages mapped. To resolve this, add another page pointer to the faultstate so we can keep the page xbusy until we're done with pmap_enter(). Handle busy pages in scan_all_shadowed. This is already done in vm_object_collapse_scan(). Reviewed by: kib, markj Differential Revision: https://reviews.freebsd.org/D23155
This commit is contained in:
parent
73c6e0c358
commit
5844774900
@ -121,6 +121,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
struct faultstate {
|
||||
vm_page_t m;
|
||||
vm_page_t m_cow;
|
||||
vm_object_t object;
|
||||
vm_pindex_t pindex;
|
||||
vm_page_t first_m;
|
||||
@ -208,6 +209,7 @@ static void
|
||||
fault_deallocate(struct faultstate *fs)
|
||||
{
|
||||
|
||||
fault_page_release(&fs->m_cow);
|
||||
fault_page_release(&fs->m);
|
||||
vm_object_pip_wakeup(fs->object);
|
||||
if (fs->object != fs->first_object) {
|
||||
@ -818,7 +820,7 @@ vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type,
|
||||
|
||||
fs.lookup_still_valid = true;
|
||||
|
||||
fs.m = fs.first_m = NULL;
|
||||
fs.m_cow = fs.m = fs.first_m = NULL;
|
||||
|
||||
/*
|
||||
* Search for the page at object/offset.
|
||||
@ -1254,9 +1256,11 @@ vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type,
|
||||
vm_page_unwire(fs.m, PQ_INACTIVE);
|
||||
}
|
||||
/*
|
||||
* We no longer need the old page or object.
|
||||
* Save the cow page to be released after
|
||||
* pmap_enter is complete.
|
||||
*/
|
||||
fault_page_release(&fs.m);
|
||||
fs.m_cow = fs.m;
|
||||
fs.m = NULL;
|
||||
}
|
||||
/*
|
||||
* fs.object != fs.first_object due to above
|
||||
|
@ -1604,6 +1604,14 @@ vm_object_scan_all_shadowed(vm_object_t object)
|
||||
if (new_pindex >= object->size)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If the backing object page is busy a grandparent or older
|
||||
* page may still be undergoing CoW. It is not safe to
|
||||
* collapse the backing object until it is quiesced.
|
||||
*/
|
||||
if (p != NULL && vm_page_busied(p))
|
||||
return (false);
|
||||
|
||||
/*
|
||||
* See if the parent has the page or if the parent's object
|
||||
* pager has the page. If the parent has the page but the page
|
||||
@ -1907,8 +1915,7 @@ vm_object_collapse(vm_object_t object)
|
||||
* If we do not entirely shadow the backing object,
|
||||
* there is nothing we can do so we give up.
|
||||
*/
|
||||
if (object->resident_page_count != object->size &&
|
||||
!vm_object_scan_all_shadowed(object)) {
|
||||
if (!vm_object_scan_all_shadowed(object)) {
|
||||
VM_OBJECT_WUNLOCK(backing_object);
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user