From 48e98a2afc78325afd24abc4e9f7ab924daa8fa4 Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Sat, 11 May 2019 10:16:43 +0000 Subject: [PATCH] Callers of swp_pager_getswapspace get either as many blocks as they requested, or none, and in the latter case it is up to them to pick a smaller request to make - which they always do by halving the failed request. This change to swp_pager_getswapspace leaves the task of downsizing the request to the function and not its caller. It still does so by halving the original request. Approved by: kib (mentor) Differential Revision: https://reviews.freebsd.org/D20228 --- sys/vm/swap_pager.c | 108 ++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index 851398010ea7..d540c307e739 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -407,7 +407,7 @@ static int swapoff_one(struct swdevt *sp, struct ucred *cred); * Swap bitmap functions */ static void swp_pager_freeswapspace(daddr_t blk, daddr_t npages); -static daddr_t swp_pager_getswapspace(int npages); +static daddr_t swp_pager_getswapspace(int *npages, int limit); /* * Metadata functions @@ -708,9 +708,10 @@ swap_pager_dealloc(vm_object_t object) /* * SWP_PAGER_GETSWAPSPACE() - allocate raw swap space * - * Allocate swap for the requested number of pages. The starting - * swap block number (a page index) is returned or SWAPBLK_NONE - * if the allocation failed. + * Allocate swap for up to the requested number of pages, and at + * least a minimum number of pages. The starting swap block number + * (a page index) is returned or SWAPBLK_NONE if the allocation + * failed. * * Also has the side effect of advising that somebody made a mistake * when they configured swap and didn't configure enough. @@ -720,38 +721,46 @@ swap_pager_dealloc(vm_object_t object) * We allocate in round-robin fashion from the configured devices. */ static daddr_t -swp_pager_getswapspace(int npages) +swp_pager_getswapspace(int *io_npages, int limit) { daddr_t blk; struct swdevt *sp; - int i; + int npages; blk = SWAPBLK_NONE; + npages = *io_npages; mtx_lock(&sw_dev_mtx); sp = swdevhd; - for (i = 0; i < nswapdev; i++) { + while (!TAILQ_EMPTY(&swtailq)) { if (sp == NULL) sp = TAILQ_FIRST(&swtailq); - if (!(sp->sw_flags & SW_CLOSING)) { + if ((sp->sw_flags & SW_CLOSING) == 0) blk = blist_alloc(sp->sw_blist, npages); - if (blk != SWAPBLK_NONE) { - blk += sp->sw_first; - sp->sw_used += npages; - swap_pager_avail -= npages; - swp_sizecheck(); - swdevhd = TAILQ_NEXT(sp, sw_list); - goto done; - } - } + if (blk != SWAPBLK_NONE) + break; sp = TAILQ_NEXT(sp, sw_list); + if (swdevhd == sp) { + if (npages <= limit) + break; + npages >>= 1; + } } - if (swap_pager_full != 2) { - printf("swap_pager_getswapspace(%d): failed\n", npages); - swap_pager_full = 2; - swap_pager_almost_full = 1; + if (blk != SWAPBLK_NONE) { + *io_npages = npages; + blk += sp->sw_first; + sp->sw_used += npages; + swap_pager_avail -= npages; + swp_sizecheck(); + swdevhd = TAILQ_NEXT(sp, sw_list); + } else { + if (swap_pager_full != 2) { + printf("swp_pager_getswapspace(%d): failed\n", + *io_npages); + swap_pager_full = 2; + swap_pager_almost_full = 1; + } + swdevhd = NULL; } - swdevhd = NULL; -done: mtx_unlock(&sw_dev_mtx); return (blk); } @@ -886,35 +895,28 @@ swap_pager_freespace(vm_object_t object, vm_pindex_t start, vm_size_t size) int swap_pager_reserve(vm_object_t object, vm_pindex_t start, vm_size_t size) { - int n = 0; - daddr_t blk = SWAPBLK_NONE; - vm_pindex_t beg = start; /* save start index */ - daddr_t addr, n_free, s_free; + daddr_t addr, blk, n_free, s_free; + int i, j, n; swp_pager_init_freerange(&s_free, &n_free); VM_OBJECT_WLOCK(object); - while (size) { - if (n == 0) { - n = BLIST_MAX_ALLOC; - while ((blk = swp_pager_getswapspace(n)) == SWAPBLK_NONE) { - n >>= 1; - if (n == 0) { - swp_pager_meta_free(object, beg, start - beg); - VM_OBJECT_WUNLOCK(object); - return (-1); - } - } + for (i = 0; i < size; i += n) { + n = min(BLIST_MAX_ALLOC, size - i); + blk = swp_pager_getswapspace(&n, 1); + if (blk == SWAPBLK_NONE) { + swp_pager_meta_free(object, start, i); + VM_OBJECT_WUNLOCK(object); + return (-1); + } + for (j = 0; j < n; ++j) { + addr = swp_pager_meta_build(object, + start + i + j, blk + j); + if (addr != SWAPBLK_NONE) + swp_pager_update_freerange(&s_free, &n_free, + addr); } - addr = swp_pager_meta_build(object, start, blk); - if (addr != SWAPBLK_NONE) - swp_pager_update_freerange(&s_free, &n_free, addr); - --size; - ++start; - ++blk; - --n; } swp_pager_freeswapspace(s_free, n_free); - swp_pager_meta_free(object, start, n); VM_OBJECT_WUNLOCK(object); return (0); } @@ -1384,18 +1386,8 @@ swap_pager_putpages(vm_object_t object, vm_page_t *ma, int count, n = min(BLIST_MAX_ALLOC, count - i); n = min(n, nsw_cluster_max); - /* - * Get biggest block of swap we can. If we fail, fall - * back and try to allocate a smaller block. Don't go - * overboard trying to allocate space if it would overly - * fragment swap. - */ - while ( - (blk = swp_pager_getswapspace(n)) == SWAPBLK_NONE && - n > 4 - ) { - n >>= 1; - } + /* Get a block of swap of size up to size n. */ + blk = swp_pager_getswapspace(&n, 4); if (blk == SWAPBLK_NONE) { for (j = 0; j < n; ++j) rtvals[i+j] = VM_PAGER_FAIL;