summaryrefslogtreecommitdiffstats
path: root/sys/vm
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2017-01-01 11:38:34 +0000
committerkib <kib@FreeBSD.org>2017-01-01 11:38:34 +0000
commit24fe758c527a68bf8d6a24d46467c589fefe7f13 (patch)
tree4809a85ea035a39aee559b8aa6503fe47eab4a9e /sys/vm
parent762d7722438ce9a7fb651868254beaeca46afceb (diff)
downloadFreeBSD-src-24fe758c527a68bf8d6a24d46467c589fefe7f13.zip
FreeBSD-src-24fe758c527a68bf8d6a24d46467c589fefe7f13.tar.gz
MFC r310234:
Improve vm_object_scan_all_shadowed() to also check swap backing objects.
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/swap_pager.c38
-rw-r--r--sys/vm/swap_pager.h1
-rw-r--r--sys/vm/vm_object.c44
3 files changed, 63 insertions, 20 deletions
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index f94a385..3402c0a 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -2010,6 +2010,44 @@ swp_pager_meta_ctl(vm_object_t object, vm_pindex_t pindex, int flags)
}
/*
+ * Returns the least page index which is greater than or equal to the
+ * parameter pindex and for which there is a swap block allocated.
+ * Returns object's size if the object's type is not swap or if there
+ * are no allocated swap blocks for the object after the requested
+ * pindex.
+ */
+vm_pindex_t
+swap_pager_find_least(vm_object_t object, vm_pindex_t pindex)
+{
+ struct swblock **pswap, *swap;
+ vm_pindex_t i, j, lim;
+ int idx;
+
+ VM_OBJECT_ASSERT_LOCKED(object);
+ if (object->type != OBJT_SWAP || object->un_pager.swp.swp_bcount == 0)
+ return (object->size);
+
+ mtx_lock(&swhash_mtx);
+ for (j = pindex; j < object->size; j = lim) {
+ pswap = swp_pager_hash(object, j);
+ lim = rounddown2(j + SWAP_META_PAGES, SWAP_META_PAGES);
+ if (lim > object->size)
+ lim = object->size;
+ if ((swap = *pswap) != NULL) {
+ for (idx = j & SWAP_META_MASK, i = j; i < lim;
+ i++, idx++) {
+ if (swap->swb_pages[idx] != SWAPBLK_NONE)
+ goto found;
+ }
+ }
+ }
+ i = object->size;
+found:
+ mtx_unlock(&swhash_mtx);
+ return (i);
+}
+
+/*
* System call swapon(name) enables swapping on device name,
* which must be in the swdevsw. Return EBUSY
* if already swapping on this device.
diff --git a/sys/vm/swap_pager.h b/sys/vm/swap_pager.h
index 79f8767..83567f4 100644
--- a/sys/vm/swap_pager.h
+++ b/sys/vm/swap_pager.h
@@ -79,6 +79,7 @@ extern int swap_pager_avail;
struct xswdev;
int swap_dev_info(int name, struct xswdev *xs, char *devname, size_t len);
void swap_pager_copy(vm_object_t, vm_object_t, vm_pindex_t, int);
+vm_pindex_t swap_pager_find_least(vm_object_t object, vm_pindex_t pindex);
void swap_pager_freespace(vm_object_t, vm_pindex_t, vm_size_t);
void swap_pager_swap_init(void);
int swap_pager_isswapped(vm_object_t, struct swdevt *);
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 7321990..6536b9e 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -1464,36 +1464,40 @@ vm_object_scan_all_shadowed(vm_object_t object)
{
vm_object_t backing_object;
vm_page_t p, pp;
- vm_pindex_t backing_offset_index, new_pindex;
+ vm_pindex_t backing_offset_index, new_pindex, pi, ps;
VM_OBJECT_ASSERT_WLOCKED(object);
VM_OBJECT_ASSERT_WLOCKED(object->backing_object);
backing_object = object->backing_object;
- /*
- * 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 (backing_object->type != OBJT_DEFAULT)
+ if (backing_object->type != OBJT_DEFAULT &&
+ backing_object->type != OBJT_SWAP)
return (false);
- backing_offset_index = OFF_TO_IDX(object->backing_object_offset);
+ pi = backing_offset_index = OFF_TO_IDX(object->backing_object_offset);
+ p = vm_page_find_least(backing_object, pi);
+ ps = swap_pager_find_least(backing_object, pi);
- for (p = TAILQ_FIRST(&backing_object->memq); p != NULL;
- p = TAILQ_NEXT(p, listq)) {
- new_pindex = p->pindex - backing_offset_index;
+ /*
+ * Only check pages inside the parent object's range and
+ * inside the parent object's mapping of the backing object.
+ */
+ for (;; pi++) {
+ if (p != NULL && p->pindex < pi)
+ p = TAILQ_NEXT(p, listq);
+ if (ps < pi)
+ ps = swap_pager_find_least(backing_object, pi);
+ if (p == NULL && ps >= backing_object->size)
+ break;
+ else if (p == NULL)
+ pi = ps;
+ else
+ pi = MIN(p->pindex, ps);
- /*
- * 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;
+ new_pindex = pi - backing_offset_index;
+ if (new_pindex >= object->size)
+ break;
/*
* See if the parent has the page or if the parent's object
OpenPOWER on IntegriCloud