This allows to release multiple swap blocks via swp_pager_freeswapspace(). For each call, swp_pager_freeswapspace() locks. Releasing multiple blocks helps to reduce number of locks. If a swblk contains continuous blocks, it reduces up to SWAP_META_PAGES-1 locks. This patch covers 2 case: 1. when a process exits and all of its swap blocks are released and 2. when a process is paged in from swap space. I'm looking at swapoff case but this requires more work. Index: sys/vm/swap_pager.c =================================================================== --- sys/vm/swap_pager.c (revision 325969) +++ sys/vm/swap_pager.c (working copy) @@ -792,6 +879,43 @@ } /* + * SWP_FIND_CONTINUOUS_REGION() - find a continuous region of swap blocks + * + * Given the "start" entry is not SWAPBLK_NONE, it searches a range + * if SWAPBLK to be up to including "last" element. + * + * The return value indicates the number of blocks freed. + * + * An example of good case is when swblk holds [2, 3, 4, 5, 6, 7, 8, 9], + * caller passes (&d[0], and &[7]) as arguments and 8 is returned. + * + * Another example is with [NONE, 3, NONE, 11, 12, 13, 4, NONE], + * caller wants to skip d[0] and passes (&d[1], &d[7]) which + * returns 1 block. Then, caller skips d[2] and pass (&d[3], &d[7]) which + * returns 3 blocks as 4 is not a number fater 13 and not continous. + * Then callers get 1 block back for &d[6] and won't want to call + * for &d[7] as it is NONE. + */ +static int +swp_find_continuous_region(const daddr_t *start, const daddr_t *last) +{ + const daddr_t *next; + daddr_t expected; + + if (*start == SWAPBLK_NONE) + return 0; + + next = start + 1; + expected = *start + 1; + while (next <= last && (expected == *next)) + { + next++; + expected++; + } + return npages = next - start; +} + +/* * SYSCTL_SWAP_FRAGMENTATION() - produce raw swap space stats */ static int @@ -1888,6 +2047,7 @@ static void swp_pager_meta_free(vm_object_t object, vm_pindex_t pindex, vm_pindex_t count) { + int offset, npages; struct swblk *sb; vm_pindex_t last; int i; @@ -1908,7 +2072,18 @@ if (sb->d[i] == SWAPBLK_NONE) continue; if (pindex <= sb->p + i && sb->p + i <= last) { - swp_pager_freeswapspace(sb->d[i], 1); + offset = last - (sb->p + i); + if (offset == 0) { + npages = 1; + } else { + offset = min(offset, (SWAP_META_PAGES - 1 - i)); + npages = swp_find_continuous_region(&sb->d[i], &sb->d[i + offset]); +printf("swp_find_continuous_region:start %lld@d[%d] offset=%d %lld->%d\n", + sb->d[i], i, offset, sb->d[i], npages); + } + swp_pager_freeswapspace(sb->d[i], npages); + while( npages-- > 1 ) + sb->d[i++] = SWAPBLK_NONE; sb->d[i] = SWAPBLK_NONE; } else empty = false; @@ -1933,7 +2108,7 @@ { struct swblk *sb; vm_pindex_t pindex; - int i; + int i, npages; VM_OBJECT_ASSERT_WLOCKED(object); if (object->type != OBJT_SWAP) @@ -1942,9 +2117,14 @@ for (pindex = 0; (sb = SWAP_PCTRIE_LOOKUP_GE( &object->un_pager.swp.swp_blks, pindex)) != NULL;) { pindex = sb->p + SWAP_META_PAGES; - for (i = 0; i < SWAP_META_PAGES; i++) { - if (sb->d[i] != SWAPBLK_NONE) - swp_pager_freeswapspace(sb->d[i], 1); + for (i = 0; i < SWAP_META_PAGES;) { + if (sb->d[i] != SWAPBLK_NONE) { + npages = swp_find_continuous_region(&sb->d[i], &sb->d[SWAP_META_PAGES - 1]); + swp_pager_freeswapspace(sb->d[i], npages); + i += npages; + } else + i++; + } SWAP_PCTRIE_REMOVE(&object->un_pager.swp.swp_blks, sb->p); uma_zfree(swblk_zone, sb);