diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 8db807e77ba9..38819a8565f8 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -693,6 +693,54 @@ vm_object_destroy(vm_object_t object) uma_zfree(obj_zone, object); } +/* + * vm_object_terminate_pages removes any remaining pageable pages + * from the object and resets the object to an empty state. + */ +static void +vm_object_terminate_pages(vm_object_t object) +{ + vm_page_t p, p_next; + + VM_OBJECT_ASSERT_WLOCKED(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. + */ + TAILQ_FOREACH_SAFE(p, &object->memq, listq, p_next) { + vm_page_assert_unbusied(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); + VM_CNT_INC(v_pfree); + } + 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) { + vm_radix_reclaim_allnodes(&object->rtree); + TAILQ_INIT(&object->memq); + object->resident_page_count = 0; + if (object->type == OBJT_VNODE) + vdrop(object->handle); + } +} + /* * vm_object_terminate actually destroys the specified object, freeing * up all previously used resources. @@ -703,7 +751,6 @@ vm_object_destroy(vm_object_t object) void vm_object_terminate(vm_object_t object) { - vm_page_t p, p_next; VM_OBJECT_ASSERT_WLOCKED(object); @@ -746,41 +793,8 @@ vm_object_terminate(vm_object_t object) ("vm_object_terminate: object with references, ref_count=%d", object->ref_count)); - /* - * 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. - */ - TAILQ_FOREACH_SAFE(p, &object->memq, listq, p_next) { - vm_page_assert_unbusied(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); - VM_CNT_INC(v_pfree); - } - 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) { - vm_radix_reclaim_allnodes(&object->rtree); - TAILQ_INIT(&object->memq); - object->resident_page_count = 0; - if (object->type == OBJT_VNODE) - vdrop(object->handle); - } + if ((object->flags & OBJ_PG_DTOR) == 0) + vm_object_terminate_pages(object); #if VM_NRESERVLEVEL > 0 if (__predict_false(!LIST_EMPTY(&object->rvq))) diff --git a/sys/vm/vm_object.h b/sys/vm/vm_object.h index 60c98214af5d..e8def4b6262f 100644 --- a/sys/vm/vm_object.h +++ b/sys/vm/vm_object.h @@ -175,6 +175,7 @@ struct vm_object { #define OBJ_NOSPLIT 0x0010 /* dont split this object */ #define OBJ_UMTXDEAD 0x0020 /* umtx pshared was terminated */ #define OBJ_PIPWNT 0x0040 /* paging in progress wanted */ +#define OBJ_PG_DTOR 0x0080 /* dont reset object, leave that for dtor */ #define OBJ_MIGHTBEDIRTY 0x0100 /* object might be dirty, only for vnode */ #define OBJ_TMPFS_NODE 0x0200 /* object belongs to tmpfs VREG node */ #define OBJ_TMPFS_DIRTY 0x0400 /* dirty tmpfs obj */