1df8bae1dSRodney W. Grimes /* 226f9a767SRodney W. Grimes * Copyright (c) 1994 John S. Dyson 3df8bae1dSRodney W. Grimes * Copyright (c) 1990 University of Utah. 4df8bae1dSRodney W. Grimes * Copyright (c) 1991, 1993 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 8df8bae1dSRodney W. Grimes * the Systems Programming Group of the University of Utah Computer 9df8bae1dSRodney W. Grimes * Science Department. 10df8bae1dSRodney W. Grimes * 11df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 12df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 13df8bae1dSRodney W. Grimes * are met: 14df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 15df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 16df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 17df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 18df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 19df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 20df8bae1dSRodney W. Grimes * must display the following acknowledgement: 21df8bae1dSRodney W. Grimes * This product includes software developed by the University of 22df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 23df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 24df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 25df8bae1dSRodney W. Grimes * without specific prior written permission. 26df8bae1dSRodney W. Grimes * 27df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37df8bae1dSRodney W. Grimes * SUCH DAMAGE. 38df8bae1dSRodney W. Grimes * 39df8bae1dSRodney W. Grimes * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$ 40df8bae1dSRodney W. Grimes * 41df8bae1dSRodney W. Grimes * @(#)swap_pager.c 8.9 (Berkeley) 3/21/94 420a47b48bSJohn Dyson * $Id: swap_pager.c,v 1.66 1996/05/18 03:37:32 dyson Exp $ 43df8bae1dSRodney W. Grimes */ 44df8bae1dSRodney W. Grimes 45df8bae1dSRodney W. Grimes /* 46df8bae1dSRodney W. Grimes * Quick hack to page to dedicated partition(s). 47df8bae1dSRodney W. Grimes * TODO: 48df8bae1dSRodney W. Grimes * Add multiprocessor locks 49df8bae1dSRodney W. Grimes * Deal with async writes in a better fashion 50df8bae1dSRodney W. Grimes */ 51df8bae1dSRodney W. Grimes 52df8bae1dSRodney W. Grimes #include <sys/param.h> 53df8bae1dSRodney W. Grimes #include <sys/systm.h> 5464abb5a5SDavid Greenman #include <sys/kernel.h> 55df8bae1dSRodney W. Grimes #include <sys/proc.h> 56df8bae1dSRodney W. Grimes #include <sys/buf.h> 57df8bae1dSRodney W. Grimes #include <sys/vnode.h> 58df8bae1dSRodney W. Grimes #include <sys/malloc.h> 59efeaf95aSDavid Greenman #include <sys/vmmeter.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 6226f9a767SRodney W. Grimes #include <sys/rlist.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #include <vm/vm.h> 65efeaf95aSDavid Greenman #include <vm/vm_param.h> 66efeaf95aSDavid Greenman #include <vm/vm_prot.h> 67efeaf95aSDavid Greenman #include <vm/vm_object.h> 68df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 69efeaf95aSDavid Greenman #include <vm/vm_pager.h> 70df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h> 71df8bae1dSRodney W. Grimes #include <vm/swap_pager.h> 7264abb5a5SDavid Greenman #include <vm/vm_kern.h> 73efeaf95aSDavid Greenman #include <vm/vm_extern.h> 74df8bae1dSRodney W. Grimes 75df8bae1dSRodney W. Grimes #ifndef NPENDINGIO 760d94caffSDavid Greenman #define NPENDINGIO 10 77df8bae1dSRodney W. Grimes #endif 78df8bae1dSRodney W. Grimes 79f708ef1bSPoul-Henning Kamp static int nswiodone; 8026f9a767SRodney W. Grimes int swap_pager_full; 8126f9a767SRodney W. Grimes extern int vm_swap_size; 82f5a12711SPoul-Henning Kamp static int no_swap_space = 1; 83836e5d13SJohn Dyson struct rlisthdr swaplist; 8426f9a767SRodney W. Grimes 85a316d390SJohn Dyson #define MAX_PAGEOUT_CLUSTER 16 86df8bae1dSRodney W. Grimes 87df8bae1dSRodney W. Grimes TAILQ_HEAD(swpclean, swpagerclean); 88df8bae1dSRodney W. Grimes 8926f9a767SRodney W. Grimes typedef struct swpagerclean *swp_clean_t; 9026f9a767SRodney W. Grimes 91f708ef1bSPoul-Henning Kamp static struct swpagerclean { 92df8bae1dSRodney W. Grimes TAILQ_ENTRY(swpagerclean) spc_list; 93df8bae1dSRodney W. Grimes int spc_flags; 94df8bae1dSRodney W. Grimes struct buf *spc_bp; 952a4895f4SDavid Greenman vm_object_t spc_object; 96df8bae1dSRodney W. Grimes vm_offset_t spc_kva; 9726f9a767SRodney W. Grimes int spc_count; 9826f9a767SRodney W. Grimes vm_page_t spc_m[MAX_PAGEOUT_CLUSTER]; 99df8bae1dSRodney W. Grimes } swcleanlist[NPENDINGIO]; 10026f9a767SRodney W. Grimes 10126f9a767SRodney W. Grimes 102df8bae1dSRodney W. Grimes /* spc_flags values */ 10326f9a767SRodney W. Grimes #define SPC_ERROR 0x01 104df8bae1dSRodney W. Grimes 10526f9a767SRodney W. Grimes #define SWB_EMPTY (-1) 106df8bae1dSRodney W. Grimes 107f708ef1bSPoul-Henning Kamp /* list of completed page cleans */ 108f708ef1bSPoul-Henning Kamp static struct swpclean swap_pager_done; 109f708ef1bSPoul-Henning Kamp 110f708ef1bSPoul-Henning Kamp /* list of pending page cleans */ 111f708ef1bSPoul-Henning Kamp static struct swpclean swap_pager_inuse; 112f708ef1bSPoul-Henning Kamp 113f708ef1bSPoul-Henning Kamp /* list of free pager clean structs */ 114f708ef1bSPoul-Henning Kamp static struct swpclean swap_pager_free; 115f708ef1bSPoul-Henning Kamp 116f708ef1bSPoul-Henning Kamp /* list of "named" anon region objects */ 117f708ef1bSPoul-Henning Kamp static struct pagerlst swap_pager_object_list; 118f708ef1bSPoul-Henning Kamp 119f708ef1bSPoul-Henning Kamp /* list of "unnamed" anon region objects */ 120f708ef1bSPoul-Henning Kamp struct pagerlst swap_pager_un_object_list; 121df8bae1dSRodney W. Grimes 12226f9a767SRodney W. Grimes #define SWAP_FREE_NEEDED 0x1 /* need a swap block */ 123a1f6d91cSDavid Greenman #define SWAP_FREE_NEEDED_BY_PAGEOUT 0x2 124f708ef1bSPoul-Henning Kamp static int swap_pager_needflags; 12526f9a767SRodney W. Grimes 126f5a12711SPoul-Henning Kamp static struct pagerlst *swp_qs[] = { 12724a1cce3SDavid Greenman &swap_pager_object_list, &swap_pager_un_object_list, (struct pagerlst *) 0 12826f9a767SRodney W. Grimes }; 12926f9a767SRodney W. Grimes 13024a1cce3SDavid Greenman /* 13124a1cce3SDavid Greenman * pagerops for OBJT_SWAP - "swap pager". 13224a1cce3SDavid Greenman */ 133ff98689dSBruce Evans static vm_object_t 134ff98689dSBruce Evans swap_pager_alloc __P((void *handle, vm_size_t size, 135a316d390SJohn Dyson vm_prot_t prot, vm_ooffset_t offset)); 136ff98689dSBruce Evans static void swap_pager_dealloc __P((vm_object_t object)); 137ff98689dSBruce Evans static boolean_t 138a316d390SJohn Dyson swap_pager_haspage __P((vm_object_t object, vm_pindex_t pindex, 139ff98689dSBruce Evans int *before, int *after)); 140f708ef1bSPoul-Henning Kamp static int swap_pager_getpages __P((vm_object_t, vm_page_t *, int, int)); 141ff98689dSBruce Evans static void swap_pager_init __P((void)); 142f708ef1bSPoul-Henning Kamp static void swap_pager_sync __P((void)); 143f708ef1bSPoul-Henning Kamp 144df8bae1dSRodney W. Grimes struct pagerops swappagerops = { 145df8bae1dSRodney W. Grimes swap_pager_init, 146df8bae1dSRodney W. Grimes swap_pager_alloc, 147df8bae1dSRodney W. Grimes swap_pager_dealloc, 14824a1cce3SDavid Greenman swap_pager_getpages, 14924a1cce3SDavid Greenman swap_pager_putpages, 15024a1cce3SDavid Greenman swap_pager_haspage, 15124a1cce3SDavid Greenman swap_pager_sync 152df8bae1dSRodney W. Grimes }; 153df8bae1dSRodney W. Grimes 154f5a12711SPoul-Henning Kamp static int npendingio = NPENDINGIO; 155f708ef1bSPoul-Henning Kamp static int dmmin; 156f708ef1bSPoul-Henning Kamp int dmmax; 15726f9a767SRodney W. Grimes 158cac597e4SBruce Evans static __pure int 159f2c6b65bSBruce Evans swap_pager_block_index __P((vm_pindex_t pindex)) __pure2; 160cac597e4SBruce Evans static __pure int 161f2c6b65bSBruce Evans swap_pager_block_offset __P((vm_pindex_t pindex)) __pure2; 162a316d390SJohn Dyson static daddr_t *swap_pager_diskaddr __P((vm_object_t object, 163a316d390SJohn Dyson vm_pindex_t pindex, int *valid)); 164cac597e4SBruce Evans static void swap_pager_finish __P((swp_clean_t spc)); 165cac597e4SBruce Evans static void swap_pager_freepage __P((vm_page_t m)); 166cac597e4SBruce Evans static void swap_pager_free_swap __P((vm_object_t object)); 167cac597e4SBruce Evans static void swap_pager_freeswapspace __P((vm_object_t object, 168cac597e4SBruce Evans unsigned int from, 169cac597e4SBruce Evans unsigned int to)); 170cac597e4SBruce Evans static int swap_pager_getswapspace __P((vm_object_t object, 171cac597e4SBruce Evans unsigned int amount, 172a316d390SJohn Dyson daddr_t *rtval)); 173ff98689dSBruce Evans static void swap_pager_iodone __P((struct buf *)); 174cac597e4SBruce Evans static void swap_pager_iodone1 __P((struct buf *bp)); 175cac597e4SBruce Evans static void swap_pager_reclaim __P((void)); 176cac597e4SBruce Evans static void swap_pager_ridpages __P((vm_page_t *m, int count, 177cac597e4SBruce Evans int reqpage)); 178cac597e4SBruce Evans static void swap_pager_setvalid __P((vm_object_t object, 179cac597e4SBruce Evans vm_offset_t offset, int valid)); 180cac597e4SBruce Evans static void swapsizecheck __P((void)); 18124a1cce3SDavid Greenman 182de5f6a77SJohn Dyson #define SWAPLOW (vm_swap_size < (512 * btodb(PAGE_SIZE))) 183de5f6a77SJohn Dyson 1840d94caffSDavid Greenman static inline void 1850d94caffSDavid Greenman swapsizecheck() 1860d94caffSDavid Greenman { 18726f9a767SRodney W. Grimes if (vm_swap_size < 128 * btodb(PAGE_SIZE)) { 188a1f6d91cSDavid Greenman if (swap_pager_full == 0) 1891af87c92SDavid Greenman printf("swap_pager: out of swap space\n"); 19026f9a767SRodney W. Grimes swap_pager_full = 1; 19126f9a767SRodney W. Grimes } else if (vm_swap_size > 192 * btodb(PAGE_SIZE)) 19226f9a767SRodney W. Grimes swap_pager_full = 0; 19326f9a767SRodney W. Grimes } 19426f9a767SRodney W. Grimes 195f5a12711SPoul-Henning Kamp static void 196df8bae1dSRodney W. Grimes swap_pager_init() 197df8bae1dSRodney W. Grimes { 19824a1cce3SDavid Greenman TAILQ_INIT(&swap_pager_object_list); 19924a1cce3SDavid Greenman TAILQ_INIT(&swap_pager_un_object_list); 200df8bae1dSRodney W. Grimes 201df8bae1dSRodney W. Grimes /* 202df8bae1dSRodney W. Grimes * Initialize clean lists 203df8bae1dSRodney W. Grimes */ 204df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_inuse); 20526f9a767SRodney W. Grimes TAILQ_INIT(&swap_pager_done); 206df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_free); 20726f9a767SRodney W. Grimes 208df8bae1dSRodney W. Grimes /* 209df8bae1dSRodney W. Grimes * Calculate the swap allocation constants. 210df8bae1dSRodney W. Grimes */ 211e911eafcSPoul-Henning Kamp dmmin = PAGE_SIZE / DEV_BSIZE; 21226f9a767SRodney W. Grimes dmmax = btodb(SWB_NPAGES * PAGE_SIZE) * 2; 213df8bae1dSRodney W. Grimes } 214df8bae1dSRodney W. Grimes 21524a1cce3SDavid Greenman void 21624a1cce3SDavid Greenman swap_pager_swap_init() 217df8bae1dSRodney W. Grimes { 21826f9a767SRodney W. Grimes swp_clean_t spc; 21926f9a767SRodney W. Grimes struct buf *bp; 22024a1cce3SDavid Greenman int i; 2210d94caffSDavid Greenman 22226f9a767SRodney W. Grimes /* 2230d94caffSDavid Greenman * kva's are allocated here so that we dont need to keep doing 2240d94caffSDavid Greenman * kmem_alloc pageables at runtime 22526f9a767SRodney W. Grimes */ 22626f9a767SRodney W. Grimes for (i = 0, spc = swcleanlist; i < npendingio; i++, spc++) { 227fff93ab6SDavid Greenman spc->spc_kva = kmem_alloc_pageable(pager_map, PAGE_SIZE * MAX_PAGEOUT_CLUSTER); 22826f9a767SRodney W. Grimes if (!spc->spc_kva) { 22926f9a767SRodney W. Grimes break; 23026f9a767SRodney W. Grimes } 231a1f6d91cSDavid Greenman spc->spc_bp = malloc(sizeof(*bp), M_TEMP, M_KERNEL); 23226f9a767SRodney W. Grimes if (!spc->spc_bp) { 23326f9a767SRodney W. Grimes kmem_free_wakeup(pager_map, spc->spc_kva, PAGE_SIZE); 23426f9a767SRodney W. Grimes break; 23526f9a767SRodney W. Grimes } 23626f9a767SRodney W. Grimes spc->spc_flags = 0; 23726f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 23826f9a767SRodney W. Grimes } 23926f9a767SRodney W. Grimes } 24024a1cce3SDavid Greenman 24124a1cce3SDavid Greenman int 24224a1cce3SDavid Greenman swap_pager_swp_alloc(object, wait) 24324a1cce3SDavid Greenman vm_object_t object; 24424a1cce3SDavid Greenman int wait; 24524a1cce3SDavid Greenman { 2462a4895f4SDavid Greenman sw_blk_t swb; 2472a4895f4SDavid Greenman int nblocks; 24824a1cce3SDavid Greenman int i, j; 24924a1cce3SDavid Greenman 250a316d390SJohn Dyson nblocks = (object->size + SWB_NPAGES - 1) / SWB_NPAGES; 2512a4895f4SDavid Greenman swb = malloc(nblocks * sizeof(*swb), M_VMPGDATA, wait); 2522a4895f4SDavid Greenman if (swb == NULL) 25324a1cce3SDavid Greenman return 1; 25424a1cce3SDavid Greenman 2552a4895f4SDavid Greenman for (i = 0; i < nblocks; i++) { 2562a4895f4SDavid Greenman swb[i].swb_valid = 0; 2572a4895f4SDavid Greenman swb[i].swb_locked = 0; 25826f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) 2592a4895f4SDavid Greenman swb[i].swb_block[j] = SWB_EMPTY; 26026f9a767SRodney W. Grimes } 26126f9a767SRodney W. Grimes 2622a4895f4SDavid Greenman object->un_pager.swp.swp_nblocks = nblocks; 2632a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize = 0; 2642a4895f4SDavid Greenman object->un_pager.swp.swp_blocks = swb; 2652a4895f4SDavid Greenman object->un_pager.swp.swp_poip = 0; 26624a1cce3SDavid Greenman 26724a1cce3SDavid Greenman if (object->handle != NULL) { 26824a1cce3SDavid Greenman TAILQ_INSERT_TAIL(&swap_pager_object_list, object, pager_object_list); 269df8bae1dSRodney W. Grimes } else { 27024a1cce3SDavid Greenman TAILQ_INSERT_TAIL(&swap_pager_un_object_list, object, pager_object_list); 271df8bae1dSRodney W. Grimes } 272df8bae1dSRodney W. Grimes 27324a1cce3SDavid Greenman return 0; 27424a1cce3SDavid Greenman } 27524a1cce3SDavid Greenman 27624a1cce3SDavid Greenman /* 2772a4895f4SDavid Greenman * Allocate an object and associated resources. 27824a1cce3SDavid Greenman * Note that if we are called from the pageout daemon (handle == NULL) 27924a1cce3SDavid Greenman * we should not wait for memory as it could resulting in deadlock. 28024a1cce3SDavid Greenman */ 281f5a12711SPoul-Henning Kamp static vm_object_t 28224a1cce3SDavid Greenman swap_pager_alloc(handle, size, prot, offset) 28324a1cce3SDavid Greenman void *handle; 28424a1cce3SDavid Greenman register vm_size_t size; 28524a1cce3SDavid Greenman vm_prot_t prot; 286a316d390SJohn Dyson vm_ooffset_t offset; 28724a1cce3SDavid Greenman { 28824a1cce3SDavid Greenman vm_object_t object; 28924a1cce3SDavid Greenman 29024a1cce3SDavid Greenman /* 29124a1cce3SDavid Greenman * If this is a "named" anonymous region, look it up and use the 29224a1cce3SDavid Greenman * object if it exists, otherwise allocate a new one. 29324a1cce3SDavid Greenman */ 29424a1cce3SDavid Greenman if (handle) { 29524a1cce3SDavid Greenman object = vm_pager_object_lookup(&swap_pager_object_list, handle); 29624a1cce3SDavid Greenman if (object != NULL) { 29724a1cce3SDavid Greenman vm_object_reference(object); 29824a1cce3SDavid Greenman } else { 29924a1cce3SDavid Greenman /* 30024a1cce3SDavid Greenman * XXX - there is a race condition here. Two processes 30124a1cce3SDavid Greenman * can request the same named object simultaneuously, 30224a1cce3SDavid Greenman * and if one blocks for memory, the result is a disaster. 30324a1cce3SDavid Greenman * Probably quite rare, but is yet another reason to just 30424a1cce3SDavid Greenman * rip support of "named anonymous regions" out altogether. 30524a1cce3SDavid Greenman */ 306a316d390SJohn Dyson object = vm_object_allocate(OBJT_SWAP, 307aa8de40aSPoul-Henning Kamp OFF_TO_IDX(offset + PAGE_MASK) + size); 30824a1cce3SDavid Greenman object->handle = handle; 30924a1cce3SDavid Greenman (void) swap_pager_swp_alloc(object, M_WAITOK); 31024a1cce3SDavid Greenman } 31124a1cce3SDavid Greenman } else { 312a316d390SJohn Dyson object = vm_object_allocate(OBJT_SWAP, 313aa8de40aSPoul-Henning Kamp OFF_TO_IDX(offset + PAGE_MASK) + size); 31424a1cce3SDavid Greenman (void) swap_pager_swp_alloc(object, M_WAITOK); 31524a1cce3SDavid Greenman } 31624a1cce3SDavid Greenman 31724a1cce3SDavid Greenman return (object); 318df8bae1dSRodney W. Grimes } 319df8bae1dSRodney W. Grimes 32026f9a767SRodney W. Grimes /* 32126f9a767SRodney W. Grimes * returns disk block associated with pager and offset 32226f9a767SRodney W. Grimes * additionally, as a side effect returns a flag indicating 32326f9a767SRodney W. Grimes * if the block has been written 32426f9a767SRodney W. Grimes */ 32526f9a767SRodney W. Grimes 326a316d390SJohn Dyson inline static daddr_t * 327a316d390SJohn Dyson swap_pager_diskaddr(object, pindex, valid) 32824a1cce3SDavid Greenman vm_object_t object; 329a316d390SJohn Dyson vm_pindex_t pindex; 33026f9a767SRodney W. Grimes int *valid; 33126f9a767SRodney W. Grimes { 33226f9a767SRodney W. Grimes register sw_blk_t swb; 33326f9a767SRodney W. Grimes int ix; 33426f9a767SRodney W. Grimes 33526f9a767SRodney W. Grimes if (valid) 33626f9a767SRodney W. Grimes *valid = 0; 337a316d390SJohn Dyson ix = pindex / SWB_NPAGES; 3382a4895f4SDavid Greenman if ((ix >= object->un_pager.swp.swp_nblocks) || 339a316d390SJohn Dyson (pindex >= object->size)) { 34026f9a767SRodney W. Grimes return (FALSE); 34126f9a767SRodney W. Grimes } 3422a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 343a316d390SJohn Dyson ix = pindex % SWB_NPAGES; 34426f9a767SRodney W. Grimes if (valid) 34526f9a767SRodney W. Grimes *valid = swb->swb_valid & (1 << ix); 34626f9a767SRodney W. Grimes return &swb->swb_block[ix]; 34726f9a767SRodney W. Grimes } 34826f9a767SRodney W. Grimes 34926f9a767SRodney W. Grimes /* 35026f9a767SRodney W. Grimes * Utility routine to set the valid (written) bit for 35126f9a767SRodney W. Grimes * a block associated with a pager and offset 35226f9a767SRodney W. Grimes */ 353df8bae1dSRodney W. Grimes static void 3542a4895f4SDavid Greenman swap_pager_setvalid(object, offset, valid) 3552a4895f4SDavid Greenman vm_object_t object; 35626f9a767SRodney W. Grimes vm_offset_t offset; 35726f9a767SRodney W. Grimes int valid; 35826f9a767SRodney W. Grimes { 35926f9a767SRodney W. Grimes register sw_blk_t swb; 36026f9a767SRodney W. Grimes int ix; 36126f9a767SRodney W. Grimes 362a316d390SJohn Dyson ix = offset / SWB_NPAGES; 3632a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) 36426f9a767SRodney W. Grimes return; 36526f9a767SRodney W. Grimes 3662a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 367a316d390SJohn Dyson ix = offset % SWB_NPAGES; 36826f9a767SRodney W. Grimes if (valid) 36926f9a767SRodney W. Grimes swb->swb_valid |= (1 << ix); 37026f9a767SRodney W. Grimes else 37126f9a767SRodney W. Grimes swb->swb_valid &= ~(1 << ix); 37226f9a767SRodney W. Grimes return; 37326f9a767SRodney W. Grimes } 37426f9a767SRodney W. Grimes 37526f9a767SRodney W. Grimes /* 37626f9a767SRodney W. Grimes * this routine allocates swap space with a fragmentation 37726f9a767SRodney W. Grimes * minimization policy. 37826f9a767SRodney W. Grimes */ 379f5a12711SPoul-Henning Kamp static int 3802a4895f4SDavid Greenman swap_pager_getswapspace(object, amount, rtval) 3812a4895f4SDavid Greenman vm_object_t object; 3822a4895f4SDavid Greenman unsigned int amount; 383a316d390SJohn Dyson daddr_t *rtval; 3840d94caffSDavid Greenman { 385a316d390SJohn Dyson unsigned location; 38624ea4a96SDavid Greenman vm_swap_size -= amount; 387a316d390SJohn Dyson if (!rlist_alloc(&swaplist, amount, &location)) { 38824ea4a96SDavid Greenman vm_swap_size += amount; 38926f9a767SRodney W. Grimes return 0; 39024ea4a96SDavid Greenman } else { 39124ea4a96SDavid Greenman swapsizecheck(); 3922a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize += amount; 393a316d390SJohn Dyson *rtval = location; 39426f9a767SRodney W. Grimes return 1; 39526f9a767SRodney W. Grimes } 39626f9a767SRodney W. Grimes } 39726f9a767SRodney W. Grimes 39826f9a767SRodney W. Grimes /* 39926f9a767SRodney W. Grimes * this routine frees swap space with a fragmentation 40026f9a767SRodney W. Grimes * minimization policy. 40126f9a767SRodney W. Grimes */ 402f5a12711SPoul-Henning Kamp static void 4032a4895f4SDavid Greenman swap_pager_freeswapspace(object, from, to) 4042a4895f4SDavid Greenman vm_object_t object; 4052a4895f4SDavid Greenman unsigned int from; 4062a4895f4SDavid Greenman unsigned int to; 4070d94caffSDavid Greenman { 40835c10d22SDavid Greenman rlist_free(&swaplist, from, to); 40924ea4a96SDavid Greenman vm_swap_size += (to - from) + 1; 4102a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize -= (to - from) + 1; 41124ea4a96SDavid Greenman swapsizecheck(); 41226f9a767SRodney W. Grimes } 41326f9a767SRodney W. Grimes /* 41426f9a767SRodney W. Grimes * this routine frees swap blocks from a specified pager 41526f9a767SRodney W. Grimes */ 41626f9a767SRodney W. Grimes void 41724a1cce3SDavid Greenman swap_pager_freespace(object, start, size) 41824a1cce3SDavid Greenman vm_object_t object; 419a316d390SJohn Dyson vm_pindex_t start; 420a316d390SJohn Dyson vm_size_t size; 42126f9a767SRodney W. Grimes { 422a316d390SJohn Dyson vm_pindex_t i; 42326f9a767SRodney W. Grimes int s; 42426f9a767SRodney W. Grimes 42526f9a767SRodney W. Grimes s = splbio(); 426a316d390SJohn Dyson for (i = start; i < start + size; i += 1) { 42726f9a767SRodney W. Grimes int valid; 428a316d390SJohn Dyson daddr_t *addr = swap_pager_diskaddr(object, i, &valid); 4290d94caffSDavid Greenman 43026f9a767SRodney W. Grimes if (addr && *addr != SWB_EMPTY) { 4312a4895f4SDavid Greenman swap_pager_freeswapspace(object, *addr, *addr + btodb(PAGE_SIZE) - 1); 43226f9a767SRodney W. Grimes if (valid) { 4332a4895f4SDavid Greenman swap_pager_setvalid(object, i, 0); 43426f9a767SRodney W. Grimes } 43526f9a767SRodney W. Grimes *addr = SWB_EMPTY; 43626f9a767SRodney W. Grimes } 43726f9a767SRodney W. Grimes } 43826f9a767SRodney W. Grimes splx(s); 43926f9a767SRodney W. Grimes } 44026f9a767SRodney W. Grimes 4410a47b48bSJohn Dyson /* 4420a47b48bSJohn Dyson * same as freespace, but don't free, just force a DMZ next time 4430a47b48bSJohn Dyson */ 4440a47b48bSJohn Dyson void 4450a47b48bSJohn Dyson swap_pager_dmzspace(object, start, size) 4460a47b48bSJohn Dyson vm_object_t object; 4470a47b48bSJohn Dyson vm_pindex_t start; 4480a47b48bSJohn Dyson vm_size_t size; 4490a47b48bSJohn Dyson { 4500a47b48bSJohn Dyson vm_pindex_t i; 4510a47b48bSJohn Dyson int s; 4520a47b48bSJohn Dyson 4530a47b48bSJohn Dyson s = splbio(); 4540a47b48bSJohn Dyson for (i = start; i < start + size; i += 1) { 4550a47b48bSJohn Dyson int valid; 4560a47b48bSJohn Dyson daddr_t *addr = swap_pager_diskaddr(object, i, &valid); 4570a47b48bSJohn Dyson 4580a47b48bSJohn Dyson if (addr && *addr != SWB_EMPTY) { 4590a47b48bSJohn Dyson if (valid) { 4600a47b48bSJohn Dyson swap_pager_setvalid(object, i, 0); 4610a47b48bSJohn Dyson } 4620a47b48bSJohn Dyson } 4630a47b48bSJohn Dyson } 4640a47b48bSJohn Dyson splx(s); 4650a47b48bSJohn Dyson } 4660a47b48bSJohn Dyson 467a1f6d91cSDavid Greenman static void 4682a4895f4SDavid Greenman swap_pager_free_swap(object) 4692a4895f4SDavid Greenman vm_object_t object; 470a1f6d91cSDavid Greenman { 471a1f6d91cSDavid Greenman register int i, j; 4722a4895f4SDavid Greenman register sw_blk_t swb; 473a1f6d91cSDavid Greenman int first_block=0, block_count=0; 474a1f6d91cSDavid Greenman int s; 475a1f6d91cSDavid Greenman /* 476a1f6d91cSDavid Greenman * Free left over swap blocks 477a1f6d91cSDavid Greenman */ 478a1f6d91cSDavid Greenman s = splbio(); 4792a4895f4SDavid Greenman for (i = 0, swb = object->un_pager.swp.swp_blocks; 4802a4895f4SDavid Greenman i < object->un_pager.swp.swp_nblocks; i++, swb++) { 481a1f6d91cSDavid Greenman for (j = 0; j < SWB_NPAGES; j++) { 4822a4895f4SDavid Greenman if (swb->swb_block[j] != SWB_EMPTY) { 483a1f6d91cSDavid Greenman /* 484a1f6d91cSDavid Greenman * initially the length of the run is zero 485a1f6d91cSDavid Greenman */ 486a1f6d91cSDavid Greenman if (block_count == 0) { 4872a4895f4SDavid Greenman first_block = swb->swb_block[j]; 488a1f6d91cSDavid Greenman block_count = btodb(PAGE_SIZE); 4892a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 490a1f6d91cSDavid Greenman /* 491a1f6d91cSDavid Greenman * if the new block can be included into the current run 492a1f6d91cSDavid Greenman */ 4932a4895f4SDavid Greenman } else if (swb->swb_block[j] == first_block + block_count) { 494a1f6d91cSDavid Greenman block_count += btodb(PAGE_SIZE); 4952a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 496a1f6d91cSDavid Greenman /* 497a1f6d91cSDavid Greenman * terminate the previous run, and start a new one 498a1f6d91cSDavid Greenman */ 499a1f6d91cSDavid Greenman } else { 5002a4895f4SDavid Greenman swap_pager_freeswapspace(object, first_block, 501a1f6d91cSDavid Greenman (unsigned) first_block + block_count - 1); 5022a4895f4SDavid Greenman first_block = swb->swb_block[j]; 503a1f6d91cSDavid Greenman block_count = btodb(PAGE_SIZE); 5042a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 505a1f6d91cSDavid Greenman } 506a1f6d91cSDavid Greenman } 507a1f6d91cSDavid Greenman } 508a1f6d91cSDavid Greenman } 509a1f6d91cSDavid Greenman 510a1f6d91cSDavid Greenman if (block_count) { 5112a4895f4SDavid Greenman swap_pager_freeswapspace(object, first_block, 512a1f6d91cSDavid Greenman (unsigned) first_block + block_count - 1); 513a1f6d91cSDavid Greenman } 514a1f6d91cSDavid Greenman splx(s); 515a1f6d91cSDavid Greenman } 516a1f6d91cSDavid Greenman 517a1f6d91cSDavid Greenman 51826f9a767SRodney W. Grimes /* 51926f9a767SRodney W. Grimes * swap_pager_reclaim frees up over-allocated space from all pagers 52026f9a767SRodney W. Grimes * this eliminates internal fragmentation due to allocation of space 52126f9a767SRodney W. Grimes * for segments that are never swapped to. It has been written so that 52226f9a767SRodney W. Grimes * it does not block until the rlist_free operation occurs; it keeps 52326f9a767SRodney W. Grimes * the queues consistant. 52426f9a767SRodney W. Grimes */ 52526f9a767SRodney W. Grimes 52626f9a767SRodney W. Grimes /* 52726f9a767SRodney W. Grimes * Maximum number of blocks (pages) to reclaim per pass 52826f9a767SRodney W. Grimes */ 529a1f6d91cSDavid Greenman #define MAXRECLAIM 128 53026f9a767SRodney W. Grimes 531f5a12711SPoul-Henning Kamp static void 53226f9a767SRodney W. Grimes swap_pager_reclaim() 53326f9a767SRodney W. Grimes { 53424a1cce3SDavid Greenman vm_object_t object; 53526f9a767SRodney W. Grimes int i, j, k; 53626f9a767SRodney W. Grimes int s; 53726f9a767SRodney W. Grimes int reclaimcount; 538a1f6d91cSDavid Greenman static struct { 539a1f6d91cSDavid Greenman int address; 5402a4895f4SDavid Greenman vm_object_t object; 541a1f6d91cSDavid Greenman } reclaims[MAXRECLAIM]; 54226f9a767SRodney W. Grimes static int in_reclaim; 54326f9a767SRodney W. Grimes 54426f9a767SRodney W. Grimes /* 54526f9a767SRodney W. Grimes * allow only one process to be in the swap_pager_reclaim subroutine 54626f9a767SRodney W. Grimes */ 54726f9a767SRodney W. Grimes s = splbio(); 54826f9a767SRodney W. Grimes if (in_reclaim) { 54924a1cce3SDavid Greenman tsleep(&in_reclaim, PSWP, "swrclm", 0); 55026f9a767SRodney W. Grimes splx(s); 55126f9a767SRodney W. Grimes return; 55226f9a767SRodney W. Grimes } 55326f9a767SRodney W. Grimes in_reclaim = 1; 55426f9a767SRodney W. Grimes reclaimcount = 0; 55526f9a767SRodney W. Grimes 55626f9a767SRodney W. Grimes /* for each pager queue */ 55726f9a767SRodney W. Grimes for (k = 0; swp_qs[k]; k++) { 55826f9a767SRodney W. Grimes 559b18bfc3dSJohn Dyson object = TAILQ_FIRST(swp_qs[k]); 56024a1cce3SDavid Greenman while (object && (reclaimcount < MAXRECLAIM)) { 56126f9a767SRodney W. Grimes 56226f9a767SRodney W. Grimes /* 56326f9a767SRodney W. Grimes * see if any blocks associated with a pager has been 56426f9a767SRodney W. Grimes * allocated but not used (written) 56526f9a767SRodney W. Grimes */ 566a316d390SJohn Dyson if (object->paging_in_progress == 0) { 5672a4895f4SDavid Greenman for (i = 0; i < object->un_pager.swp.swp_nblocks; i++) { 5682a4895f4SDavid Greenman sw_blk_t swb = &object->un_pager.swp.swp_blocks[i]; 5690d94caffSDavid Greenman 57026f9a767SRodney W. Grimes if (swb->swb_locked) 57126f9a767SRodney W. Grimes continue; 57226f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) { 57326f9a767SRodney W. Grimes if (swb->swb_block[j] != SWB_EMPTY && 57426f9a767SRodney W. Grimes (swb->swb_valid & (1 << j)) == 0) { 575a1f6d91cSDavid Greenman reclaims[reclaimcount].address = swb->swb_block[j]; 5762a4895f4SDavid Greenman reclaims[reclaimcount++].object = object; 57726f9a767SRodney W. Grimes swb->swb_block[j] = SWB_EMPTY; 57826f9a767SRodney W. Grimes if (reclaimcount >= MAXRECLAIM) 57926f9a767SRodney W. Grimes goto rfinished; 58026f9a767SRodney W. Grimes } 58126f9a767SRodney W. Grimes } 58226f9a767SRodney W. Grimes } 583a316d390SJohn Dyson } 584b18bfc3dSJohn Dyson object = TAILQ_NEXT(object, pager_object_list); 58526f9a767SRodney W. Grimes } 58626f9a767SRodney W. Grimes } 58726f9a767SRodney W. Grimes 58826f9a767SRodney W. Grimes rfinished: 58926f9a767SRodney W. Grimes 59026f9a767SRodney W. Grimes /* 59126f9a767SRodney W. Grimes * free the blocks that have been added to the reclaim list 59226f9a767SRodney W. Grimes */ 59326f9a767SRodney W. Grimes for (i = 0; i < reclaimcount; i++) { 5942a4895f4SDavid Greenman swap_pager_freeswapspace(reclaims[i].object, 5952a4895f4SDavid Greenman reclaims[i].address, reclaims[i].address + btodb(PAGE_SIZE) - 1); 59626f9a767SRodney W. Grimes } 59726f9a767SRodney W. Grimes splx(s); 59826f9a767SRodney W. Grimes in_reclaim = 0; 59924a1cce3SDavid Greenman wakeup(&in_reclaim); 60026f9a767SRodney W. Grimes } 60126f9a767SRodney W. Grimes 60226f9a767SRodney W. Grimes 60326f9a767SRodney W. Grimes /* 60426f9a767SRodney W. Grimes * swap_pager_copy copies blocks from one pager to another and 60526f9a767SRodney W. Grimes * destroys the source pager 60626f9a767SRodney W. Grimes */ 60726f9a767SRodney W. Grimes 60826f9a767SRodney W. Grimes void 60924a1cce3SDavid Greenman swap_pager_copy(srcobject, srcoffset, dstobject, dstoffset, offset) 61024a1cce3SDavid Greenman vm_object_t srcobject; 611a316d390SJohn Dyson vm_pindex_t srcoffset; 61224a1cce3SDavid Greenman vm_object_t dstobject; 613a316d390SJohn Dyson vm_pindex_t dstoffset; 614a316d390SJohn Dyson vm_pindex_t offset; 61526f9a767SRodney W. Grimes { 616a316d390SJohn Dyson vm_pindex_t i; 617a1f6d91cSDavid Greenman int origsize; 61826f9a767SRodney W. Grimes int s; 61926f9a767SRodney W. Grimes 62024ea4a96SDavid Greenman if (vm_swap_size) 62124ea4a96SDavid Greenman no_swap_space = 0; 62224ea4a96SDavid Greenman 6232a4895f4SDavid Greenman origsize = srcobject->un_pager.swp.swp_allocsize; 62426f9a767SRodney W. Grimes 62526f9a767SRodney W. Grimes /* 62624a1cce3SDavid Greenman * remove the source object from the swap_pager internal queue 62726f9a767SRodney W. Grimes */ 62824a1cce3SDavid Greenman if (srcobject->handle == NULL) { 62924a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_un_object_list, srcobject, pager_object_list); 63026f9a767SRodney W. Grimes } else { 63124a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_object_list, srcobject, pager_object_list); 63226f9a767SRodney W. Grimes } 63326f9a767SRodney W. Grimes 63424a1cce3SDavid Greenman s = splbio(); 6352a4895f4SDavid Greenman while (srcobject->un_pager.swp.swp_poip) { 6362a4895f4SDavid Greenman tsleep(srcobject, PVM, "spgout", 0); 63726f9a767SRodney W. Grimes } 63826f9a767SRodney W. Grimes splx(s); 63926f9a767SRodney W. Grimes 64026f9a767SRodney W. Grimes /* 64126f9a767SRodney W. Grimes * clean all of the pages that are currently active and finished 64226f9a767SRodney W. Grimes */ 64324a1cce3SDavid Greenman swap_pager_sync(); 64426f9a767SRodney W. Grimes 64526f9a767SRodney W. Grimes s = splbio(); 64626f9a767SRodney W. Grimes /* 64726f9a767SRodney W. Grimes * transfer source to destination 64826f9a767SRodney W. Grimes */ 649a316d390SJohn Dyson for (i = 0; i < dstobject->size; i += 1) { 65026f9a767SRodney W. Grimes int srcvalid, dstvalid; 651a316d390SJohn Dyson daddr_t *srcaddrp = swap_pager_diskaddr(srcobject, i + offset + srcoffset, 65226f9a767SRodney W. Grimes &srcvalid); 653a316d390SJohn Dyson daddr_t *dstaddrp; 6540d94caffSDavid Greenman 65526f9a767SRodney W. Grimes /* 65626f9a767SRodney W. Grimes * see if the source has space allocated 65726f9a767SRodney W. Grimes */ 65826f9a767SRodney W. Grimes if (srcaddrp && *srcaddrp != SWB_EMPTY) { 65926f9a767SRodney W. Grimes /* 6600d94caffSDavid Greenman * if the source is valid and the dest has no space, 6610d94caffSDavid Greenman * then copy the allocation from the srouce to the 6620d94caffSDavid Greenman * dest. 66326f9a767SRodney W. Grimes */ 66426f9a767SRodney W. Grimes if (srcvalid) { 66524a1cce3SDavid Greenman dstaddrp = swap_pager_diskaddr(dstobject, i + dstoffset, 666a1f6d91cSDavid Greenman &dstvalid); 66726f9a767SRodney W. Grimes /* 6680d94caffSDavid Greenman * if the dest already has a valid block, 6690d94caffSDavid Greenman * deallocate the source block without 6700d94caffSDavid Greenman * copying. 67126f9a767SRodney W. Grimes */ 67226f9a767SRodney W. Grimes if (!dstvalid && dstaddrp && *dstaddrp != SWB_EMPTY) { 6732a4895f4SDavid Greenman swap_pager_freeswapspace(dstobject, *dstaddrp, 674a1f6d91cSDavid Greenman *dstaddrp + btodb(PAGE_SIZE) - 1); 67526f9a767SRodney W. Grimes *dstaddrp = SWB_EMPTY; 67626f9a767SRodney W. Grimes } 67726f9a767SRodney W. Grimes if (dstaddrp && *dstaddrp == SWB_EMPTY) { 67826f9a767SRodney W. Grimes *dstaddrp = *srcaddrp; 67926f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 6802a4895f4SDavid Greenman dstobject->un_pager.swp.swp_allocsize += btodb(PAGE_SIZE); 6812a4895f4SDavid Greenman srcobject->un_pager.swp.swp_allocsize -= btodb(PAGE_SIZE); 6822a4895f4SDavid Greenman swap_pager_setvalid(dstobject, i + dstoffset, 1); 68326f9a767SRodney W. Grimes } 68426f9a767SRodney W. Grimes } 68526f9a767SRodney W. Grimes /* 6860d94caffSDavid Greenman * if the source is not empty at this point, then 6870d94caffSDavid Greenman * deallocate the space. 68826f9a767SRodney W. Grimes */ 68926f9a767SRodney W. Grimes if (*srcaddrp != SWB_EMPTY) { 6902a4895f4SDavid Greenman swap_pager_freeswapspace(srcobject, *srcaddrp, 691a1f6d91cSDavid Greenman *srcaddrp + btodb(PAGE_SIZE) - 1); 69226f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 69326f9a767SRodney W. Grimes } 69426f9a767SRodney W. Grimes } 69526f9a767SRodney W. Grimes } 69626f9a767SRodney W. Grimes splx(s); 69726f9a767SRodney W. Grimes 698a1f6d91cSDavid Greenman /* 699a1f6d91cSDavid Greenman * Free left over swap blocks 700a1f6d91cSDavid Greenman */ 7012a4895f4SDavid Greenman swap_pager_free_swap(srcobject); 702a1f6d91cSDavid Greenman 7032a4895f4SDavid Greenman if (srcobject->un_pager.swp.swp_allocsize) { 7042a4895f4SDavid Greenman printf("swap_pager_copy: *warning* pager with %d blocks (orig: %d)\n", 7052a4895f4SDavid Greenman srcobject->un_pager.swp.swp_allocsize, origsize); 7062a4895f4SDavid Greenman } 7072a4895f4SDavid Greenman 7082a4895f4SDavid Greenman free(srcobject->un_pager.swp.swp_blocks, M_VMPGDATA); 7092a4895f4SDavid Greenman srcobject->un_pager.swp.swp_blocks = NULL; 71026f9a767SRodney W. Grimes 71126f9a767SRodney W. Grimes return; 71226f9a767SRodney W. Grimes } 71326f9a767SRodney W. Grimes 714f5a12711SPoul-Henning Kamp static void 71524a1cce3SDavid Greenman swap_pager_dealloc(object) 71624a1cce3SDavid Greenman vm_object_t object; 717df8bae1dSRodney W. Grimes { 718df8bae1dSRodney W. Grimes int s; 719df8bae1dSRodney W. Grimes 720df8bae1dSRodney W. Grimes /* 7210d94caffSDavid Greenman * Remove from list right away so lookups will fail if we block for 7220d94caffSDavid Greenman * pageout completion. 723df8bae1dSRodney W. Grimes */ 72424a1cce3SDavid Greenman if (object->handle == NULL) { 72524a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_un_object_list, object, pager_object_list); 72626f9a767SRodney W. Grimes } else { 72724a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_object_list, object, pager_object_list); 728df8bae1dSRodney W. Grimes } 72924a1cce3SDavid Greenman 730df8bae1dSRodney W. Grimes /* 7310d94caffSDavid Greenman * Wait for all pageouts to finish and remove all entries from 7320d94caffSDavid Greenman * cleaning list. 733df8bae1dSRodney W. Grimes */ 73426f9a767SRodney W. Grimes 73524a1cce3SDavid Greenman s = splbio(); 7362a4895f4SDavid Greenman while (object->un_pager.swp.swp_poip) { 7372a4895f4SDavid Greenman tsleep(object, PVM, "swpout", 0); 738df8bae1dSRodney W. Grimes } 739df8bae1dSRodney W. Grimes splx(s); 74026f9a767SRodney W. Grimes 74126f9a767SRodney W. Grimes 74224a1cce3SDavid Greenman swap_pager_sync(); 743df8bae1dSRodney W. Grimes 744df8bae1dSRodney W. Grimes /* 745df8bae1dSRodney W. Grimes * Free left over swap blocks 746df8bae1dSRodney W. Grimes */ 7472a4895f4SDavid Greenman swap_pager_free_swap(object); 74826f9a767SRodney W. Grimes 7492a4895f4SDavid Greenman if (object->un_pager.swp.swp_allocsize) { 7502a4895f4SDavid Greenman printf("swap_pager_dealloc: *warning* freeing pager with %d blocks\n", 7512a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize); 7522a4895f4SDavid Greenman } 753df8bae1dSRodney W. Grimes /* 754df8bae1dSRodney W. Grimes * Free swap management resources 755df8bae1dSRodney W. Grimes */ 7562a4895f4SDavid Greenman free(object->un_pager.swp.swp_blocks, M_VMPGDATA); 7572a4895f4SDavid Greenman object->un_pager.swp.swp_blocks = NULL; 75826f9a767SRodney W. Grimes } 75926f9a767SRodney W. Grimes 760cac597e4SBruce Evans static inline __pure int 761a316d390SJohn Dyson swap_pager_block_index(pindex) 762a316d390SJohn Dyson vm_pindex_t pindex; 76326f9a767SRodney W. Grimes { 764a316d390SJohn Dyson return (pindex / SWB_NPAGES); 76526f9a767SRodney W. Grimes } 76626f9a767SRodney W. Grimes 767cac597e4SBruce Evans static inline __pure int 768a316d390SJohn Dyson swap_pager_block_offset(pindex) 769a316d390SJohn Dyson vm_pindex_t pindex; 77026f9a767SRodney W. Grimes { 771a316d390SJohn Dyson return (pindex % SWB_NPAGES); 77226f9a767SRodney W. Grimes } 77326f9a767SRodney W. Grimes 77426f9a767SRodney W. Grimes /* 77524a1cce3SDavid Greenman * swap_pager_haspage returns TRUE if the pager has data that has 77626f9a767SRodney W. Grimes * been written out. 77726f9a767SRodney W. Grimes */ 778f5a12711SPoul-Henning Kamp static boolean_t 779a316d390SJohn Dyson swap_pager_haspage(object, pindex, before, after) 78024a1cce3SDavid Greenman vm_object_t object; 781a316d390SJohn Dyson vm_pindex_t pindex; 78224a1cce3SDavid Greenman int *before; 78324a1cce3SDavid Greenman int *after; 78426f9a767SRodney W. Grimes { 78526f9a767SRodney W. Grimes register sw_blk_t swb; 78626f9a767SRodney W. Grimes int ix; 78726f9a767SRodney W. Grimes 78824a1cce3SDavid Greenman if (before != NULL) 78924a1cce3SDavid Greenman *before = 0; 79024a1cce3SDavid Greenman if (after != NULL) 79124a1cce3SDavid Greenman *after = 0; 792a316d390SJohn Dyson ix = pindex / SWB_NPAGES; 7932a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 79426f9a767SRodney W. Grimes return (FALSE); 79526f9a767SRodney W. Grimes } 7962a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 797a316d390SJohn Dyson ix = pindex % SWB_NPAGES; 798170db9c6SJohn Dyson 79926f9a767SRodney W. Grimes if (swb->swb_block[ix] != SWB_EMPTY) { 800170db9c6SJohn Dyson 801170db9c6SJohn Dyson if (swb->swb_valid & (1 << ix)) { 802170db9c6SJohn Dyson int tix; 803170db9c6SJohn Dyson if (before) { 804170db9c6SJohn Dyson for(tix = ix - 1; tix >= 0; --tix) { 8052f82e604SDavid Greenman if ((swb->swb_valid & (1 << tix)) == 0) 8062f82e604SDavid Greenman break; 807ca56715fSJohn Dyson if ((swb->swb_block[tix] + 808170db9c6SJohn Dyson (ix - tix) * (PAGE_SIZE/DEV_BSIZE)) != 809170db9c6SJohn Dyson swb->swb_block[ix]) 810170db9c6SJohn Dyson break; 811170db9c6SJohn Dyson (*before)++; 812170db9c6SJohn Dyson } 813170db9c6SJohn Dyson } 814170db9c6SJohn Dyson 815170db9c6SJohn Dyson if (after) { 816170db9c6SJohn Dyson for(tix = ix + 1; tix < SWB_NPAGES; tix++) { 8172f82e604SDavid Greenman if ((swb->swb_valid & (1 << tix)) == 0) 8182f82e604SDavid Greenman break; 819ca56715fSJohn Dyson if ((swb->swb_block[tix] - 820170db9c6SJohn Dyson (tix - ix) * (PAGE_SIZE/DEV_BSIZE)) != 821170db9c6SJohn Dyson swb->swb_block[ix]) 822170db9c6SJohn Dyson break; 823170db9c6SJohn Dyson (*after)++; 824170db9c6SJohn Dyson } 825170db9c6SJohn Dyson } 826170db9c6SJohn Dyson 82726f9a767SRodney W. Grimes return TRUE; 82826f9a767SRodney W. Grimes } 829170db9c6SJohn Dyson } 83026f9a767SRodney W. Grimes return (FALSE); 83126f9a767SRodney W. Grimes } 83226f9a767SRodney W. Grimes 83326f9a767SRodney W. Grimes /* 83426f9a767SRodney W. Grimes * swap_pager_freepage is a convienience routine that clears the busy 83526f9a767SRodney W. Grimes * bit and deallocates a page. 836df8bae1dSRodney W. Grimes */ 83726f9a767SRodney W. Grimes static void 83826f9a767SRodney W. Grimes swap_pager_freepage(m) 83926f9a767SRodney W. Grimes vm_page_t m; 84026f9a767SRodney W. Grimes { 84126f9a767SRodney W. Grimes PAGE_WAKEUP(m); 84226f9a767SRodney W. Grimes vm_page_free(m); 84326f9a767SRodney W. Grimes } 84426f9a767SRodney W. Grimes 84526f9a767SRodney W. Grimes /* 84626f9a767SRodney W. Grimes * swap_pager_ridpages is a convienience routine that deallocates all 84726f9a767SRodney W. Grimes * but the required page. this is usually used in error returns that 84826f9a767SRodney W. Grimes * need to invalidate the "extra" readahead pages. 84926f9a767SRodney W. Grimes */ 85026f9a767SRodney W. Grimes static void 85126f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage) 85226f9a767SRodney W. Grimes vm_page_t *m; 85326f9a767SRodney W. Grimes int count; 85426f9a767SRodney W. Grimes int reqpage; 85526f9a767SRodney W. Grimes { 85626f9a767SRodney W. Grimes int i; 8570d94caffSDavid Greenman 85826f9a767SRodney W. Grimes for (i = 0; i < count; i++) 85926f9a767SRodney W. Grimes if (i != reqpage) 86026f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 86126f9a767SRodney W. Grimes } 86226f9a767SRodney W. Grimes 86326f9a767SRodney W. Grimes /* 86426f9a767SRodney W. Grimes * swap_pager_iodone1 is the completion routine for both reads and async writes 86526f9a767SRodney W. Grimes */ 866f5a12711SPoul-Henning Kamp static void 86726f9a767SRodney W. Grimes swap_pager_iodone1(bp) 86826f9a767SRodney W. Grimes struct buf *bp; 86926f9a767SRodney W. Grimes { 87026f9a767SRodney W. Grimes bp->b_flags |= B_DONE; 87126f9a767SRodney W. Grimes bp->b_flags &= ~B_ASYNC; 87224a1cce3SDavid Greenman wakeup(bp); 87326f9a767SRodney W. Grimes } 87426f9a767SRodney W. Grimes 875f708ef1bSPoul-Henning Kamp static int 87624a1cce3SDavid Greenman swap_pager_getpages(object, m, count, reqpage) 87724a1cce3SDavid Greenman vm_object_t object; 87826f9a767SRodney W. Grimes vm_page_t *m; 87926f9a767SRodney W. Grimes int count, reqpage; 880df8bae1dSRodney W. Grimes { 881df8bae1dSRodney W. Grimes register struct buf *bp; 88226f9a767SRodney W. Grimes sw_blk_t swb[count]; 883df8bae1dSRodney W. Grimes register int s; 88426f9a767SRodney W. Grimes int i; 885df8bae1dSRodney W. Grimes boolean_t rv; 88626f9a767SRodney W. Grimes vm_offset_t kva, off[count]; 887df8bae1dSRodney W. Grimes swp_clean_t spc; 888a316d390SJohn Dyson vm_pindex_t paging_offset; 88926f9a767SRodney W. Grimes int reqaddr[count]; 8906d40c3d3SDavid Greenman int sequential; 891df8bae1dSRodney W. Grimes 89226f9a767SRodney W. Grimes int first, last; 89326f9a767SRodney W. Grimes int failed; 89426f9a767SRodney W. Grimes int reqdskregion; 895df8bae1dSRodney W. Grimes 89626f9a767SRodney W. Grimes object = m[reqpage]->object; 897a316d390SJohn Dyson paging_offset = OFF_TO_IDX(object->paging_offset); 898a316d390SJohn Dyson sequential = (m[reqpage]->pindex == (object->last_read + 1)); 8992a4895f4SDavid Greenman 90026f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 901a316d390SJohn Dyson vm_pindex_t fidx = m[i]->pindex + paging_offset; 902a316d390SJohn Dyson int ix = swap_pager_block_index(fidx); 9030d94caffSDavid Greenman 9042a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 90526f9a767SRodney W. Grimes int j; 9060d94caffSDavid Greenman 90726f9a767SRodney W. Grimes if (i <= reqpage) { 90826f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 909df8bae1dSRodney W. Grimes return (VM_PAGER_FAIL); 91026f9a767SRodney W. Grimes } 91126f9a767SRodney W. Grimes for (j = i; j < count; j++) { 91226f9a767SRodney W. Grimes swap_pager_freepage(m[j]); 91326f9a767SRodney W. Grimes } 91426f9a767SRodney W. Grimes count = i; 91526f9a767SRodney W. Grimes break; 91626f9a767SRodney W. Grimes } 9172a4895f4SDavid Greenman swb[i] = &object->un_pager.swp.swp_blocks[ix]; 918a316d390SJohn Dyson off[i] = swap_pager_block_offset(fidx); 91926f9a767SRodney W. Grimes reqaddr[i] = swb[i]->swb_block[off[i]]; 92026f9a767SRodney W. Grimes } 92126f9a767SRodney W. Grimes 92226f9a767SRodney W. Grimes /* make sure that our required input request is existant */ 92326f9a767SRodney W. Grimes 92426f9a767SRodney W. Grimes if (reqaddr[reqpage] == SWB_EMPTY || 92526f9a767SRodney W. Grimes (swb[reqpage]->swb_valid & (1 << off[reqpage])) == 0) { 92626f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 92726f9a767SRodney W. Grimes return (VM_PAGER_FAIL); 92826f9a767SRodney W. Grimes } 92926f9a767SRodney W. Grimes reqdskregion = reqaddr[reqpage] / dmmax; 930df8bae1dSRodney W. Grimes 931df8bae1dSRodney W. Grimes /* 93226f9a767SRodney W. Grimes * search backwards for the first contiguous page to transfer 933df8bae1dSRodney W. Grimes */ 93426f9a767SRodney W. Grimes failed = 0; 93526f9a767SRodney W. Grimes first = 0; 93626f9a767SRodney W. Grimes for (i = reqpage - 1; i >= 0; --i) { 9376d40c3d3SDavid Greenman if (sequential || failed || (reqaddr[i] == SWB_EMPTY) || 93826f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 93926f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 94026f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 94126f9a767SRodney W. Grimes failed = 1; 94226f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 94326f9a767SRodney W. Grimes if (first == 0) 94426f9a767SRodney W. Grimes first = i + 1; 94526f9a767SRodney W. Grimes } 946df8bae1dSRodney W. Grimes } 947df8bae1dSRodney W. Grimes /* 94826f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 949df8bae1dSRodney W. Grimes */ 95026f9a767SRodney W. Grimes failed = 0; 95126f9a767SRodney W. Grimes last = count; 95226f9a767SRodney W. Grimes for (i = reqpage + 1; i < count; i++) { 95326f9a767SRodney W. Grimes if (failed || (reqaddr[i] == SWB_EMPTY) || 95426f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 95526f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 95626f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 95726f9a767SRodney W. Grimes failed = 1; 95826f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 95926f9a767SRodney W. Grimes if (last == count) 96026f9a767SRodney W. Grimes last = i; 96126f9a767SRodney W. Grimes } 96226f9a767SRodney W. Grimes } 96326f9a767SRodney W. Grimes 96426f9a767SRodney W. Grimes count = last; 96526f9a767SRodney W. Grimes if (first != 0) { 96626f9a767SRodney W. Grimes for (i = first; i < count; i++) { 96726f9a767SRodney W. Grimes m[i - first] = m[i]; 96826f9a767SRodney W. Grimes reqaddr[i - first] = reqaddr[i]; 96926f9a767SRodney W. Grimes off[i - first] = off[i]; 97026f9a767SRodney W. Grimes } 97126f9a767SRodney W. Grimes count -= first; 97226f9a767SRodney W. Grimes reqpage -= first; 97326f9a767SRodney W. Grimes } 97426f9a767SRodney W. Grimes ++swb[reqpage]->swb_locked; 97526f9a767SRodney W. Grimes 97626f9a767SRodney W. Grimes /* 9770d94caffSDavid Greenman * at this point: "m" is a pointer to the array of vm_page_t for 9780d94caffSDavid Greenman * paging I/O "count" is the number of vm_page_t entries represented 9790d94caffSDavid Greenman * by "m" "object" is the vm_object_t for I/O "reqpage" is the index 9800d94caffSDavid Greenman * into "m" for the page actually faulted 98126f9a767SRodney W. Grimes */ 98226f9a767SRodney W. Grimes 98326f9a767SRodney W. Grimes spc = NULL; /* we might not use an spc data structure */ 98426f9a767SRodney W. Grimes 985b18bfc3dSJohn Dyson if ((count == 1) && (TAILQ_FIRST(&swap_pager_free) != NULL)) { 986b18bfc3dSJohn Dyson spc = TAILQ_FIRST(&swap_pager_free); 98726f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 98826f9a767SRodney W. Grimes kva = spc->spc_kva; 98926f9a767SRodney W. Grimes bp = spc->spc_bp; 99026f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 99126f9a767SRodney W. Grimes bp->b_spc = spc; 9927609ab12SDavid Greenman bp->b_vnbufs.le_next = NOLIST; 99326f9a767SRodney W. Grimes } else { 99416f62314SDavid Greenman /* 99516f62314SDavid Greenman * Get a swap buffer header to perform the IO 99616f62314SDavid Greenman */ 99726f9a767SRodney W. Grimes bp = getpbuf(); 99816f62314SDavid Greenman kva = (vm_offset_t) bp->b_data; 99926f9a767SRodney W. Grimes } 100026f9a767SRodney W. Grimes 100116f62314SDavid Greenman /* 100216f62314SDavid Greenman * map our page(s) into kva for input 100316f62314SDavid Greenman */ 100416f62314SDavid Greenman pmap_qenter(kva, m, count); 100516f62314SDavid Greenman 1006aba8f38eSDavid Greenman bp->b_flags = B_BUSY | B_READ | B_CALL | B_PAGING; 100726f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 1008df8bae1dSRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 100926f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 101026f9a767SRodney W. Grimes crhold(bp->b_rcred); 101126f9a767SRodney W. Grimes crhold(bp->b_wcred); 101226f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva; 101326f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 101426f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE * count; 101526f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE * count; 101626f9a767SRodney W. Grimes 10170d94caffSDavid Greenman pbgetvp(swapdev_vp, bp); 1018df8bae1dSRodney W. Grimes 1019976e77fcSDavid Greenman cnt.v_swapin++; 1020976e77fcSDavid Greenman cnt.v_swappgsin += count; 1021df8bae1dSRodney W. Grimes /* 102226f9a767SRodney W. Grimes * perform the I/O 1023df8bae1dSRodney W. Grimes */ 1024df8bae1dSRodney W. Grimes VOP_STRATEGY(bp); 102526f9a767SRodney W. Grimes 102626f9a767SRodney W. Grimes /* 102726f9a767SRodney W. Grimes * wait for the sync I/O to complete 102826f9a767SRodney W. Grimes */ 10297609ab12SDavid Greenman s = splbio(); 103026f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 103124a1cce3SDavid Greenman tsleep(bp, PVM, "swread", 0); 1032df8bae1dSRodney W. Grimes } 10331b119d9dSDavid Greenman 10341b119d9dSDavid Greenman if (bp->b_flags & B_ERROR) { 10351b119d9dSDavid Greenman printf("swap_pager: I/O error - pagein failed; blkno %d, size %d, error %d\n", 10361b119d9dSDavid Greenman bp->b_blkno, bp->b_bcount, bp->b_error); 1037a83c285cSDavid Greenman rv = VM_PAGER_ERROR; 10381b119d9dSDavid Greenman } else { 10391b119d9dSDavid Greenman rv = VM_PAGER_OK; 10401b119d9dSDavid Greenman } 104126f9a767SRodney W. Grimes 104226f9a767SRodney W. Grimes /* 10430d94caffSDavid Greenman * relpbuf does this, but we maintain our own buffer list also... 104426f9a767SRodney W. Grimes */ 1045df8bae1dSRodney W. Grimes if (bp->b_vp) 10460d94caffSDavid Greenman pbrelvp(bp); 104726f9a767SRodney W. Grimes 1048df8bae1dSRodney W. Grimes splx(s); 10492a4895f4SDavid Greenman swb[reqpage]->swb_locked--; 105026f9a767SRodney W. Grimes 105126f9a767SRodney W. Grimes /* 105226f9a767SRodney W. Grimes * remove the mapping for kernel virtual 105326f9a767SRodney W. Grimes */ 105416f62314SDavid Greenman pmap_qremove(kva, count); 105526f9a767SRodney W. Grimes 105626f9a767SRodney W. Grimes if (spc) { 1057a316d390SJohn Dyson m[reqpage]->object->last_read = m[reqpage]->pindex; 10580d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 105924a1cce3SDavid Greenman wakeup(bp); 106026f9a767SRodney W. Grimes /* 106126f9a767SRodney W. Grimes * if we have used an spc, we need to free it. 106226f9a767SRodney W. Grimes */ 106326f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 106426f9a767SRodney W. Grimes crfree(bp->b_rcred); 106526f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 106626f9a767SRodney W. Grimes crfree(bp->b_wcred); 106726f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 106826f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 106924a1cce3SDavid Greenman wakeup(&swap_pager_free); 107026f9a767SRodney W. Grimes } 1071a1f6d91cSDavid Greenman if (swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1072f919ebdeSDavid Greenman pagedaemon_wakeup(); 1073a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 107445952afcSJohn Dyson if (rv == VM_PAGER_OK) { 107545952afcSJohn Dyson pmap_clear_modify(VM_PAGE_TO_PHYS(m[reqpage])); 107645952afcSJohn Dyson m[reqpage]->valid = VM_PAGE_BITS_ALL; 107745952afcSJohn Dyson m[reqpage]->dirty = 0; 107845952afcSJohn Dyson } 107926f9a767SRodney W. Grimes } else { 108026f9a767SRodney W. Grimes /* 108126f9a767SRodney W. Grimes * release the physical I/O buffer 108226f9a767SRodney W. Grimes */ 108326f9a767SRodney W. Grimes relpbuf(bp); 108426f9a767SRodney W. Grimes /* 108526f9a767SRodney W. Grimes * finish up input if everything is ok 108626f9a767SRodney W. Grimes */ 108726f9a767SRodney W. Grimes if (rv == VM_PAGER_OK) { 108826f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 108926f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 10900d94caffSDavid Greenman m[i]->dirty = 0; 1091894048d7SJohn Dyson m[i]->flags &= ~PG_ZERO; 109226f9a767SRodney W. Grimes if (i != reqpage) { 109326f9a767SRodney W. Grimes /* 10940d94caffSDavid Greenman * whether or not to leave the page 10950d94caffSDavid Greenman * activated is up in the air, but we 10960d94caffSDavid Greenman * should put the page on a page queue 10970d94caffSDavid Greenman * somewhere. (it already is in the 10980d94caffSDavid Greenman * object). After some emperical 10990d94caffSDavid Greenman * results, it is best to deactivate 11000d94caffSDavid Greenman * the readahead pages. 110126f9a767SRodney W. Grimes */ 110226f9a767SRodney W. Grimes vm_page_deactivate(m[i]); 110326f9a767SRodney W. Grimes 110426f9a767SRodney W. Grimes /* 11050d94caffSDavid Greenman * just in case someone was asking for 11060d94caffSDavid Greenman * this page we now tell them that it 11070d94caffSDavid Greenman * is ok to use 110826f9a767SRodney W. Grimes */ 11090d94caffSDavid Greenman m[i]->valid = VM_PAGE_BITS_ALL; 111026f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 111126f9a767SRodney W. Grimes } 111226f9a767SRodney W. Grimes } 11136d40c3d3SDavid Greenman 1114a316d390SJohn Dyson m[reqpage]->object->last_read = m[count-1]->pindex; 11156d40c3d3SDavid Greenman 11162e1e24ddSDavid Greenman /* 11172e1e24ddSDavid Greenman * If we're out of swap space, then attempt to free 111845952afcSJohn Dyson * some whenever multiple pages are brought in. We 111945952afcSJohn Dyson * must set the dirty bits so that the page contents 112045952afcSJohn Dyson * will be preserved. 11212e1e24ddSDavid Greenman */ 1122de5f6a77SJohn Dyson if (SWAPLOW) { 11232e1e24ddSDavid Greenman for (i = 0; i < count; i++) { 11240d94caffSDavid Greenman m[i]->dirty = VM_PAGE_BITS_ALL; 11252e1e24ddSDavid Greenman } 1126a316d390SJohn Dyson swap_pager_freespace(object, m[0]->pindex + paging_offset, count); 112726f9a767SRodney W. Grimes } 112826f9a767SRodney W. Grimes } else { 112926f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 113026f9a767SRodney W. Grimes } 113126f9a767SRodney W. Grimes } 1132df8bae1dSRodney W. Grimes return (rv); 1133df8bae1dSRodney W. Grimes } 1134df8bae1dSRodney W. Grimes 113526f9a767SRodney W. Grimes int 113624a1cce3SDavid Greenman swap_pager_putpages(object, m, count, sync, rtvals) 113724a1cce3SDavid Greenman vm_object_t object; 113826f9a767SRodney W. Grimes vm_page_t *m; 113926f9a767SRodney W. Grimes int count; 114024a1cce3SDavid Greenman boolean_t sync; 114126f9a767SRodney W. Grimes int *rtvals; 1142df8bae1dSRodney W. Grimes { 114326f9a767SRodney W. Grimes register struct buf *bp; 114426f9a767SRodney W. Grimes sw_blk_t swb[count]; 114526f9a767SRodney W. Grimes register int s; 114626f9a767SRodney W. Grimes int i, j, ix; 114726f9a767SRodney W. Grimes boolean_t rv; 1148a316d390SJohn Dyson vm_offset_t kva, off, fidx; 114926f9a767SRodney W. Grimes swp_clean_t spc; 1150a316d390SJohn Dyson vm_pindex_t paging_pindex; 115126f9a767SRodney W. Grimes int reqaddr[count]; 115226f9a767SRodney W. Grimes int failed; 1153df8bae1dSRodney W. Grimes 115424ea4a96SDavid Greenman if (vm_swap_size) 115524ea4a96SDavid Greenman no_swap_space = 0; 115624ea4a96SDavid Greenman if (no_swap_space) { 11575663e6deSDavid Greenman for (i = 0; i < count; i++) 11585663e6deSDavid Greenman rtvals[i] = VM_PAGER_FAIL; 11595663e6deSDavid Greenman return VM_PAGER_FAIL; 11605663e6deSDavid Greenman } 116126f9a767SRodney W. Grimes spc = NULL; 116226f9a767SRodney W. Grimes 116326f9a767SRodney W. Grimes object = m[0]->object; 1164a316d390SJohn Dyson paging_pindex = OFF_TO_IDX(object->paging_offset); 116526f9a767SRodney W. Grimes 116626f9a767SRodney W. Grimes failed = 0; 116726f9a767SRodney W. Grimes for (j = 0; j < count; j++) { 1168a316d390SJohn Dyson fidx = m[j]->pindex + paging_pindex; 1169a316d390SJohn Dyson ix = swap_pager_block_index(fidx); 117026f9a767SRodney W. Grimes swb[j] = 0; 11712a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 117226f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 117326f9a767SRodney W. Grimes failed = 1; 117426f9a767SRodney W. Grimes continue; 117526f9a767SRodney W. Grimes } else { 117626f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_OK; 117726f9a767SRodney W. Grimes } 11782a4895f4SDavid Greenman swb[j] = &object->un_pager.swp.swp_blocks[ix]; 11792a4895f4SDavid Greenman swb[j]->swb_locked++; 118026f9a767SRodney W. Grimes if (failed) { 118126f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 118226f9a767SRodney W. Grimes continue; 118326f9a767SRodney W. Grimes } 1184a316d390SJohn Dyson off = swap_pager_block_offset(fidx); 118526f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 118626f9a767SRodney W. Grimes if (reqaddr[j] == SWB_EMPTY) { 1187a316d390SJohn Dyson daddr_t blk; 118826f9a767SRodney W. Grimes int tries; 118926f9a767SRodney W. Grimes int ntoget; 11900d94caffSDavid Greenman 119126f9a767SRodney W. Grimes tries = 0; 1192df8bae1dSRodney W. Grimes s = splbio(); 119326f9a767SRodney W. Grimes 1194df8bae1dSRodney W. Grimes /* 11950d94caffSDavid Greenman * if any other pages have been allocated in this 11960d94caffSDavid Greenman * block, we only try to get one page. 1197df8bae1dSRodney W. Grimes */ 119826f9a767SRodney W. Grimes for (i = 0; i < SWB_NPAGES; i++) { 119926f9a767SRodney W. Grimes if (swb[j]->swb_block[i] != SWB_EMPTY) 1200df8bae1dSRodney W. Grimes break; 1201df8bae1dSRodney W. Grimes } 120226f9a767SRodney W. Grimes 120326f9a767SRodney W. Grimes ntoget = (i == SWB_NPAGES) ? SWB_NPAGES : 1; 120426f9a767SRodney W. Grimes /* 12050d94caffSDavid Greenman * this code is alittle conservative, but works (the 12060d94caffSDavid Greenman * intent of this code is to allocate small chunks for 12070d94caffSDavid Greenman * small objects) 120826f9a767SRodney W. Grimes */ 1209a316d390SJohn Dyson if ((off == 0) && ((fidx + ntoget) > object->size)) { 1210a316d390SJohn Dyson ntoget = object->size - fidx; 121126f9a767SRodney W. Grimes } 121226f9a767SRodney W. Grimes retrygetspace: 121326f9a767SRodney W. Grimes if (!swap_pager_full && ntoget > 1 && 1214a316d390SJohn Dyson swap_pager_getswapspace(object, ntoget * btodb(PAGE_SIZE), 1215a316d390SJohn Dyson &blk)) { 121626f9a767SRodney W. Grimes 121726f9a767SRodney W. Grimes for (i = 0; i < ntoget; i++) { 121826f9a767SRodney W. Grimes swb[j]->swb_block[i] = blk + btodb(PAGE_SIZE) * i; 121926f9a767SRodney W. Grimes swb[j]->swb_valid = 0; 122026f9a767SRodney W. Grimes } 122126f9a767SRodney W. Grimes 122226f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 12232a4895f4SDavid Greenman } else if (!swap_pager_getswapspace(object, btodb(PAGE_SIZE), 122426f9a767SRodney W. Grimes &swb[j]->swb_block[off])) { 122526f9a767SRodney W. Grimes /* 12260d94caffSDavid Greenman * if the allocation has failed, we try to 12270d94caffSDavid Greenman * reclaim space and retry. 122826f9a767SRodney W. Grimes */ 122926f9a767SRodney W. Grimes if (++tries == 1) { 123026f9a767SRodney W. Grimes swap_pager_reclaim(); 123126f9a767SRodney W. Grimes goto retrygetspace; 123226f9a767SRodney W. Grimes } 123326f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_AGAIN; 123426f9a767SRodney W. Grimes failed = 1; 123524ea4a96SDavid Greenman swap_pager_full = 1; 123626f9a767SRodney W. Grimes } else { 123726f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 123826f9a767SRodney W. Grimes swb[j]->swb_valid &= ~(1 << off); 1239df8bae1dSRodney W. Grimes } 1240df8bae1dSRodney W. Grimes splx(s); 124126f9a767SRodney W. Grimes } 124226f9a767SRodney W. Grimes } 124326f9a767SRodney W. Grimes 124426f9a767SRodney W. Grimes /* 124526f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 124626f9a767SRodney W. Grimes */ 124726f9a767SRodney W. Grimes failed = 0; 124826f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 1249a316d390SJohn Dyson if (failed || 1250a316d390SJohn Dyson (reqaddr[i] != reqaddr[0] + i * btodb(PAGE_SIZE)) || 1251a316d390SJohn Dyson ((reqaddr[i] / dmmax) != (reqaddr[0] / dmmax)) || 125226f9a767SRodney W. Grimes (rtvals[i] != VM_PAGER_OK)) { 125326f9a767SRodney W. Grimes failed = 1; 125426f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) 125526f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 125626f9a767SRodney W. Grimes } 125726f9a767SRodney W. Grimes } 125826f9a767SRodney W. Grimes 125926f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 126026f9a767SRodney W. Grimes if (rtvals[i] != VM_PAGER_OK) { 126126f9a767SRodney W. Grimes if (swb[i]) 126226f9a767SRodney W. Grimes --swb[i]->swb_locked; 126326f9a767SRodney W. Grimes } 126426f9a767SRodney W. Grimes } 126526f9a767SRodney W. Grimes 126626f9a767SRodney W. Grimes for (i = 0; i < count; i++) 126726f9a767SRodney W. Grimes if (rtvals[i] != VM_PAGER_OK) 126826f9a767SRodney W. Grimes break; 126926f9a767SRodney W. Grimes 127026f9a767SRodney W. Grimes if (i == 0) { 127126f9a767SRodney W. Grimes return VM_PAGER_AGAIN; 127226f9a767SRodney W. Grimes } 127326f9a767SRodney W. Grimes count = i; 127426f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 1275a316d390SJohn Dyson if (reqaddr[i] == SWB_EMPTY) { 1276a316d390SJohn Dyson printf("I/O to empty block???? -- pindex: %d, i: %d\n", 1277a316d390SJohn Dyson m[i]->pindex, i); 1278a316d390SJohn Dyson } 127926f9a767SRodney W. Grimes } 128026f9a767SRodney W. Grimes 128126f9a767SRodney W. Grimes /* 12820d94caffSDavid Greenman * For synchronous writes, we clean up all completed async pageouts. 128326f9a767SRodney W. Grimes */ 128424a1cce3SDavid Greenman if (sync == TRUE) { 128524a1cce3SDavid Greenman swap_pager_sync(); 128626f9a767SRodney W. Grimes } 128726f9a767SRodney W. Grimes kva = 0; 128826f9a767SRodney W. Grimes 128926f9a767SRodney W. Grimes /* 129026f9a767SRodney W. Grimes * get a swap pager clean data structure, block until we get it 129126f9a767SRodney W. Grimes */ 1292b18bfc3dSJohn Dyson if (TAILQ_FIRST(&swap_pager_free) == NULL || 1293b18bfc3dSJohn Dyson TAILQ_NEXT(TAILQ_FIRST(&swap_pager_free),spc_list) == NULL || 1294b18bfc3dSJohn Dyson TAILQ_NEXT(TAILQ_NEXT(TAILQ_FIRST(&swap_pager_free),spc_list),spc_list) == NULL) { 129526f9a767SRodney W. Grimes s = splbio(); 12960d94caffSDavid Greenman if (curproc == pageproc) { 1297bd7e5f99SJohn Dyson retryfree: 1298cb6962cdSJohn Dyson /* 1299cb6962cdSJohn Dyson * pageout daemon needs a swap control block 1300cb6962cdSJohn Dyson */ 1301cb6962cdSJohn Dyson swap_pager_needflags |= SWAP_FREE_NEEDED_BY_PAGEOUT|SWAP_FREE_NEEDED; 1302cb6962cdSJohn Dyson /* 1303cb6962cdSJohn Dyson * if it does not get one within a short time, then 1304cb6962cdSJohn Dyson * there is a potential deadlock, so we go-on trying 1305bd7e5f99SJohn Dyson * to free pages. It is important to block here as opposed 1306bd7e5f99SJohn Dyson * to returning, thereby allowing the pageout daemon to continue. 1307bd7e5f99SJohn Dyson * It is likely that pageout daemon will start suboptimally 1308bd7e5f99SJohn Dyson * reclaiming vnode backed pages if we don't block. Since the 1309bd7e5f99SJohn Dyson * I/O subsystem is probably already fully utilized, might as 1310bd7e5f99SJohn Dyson * well wait. 1311cb6962cdSJohn Dyson */ 1312bd7e5f99SJohn Dyson if (tsleep(&swap_pager_free, PVM, "swpfre", hz/5)) { 131324a1cce3SDavid Greenman swap_pager_sync(); 1314b18bfc3dSJohn Dyson if (TAILQ_FIRST(&swap_pager_free) == NULL || 1315b18bfc3dSJohn Dyson TAILQ_NEXT(TAILQ_FIRST(&swap_pager_free),spc_list) == NULL || 1316b18bfc3dSJohn Dyson TAILQ_NEXT(TAILQ_NEXT(TAILQ_FIRST(&swap_pager_free),spc_list),spc_list) == NULL) { 13170d94caffSDavid Greenman splx(s); 13180d94caffSDavid Greenman return VM_PAGER_AGAIN; 1319cb6962cdSJohn Dyson } 1320bd7e5f99SJohn Dyson } else { 1321bd7e5f99SJohn Dyson /* 1322bd7e5f99SJohn Dyson * we make sure that pageouts aren't taking up all of 1323bd7e5f99SJohn Dyson * the free swap control blocks. 1324bd7e5f99SJohn Dyson */ 1325bd7e5f99SJohn Dyson swap_pager_sync(); 1326b18bfc3dSJohn Dyson if (TAILQ_FIRST(&swap_pager_free) == NULL || 1327b18bfc3dSJohn Dyson TAILQ_NEXT(TAILQ_FIRST(&swap_pager_free),spc_list) == NULL || 1328b18bfc3dSJohn Dyson TAILQ_NEXT(TAILQ_NEXT(TAILQ_FIRST(&swap_pager_free),spc_list),spc_list) == NULL) { 1329bd7e5f99SJohn Dyson goto retryfree; 1330bd7e5f99SJohn Dyson } 1331bd7e5f99SJohn Dyson } 1332bd7e5f99SJohn Dyson } else { 1333f919ebdeSDavid Greenman pagedaemon_wakeup(); 1334b18bfc3dSJohn Dyson while (TAILQ_FIRST(&swap_pager_free) == NULL || 1335b18bfc3dSJohn Dyson TAILQ_NEXT(TAILQ_FIRST(&swap_pager_free),spc_list) == NULL || 1336b18bfc3dSJohn Dyson TAILQ_NEXT(TAILQ_NEXT(TAILQ_FIRST(&swap_pager_free),spc_list),spc_list) == NULL) { 133726f9a767SRodney W. Grimes swap_pager_needflags |= SWAP_FREE_NEEDED; 133824a1cce3SDavid Greenman tsleep(&swap_pager_free, PVM, "swpfre", 0); 1339f919ebdeSDavid Greenman pagedaemon_wakeup(); 134026f9a767SRodney W. Grimes } 1341bd7e5f99SJohn Dyson } 134226f9a767SRodney W. Grimes splx(s); 134326f9a767SRodney W. Grimes } 1344b18bfc3dSJohn Dyson spc = TAILQ_FIRST(&swap_pager_free); 134526f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 1346fff93ab6SDavid Greenman 134726f9a767SRodney W. Grimes kva = spc->spc_kva; 134826f9a767SRodney W. Grimes 134926f9a767SRodney W. Grimes /* 135026f9a767SRodney W. Grimes * map our page(s) into kva for I/O 135126f9a767SRodney W. Grimes */ 135216f62314SDavid Greenman pmap_qenter(kva, m, count); 135326f9a767SRodney W. Grimes 135426f9a767SRodney W. Grimes /* 135526f9a767SRodney W. Grimes * get the base I/O offset into the swap file 135626f9a767SRodney W. Grimes */ 135726f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 1358a316d390SJohn Dyson fidx = m[i]->pindex + paging_pindex; 1359a316d390SJohn Dyson off = swap_pager_block_offset(fidx); 136026f9a767SRodney W. Grimes /* 136126f9a767SRodney W. Grimes * set the valid bit 136226f9a767SRodney W. Grimes */ 136326f9a767SRodney W. Grimes swb[i]->swb_valid |= (1 << off); 136426f9a767SRodney W. Grimes /* 136526f9a767SRodney W. Grimes * and unlock the data structure 136626f9a767SRodney W. Grimes */ 13672a4895f4SDavid Greenman swb[i]->swb_locked--; 136826f9a767SRodney W. Grimes } 136926f9a767SRodney W. Grimes 137026f9a767SRodney W. Grimes /* 137126f9a767SRodney W. Grimes * Get a swap buffer header and perform the IO 137226f9a767SRodney W. Grimes */ 137326f9a767SRodney W. Grimes bp = spc->spc_bp; 137426f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 137526f9a767SRodney W. Grimes bp->b_spc = spc; 13767609ab12SDavid Greenman bp->b_vnbufs.le_next = NOLIST; 137726f9a767SRodney W. Grimes 1378aba8f38eSDavid Greenman bp->b_flags = B_BUSY | B_PAGING; 137926f9a767SRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 138026f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 1381a481f200SDavid Greenman if (bp->b_rcred != NOCRED) 138226f9a767SRodney W. Grimes crhold(bp->b_rcred); 1383a481f200SDavid Greenman if (bp->b_wcred != NOCRED) 138426f9a767SRodney W. Grimes crhold(bp->b_wcred); 1385a481f200SDavid Greenman bp->b_data = (caddr_t) kva; 138626f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 13870d94caffSDavid Greenman pbgetvp(swapdev_vp, bp); 138816f62314SDavid Greenman 138926f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE * count; 139026f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE * count; 139126f9a767SRodney W. Grimes swapdev_vp->v_numoutput++; 139226f9a767SRodney W. Grimes 139326f9a767SRodney W. Grimes /* 13940d94caffSDavid Greenman * If this is an async write we set up additional buffer fields and 13950d94caffSDavid Greenman * place a "cleaning" entry on the inuse queue. 139626f9a767SRodney W. Grimes */ 13977609ab12SDavid Greenman s = splbio(); 139824a1cce3SDavid Greenman if (sync == FALSE) { 139926f9a767SRodney W. Grimes spc->spc_flags = 0; 14002a4895f4SDavid Greenman spc->spc_object = object; 140126f9a767SRodney W. Grimes for (i = 0; i < count; i++) 140226f9a767SRodney W. Grimes spc->spc_m[i] = m[i]; 140326f9a767SRodney W. Grimes spc->spc_count = count; 140426f9a767SRodney W. Grimes /* 140526f9a767SRodney W. Grimes * the completion routine for async writes 140626f9a767SRodney W. Grimes */ 140726f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 140826f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone; 140926f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 141026f9a767SRodney W. Grimes bp->b_dirtyend = bp->b_bcount; 14112a4895f4SDavid Greenman object->un_pager.swp.swp_poip++; 141226f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list); 141326f9a767SRodney W. Grimes } else { 14142a4895f4SDavid Greenman object->un_pager.swp.swp_poip++; 141526f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 141626f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 141726f9a767SRodney W. Grimes } 1418976e77fcSDavid Greenman 1419976e77fcSDavid Greenman cnt.v_swapout++; 1420976e77fcSDavid Greenman cnt.v_swappgsout += count; 142126f9a767SRodney W. Grimes /* 142226f9a767SRodney W. Grimes * perform the I/O 142326f9a767SRodney W. Grimes */ 142426f9a767SRodney W. Grimes VOP_STRATEGY(bp); 142524a1cce3SDavid Greenman if (sync == FALSE) { 142626f9a767SRodney W. Grimes if ((bp->b_flags & B_DONE) == B_DONE) { 142724a1cce3SDavid Greenman swap_pager_sync(); 142826f9a767SRodney W. Grimes } 142926f9a767SRodney W. Grimes splx(s); 143026f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 143126f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_PEND; 143226f9a767SRodney W. Grimes } 143326f9a767SRodney W. Grimes return VM_PAGER_PEND; 143426f9a767SRodney W. Grimes } 143526f9a767SRodney W. Grimes /* 143626f9a767SRodney W. Grimes * wait for the sync I/O to complete 143726f9a767SRodney W. Grimes */ 143826f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 143924a1cce3SDavid Greenman tsleep(bp, PVM, "swwrt", 0); 144026f9a767SRodney W. Grimes } 14411b119d9dSDavid Greenman if (bp->b_flags & B_ERROR) { 14421b119d9dSDavid Greenman printf("swap_pager: I/O error - pageout failed; blkno %d, size %d, error %d\n", 14431b119d9dSDavid Greenman bp->b_blkno, bp->b_bcount, bp->b_error); 1444a83c285cSDavid Greenman rv = VM_PAGER_ERROR; 14451b119d9dSDavid Greenman } else { 14461b119d9dSDavid Greenman rv = VM_PAGER_OK; 14471b119d9dSDavid Greenman } 144826f9a767SRodney W. Grimes 14492a4895f4SDavid Greenman object->un_pager.swp.swp_poip--; 14502a4895f4SDavid Greenman if (object->un_pager.swp.swp_poip == 0) 14512a4895f4SDavid Greenman wakeup(object); 145226f9a767SRodney W. Grimes 145326f9a767SRodney W. Grimes if (bp->b_vp) 14540d94caffSDavid Greenman pbrelvp(bp); 14550d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 145624a1cce3SDavid Greenman wakeup(bp); 145726f9a767SRodney W. Grimes 145826f9a767SRodney W. Grimes splx(s); 145926f9a767SRodney W. Grimes 146026f9a767SRodney W. Grimes /* 146126f9a767SRodney W. Grimes * remove the mapping for kernel virtual 146226f9a767SRodney W. Grimes */ 146316f62314SDavid Greenman pmap_qremove(kva, count); 146426f9a767SRodney W. Grimes 146526f9a767SRodney W. Grimes /* 14660d94caffSDavid Greenman * if we have written the page, then indicate that the page is clean. 146726f9a767SRodney W. Grimes */ 146826f9a767SRodney W. Grimes if (rv == VM_PAGER_OK) { 146926f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 147026f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) { 147126f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 14720d94caffSDavid Greenman m[i]->dirty = 0; 147326f9a767SRodney W. Grimes /* 14740d94caffSDavid Greenman * optimization, if a page has been read 14750d94caffSDavid Greenman * during the pageout process, we activate it. 147626f9a767SRodney W. Grimes */ 1477bd7e5f99SJohn Dyson if ((m[i]->queue != PQ_ACTIVE) && 14787fb0c17eSDavid Greenman ((m[i]->flags & (PG_WANTED|PG_REFERENCED)) || 14797fb0c17eSDavid Greenman pmap_is_referenced(VM_PAGE_TO_PHYS(m[i])))) { 148026f9a767SRodney W. Grimes vm_page_activate(m[i]); 148126f9a767SRodney W. Grimes } 148226f9a767SRodney W. Grimes } 14837fb0c17eSDavid Greenman } 148426f9a767SRodney W. Grimes } else { 148526f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 148626f9a767SRodney W. Grimes rtvals[i] = rv; 148726f9a767SRodney W. Grimes } 148826f9a767SRodney W. Grimes } 148926f9a767SRodney W. Grimes 149026f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 149126f9a767SRodney W. Grimes crfree(bp->b_rcred); 149226f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 149326f9a767SRodney W. Grimes crfree(bp->b_wcred); 149426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 149526f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 149624a1cce3SDavid Greenman wakeup(&swap_pager_free); 149726f9a767SRodney W. Grimes } 1498a1f6d91cSDavid Greenman if (swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1499f919ebdeSDavid Greenman pagedaemon_wakeup(); 1500a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 150126f9a767SRodney W. Grimes return (rv); 150226f9a767SRodney W. Grimes } 150326f9a767SRodney W. Grimes 1504f708ef1bSPoul-Henning Kamp static void 150524a1cce3SDavid Greenman swap_pager_sync() 150626f9a767SRodney W. Grimes { 150726f9a767SRodney W. Grimes register swp_clean_t spc, tspc; 150826f9a767SRodney W. Grimes register int s; 150926f9a767SRodney W. Grimes 151026f9a767SRodney W. Grimes tspc = NULL; 1511b18bfc3dSJohn Dyson if (TAILQ_FIRST(&swap_pager_done) == NULL) 151224a1cce3SDavid Greenman return; 151326f9a767SRodney W. Grimes for (;;) { 151426f9a767SRodney W. Grimes s = splbio(); 151526f9a767SRodney W. Grimes /* 15160d94caffSDavid Greenman * Look up and removal from done list must be done at splbio() 15170d94caffSDavid Greenman * to avoid conflicts with swap_pager_iodone. 151826f9a767SRodney W. Grimes */ 1519b18bfc3dSJohn Dyson while ((spc = TAILQ_FIRST(&swap_pager_done)) != 0) { 1520fff93ab6SDavid Greenman pmap_qremove(spc->spc_kva, spc->spc_count); 152126f9a767SRodney W. Grimes swap_pager_finish(spc); 152226f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_done, spc, spc_list); 152326f9a767SRodney W. Grimes goto doclean; 152426f9a767SRodney W. Grimes } 1525df8bae1dSRodney W. Grimes 1526df8bae1dSRodney W. Grimes /* 1527df8bae1dSRodney W. Grimes * No operations done, thats all we can do for now. 1528df8bae1dSRodney W. Grimes */ 152926f9a767SRodney W. Grimes 153026f9a767SRodney W. Grimes splx(s); 1531df8bae1dSRodney W. Grimes break; 1532df8bae1dSRodney W. Grimes 1533df8bae1dSRodney W. Grimes /* 15340d94caffSDavid Greenman * The desired page was found to be busy earlier in the scan 15350d94caffSDavid Greenman * but has since completed. 1536df8bae1dSRodney W. Grimes */ 153726f9a767SRodney W. Grimes doclean: 153826f9a767SRodney W. Grimes if (tspc && tspc == spc) { 153926f9a767SRodney W. Grimes tspc = NULL; 154026f9a767SRodney W. Grimes } 154126f9a767SRodney W. Grimes spc->spc_flags = 0; 154226f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 154326f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 154424a1cce3SDavid Greenman wakeup(&swap_pager_free); 154526f9a767SRodney W. Grimes } 1546a1f6d91cSDavid Greenman if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1547f919ebdeSDavid Greenman pagedaemon_wakeup(); 1548a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 154926f9a767SRodney W. Grimes splx(s); 155026f9a767SRodney W. Grimes } 155126f9a767SRodney W. Grimes 155224a1cce3SDavid Greenman return; 155326f9a767SRodney W. Grimes } 155426f9a767SRodney W. Grimes 155526f9a767SRodney W. Grimes void 155626f9a767SRodney W. Grimes swap_pager_finish(spc) 155726f9a767SRodney W. Grimes register swp_clean_t spc; 155826f9a767SRodney W. Grimes { 155926f9a767SRodney W. Grimes vm_object_t object = spc->spc_m[0]->object; 156026f9a767SRodney W. Grimes int i; 156126f9a767SRodney W. Grimes 1562c0503609SDavid Greenman object->paging_in_progress -= spc->spc_count; 1563c0503609SDavid Greenman if ((object->paging_in_progress == 0) && 1564c0503609SDavid Greenman (object->flags & OBJ_PIPWNT)) { 1565c0503609SDavid Greenman object->flags &= ~OBJ_PIPWNT; 156624a1cce3SDavid Greenman wakeup(object); 1567c0503609SDavid Greenman } 1568df8bae1dSRodney W. Grimes 1569df8bae1dSRodney W. Grimes /* 15705f55e841SDavid Greenman * If no error, mark as clean and inform the pmap system. If error, 15710d94caffSDavid Greenman * mark as dirty so we will try again. (XXX could get stuck doing 15720d94caffSDavid Greenman * this, should give up after awhile) 1573df8bae1dSRodney W. Grimes */ 1574df8bae1dSRodney W. Grimes if (spc->spc_flags & SPC_ERROR) { 157526f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 1576a83c285cSDavid Greenman printf("swap_pager_finish: I/O error, clean of page %lx failed\n", 157705f0fdd2SPoul-Henning Kamp (u_long) VM_PAGE_TO_PHYS(spc->spc_m[i])); 157826f9a767SRodney W. Grimes } 1579df8bae1dSRodney W. Grimes } else { 158026f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 158126f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m[i])); 15820d94caffSDavid Greenman spc->spc_m[i]->dirty = 0; 1583bd7e5f99SJohn Dyson if ((spc->spc_m[i]->queue != PQ_ACTIVE) && 15840d94caffSDavid Greenman ((spc->spc_m[i]->flags & PG_WANTED) || pmap_is_referenced(VM_PAGE_TO_PHYS(spc->spc_m[i])))) 15850d94caffSDavid Greenman vm_page_activate(spc->spc_m[i]); 1586df8bae1dSRodney W. Grimes } 1587df8bae1dSRodney W. Grimes } 1588df8bae1dSRodney W. Grimes 158926f9a767SRodney W. Grimes 159026f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 1591df8bae1dSRodney W. Grimes /* 15920d94caffSDavid Greenman * we wakeup any processes that are waiting on these pages. 1593df8bae1dSRodney W. Grimes */ 159426f9a767SRodney W. Grimes PAGE_WAKEUP(spc->spc_m[i]); 1595df8bae1dSRodney W. Grimes } 159626f9a767SRodney W. Grimes nswiodone -= spc->spc_count; 1597df8bae1dSRodney W. Grimes 1598df8bae1dSRodney W. Grimes return; 159926f9a767SRodney W. Grimes } 1600df8bae1dSRodney W. Grimes 160126f9a767SRodney W. Grimes /* 160226f9a767SRodney W. Grimes * swap_pager_iodone 160326f9a767SRodney W. Grimes */ 1604f5a12711SPoul-Henning Kamp static void 1605df8bae1dSRodney W. Grimes swap_pager_iodone(bp) 1606df8bae1dSRodney W. Grimes register struct buf *bp; 1607df8bae1dSRodney W. Grimes { 1608df8bae1dSRodney W. Grimes register swp_clean_t spc; 1609df8bae1dSRodney W. Grimes int s; 1610df8bae1dSRodney W. Grimes 1611df8bae1dSRodney W. Grimes s = splbio(); 161226f9a767SRodney W. Grimes spc = (swp_clean_t) bp->b_spc; 161326f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list); 161426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_done, spc, spc_list); 161526f9a767SRodney W. Grimes if (bp->b_flags & B_ERROR) { 1616df8bae1dSRodney W. Grimes spc->spc_flags |= SPC_ERROR; 1617c3a1e425SDavid Greenman printf("swap_pager: I/O error - async %s failed; blkno %lu, size %ld, error %d\n", 16181b119d9dSDavid Greenman (bp->b_flags & B_READ) ? "pagein" : "pageout", 1619c3a1e425SDavid Greenman (u_long) bp->b_blkno, bp->b_bcount, bp->b_error); 1620df8bae1dSRodney W. Grimes } 162126f9a767SRodney W. Grimes 16220d94caffSDavid Greenman if (bp->b_vp) 16230d94caffSDavid Greenman pbrelvp(bp); 16240d94caffSDavid Greenman 16250d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 162624a1cce3SDavid Greenman wakeup(bp); 16270d94caffSDavid Greenman 162826f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 162926f9a767SRodney W. Grimes crfree(bp->b_rcred); 163026f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 163126f9a767SRodney W. Grimes crfree(bp->b_wcred); 163226f9a767SRodney W. Grimes 163326f9a767SRodney W. Grimes nswiodone += spc->spc_count; 16342a4895f4SDavid Greenman if (--spc->spc_object->un_pager.swp.swp_poip == 0) { 16352a4895f4SDavid Greenman wakeup(spc->spc_object); 163626f9a767SRodney W. Grimes } 163726f9a767SRodney W. Grimes if ((swap_pager_needflags & SWAP_FREE_NEEDED) || 1638b18bfc3dSJohn Dyson TAILQ_FIRST(&swap_pager_inuse) == 0) { 163926f9a767SRodney W. Grimes swap_pager_needflags &= ~SWAP_FREE_NEEDED; 164024a1cce3SDavid Greenman wakeup(&swap_pager_free); 1641a1f6d91cSDavid Greenman } 1642a1f6d91cSDavid Greenman 1643a1f6d91cSDavid Greenman if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) { 1644a1f6d91cSDavid Greenman swap_pager_needflags &= ~SWAP_FREE_NEEDED_BY_PAGEOUT; 1645f919ebdeSDavid Greenman pagedaemon_wakeup(); 164626f9a767SRodney W. Grimes } 1647a1f6d91cSDavid Greenman 164826f9a767SRodney W. Grimes if (vm_pageout_pages_needed) { 164924a1cce3SDavid Greenman wakeup(&vm_pageout_pages_needed); 1650a1f6d91cSDavid Greenman vm_pageout_pages_needed = 0; 165126f9a767SRodney W. Grimes } 1652b18bfc3dSJohn Dyson if ((TAILQ_FIRST(&swap_pager_inuse) == NULL) || 16530d94caffSDavid Greenman ((cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min && 16540d94caffSDavid Greenman nswiodone + cnt.v_free_count + cnt.v_cache_count >= cnt.v_free_min)) { 1655f919ebdeSDavid Greenman pagedaemon_wakeup(); 165626f9a767SRodney W. Grimes } 165726f9a767SRodney W. Grimes splx(s); 165826f9a767SRodney W. Grimes } 1659