Index: sys/vm/swap_pager.c =================================================================== --- sys/vm/swap_pager.c +++ sys/vm/swap_pager.c @@ -2216,33 +2216,47 @@ start = (sb != NULL && sb->p < pindex) ? pindex - sb->p : 0; for (; sb != NULL; sb = swblk_start_limit(srcobject, pindex, last), start = 0) { - limit = MIN(last - sb->p, SWAP_META_PAGES); + vm_pindex_t p = sb->p; + limit = MIN(last - p, SWAP_META_PAGES); for (i = start; i < limit; i++) { if (sb->d[i] == SWAPBLK_NONE) continue; - blk = swp_pager_meta_build(dstobject, - sb->p + i - offset, sb->d[i], true); + blk = swp_pager_meta_build(dstobject, p + i - offset, + sb->d[i], true); if (blk == sb->d[i]) { /* * Destination has no swapblk and is not - * resident, so transfer source. + * resident, so transfer source. But * swp_pager_meta_build() failed memory * allocation already, likely to sleep in retry. */ - VM_OBJECT_WUNLOCK(srcobject); - swp_pager_meta_build(dstobject, - sb->p + i - offset, sb->d[i], false); - VM_OBJECT_WLOCK(srcobject); - } else if (blk != SWAPBLK_NONE) + sb->d[i] = SWAPBLK_NONE; + break; + } + if (blk != SWAPBLK_NONE) swp_pager_update_freerange(&range, 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)) { swblk_lookup_remove(srcobject, sb); uma_zfree(swblk_zone, sb); } + if (i < limit) { + /* Retry meta_build again with lock held. */ + if (blk == swp_pager_meta_build(dstobject, + p + i - offset, blk, true)) { + /* + * Retry with lock released so that meta_build + * can sleep. + */ + VM_OBJECT_WUNLOCK(srcobject); + swp_pager_meta_build(dstobject, p + i - offset, + blk, false); + VM_OBJECT_WLOCK(srcobject); + } + } else + pindex = p + SWAP_META_PAGES; } swp_pager_freeswapspace(&range); }