diff options
author | dillon <dillon@FreeBSD.org> | 1999-02-04 17:47:52 +0000 |
---|---|---|
committer | dillon <dillon@FreeBSD.org> | 1999-02-04 17:47:52 +0000 |
commit | 1648ae3fae758c49b92fa7bd5daf7e9c49b545f4 (patch) | |
tree | 8da0f565ba3d595c9f82493b2a6b1ef76324537c /sys/vm | |
parent | 72ab07e9dba7c0449e325b07698b6102e22b9bb0 (diff) | |
download | FreeBSD-src-1648ae3fae758c49b92fa7bd5daf7e9c49b545f4.zip FreeBSD-src-1648ae3fae758c49b92fa7bd5daf7e9c49b545f4.tar.gz |
Fix bug in a KASSERT I introduced in vm_page_qcollapse() rev 1.139.
Since paging is in progress, page scan in vm_page_qcollapse() must be
protected at atleast splbio() to prevent pages from being ripped out from
under the scan.
Diffstat (limited to 'sys/vm')
-rw-r--r-- | sys/vm/vm_object.c | 57 |
1 files changed, 40 insertions, 17 deletions
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 14e5486..455af83 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_object.c,v 1.142 1999/01/28 00:57:57 dillon Exp $ + * $Id: vm_object.c,v 1.143 1999/02/03 01:57:17 dillon Exp $ */ /* @@ -972,9 +972,9 @@ vm_object_qcollapse(object) { register vm_object_t backing_object; register vm_pindex_t backing_offset_index; - vm_pindex_t new_pindex; register vm_page_t p, pp; register vm_size_t size; + int s; backing_object = object->backing_object; if (backing_object->ref_count != 1) @@ -985,9 +985,19 @@ vm_object_qcollapse(object) backing_offset_index = OFF_TO_IDX(object->backing_object_offset); size = object->size; + /* + * Since paging is in progress, we have to run at splbio() to + * avoid busied pages from getting ripped out from under us + * and screwing up the list sequencing. + */ + + s = splbio(); + p = TAILQ_FIRST(&backing_object->memq); while (p) { vm_page_t next; + vm_pindex_t new_pindex; + vm_pindex_t old_pindex; /* * setup for loop. @@ -1008,15 +1018,16 @@ vm_object_qcollapse(object) vm_page_busy(p); - KASSERT(p->object == object, ("vm_object_qcollapse(): object mismatch")); + KASSERT(p->object == backing_object, ("vm_object_qcollapse(): object mismatch")); - new_pindex = p->pindex - backing_offset_index; - if (p->pindex < backing_offset_index || - new_pindex >= size) { - if (backing_object->type == OBJT_SWAP) - swap_pager_freespace(backing_object, - p->pindex, - 1); + old_pindex = p->pindex; + new_pindex = old_pindex - backing_offset_index; + + if (old_pindex < backing_offset_index || new_pindex >= size) { + /* + * Page is out of the parent object's range, we + * can simply destroy it. + */ vm_page_protect(p, VM_PROT_NONE); vm_page_free(p); } else { @@ -1024,16 +1035,18 @@ vm_object_qcollapse(object) if (pp != NULL || (object->type == OBJT_SWAP && vm_pager_has_page(object, new_pindex, NULL, NULL))) { - if (backing_object->type == OBJT_SWAP) - swap_pager_freespace(backing_object, - p->pindex, 1); + /* + * page already exists in parent OR swap exists + * for this location in the parent. Destroy + * the original page from the backing object. + */ vm_page_protect(p, VM_PROT_NONE); vm_page_free(p); } else { - if (backing_object->type == OBJT_SWAP) - swap_pager_freespace(backing_object, - p->pindex, 1); - + /* + * Page does not exist in parent, rename the + * page. + */ if ((p->queue - p->pc) == PQ_CACHE) vm_page_deactivate(p); else @@ -1043,9 +1056,19 @@ vm_object_qcollapse(object) /* page automatically made dirty by rename */ } } + + /* + * Destroy any swap assigned to the backing object at this + * location. This is an optimization. + */ + if (backing_object->type == OBJT_SWAP) { + swap_pager_freespace(backing_object, old_pindex, 1); + } p = next; } backing_object->ref_count -= 2; + + splx(s); } /* |