summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2010-11-20 22:30:09 +0000
committeralc <alc@FreeBSD.org>2010-11-20 22:30:09 +0000
commit5bd8badd5ec0af1082cbc5e11e674721bbfab61f (patch)
treefe4fe4be2a70ebeb8f74fc966fb59894f4f88cee /sys
parentc2d4047d05b775388f114756ed4889c6d6e6e3d5 (diff)
downloadFreeBSD-src-5bd8badd5ec0af1082cbc5e11e674721bbfab61f.zip
FreeBSD-src-5bd8badd5ec0af1082cbc5e11e674721bbfab61f.tar.gz
Optimize vm_object_terminate().
Reviewed by: kib MFC after: 1 week
Diffstat (limited to 'sys')
-rw-r--r--sys/vm/vm_object.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 48dd3b6..b7f47b5 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -661,7 +661,7 @@ vm_object_destroy(vm_object_t object)
void
vm_object_terminate(vm_object_t object)
{
- vm_page_t p;
+ vm_page_t p, p_next;
VM_OBJECT_LOCK_ASSERT(object, MA_OWNED);
@@ -701,22 +701,41 @@ vm_object_terminate(vm_object_t object)
object->ref_count));
/*
- * Now free any remaining pages. For internal objects, this also
- * removes them from paging queues. Don't free wired pages, just
- * remove them from the object.
+ * Free any remaining pageable pages. This also removes them from the
+ * paging queues. However, don't free wired pages, just remove them
+ * from the object. Rather than incrementally removing each page from
+ * the object, the page and object are reset to any empty state.
*/
- while ((p = TAILQ_FIRST(&object->memq)) != NULL) {
+ TAILQ_FOREACH_SAFE(p, &object->memq, listq, p_next) {
KASSERT(!p->busy && (p->oflags & VPO_BUSY) == 0,
- ("vm_object_terminate: freeing busy page %p "
- "p->busy = %d, p->oflags %x\n", p, p->busy, p->oflags));
+ ("vm_object_terminate: freeing busy page %p", p));
vm_page_lock(p);
+ /*
+ * Optimize the page's removal from the object by resetting
+ * its "object" field. Specifically, if the page is not
+ * wired, then the effect of this assignment is that
+ * vm_page_free()'s call to vm_page_remove() will return
+ * immediately without modifying the page or the object.
+ */
+ p->object = NULL;
if (p->wire_count == 0) {
vm_page_free(p);
PCPU_INC(cnt.v_pfree);
- } else
- vm_page_remove(p);
+ }
vm_page_unlock(p);
}
+ /*
+ * If the object contained any pages, then reset it to an empty state.
+ * None of the object's fields, including "resident_page_count", were
+ * modified by the preceding loop.
+ */
+ if (object->resident_page_count != 0) {
+ object->root = NULL;
+ TAILQ_INIT(&object->memq);
+ object->resident_page_count = 0;
+ if (object->type == OBJT_VNODE)
+ vdrop(object->handle);
+ }
#if VM_NRESERVLEVEL > 0
if (__predict_false(!LIST_EMPTY(&object->rvq)))
OpenPOWER on IntegriCloud