diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1996-08-12 12:33:35 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1996-08-12 12:33:35 +0000 |
commit | a830fe870b4b08ba6ca039077e35040335209caf (patch) | |
tree | 66fb5d0c6899f45bd55a3b7dd1a0294b298eed90 /sys/vm/vm_object.c | |
parent | 417047165b9fa6e1db61b0fdc6714be711f4d049 (diff) |
Fixed CRITICAL bug hitting in former swap leak scenarios
when collapsing two objects a formerly COWed page might lose it's backing store
causing stuff like lost ld.so fixups of shared lib images. Also handle fake
pages in all cases. In short: UPDATE!
Diffstat (limited to 'sys/vm/vm_object.c')
-rw-r--r-- | sys/vm/vm_object.c | 72 |
1 files changed, 58 insertions, 14 deletions
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index d6d93b62e75..92901ab2821 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm_object.c,v 1.6 1996/08/02 00:06:02 niklas Exp $ */ +/* $OpenBSD: vm_object.c,v 1.7 1996/08/12 12:33:34 niklas Exp $ */ /* $NetBSD: vm_object.c,v 1.34 1996/02/28 22:35:35 gwr Exp $ */ /* @@ -1060,7 +1060,6 @@ vm_object_cache_clear() * * Tell object's pager that it needn't back the page * anymore. If the pager ends up empty, deallocate it. - * Assume object->pager is non-NULL. */ static int vm_object_remove_from_pager(object, from, to) @@ -1070,6 +1069,9 @@ vm_object_remove_from_pager(object, from, to) vm_pager_t pager = object->pager; int cnt = 0; + if (pager == NULL) + return 0; + cnt = vm_pager_remove(pager, from, to); /* If pager became empty, remove it. */ @@ -1152,8 +1154,24 @@ vm_object_collapse_aux(object) vm_page_unlock_queues(); } - /* Just move the page up front. */ + /* Move the page up front. */ vm_page_rename(backing_page, object, offset); + + /* + * If the backing page was ever paged out, it was + * due to it being dirty at one point. Unless we + * have no pager allocated to the front object + * (thus will move forward the shadow's one), + * mark it dirty again so it won't be thrown away + * without being paged out to the front pager. + */ + if (object->pager != NULL && + vm_object_remove_from_pager(backing_object, + backing_offset, backing_offset + PAGE_SIZE)) { + backing_page->flags &= ~PG_CLEAN; + if (backing_page->flags & PG_INACTIVE) + backing_page->flags |= PG_LAUNDRY; + } } } @@ -1208,21 +1226,34 @@ vm_object_collapse_aux(object) * the loop condition to get us out of here * quickly if we remove the last paged out page. * - * XXX Should pages found paged out in the backing - * object be marked for pageout in the shadowing - * object? - * * XXX Would clustering several pages at a time * be a win in this situation? * - * XXX "fake" page handling??? + * XXX Is the "fake" page handling correct??? */ - if (vm_page_lookup(object, offset - backing_offset) == - NULL && !vm_pager_has_page(object->pager, + if (((page = vm_page_lookup(object, + offset - backing_offset)) == NULL || + (page->flags & PG_FAKE)) && + !vm_pager_has_page(object->pager, offset - backing_offset)) { /* - * Suck the page from the pager and give it - * to the shadowing object. + * If a "fake" page was found, someone + * may be waiting for it. Wake her up + * and then remove the page. + */ + if (page) { +#ifdef DIAGNOSTIC + printf("fake page blown away\n"); +#endif + PAGE_WAKEUP(page); + vm_page_lock_queues(); + vm_page_free(page); + vm_page_unlock_queues(); + } + + /* + * Suck the page from the pager and give + * it to the shadowing object. */ #ifdef DEBUG if (vmdebug & VMDEBUG_COLLAPSE_PAGEIN) @@ -1262,8 +1293,21 @@ vm_object_collapse_aux(object) offset); cnt.v_pgpgin++; - backing_page->flags &= ~PG_FAKE; - backing_page->flags |= PG_CLEAN; + + /* + * This page was once dirty, otherwise + * it hadn't been paged out in this + * shadow object. As we now remove the + * persistant store of the page, make + * sure it will be paged out in the + * front pager by dirtying it. + * + * XXX these flag adjustments may be + * overkill, look into them some time. + */ + backing_page->flags &= ~(PG_FAKE|PG_CLEAN); + if (backing_page->flags & PG_INACTIVE) + backing_page->flags |= PG_LAUNDRY; pmap_clear_modify(VM_PAGE_TO_PHYS( backing_page)); |