Index: sys/vm/swap_pager.c =================================================================== --- sys/vm/swap_pager.c +++ sys/vm/swap_pager.c @@ -321,8 +321,6 @@ #endif } -#define SWM_POP 0x01 /* pop out */ - static int swap_pager_full = 2; /* swap space exhaustion (task killing) */ static int swap_pager_almost_full = 1; /* swap space exhaustion (w/hysteresis)*/ static struct mtx swbuf_mtx; /* to sync nsw_wcount_async */ @@ -423,7 +421,8 @@ 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_free_all(vm_object_t); -static daddr_t swp_pager_meta_ctl(vm_object_t, vm_pindex_t, int); +static daddr_t swp_pager_meta_lookup(vm_object_t, vm_pindex_t); +static daddr_t swp_pager_meta_remove(vm_object_t, vm_pindex_t); static void swp_pager_init_freerange(daddr_t *start, daddr_t *num) @@ -956,8 +955,10 @@ swap_pager_copy(vm_object_t srcobject, vm_object_t dstobject, vm_pindex_t offset, int destroysource) { + struct swblk *sb; vm_pindex_t i; daddr_t dstaddr, n_free, s_free, srcaddr; + int limit, start; VM_OBJECT_ASSERT_WLOCKED(srcobject); VM_OBJECT_ASSERT_WLOCKED(dstobject); @@ -985,11 +986,39 @@ * 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) + for (i = 0; i < dstobject->size; i++) { + /* + * Find the next source block and remove it. + */ + sb = SWAP_PCTRIE_LOOKUP_GE(&srcobject->un_pager.swp.swp_blks, + rounddown(i + offset, SWAP_META_PAGES)); + if (sb == NULL || sb->p >= dstobject->size + offset) + break; + limit = dstobject->size + offset - sb->p < SWAP_META_PAGES ? + dstobject->size + offset - sb->p : SWAP_META_PAGES; + for (start = i + offset > sb->p ? i + offset - sb->p : 0; + start < limit; start++) { + if (sb->d[start] != SWAPBLK_NONE) { + i = sb->p + start - offset; + break; + } + } + if (start == limit) { + i = sb->p + start - offset - 1; continue; - dstaddr = swp_pager_meta_ctl(dstobject, i, 0); + } + srcaddr = sb->d[start]; + sb->d[start] = SWAPBLK_NONE; + if (swp_pager_swblk_empty(sb, 0, SWAP_META_PAGES)) { + SWAP_PCTRIE_REMOVE(&srcobject->un_pager.swp.swp_blks, + rounddown(i + offset, SWAP_META_PAGES)); + uma_zfree(swblk_zone, sb); + } + + /* + * Find the matching destination block, if any. + */ + dstaddr = swp_pager_meta_lookup(dstobject, i); if (dstaddr != SWAPBLK_NONE) { /* * Destination has valid swapblk or it is represented @@ -1057,7 +1086,7 @@ /* * do we have good backing store at the requested index ? */ - blk0 = swp_pager_meta_ctl(object, pindex, 0); + blk0 = swp_pager_meta_lookup(object, pindex); if (blk0 == SWAPBLK_NONE) { if (before) *before = 0; @@ -1073,7 +1102,7 @@ for (i = 1; i < SWB_NPAGES; i++) { if (i > pindex) break; - blk = swp_pager_meta_ctl(object, pindex - i, 0); + blk = swp_pager_meta_lookup(object, pindex - i); if (blk != blk0 - i) break; } @@ -1085,7 +1114,7 @@ */ if (after != NULL) { for (i = 1; i < SWB_NPAGES; i++) { - blk = swp_pager_meta_ctl(object, pindex + i, 0); + blk = swp_pager_meta_lookup(object, pindex + i); if (blk != blk0 + i) break; } @@ -1118,7 +1147,7 @@ { daddr_t srcaddr; - srcaddr = swp_pager_meta_ctl(m->object, m->pindex, SWM_POP); + srcaddr = swp_pager_meta_remove(m->object, m->pindex); if (srcaddr != SWAPBLK_NONE) swp_pager_freeswapspace(srcaddr, 1); } @@ -1214,7 +1243,7 @@ vm_object_pip_add(object, count); pindex = bm->pindex; - blk = swp_pager_meta_ctl(object, pindex, 0); + blk = swp_pager_meta_lookup(object, pindex); KASSERT(blk != SWAPBLK_NONE, ("no swap blocking containing %p(%jx)", object, (uintmax_t)pindex)); @@ -2085,28 +2114,55 @@ } /* - * SWP_PAGER_METACTL() - misc control of swap meta data. + * SWP_PAGER_META_LOOKUP() - look up swap meta data. * - * This routine is capable of looking up, or removing swapblk - * assignments in the swap meta data. It returns the swapblk being - * looked-up, popped, or SWAPBLK_NONE if the block was invalid. + * Look up swapblk assignments in the swap meta data. Returns the swapblk + * for (pindex = 0; (sb = being looked-up, or SWAPBLK_NONE if the block + * was invalid. * * When acting on a busy resident page and paging is in progress, we * have to wait until paging is complete but otherwise can act on the * busy page. + */ +static daddr_t +swp_pager_meta_lookup(vm_object_t object, vm_pindex_t pindex) +{ + struct swblk *sb; + + VM_OBJECT_ASSERT_LOCKED(object); + + /* + * The meta data only exists if the object is OBJT_SWAP + * and even then might not be allocated yet. + */ + if (object->type != OBJT_SWAP) + return (SWAPBLK_NONE); + + sb = SWAP_PCTRIE_LOOKUP(&object->un_pager.swp.swp_blks, + rounddown(pindex, SWAP_META_PAGES)); + if (sb == NULL) + return (SWAPBLK_NONE); + return (sb->d[pindex % SWAP_META_PAGES]); +} + +/* + * SWP_PAGER_META_REMOVE() - remove swap meta data. * - * SWM_POP remove from meta data but do not free it + * This routine is capable of removing swapblk assignments in the swap + * for (pindex = 0; (sb = meta data. It returns the swapblk being + * removed, or SWAPBLK_NONE if the block was invalid. + * + * When acting on a busy resident page and paging is in progress, we + * have to wait until paging is complete but otherwise can act on the + * busy page. */ static daddr_t -swp_pager_meta_ctl(vm_object_t object, vm_pindex_t pindex, int flags) +swp_pager_meta_remove(vm_object_t object, vm_pindex_t pindex) { struct swblk *sb; daddr_t r1; - if ((flags & SWM_POP) != 0) - VM_OBJECT_ASSERT_WLOCKED(object); - else - VM_OBJECT_ASSERT_LOCKED(object); + VM_OBJECT_ASSERT_WLOCKED(object); /* * The meta data only exists if the object is OBJT_SWAP @@ -2122,13 +2178,11 @@ r1 = sb->d[pindex % SWAP_META_PAGES]; if (r1 == SWAPBLK_NONE) return (SWAPBLK_NONE); - if ((flags & SWM_POP) != 0) { - sb->d[pindex % SWAP_META_PAGES] = SWAPBLK_NONE; - if (swp_pager_swblk_empty(sb, 0, SWAP_META_PAGES)) { - SWAP_PCTRIE_REMOVE(&object->un_pager.swp.swp_blks, - rounddown(pindex, SWAP_META_PAGES)); - uma_zfree(swblk_zone, sb); - } + sb->d[pindex % SWAP_META_PAGES] = SWAPBLK_NONE; + if (swp_pager_swblk_empty(sb, 0, SWAP_META_PAGES)) { + SWAP_PCTRIE_REMOVE(&object->un_pager.swp.swp_blks, + rounddown(pindex, SWAP_META_PAGES)); + uma_zfree(swblk_zone, sb); } return (r1); }