svn commit: r291704 - head/sys/vm
Conrad E. Meyer
cem at FreeBSD.org
Thu Dec 3 17:21:11 UTC 2015
Author: cem
Date: Thu Dec 3 17:21:10 2015
New Revision: 291704
URL: https://svnweb.freebsd.org/changeset/base/291704
Log:
Pull vm_object_scan_all_shadowed out of vm_object_backing_scan
These two functions were largely unrelated, they just used the same same
loop logic to walk through a backing object's memq. Pull out the
all_shadowed test as its own function and eliminate
OBSC_TEST_ALL_SHADOWED. Rename vm_object_backing_scan to
vm_object_collapse_scan.
No functional change.
Sponsored by: EMC / Isilon Storage Division
Differential Revision: https://reviews.freebsd.org/D4335
Modified:
head/sys/vm/vm_object.c
Modified: head/sys/vm/vm_object.c
==============================================================================
--- head/sys/vm/vm_object.c Thu Dec 3 16:54:45 2015 (r291703)
+++ head/sys/vm/vm_object.c Thu Dec 3 17:21:10 2015 (r291704)
@@ -1419,12 +1419,11 @@ retry:
VM_OBJECT_WLOCK(new_object);
}
-#define OBSC_TEST_ALL_SHADOWED 0x0001
#define OBSC_COLLAPSE_NOWAIT 0x0002
#define OBSC_COLLAPSE_WAIT 0x0004
static vm_page_t
-vm_object_backing_scan_wait(vm_object_t object, vm_page_t p, vm_page_t next,
+vm_object_collapse_scan_wait(vm_object_t object, vm_page_t p, vm_page_t next,
int op)
{
vm_object_t backing_object;
@@ -1452,192 +1451,185 @@ vm_object_backing_scan_wait(vm_object_t
}
static bool
-vm_object_backing_scan(vm_object_t object, int op)
+vm_object_scan_all_shadowed(vm_object_t object)
{
vm_object_t backing_object;
- vm_page_t next, p, pp;
+ vm_page_t p, pp;
vm_pindex_t backing_offset_index, new_pindex;
VM_OBJECT_ASSERT_WLOCKED(object);
VM_OBJECT_ASSERT_WLOCKED(object->backing_object);
backing_object = object->backing_object;
- backing_offset_index = OFF_TO_IDX(object->backing_object_offset);
/*
- * Initial conditions
+ * Initial conditions:
+ *
+ * We do not want to have to test for the existence of cache or swap
+ * pages in the backing object. XXX but with the new swapper this
+ * would be pretty easy to do.
*/
- if (op & OBSC_TEST_ALL_SHADOWED) {
+ if (backing_object->type != OBJT_DEFAULT)
+ return (false);
+
+ backing_offset_index = OFF_TO_IDX(object->backing_object_offset);
+
+ for (p = TAILQ_FIRST(&backing_object->memq); p != NULL;
+ p = TAILQ_NEXT(p, listq)) {
+ new_pindex = p->pindex - backing_offset_index;
+
+ /*
+ * Ignore pages outside the parent object's range and outside
+ * the parent object's mapping of the backing object.
+ */
+ if (p->pindex < backing_offset_index ||
+ new_pindex >= object->size)
+ continue;
+
/*
- * We do not want to have to test for the existence of cache
- * or swap pages in the backing object. XXX but with the
- * new swapper this would be pretty easy to do.
+ * 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
+ * is not valid, the parent's object pager must have the page.
*
- * XXX what about anonymous MAP_SHARED memory that hasn't
- * been ZFOD faulted yet? If we do not test for this, the
- * shadow test may succeed! XXX
+ * If this fails, the parent does not completely shadow the
+ * object and we might as well give up now.
*/
- if (backing_object->type != OBJT_DEFAULT) {
+ pp = vm_page_lookup(object, new_pindex);
+ if ((pp == NULL || pp->valid == 0) &&
+ !vm_pager_has_page(object, new_pindex, NULL, NULL))
return (false);
- }
}
- if (op & OBSC_COLLAPSE_WAIT) {
+ return (true);
+}
+
+static bool
+vm_object_collapse_scan(vm_object_t object, int op)
+{
+ vm_object_t backing_object;
+ vm_page_t next, p, pp;
+ vm_pindex_t backing_offset_index, new_pindex;
+
+ VM_OBJECT_ASSERT_WLOCKED(object);
+ VM_OBJECT_ASSERT_WLOCKED(object->backing_object);
+
+ backing_object = object->backing_object;
+ backing_offset_index = OFF_TO_IDX(object->backing_object_offset);
+
+ /*
+ * Initial conditions
+ */
+ if ((op & OBSC_COLLAPSE_WAIT) != 0)
vm_object_set_flag(backing_object, OBJ_DEAD);
- }
/*
* Our scan
*/
- p = TAILQ_FIRST(&backing_object->memq);
- while (p) {
+ for (p = TAILQ_FIRST(&backing_object->memq); p != NULL; p = next) {
next = TAILQ_NEXT(p, listq);
new_pindex = p->pindex - backing_offset_index;
- if (op & OBSC_TEST_ALL_SHADOWED) {
- /*
- * Ignore pages outside the parent object's range
- * and outside the parent object's mapping of the
- * backing object.
- *
- * Note that we do not busy the backing object's
- * page.
- */
- if (p->pindex < backing_offset_index ||
- new_pindex >= object->size) {
- p = next;
- continue;
- }
-
- /*
- * 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 is not valid, the parent's
- * object pager must have the page.
- *
- * If this fails, the parent does not completely shadow
- * the object and we might as well give up now.
- */
-
- pp = vm_page_lookup(object, new_pindex);
- if ((pp == NULL || pp->valid == 0) &&
- !vm_pager_has_page(object, new_pindex, NULL, NULL))
- return (false);
- }
/*
* Check for busy page
*/
- if (op & (OBSC_COLLAPSE_WAIT | OBSC_COLLAPSE_NOWAIT)) {
- if (vm_page_busied(p)) {
- p = vm_object_backing_scan_wait(object, p,
- next, op);
- continue;
- }
-
- KASSERT(p->object == backing_object,
- ("vm_object_backing_scan: object mismatch"));
-
- if (p->pindex < backing_offset_index ||
- new_pindex >= object->size) {
- if (backing_object->type == OBJT_SWAP)
- swap_pager_freespace(backing_object,
- p->pindex, 1);
+ if (vm_page_busied(p)) {
+ next = vm_object_collapse_scan_wait(object, p, next, op);
+ continue;
+ }
- /*
- * Page is out of the parent object's range, we
- * can simply destroy it.
- */
- vm_page_lock(p);
- KASSERT(!pmap_page_is_mapped(p),
- ("freeing mapped page %p", p));
- if (p->wire_count == 0)
- vm_page_free(p);
- else
- vm_page_remove(p);
- vm_page_unlock(p);
- p = next;
- continue;
- }
+ KASSERT(p->object == backing_object,
+ ("vm_object_collapse_scan: object mismatch"));
- pp = vm_page_lookup(object, new_pindex);
- if (pp != NULL && vm_page_busied(pp)) {
- /*
- * The page in the parent is busy and
- * possibly not (yet) valid. Until
- * its state is finalized by the busy
- * bit owner, we can't tell whether it
- * shadows the original page.
- * Therefore, we must either skip it
- * and the original (backing_object)
- * page or wait for its state to be
- * finalized.
- *
- * This is due to a race with vm_fault()
- * where we must unbusy the original
- * (backing_obj) page before we can
- * (re)lock the parent. Hence we can
- * get here.
- */
- p = vm_object_backing_scan_wait(object, pp,
- next, op);
- continue;
- }
-
- KASSERT(pp == NULL || pp->valid != 0,
- ("unbusy invalid page %p", pp));
+ if (p->pindex < backing_offset_index ||
+ new_pindex >= object->size) {
+ if (backing_object->type == OBJT_SWAP)
+ swap_pager_freespace(backing_object, p->pindex,
+ 1);
- if (pp != NULL || vm_pager_has_page(object,
- new_pindex, NULL, NULL)) {
- /*
- * The page already exists in the
- * parent OR swap exists for this
- * location in the parent. Leave the
- * parent's page alone. Destroy the
- * original page from the backing
- * object.
- */
- if (backing_object->type == OBJT_SWAP)
- swap_pager_freespace(backing_object,
- p->pindex, 1);
- vm_page_lock(p);
- KASSERT(!pmap_page_is_mapped(p),
- ("freeing mapped page %p", p));
- if (p->wire_count == 0)
- vm_page_free(p);
- else
- vm_page_remove(p);
- vm_page_unlock(p);
- p = next;
- continue;
- }
+ /*
+ * Page is out of the parent object's range, we can
+ * simply destroy it.
+ */
+ vm_page_lock(p);
+ KASSERT(!pmap_page_is_mapped(p),
+ ("freeing mapped page %p", p));
+ if (p->wire_count == 0)
+ vm_page_free(p);
+ else
+ vm_page_remove(p);
+ vm_page_unlock(p);
+ continue;
+ }
+ pp = vm_page_lookup(object, new_pindex);
+ if (pp != NULL && vm_page_busied(pp)) {
/*
- * Page does not exist in parent, rename the
- * page from the backing object to the main object.
+ * The page in the parent is busy and possibly not
+ * (yet) valid. Until its state is finalized by the
+ * busy bit owner, we can't tell whether it shadows the
+ * original page. Therefore, we must either skip it
+ * and the original (backing_object) page or wait for
+ * its state to be finalized.
*
- * If the page was mapped to a process, it can remain
- * mapped through the rename.
- * vm_page_rename() will handle dirty and cache.
+ * This is due to a race with vm_fault() where we must
+ * unbusy the original (backing_obj) page before we can
+ * (re)lock the parent. Hence we can get here.
*/
- if (vm_page_rename(p, object, new_pindex)) {
- p = vm_object_backing_scan_wait(object, NULL,
- next, op);
- continue;
- }
+ next = vm_object_collapse_scan_wait(object, pp, next,
+ op);
+ continue;
+ }
- /* Use the old pindex to free the right page. */
- if (backing_object->type == OBJT_SWAP)
- swap_pager_freespace(backing_object,
- new_pindex + backing_offset_index, 1);
+ KASSERT(pp == NULL || pp->valid != 0,
+ ("unbusy invalid page %p", pp));
-#if VM_NRESERVLEVEL > 0
+ if (pp != NULL || vm_pager_has_page(object, new_pindex, NULL,
+ NULL)) {
/*
- * Rename the reservation.
+ * The page already exists in the parent OR swap exists
+ * for this location in the parent. Leave the parent's
+ * page alone. Destroy the original page from the
+ * backing object.
*/
- vm_reserv_rename(p, object, backing_object,
- backing_offset_index);
-#endif
+ if (backing_object->type == OBJT_SWAP)
+ swap_pager_freespace(backing_object, p->pindex,
+ 1);
+ vm_page_lock(p);
+ KASSERT(!pmap_page_is_mapped(p),
+ ("freeing mapped page %p", p));
+ if (p->wire_count == 0)
+ vm_page_free(p);
+ else
+ vm_page_remove(p);
+ vm_page_unlock(p);
+ continue;
+ }
+
+ /*
+ * Page does not exist in parent, rename the page from the
+ * backing object to the main object.
+ *
+ * If the page was mapped to a process, it can remain mapped
+ * through the rename. vm_page_rename() will handle dirty and
+ * cache.
+ */
+ if (vm_page_rename(p, object, new_pindex)) {
+ next = vm_object_collapse_scan_wait(object, NULL, next,
+ op);
+ continue;
}
- p = next;
+
+ /* Use the old pindex to free the right page. */
+ if (backing_object->type == OBJT_SWAP)
+ swap_pager_freespace(backing_object,
+ new_pindex + backing_offset_index, 1);
+
+#if VM_NRESERVLEVEL > 0
+ /*
+ * Rename the reservation.
+ */
+ vm_reserv_rename(p, object, backing_object,
+ backing_offset_index);
+#endif
}
return (true);
}
@@ -1659,7 +1651,7 @@ vm_object_qcollapse(vm_object_t object)
if (backing_object->ref_count != 1)
return;
- vm_object_backing_scan(object, OBSC_COLLAPSE_NOWAIT);
+ vm_object_collapse_scan(object, OBSC_COLLAPSE_NOWAIT);
}
/*
@@ -1717,15 +1709,15 @@ vm_object_collapse(vm_object_t object)
* all the resident pages in the entire backing object.
*
* This is ignoring pager-backed pages such as swap pages.
- * vm_object_backing_scan fails the shadowing test in this
+ * vm_object_collapse_scan fails the shadowing test in this
* case.
*/
if (backing_object->ref_count == 1) {
/*
* If there is exactly one reference to the backing
- * object, we can collapse it into the parent.
+ * object, we can collapse it into the parent.
*/
- vm_object_backing_scan(object, OBSC_COLLAPSE_WAIT);
+ vm_object_collapse_scan(object, OBSC_COLLAPSE_WAIT);
#if VM_NRESERVLEVEL > 0
/*
@@ -1806,8 +1798,7 @@ vm_object_collapse(vm_object_t object)
* there is nothing we can do so we give up.
*/
if (object->resident_page_count != object->size &&
- !vm_object_backing_scan(object,
- OBSC_TEST_ALL_SHADOWED)) {
+ !vm_object_scan_all_shadowed(object)) {
VM_OBJECT_WUNLOCK(backing_object);
break;
}
More information about the svn-src-head
mailing list