swap_pager_meta_free() frees allocated blocks in a way that
exploits the sparsity of allocated blocks in a range, without issuing an "are you there?" query for every block in the range. swap_pager_copy() is not so smart. Modify the implementation of swap_pager_meta_free() slightly so that swap_pager_copy() can use that smarter implementation too. Based on an observation of: Yoshihiro Ota (ota_j.email.ne.jp) Reviewed by: kib,alc Tested by: pho Differential Revision: https://reviews.freebsd.org/D22280
This commit is contained in:
parent
c17cd08f53
commit
467057fcd9
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=354618
@ -422,6 +422,8 @@ static daddr_t swp_pager_getswapspace(int *npages, int limit);
|
||||
*/
|
||||
static daddr_t swp_pager_meta_build(vm_object_t, vm_pindex_t, daddr_t);
|
||||
static void swp_pager_meta_free(vm_object_t, vm_pindex_t, vm_pindex_t);
|
||||
static void swp_pager_meta_transfer(vm_object_t src, vm_object_t dst,
|
||||
vm_pindex_t pindex, vm_pindex_t count);
|
||||
static void swp_pager_meta_free_all(vm_object_t);
|
||||
static daddr_t swp_pager_meta_ctl(vm_object_t, vm_pindex_t, int);
|
||||
|
||||
@ -933,6 +935,33 @@ swap_pager_reserve(vm_object_t object, vm_pindex_t start, vm_size_t size)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static bool
|
||||
swp_pager_xfer_source(vm_object_t srcobject, vm_object_t dstobject,
|
||||
vm_pindex_t pindex, daddr_t addr)
|
||||
{
|
||||
daddr_t dstaddr;
|
||||
|
||||
if (swp_pager_meta_ctl(dstobject, pindex, 0) != SWAPBLK_NONE) {
|
||||
/* Caller should destroy the source block. */
|
||||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destination has no swapblk and is not resident, transfer source.
|
||||
* swp_pager_meta_build() can sleep.
|
||||
*/
|
||||
vm_object_pip_add(srcobject, 1);
|
||||
VM_OBJECT_WUNLOCK(srcobject);
|
||||
vm_object_pip_add(dstobject, 1);
|
||||
dstaddr = swp_pager_meta_build(dstobject, pindex, addr);
|
||||
KASSERT(dstaddr == SWAPBLK_NONE,
|
||||
("Unexpected destination swapblk"));
|
||||
vm_object_pip_wakeup(dstobject);
|
||||
VM_OBJECT_WLOCK(srcobject);
|
||||
vm_object_pip_wakeup(srcobject);
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
* SWAP_PAGER_COPY() - copy blocks from source pager to destination pager
|
||||
* and destroy the source.
|
||||
@ -956,8 +985,6 @@ void
|
||||
swap_pager_copy(vm_object_t srcobject, vm_object_t dstobject,
|
||||
vm_pindex_t offset, int destroysource)
|
||||
{
|
||||
vm_pindex_t i;
|
||||
daddr_t dstaddr, n_free, s_free, srcaddr;
|
||||
|
||||
VM_OBJECT_ASSERT_WLOCKED(srcobject);
|
||||
VM_OBJECT_ASSERT_WLOCKED(dstobject);
|
||||
@ -984,38 +1011,7 @@ swap_pager_copy(vm_object_t srcobject, vm_object_t dstobject,
|
||||
/*
|
||||
* Transfer source to destination.
|
||||
*/
|
||||
swp_pager_init_freerange(&s_free, &n_free);
|
||||
for (i = 0; i < dstobject->size; ++i) {
|
||||
srcaddr = swp_pager_meta_ctl(srcobject, i + offset, SWM_POP);
|
||||
if (srcaddr == SWAPBLK_NONE)
|
||||
continue;
|
||||
dstaddr = swp_pager_meta_ctl(dstobject, i, 0);
|
||||
if (dstaddr != SWAPBLK_NONE) {
|
||||
/*
|
||||
* Destination has valid swapblk or it is represented
|
||||
* by a resident page. We destroy the source block.
|
||||
*/
|
||||
swp_pager_update_freerange(&s_free, &n_free, srcaddr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destination has no swapblk and is not resident,
|
||||
* copy source.
|
||||
*
|
||||
* swp_pager_meta_build() can sleep.
|
||||
*/
|
||||
vm_object_pip_add(srcobject, 1);
|
||||
VM_OBJECT_WUNLOCK(srcobject);
|
||||
vm_object_pip_add(dstobject, 1);
|
||||
dstaddr = swp_pager_meta_build(dstobject, i, srcaddr);
|
||||
KASSERT(dstaddr == SWAPBLK_NONE,
|
||||
("Unexpected destination swapblk"));
|
||||
vm_object_pip_wakeup(dstobject);
|
||||
VM_OBJECT_WLOCK(srcobject);
|
||||
vm_object_pip_wakeup(srcobject);
|
||||
}
|
||||
swp_pager_freeswapspace(s_free, n_free);
|
||||
swp_pager_meta_transfer(srcobject, dstobject, offset, dstobject->size);
|
||||
|
||||
/*
|
||||
* Free left over swap blocks in source.
|
||||
@ -2002,6 +1998,59 @@ swp_pager_meta_build(vm_object_t object, vm_pindex_t pindex, daddr_t swapblk)
|
||||
return (prev_swapblk);
|
||||
}
|
||||
|
||||
/*
|
||||
* SWP_PAGER_META_TRANSFER() - free a range of blocks in the srcobject's swap
|
||||
* metadata, or transfer it into dstobject.
|
||||
*
|
||||
* This routine will free swap metadata structures as they are cleaned
|
||||
* out.
|
||||
*/
|
||||
static void
|
||||
swp_pager_meta_transfer(vm_object_t srcobject, vm_object_t dstobject,
|
||||
vm_pindex_t pindex, vm_pindex_t count)
|
||||
{
|
||||
struct swblk *sb;
|
||||
daddr_t n_free, s_free;
|
||||
vm_pindex_t offset, last;
|
||||
int i, limit, start;
|
||||
|
||||
VM_OBJECT_ASSERT_WLOCKED(srcobject);
|
||||
if (srcobject->type != OBJT_SWAP || count == 0)
|
||||
return;
|
||||
|
||||
swp_pager_init_freerange(&s_free, &n_free);
|
||||
offset = pindex;
|
||||
last = pindex + count;
|
||||
for (;;) {
|
||||
sb = SWAP_PCTRIE_LOOKUP_GE(&srcobject->un_pager.swp.swp_blks,
|
||||
rounddown(pindex, SWAP_META_PAGES));
|
||||
if (sb == NULL || sb->p >= last)
|
||||
break;
|
||||
start = pindex > sb->p ? pindex - sb->p : 0;
|
||||
limit = last - sb->p < SWAP_META_PAGES ? last - sb->p :
|
||||
SWAP_META_PAGES;
|
||||
for (i = start; i < limit; i++) {
|
||||
if (sb->d[i] == SWAPBLK_NONE)
|
||||
continue;
|
||||
if (dstobject == NULL ||
|
||||
!swp_pager_xfer_source(srcobject, dstobject,
|
||||
sb->p + i - offset, sb->d[i])) {
|
||||
swp_pager_update_freerange(&s_free, &n_free,
|
||||
sb->d[i]);
|
||||
}
|
||||
sb->d[i] = SWAPBLK_NONE;
|
||||
}
|
||||
pindex = sb->p + SWAP_META_PAGES;
|
||||
if (swp_pager_swblk_empty(sb, 0, start) &&
|
||||
swp_pager_swblk_empty(sb, limit, SWAP_META_PAGES)) {
|
||||
SWAP_PCTRIE_REMOVE(&srcobject->un_pager.swp.swp_blks,
|
||||
sb->p);
|
||||
uma_zfree(swblk_zone, sb);
|
||||
}
|
||||
}
|
||||
swp_pager_freeswapspace(s_free, n_free);
|
||||
}
|
||||
|
||||
/*
|
||||
* SWP_PAGER_META_FREE() - free a range of blocks in the object's swap metadata
|
||||
*
|
||||
@ -2015,40 +2064,7 @@ swp_pager_meta_build(vm_object_t object, vm_pindex_t pindex, daddr_t swapblk)
|
||||
static void
|
||||
swp_pager_meta_free(vm_object_t object, vm_pindex_t pindex, vm_pindex_t count)
|
||||
{
|
||||
struct swblk *sb;
|
||||
daddr_t n_free, s_free;
|
||||
vm_pindex_t last;
|
||||
int i, limit, start;
|
||||
|
||||
VM_OBJECT_ASSERT_WLOCKED(object);
|
||||
if (object->type != OBJT_SWAP || count == 0)
|
||||
return;
|
||||
|
||||
swp_pager_init_freerange(&s_free, &n_free);
|
||||
last = pindex + count;
|
||||
for (;;) {
|
||||
sb = SWAP_PCTRIE_LOOKUP_GE(&object->un_pager.swp.swp_blks,
|
||||
rounddown(pindex, SWAP_META_PAGES));
|
||||
if (sb == NULL || sb->p >= last)
|
||||
break;
|
||||
start = pindex > sb->p ? pindex - sb->p : 0;
|
||||
limit = last - sb->p < SWAP_META_PAGES ? last - sb->p :
|
||||
SWAP_META_PAGES;
|
||||
for (i = start; i < limit; i++) {
|
||||
if (sb->d[i] == SWAPBLK_NONE)
|
||||
continue;
|
||||
swp_pager_update_freerange(&s_free, &n_free, sb->d[i]);
|
||||
sb->d[i] = SWAPBLK_NONE;
|
||||
}
|
||||
pindex = sb->p + SWAP_META_PAGES;
|
||||
if (swp_pager_swblk_empty(sb, 0, start) &&
|
||||
swp_pager_swblk_empty(sb, limit, SWAP_META_PAGES)) {
|
||||
SWAP_PCTRIE_REMOVE(&object->un_pager.swp.swp_blks,
|
||||
sb->p);
|
||||
uma_zfree(swblk_zone, sb);
|
||||
}
|
||||
}
|
||||
swp_pager_freeswapspace(s_free, n_free);
|
||||
swp_pager_meta_transfer(object, NULL, pindex, count);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user