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 42efeaf95aSDavid Greenman * $Id: swap_pager.c,v 1.52 1995/12/03 12:18:33 bde 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 7926f9a767SRodney W. Grimes 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; 8335c10d22SDavid Greenman struct rlist *swaplist; 8435c10d22SDavid Greenman int nswaplist; 8526f9a767SRodney W. Grimes 8626f9a767SRodney W. Grimes #define MAX_PAGEOUT_CLUSTER 8 87df8bae1dSRodney W. Grimes 88df8bae1dSRodney W. Grimes TAILQ_HEAD(swpclean, swpagerclean); 89df8bae1dSRodney W. Grimes 9026f9a767SRodney W. Grimes typedef struct swpagerclean *swp_clean_t; 9126f9a767SRodney W. Grimes 92df8bae1dSRodney W. Grimes struct swpagerclean { 93df8bae1dSRodney W. Grimes TAILQ_ENTRY(swpagerclean) spc_list; 94df8bae1dSRodney W. Grimes int spc_flags; 95df8bae1dSRodney W. Grimes struct buf *spc_bp; 962a4895f4SDavid Greenman vm_object_t spc_object; 97df8bae1dSRodney W. Grimes vm_offset_t spc_kva; 9826f9a767SRodney W. Grimes int spc_count; 9926f9a767SRodney W. Grimes vm_page_t spc_m[MAX_PAGEOUT_CLUSTER]; 100df8bae1dSRodney W. Grimes } swcleanlist[NPENDINGIO]; 10126f9a767SRodney W. Grimes 10226f9a767SRodney W. Grimes 103df8bae1dSRodney W. Grimes /* spc_flags values */ 10426f9a767SRodney W. Grimes #define SPC_ERROR 0x01 105df8bae1dSRodney W. Grimes 10626f9a767SRodney W. Grimes #define SWB_EMPTY (-1) 107df8bae1dSRodney W. Grimes 108a401ebbeSDavid Greenman struct swpclean swap_pager_done; /* list of completed page cleans */ 109df8bae1dSRodney W. Grimes struct swpclean swap_pager_inuse; /* list of pending page cleans */ 110df8bae1dSRodney W. Grimes struct swpclean swap_pager_free; /* list of free pager clean structs */ 11124a1cce3SDavid Greenman struct pagerlst swap_pager_object_list; /* list of "named" anon region objects */ 11224a1cce3SDavid Greenman struct pagerlst swap_pager_un_object_list; /* list of "unnamed" anon region objects */ 113df8bae1dSRodney W. Grimes 11426f9a767SRodney W. Grimes #define SWAP_FREE_NEEDED 0x1 /* need a swap block */ 115a1f6d91cSDavid Greenman #define SWAP_FREE_NEEDED_BY_PAGEOUT 0x2 11626f9a767SRodney W. Grimes int swap_pager_needflags; 11726f9a767SRodney W. Grimes 118f5a12711SPoul-Henning Kamp static struct pagerlst *swp_qs[] = { 11924a1cce3SDavid Greenman &swap_pager_object_list, &swap_pager_un_object_list, (struct pagerlst *) 0 12026f9a767SRodney W. Grimes }; 12126f9a767SRodney W. Grimes 12224a1cce3SDavid Greenman /* 12324a1cce3SDavid Greenman * pagerops for OBJT_SWAP - "swap pager". 12424a1cce3SDavid Greenman */ 125ff98689dSBruce Evans static vm_object_t 126ff98689dSBruce Evans swap_pager_alloc __P((void *handle, vm_size_t size, 127ff98689dSBruce Evans vm_prot_t prot, vm_offset_t offset)); 128ff98689dSBruce Evans static void swap_pager_dealloc __P((vm_object_t object)); 129ff98689dSBruce Evans static boolean_t 130ff98689dSBruce Evans swap_pager_haspage __P((vm_object_t object, vm_offset_t offset, 131ff98689dSBruce Evans int *before, int *after)); 132ff98689dSBruce Evans static void swap_pager_init __P((void)); 133df8bae1dSRodney W. Grimes struct pagerops swappagerops = { 134df8bae1dSRodney W. Grimes swap_pager_init, 135df8bae1dSRodney W. Grimes swap_pager_alloc, 136df8bae1dSRodney W. Grimes swap_pager_dealloc, 13724a1cce3SDavid Greenman swap_pager_getpages, 13824a1cce3SDavid Greenman swap_pager_putpages, 13924a1cce3SDavid Greenman swap_pager_haspage, 14024a1cce3SDavid Greenman swap_pager_sync 141df8bae1dSRodney W. Grimes }; 142df8bae1dSRodney W. Grimes 143f5a12711SPoul-Henning Kamp static int npendingio = NPENDINGIO; 14426f9a767SRodney W. Grimes int dmmin, dmmax; 14526f9a767SRodney W. Grimes 146cac597e4SBruce Evans static __pure int 147cac597e4SBruce Evans swap_pager_block_index __P((vm_offset_t offset)) __pure2; 148cac597e4SBruce Evans static __pure int 149cac597e4SBruce Evans swap_pager_block_offset __P((vm_offset_t offset)) __pure2; 150cac597e4SBruce Evans static int *swap_pager_diskaddr __P((vm_object_t object, 151cac597e4SBruce Evans vm_offset_t offset, int *valid)); 152cac597e4SBruce Evans static void swap_pager_finish __P((swp_clean_t spc)); 153cac597e4SBruce Evans static void swap_pager_freepage __P((vm_page_t m)); 154cac597e4SBruce Evans static void swap_pager_free_swap __P((vm_object_t object)); 155cac597e4SBruce Evans static void swap_pager_freeswapspace __P((vm_object_t object, 156cac597e4SBruce Evans unsigned int from, 157cac597e4SBruce Evans unsigned int to)); 158cac597e4SBruce Evans static int swap_pager_getswapspace __P((vm_object_t object, 159cac597e4SBruce Evans unsigned int amount, 160cac597e4SBruce Evans unsigned int *rtval)); 161ff98689dSBruce Evans static void swap_pager_iodone __P((struct buf *)); 162cac597e4SBruce Evans static void swap_pager_iodone1 __P((struct buf *bp)); 163cac597e4SBruce Evans static int swap_pager_ready __P((void)); 164cac597e4SBruce Evans static void swap_pager_reclaim __P((void)); 165cac597e4SBruce Evans static void swap_pager_ridpages __P((vm_page_t *m, int count, 166cac597e4SBruce Evans int reqpage)); 167cac597e4SBruce Evans static void swap_pager_setvalid __P((vm_object_t object, 168cac597e4SBruce Evans vm_offset_t offset, int valid)); 169cac597e4SBruce Evans static void swapsizecheck __P((void)); 17024a1cce3SDavid Greenman 1710d94caffSDavid Greenman static inline void 1720d94caffSDavid Greenman swapsizecheck() 1730d94caffSDavid Greenman { 17426f9a767SRodney W. Grimes if (vm_swap_size < 128 * btodb(PAGE_SIZE)) { 175a1f6d91cSDavid Greenman if (swap_pager_full == 0) 17626f9a767SRodney W. Grimes printf("swap_pager: out of space\n"); 17726f9a767SRodney W. Grimes swap_pager_full = 1; 17826f9a767SRodney W. Grimes } else if (vm_swap_size > 192 * btodb(PAGE_SIZE)) 17926f9a767SRodney W. Grimes swap_pager_full = 0; 18026f9a767SRodney W. Grimes } 18126f9a767SRodney W. Grimes 182f5a12711SPoul-Henning Kamp static void 183df8bae1dSRodney W. Grimes swap_pager_init() 184df8bae1dSRodney W. Grimes { 18524a1cce3SDavid Greenman TAILQ_INIT(&swap_pager_object_list); 18624a1cce3SDavid Greenman TAILQ_INIT(&swap_pager_un_object_list); 187df8bae1dSRodney W. Grimes 188df8bae1dSRodney W. Grimes /* 189df8bae1dSRodney W. Grimes * Initialize clean lists 190df8bae1dSRodney W. Grimes */ 191df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_inuse); 19226f9a767SRodney W. Grimes TAILQ_INIT(&swap_pager_done); 193df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_free); 19426f9a767SRodney W. Grimes 195df8bae1dSRodney W. Grimes /* 196df8bae1dSRodney W. Grimes * Calculate the swap allocation constants. 197df8bae1dSRodney W. Grimes */ 19826f9a767SRodney W. Grimes dmmin = CLBYTES / DEV_BSIZE; 19926f9a767SRodney W. Grimes dmmax = btodb(SWB_NPAGES * PAGE_SIZE) * 2; 200df8bae1dSRodney W. Grimes } 201df8bae1dSRodney W. Grimes 20224a1cce3SDavid Greenman void 20324a1cce3SDavid Greenman swap_pager_swap_init() 204df8bae1dSRodney W. Grimes { 20526f9a767SRodney W. Grimes swp_clean_t spc; 20626f9a767SRodney W. Grimes struct buf *bp; 20724a1cce3SDavid Greenman int i; 2080d94caffSDavid Greenman 20926f9a767SRodney W. Grimes /* 2100d94caffSDavid Greenman * kva's are allocated here so that we dont need to keep doing 2110d94caffSDavid Greenman * kmem_alloc pageables at runtime 21226f9a767SRodney W. Grimes */ 21326f9a767SRodney W. Grimes for (i = 0, spc = swcleanlist; i < npendingio; i++, spc++) { 214fff93ab6SDavid Greenman spc->spc_kva = kmem_alloc_pageable(pager_map, PAGE_SIZE * MAX_PAGEOUT_CLUSTER); 21526f9a767SRodney W. Grimes if (!spc->spc_kva) { 21626f9a767SRodney W. Grimes break; 21726f9a767SRodney W. Grimes } 218a1f6d91cSDavid Greenman spc->spc_bp = malloc(sizeof(*bp), M_TEMP, M_KERNEL); 21926f9a767SRodney W. Grimes if (!spc->spc_bp) { 22026f9a767SRodney W. Grimes kmem_free_wakeup(pager_map, spc->spc_kva, PAGE_SIZE); 22126f9a767SRodney W. Grimes break; 22226f9a767SRodney W. Grimes } 22326f9a767SRodney W. Grimes spc->spc_flags = 0; 22426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 22526f9a767SRodney W. Grimes } 22626f9a767SRodney W. Grimes } 22724a1cce3SDavid Greenman 22824a1cce3SDavid Greenman int 22924a1cce3SDavid Greenman swap_pager_swp_alloc(object, wait) 23024a1cce3SDavid Greenman vm_object_t object; 23124a1cce3SDavid Greenman int wait; 23224a1cce3SDavid Greenman { 2332a4895f4SDavid Greenman sw_blk_t swb; 2342a4895f4SDavid Greenman int nblocks; 23524a1cce3SDavid Greenman int i, j; 23624a1cce3SDavid Greenman 2372a4895f4SDavid Greenman nblocks = (btodb(object->size) + btodb(SWB_NPAGES * PAGE_SIZE) - 1) / 2382a4895f4SDavid Greenman btodb(SWB_NPAGES * PAGE_SIZE); 23924a1cce3SDavid Greenman 2402a4895f4SDavid Greenman swb = malloc(nblocks * sizeof(*swb), M_VMPGDATA, wait); 2412a4895f4SDavid Greenman if (swb == NULL) 24224a1cce3SDavid Greenman return 1; 24324a1cce3SDavid Greenman 2442a4895f4SDavid Greenman for (i = 0; i < nblocks; i++) { 2452a4895f4SDavid Greenman swb[i].swb_valid = 0; 2462a4895f4SDavid Greenman swb[i].swb_locked = 0; 24726f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) 2482a4895f4SDavid Greenman swb[i].swb_block[j] = SWB_EMPTY; 24926f9a767SRodney W. Grimes } 25026f9a767SRodney W. Grimes 2512a4895f4SDavid Greenman object->un_pager.swp.swp_nblocks = nblocks; 2522a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize = 0; 2532a4895f4SDavid Greenman object->un_pager.swp.swp_blocks = swb; 2542a4895f4SDavid Greenman object->un_pager.swp.swp_poip = 0; 25524a1cce3SDavid Greenman 25624a1cce3SDavid Greenman if (object->handle != NULL) { 25724a1cce3SDavid Greenman TAILQ_INSERT_TAIL(&swap_pager_object_list, object, pager_object_list); 258df8bae1dSRodney W. Grimes } else { 25924a1cce3SDavid Greenman TAILQ_INSERT_TAIL(&swap_pager_un_object_list, object, pager_object_list); 260df8bae1dSRodney W. Grimes } 261df8bae1dSRodney W. Grimes 26224a1cce3SDavid Greenman return 0; 26324a1cce3SDavid Greenman } 26424a1cce3SDavid Greenman 26524a1cce3SDavid Greenman /* 2662a4895f4SDavid Greenman * Allocate an object and associated resources. 26724a1cce3SDavid Greenman * Note that if we are called from the pageout daemon (handle == NULL) 26824a1cce3SDavid Greenman * we should not wait for memory as it could resulting in deadlock. 26924a1cce3SDavid Greenman */ 270f5a12711SPoul-Henning Kamp static vm_object_t 27124a1cce3SDavid Greenman swap_pager_alloc(handle, size, prot, offset) 27224a1cce3SDavid Greenman void *handle; 27324a1cce3SDavid Greenman register vm_size_t size; 27424a1cce3SDavid Greenman vm_prot_t prot; 27524a1cce3SDavid Greenman vm_offset_t offset; 27624a1cce3SDavid Greenman { 27724a1cce3SDavid Greenman vm_object_t object; 27824a1cce3SDavid Greenman 27924a1cce3SDavid Greenman /* 28024a1cce3SDavid Greenman * If this is a "named" anonymous region, look it up and use the 28124a1cce3SDavid Greenman * object if it exists, otherwise allocate a new one. 28224a1cce3SDavid Greenman */ 28324a1cce3SDavid Greenman if (handle) { 28424a1cce3SDavid Greenman object = vm_pager_object_lookup(&swap_pager_object_list, handle); 28524a1cce3SDavid Greenman if (object != NULL) { 28624a1cce3SDavid Greenman vm_object_reference(object); 28724a1cce3SDavid Greenman } else { 28824a1cce3SDavid Greenman /* 28924a1cce3SDavid Greenman * XXX - there is a race condition here. Two processes 29024a1cce3SDavid Greenman * can request the same named object simultaneuously, 29124a1cce3SDavid Greenman * and if one blocks for memory, the result is a disaster. 29224a1cce3SDavid Greenman * Probably quite rare, but is yet another reason to just 29324a1cce3SDavid Greenman * rip support of "named anonymous regions" out altogether. 29424a1cce3SDavid Greenman */ 29524a1cce3SDavid Greenman object = vm_object_allocate(OBJT_SWAP, offset + size); 29624a1cce3SDavid Greenman object->handle = handle; 29724a1cce3SDavid Greenman (void) swap_pager_swp_alloc(object, M_WAITOK); 29824a1cce3SDavid Greenman } 29924a1cce3SDavid Greenman } else { 30024a1cce3SDavid Greenman object = vm_object_allocate(OBJT_SWAP, offset + size); 30124a1cce3SDavid Greenman (void) swap_pager_swp_alloc(object, M_WAITOK); 30224a1cce3SDavid Greenman } 30324a1cce3SDavid Greenman 30424a1cce3SDavid Greenman return (object); 305df8bae1dSRodney W. Grimes } 306df8bae1dSRodney W. Grimes 30726f9a767SRodney W. Grimes /* 30826f9a767SRodney W. Grimes * returns disk block associated with pager and offset 30926f9a767SRodney W. Grimes * additionally, as a side effect returns a flag indicating 31026f9a767SRodney W. Grimes * if the block has been written 31126f9a767SRodney W. Grimes */ 31226f9a767SRodney W. Grimes 313cac597e4SBruce Evans static inline int * 31424a1cce3SDavid Greenman swap_pager_diskaddr(object, offset, valid) 31524a1cce3SDavid Greenman vm_object_t object; 31626f9a767SRodney W. Grimes vm_offset_t offset; 31726f9a767SRodney W. Grimes int *valid; 31826f9a767SRodney W. Grimes { 31926f9a767SRodney W. Grimes register sw_blk_t swb; 32026f9a767SRodney W. Grimes int ix; 32126f9a767SRodney W. Grimes 32226f9a767SRodney W. Grimes if (valid) 32326f9a767SRodney W. Grimes *valid = 0; 32426f9a767SRodney W. Grimes ix = offset / (SWB_NPAGES * PAGE_SIZE); 3252a4895f4SDavid Greenman if ((ix >= object->un_pager.swp.swp_nblocks) || 32624a1cce3SDavid Greenman (offset >= object->size)) { 32726f9a767SRodney W. Grimes return (FALSE); 32826f9a767SRodney W. Grimes } 3292a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 33026f9a767SRodney W. Grimes ix = (offset % (SWB_NPAGES * PAGE_SIZE)) / PAGE_SIZE; 33126f9a767SRodney W. Grimes if (valid) 33226f9a767SRodney W. Grimes *valid = swb->swb_valid & (1 << ix); 33326f9a767SRodney W. Grimes return &swb->swb_block[ix]; 33426f9a767SRodney W. Grimes } 33526f9a767SRodney W. Grimes 33626f9a767SRodney W. Grimes /* 33726f9a767SRodney W. Grimes * Utility routine to set the valid (written) bit for 33826f9a767SRodney W. Grimes * a block associated with a pager and offset 33926f9a767SRodney W. Grimes */ 340df8bae1dSRodney W. Grimes static void 3412a4895f4SDavid Greenman swap_pager_setvalid(object, offset, valid) 3422a4895f4SDavid Greenman vm_object_t object; 34326f9a767SRodney W. Grimes vm_offset_t offset; 34426f9a767SRodney W. Grimes int valid; 34526f9a767SRodney W. Grimes { 34626f9a767SRodney W. Grimes register sw_blk_t swb; 34726f9a767SRodney W. Grimes int ix; 34826f9a767SRodney W. Grimes 34926f9a767SRodney W. Grimes ix = offset / (SWB_NPAGES * PAGE_SIZE); 3502a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) 35126f9a767SRodney W. Grimes return; 35226f9a767SRodney W. Grimes 3532a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 35426f9a767SRodney W. Grimes ix = (offset % (SWB_NPAGES * PAGE_SIZE)) / PAGE_SIZE; 35526f9a767SRodney W. Grimes if (valid) 35626f9a767SRodney W. Grimes swb->swb_valid |= (1 << ix); 35726f9a767SRodney W. Grimes else 35826f9a767SRodney W. Grimes swb->swb_valid &= ~(1 << ix); 35926f9a767SRodney W. Grimes return; 36026f9a767SRodney W. Grimes } 36126f9a767SRodney W. Grimes 36226f9a767SRodney W. Grimes /* 36326f9a767SRodney W. Grimes * this routine allocates swap space with a fragmentation 36426f9a767SRodney W. Grimes * minimization policy. 36526f9a767SRodney W. Grimes */ 366f5a12711SPoul-Henning Kamp static int 3672a4895f4SDavid Greenman swap_pager_getswapspace(object, amount, rtval) 3682a4895f4SDavid Greenman vm_object_t object; 3692a4895f4SDavid Greenman unsigned int amount; 3702a4895f4SDavid Greenman unsigned int *rtval; 3710d94caffSDavid Greenman { 37224ea4a96SDavid Greenman vm_swap_size -= amount; 37324ea4a96SDavid Greenman if (!rlist_alloc(&swaplist, amount, rtval)) { 37424ea4a96SDavid Greenman vm_swap_size += amount; 37526f9a767SRodney W. Grimes return 0; 37624ea4a96SDavid Greenman } else { 37724ea4a96SDavid Greenman swapsizecheck(); 3782a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize += amount; 37926f9a767SRodney W. Grimes return 1; 38026f9a767SRodney W. Grimes } 38126f9a767SRodney W. Grimes } 38226f9a767SRodney W. Grimes 38326f9a767SRodney W. Grimes /* 38426f9a767SRodney W. Grimes * this routine frees swap space with a fragmentation 38526f9a767SRodney W. Grimes * minimization policy. 38626f9a767SRodney W. Grimes */ 387f5a12711SPoul-Henning Kamp static void 3882a4895f4SDavid Greenman swap_pager_freeswapspace(object, from, to) 3892a4895f4SDavid Greenman vm_object_t object; 3902a4895f4SDavid Greenman unsigned int from; 3912a4895f4SDavid Greenman unsigned int to; 3920d94caffSDavid Greenman { 39335c10d22SDavid Greenman rlist_free(&swaplist, from, to); 39424ea4a96SDavid Greenman vm_swap_size += (to - from) + 1; 3952a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize -= (to - from) + 1; 39624ea4a96SDavid Greenman swapsizecheck(); 39726f9a767SRodney W. Grimes } 39826f9a767SRodney W. Grimes /* 39926f9a767SRodney W. Grimes * this routine frees swap blocks from a specified pager 40026f9a767SRodney W. Grimes */ 40126f9a767SRodney W. Grimes void 40224a1cce3SDavid Greenman swap_pager_freespace(object, start, size) 40324a1cce3SDavid Greenman vm_object_t object; 40426f9a767SRodney W. Grimes vm_offset_t start; 40526f9a767SRodney W. Grimes vm_offset_t size; 40626f9a767SRodney W. Grimes { 40726f9a767SRodney W. Grimes vm_offset_t i; 40826f9a767SRodney W. Grimes int s; 40926f9a767SRodney W. Grimes 41026f9a767SRodney W. Grimes s = splbio(); 4116f7bc393SDavid Greenman for (i = start; i < round_page(start + size); i += PAGE_SIZE) { 41226f9a767SRodney W. Grimes int valid; 41324a1cce3SDavid Greenman int *addr = swap_pager_diskaddr(object, i, &valid); 4140d94caffSDavid Greenman 41526f9a767SRodney W. Grimes if (addr && *addr != SWB_EMPTY) { 4162a4895f4SDavid Greenman swap_pager_freeswapspace(object, *addr, *addr + btodb(PAGE_SIZE) - 1); 41726f9a767SRodney W. Grimes if (valid) { 4182a4895f4SDavid Greenman swap_pager_setvalid(object, i, 0); 41926f9a767SRodney W. Grimes } 42026f9a767SRodney W. Grimes *addr = SWB_EMPTY; 42126f9a767SRodney W. Grimes } 42226f9a767SRodney W. Grimes } 42326f9a767SRodney W. Grimes splx(s); 42426f9a767SRodney W. Grimes } 42526f9a767SRodney W. Grimes 426a1f6d91cSDavid Greenman static void 4272a4895f4SDavid Greenman swap_pager_free_swap(object) 4282a4895f4SDavid Greenman vm_object_t object; 429a1f6d91cSDavid Greenman { 430a1f6d91cSDavid Greenman register int i, j; 4312a4895f4SDavid Greenman register sw_blk_t swb; 432a1f6d91cSDavid Greenman int first_block=0, block_count=0; 433a1f6d91cSDavid Greenman int s; 434a1f6d91cSDavid Greenman /* 435a1f6d91cSDavid Greenman * Free left over swap blocks 436a1f6d91cSDavid Greenman */ 437a1f6d91cSDavid Greenman s = splbio(); 4382a4895f4SDavid Greenman for (i = 0, swb = object->un_pager.swp.swp_blocks; 4392a4895f4SDavid Greenman i < object->un_pager.swp.swp_nblocks; i++, swb++) { 440a1f6d91cSDavid Greenman for (j = 0; j < SWB_NPAGES; j++) { 4412a4895f4SDavid Greenman if (swb->swb_block[j] != SWB_EMPTY) { 442a1f6d91cSDavid Greenman /* 443a1f6d91cSDavid Greenman * initially the length of the run is zero 444a1f6d91cSDavid Greenman */ 445a1f6d91cSDavid Greenman if (block_count == 0) { 4462a4895f4SDavid Greenman first_block = swb->swb_block[j]; 447a1f6d91cSDavid Greenman block_count = btodb(PAGE_SIZE); 4482a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 449a1f6d91cSDavid Greenman /* 450a1f6d91cSDavid Greenman * if the new block can be included into the current run 451a1f6d91cSDavid Greenman */ 4522a4895f4SDavid Greenman } else if (swb->swb_block[j] == first_block + block_count) { 453a1f6d91cSDavid Greenman block_count += btodb(PAGE_SIZE); 4542a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 455a1f6d91cSDavid Greenman /* 456a1f6d91cSDavid Greenman * terminate the previous run, and start a new one 457a1f6d91cSDavid Greenman */ 458a1f6d91cSDavid Greenman } else { 4592a4895f4SDavid Greenman swap_pager_freeswapspace(object, first_block, 460a1f6d91cSDavid Greenman (unsigned) first_block + block_count - 1); 4612a4895f4SDavid Greenman first_block = swb->swb_block[j]; 462a1f6d91cSDavid Greenman block_count = btodb(PAGE_SIZE); 4632a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 464a1f6d91cSDavid Greenman } 465a1f6d91cSDavid Greenman } 466a1f6d91cSDavid Greenman } 467a1f6d91cSDavid Greenman } 468a1f6d91cSDavid Greenman 469a1f6d91cSDavid Greenman if (block_count) { 4702a4895f4SDavid Greenman swap_pager_freeswapspace(object, first_block, 471a1f6d91cSDavid Greenman (unsigned) first_block + block_count - 1); 472a1f6d91cSDavid Greenman } 473a1f6d91cSDavid Greenman splx(s); 474a1f6d91cSDavid Greenman } 475a1f6d91cSDavid Greenman 476a1f6d91cSDavid Greenman 47726f9a767SRodney W. Grimes /* 47826f9a767SRodney W. Grimes * swap_pager_reclaim frees up over-allocated space from all pagers 47926f9a767SRodney W. Grimes * this eliminates internal fragmentation due to allocation of space 48026f9a767SRodney W. Grimes * for segments that are never swapped to. It has been written so that 48126f9a767SRodney W. Grimes * it does not block until the rlist_free operation occurs; it keeps 48226f9a767SRodney W. Grimes * the queues consistant. 48326f9a767SRodney W. Grimes */ 48426f9a767SRodney W. Grimes 48526f9a767SRodney W. Grimes /* 48626f9a767SRodney W. Grimes * Maximum number of blocks (pages) to reclaim per pass 48726f9a767SRodney W. Grimes */ 488a1f6d91cSDavid Greenman #define MAXRECLAIM 128 48926f9a767SRodney W. Grimes 490f5a12711SPoul-Henning Kamp static void 49126f9a767SRodney W. Grimes swap_pager_reclaim() 49226f9a767SRodney W. Grimes { 49324a1cce3SDavid Greenman vm_object_t object; 49426f9a767SRodney W. Grimes int i, j, k; 49526f9a767SRodney W. Grimes int s; 49626f9a767SRodney W. Grimes int reclaimcount; 497a1f6d91cSDavid Greenman static struct { 498a1f6d91cSDavid Greenman int address; 4992a4895f4SDavid Greenman vm_object_t object; 500a1f6d91cSDavid Greenman } reclaims[MAXRECLAIM]; 50126f9a767SRodney W. Grimes static int in_reclaim; 50226f9a767SRodney W. Grimes 50326f9a767SRodney W. Grimes /* 50426f9a767SRodney W. Grimes * allow only one process to be in the swap_pager_reclaim subroutine 50526f9a767SRodney W. Grimes */ 50626f9a767SRodney W. Grimes s = splbio(); 50726f9a767SRodney W. Grimes if (in_reclaim) { 50824a1cce3SDavid Greenman tsleep(&in_reclaim, PSWP, "swrclm", 0); 50926f9a767SRodney W. Grimes splx(s); 51026f9a767SRodney W. Grimes return; 51126f9a767SRodney W. Grimes } 51226f9a767SRodney W. Grimes in_reclaim = 1; 51326f9a767SRodney W. Grimes reclaimcount = 0; 51426f9a767SRodney W. Grimes 51526f9a767SRodney W. Grimes /* for each pager queue */ 51626f9a767SRodney W. Grimes for (k = 0; swp_qs[k]; k++) { 51726f9a767SRodney W. Grimes 51824a1cce3SDavid Greenman object = swp_qs[k]->tqh_first; 51924a1cce3SDavid Greenman while (object && (reclaimcount < MAXRECLAIM)) { 52026f9a767SRodney W. Grimes 52126f9a767SRodney W. Grimes /* 52226f9a767SRodney W. Grimes * see if any blocks associated with a pager has been 52326f9a767SRodney W. Grimes * allocated but not used (written) 52426f9a767SRodney W. Grimes */ 5252a4895f4SDavid Greenman for (i = 0; i < object->un_pager.swp.swp_nblocks; i++) { 5262a4895f4SDavid Greenman sw_blk_t swb = &object->un_pager.swp.swp_blocks[i]; 5270d94caffSDavid Greenman 52826f9a767SRodney W. Grimes if (swb->swb_locked) 52926f9a767SRodney W. Grimes continue; 53026f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) { 53126f9a767SRodney W. Grimes if (swb->swb_block[j] != SWB_EMPTY && 53226f9a767SRodney W. Grimes (swb->swb_valid & (1 << j)) == 0) { 533a1f6d91cSDavid Greenman reclaims[reclaimcount].address = swb->swb_block[j]; 5342a4895f4SDavid Greenman reclaims[reclaimcount++].object = object; 53526f9a767SRodney W. Grimes swb->swb_block[j] = SWB_EMPTY; 53626f9a767SRodney W. Grimes if (reclaimcount >= MAXRECLAIM) 53726f9a767SRodney W. Grimes goto rfinished; 53826f9a767SRodney W. Grimes } 53926f9a767SRodney W. Grimes } 54026f9a767SRodney W. Grimes } 54124a1cce3SDavid Greenman object = object->pager_object_list.tqe_next; 54226f9a767SRodney W. Grimes } 54326f9a767SRodney W. Grimes } 54426f9a767SRodney W. Grimes 54526f9a767SRodney W. Grimes rfinished: 54626f9a767SRodney W. Grimes 54726f9a767SRodney W. Grimes /* 54826f9a767SRodney W. Grimes * free the blocks that have been added to the reclaim list 54926f9a767SRodney W. Grimes */ 55026f9a767SRodney W. Grimes for (i = 0; i < reclaimcount; i++) { 5512a4895f4SDavid Greenman swap_pager_freeswapspace(reclaims[i].object, 5522a4895f4SDavid Greenman reclaims[i].address, reclaims[i].address + btodb(PAGE_SIZE) - 1); 55326f9a767SRodney W. Grimes } 55426f9a767SRodney W. Grimes splx(s); 55526f9a767SRodney W. Grimes in_reclaim = 0; 55624a1cce3SDavid Greenman wakeup(&in_reclaim); 55726f9a767SRodney W. Grimes } 55826f9a767SRodney W. Grimes 55926f9a767SRodney W. Grimes 56026f9a767SRodney W. Grimes /* 56126f9a767SRodney W. Grimes * swap_pager_copy copies blocks from one pager to another and 56226f9a767SRodney W. Grimes * destroys the source pager 56326f9a767SRodney W. Grimes */ 56426f9a767SRodney W. Grimes 56526f9a767SRodney W. Grimes void 56624a1cce3SDavid Greenman swap_pager_copy(srcobject, srcoffset, dstobject, dstoffset, offset) 56724a1cce3SDavid Greenman vm_object_t srcobject; 56826f9a767SRodney W. Grimes vm_offset_t srcoffset; 56924a1cce3SDavid Greenman vm_object_t dstobject; 57026f9a767SRodney W. Grimes vm_offset_t dstoffset; 57126f9a767SRodney W. Grimes vm_offset_t offset; 57226f9a767SRodney W. Grimes { 57326f9a767SRodney W. Grimes vm_offset_t i; 574a1f6d91cSDavid Greenman int origsize; 57526f9a767SRodney W. Grimes int s; 57626f9a767SRodney W. Grimes 57724ea4a96SDavid Greenman if (vm_swap_size) 57824ea4a96SDavid Greenman no_swap_space = 0; 57924ea4a96SDavid Greenman 5802a4895f4SDavid Greenman origsize = srcobject->un_pager.swp.swp_allocsize; 58126f9a767SRodney W. Grimes 58226f9a767SRodney W. Grimes /* 58324a1cce3SDavid Greenman * remove the source object from the swap_pager internal queue 58426f9a767SRodney W. Grimes */ 58524a1cce3SDavid Greenman if (srcobject->handle == NULL) { 58624a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_un_object_list, srcobject, pager_object_list); 58726f9a767SRodney W. Grimes } else { 58824a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_object_list, srcobject, pager_object_list); 58926f9a767SRodney W. Grimes } 59026f9a767SRodney W. Grimes 59124a1cce3SDavid Greenman s = splbio(); 5922a4895f4SDavid Greenman while (srcobject->un_pager.swp.swp_poip) { 5932a4895f4SDavid Greenman tsleep(srcobject, PVM, "spgout", 0); 59426f9a767SRodney W. Grimes } 59526f9a767SRodney W. Grimes splx(s); 59626f9a767SRodney W. Grimes 59726f9a767SRodney W. Grimes /* 59826f9a767SRodney W. Grimes * clean all of the pages that are currently active and finished 59926f9a767SRodney W. Grimes */ 60024a1cce3SDavid Greenman swap_pager_sync(); 60126f9a767SRodney W. Grimes 60226f9a767SRodney W. Grimes s = splbio(); 60326f9a767SRodney W. Grimes /* 60426f9a767SRodney W. Grimes * transfer source to destination 60526f9a767SRodney W. Grimes */ 60624a1cce3SDavid Greenman for (i = 0; i < dstobject->size; i += PAGE_SIZE) { 60726f9a767SRodney W. Grimes int srcvalid, dstvalid; 60824a1cce3SDavid Greenman int *srcaddrp = swap_pager_diskaddr(srcobject, i + offset + srcoffset, 60926f9a767SRodney W. Grimes &srcvalid); 61026f9a767SRodney W. Grimes int *dstaddrp; 6110d94caffSDavid Greenman 61226f9a767SRodney W. Grimes /* 61326f9a767SRodney W. Grimes * see if the source has space allocated 61426f9a767SRodney W. Grimes */ 61526f9a767SRodney W. Grimes if (srcaddrp && *srcaddrp != SWB_EMPTY) { 61626f9a767SRodney W. Grimes /* 6170d94caffSDavid Greenman * if the source is valid and the dest has no space, 6180d94caffSDavid Greenman * then copy the allocation from the srouce to the 6190d94caffSDavid Greenman * dest. 62026f9a767SRodney W. Grimes */ 62126f9a767SRodney W. Grimes if (srcvalid) { 62224a1cce3SDavid Greenman dstaddrp = swap_pager_diskaddr(dstobject, i + dstoffset, 623a1f6d91cSDavid Greenman &dstvalid); 62426f9a767SRodney W. Grimes /* 6250d94caffSDavid Greenman * if the dest already has a valid block, 6260d94caffSDavid Greenman * deallocate the source block without 6270d94caffSDavid Greenman * copying. 62826f9a767SRodney W. Grimes */ 62926f9a767SRodney W. Grimes if (!dstvalid && dstaddrp && *dstaddrp != SWB_EMPTY) { 6302a4895f4SDavid Greenman swap_pager_freeswapspace(dstobject, *dstaddrp, 631a1f6d91cSDavid Greenman *dstaddrp + btodb(PAGE_SIZE) - 1); 63226f9a767SRodney W. Grimes *dstaddrp = SWB_EMPTY; 63326f9a767SRodney W. Grimes } 63426f9a767SRodney W. Grimes if (dstaddrp && *dstaddrp == SWB_EMPTY) { 63526f9a767SRodney W. Grimes *dstaddrp = *srcaddrp; 63626f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 6372a4895f4SDavid Greenman dstobject->un_pager.swp.swp_allocsize += btodb(PAGE_SIZE); 6382a4895f4SDavid Greenman srcobject->un_pager.swp.swp_allocsize -= btodb(PAGE_SIZE); 6392a4895f4SDavid Greenman swap_pager_setvalid(dstobject, i + dstoffset, 1); 64026f9a767SRodney W. Grimes } 64126f9a767SRodney W. Grimes } 64226f9a767SRodney W. Grimes /* 6430d94caffSDavid Greenman * if the source is not empty at this point, then 6440d94caffSDavid Greenman * deallocate the space. 64526f9a767SRodney W. Grimes */ 64626f9a767SRodney W. Grimes if (*srcaddrp != SWB_EMPTY) { 6472a4895f4SDavid Greenman swap_pager_freeswapspace(srcobject, *srcaddrp, 648a1f6d91cSDavid Greenman *srcaddrp + btodb(PAGE_SIZE) - 1); 64926f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 65026f9a767SRodney W. Grimes } 65126f9a767SRodney W. Grimes } 65226f9a767SRodney W. Grimes } 65326f9a767SRodney W. Grimes splx(s); 65426f9a767SRodney W. Grimes 655a1f6d91cSDavid Greenman /* 656a1f6d91cSDavid Greenman * Free left over swap blocks 657a1f6d91cSDavid Greenman */ 6582a4895f4SDavid Greenman swap_pager_free_swap(srcobject); 659a1f6d91cSDavid Greenman 6602a4895f4SDavid Greenman if (srcobject->un_pager.swp.swp_allocsize) { 6612a4895f4SDavid Greenman printf("swap_pager_copy: *warning* pager with %d blocks (orig: %d)\n", 6622a4895f4SDavid Greenman srcobject->un_pager.swp.swp_allocsize, origsize); 6632a4895f4SDavid Greenman } 6642a4895f4SDavid Greenman 6652a4895f4SDavid Greenman free(srcobject->un_pager.swp.swp_blocks, M_VMPGDATA); 6662a4895f4SDavid Greenman srcobject->un_pager.swp.swp_blocks = NULL; 66726f9a767SRodney W. Grimes 66826f9a767SRodney W. Grimes return; 66926f9a767SRodney W. Grimes } 67026f9a767SRodney W. Grimes 671f5a12711SPoul-Henning Kamp static void 67224a1cce3SDavid Greenman swap_pager_dealloc(object) 67324a1cce3SDavid Greenman vm_object_t object; 674df8bae1dSRodney W. Grimes { 675df8bae1dSRodney W. Grimes int s; 676df8bae1dSRodney W. Grimes 677df8bae1dSRodney W. Grimes /* 6780d94caffSDavid Greenman * Remove from list right away so lookups will fail if we block for 6790d94caffSDavid Greenman * pageout completion. 680df8bae1dSRodney W. Grimes */ 68124a1cce3SDavid Greenman if (object->handle == NULL) { 68224a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_un_object_list, object, pager_object_list); 68326f9a767SRodney W. Grimes } else { 68424a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_object_list, object, pager_object_list); 685df8bae1dSRodney W. Grimes } 68624a1cce3SDavid Greenman 687df8bae1dSRodney W. Grimes /* 6880d94caffSDavid Greenman * Wait for all pageouts to finish and remove all entries from 6890d94caffSDavid Greenman * cleaning list. 690df8bae1dSRodney W. Grimes */ 69126f9a767SRodney W. Grimes 69224a1cce3SDavid Greenman s = splbio(); 6932a4895f4SDavid Greenman while (object->un_pager.swp.swp_poip) { 6942a4895f4SDavid Greenman tsleep(object, PVM, "swpout", 0); 695df8bae1dSRodney W. Grimes } 696df8bae1dSRodney W. Grimes splx(s); 69726f9a767SRodney W. Grimes 69826f9a767SRodney W. Grimes 69924a1cce3SDavid Greenman swap_pager_sync(); 700df8bae1dSRodney W. Grimes 701df8bae1dSRodney W. Grimes /* 702df8bae1dSRodney W. Grimes * Free left over swap blocks 703df8bae1dSRodney W. Grimes */ 7042a4895f4SDavid Greenman swap_pager_free_swap(object); 70526f9a767SRodney W. Grimes 7062a4895f4SDavid Greenman if (object->un_pager.swp.swp_allocsize) { 7072a4895f4SDavid Greenman printf("swap_pager_dealloc: *warning* freeing pager with %d blocks\n", 7082a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize); 7092a4895f4SDavid Greenman } 710df8bae1dSRodney W. Grimes /* 711df8bae1dSRodney W. Grimes * Free swap management resources 712df8bae1dSRodney W. Grimes */ 7132a4895f4SDavid Greenman free(object->un_pager.swp.swp_blocks, M_VMPGDATA); 7142a4895f4SDavid Greenman object->un_pager.swp.swp_blocks = NULL; 71526f9a767SRodney W. Grimes } 71626f9a767SRodney W. Grimes 717cac597e4SBruce Evans static inline __pure int 7182a4895f4SDavid Greenman swap_pager_block_index(offset) 71926f9a767SRodney W. Grimes vm_offset_t offset; 72026f9a767SRodney W. Grimes { 72126f9a767SRodney W. Grimes return (offset / (SWB_NPAGES * PAGE_SIZE)); 72226f9a767SRodney W. Grimes } 72326f9a767SRodney W. Grimes 724cac597e4SBruce Evans static inline __pure int 7252a4895f4SDavid Greenman swap_pager_block_offset(offset) 72626f9a767SRodney W. Grimes vm_offset_t offset; 72726f9a767SRodney W. Grimes { 72826f9a767SRodney W. Grimes return ((offset % (PAGE_SIZE * SWB_NPAGES)) / PAGE_SIZE); 72926f9a767SRodney W. Grimes } 73026f9a767SRodney W. Grimes 73126f9a767SRodney W. Grimes /* 73224a1cce3SDavid Greenman * swap_pager_haspage returns TRUE if the pager has data that has 73326f9a767SRodney W. Grimes * been written out. 73426f9a767SRodney W. Grimes */ 735f5a12711SPoul-Henning Kamp static boolean_t 73624a1cce3SDavid Greenman swap_pager_haspage(object, offset, before, after) 73724a1cce3SDavid Greenman vm_object_t object; 73826f9a767SRodney W. Grimes vm_offset_t offset; 73924a1cce3SDavid Greenman int *before; 74024a1cce3SDavid Greenman int *after; 74126f9a767SRodney W. Grimes { 74226f9a767SRodney W. Grimes register sw_blk_t swb; 74326f9a767SRodney W. Grimes int ix; 744170db9c6SJohn Dyson int gix; 74526f9a767SRodney W. Grimes 74624a1cce3SDavid Greenman if (before != NULL) 74724a1cce3SDavid Greenman *before = 0; 74824a1cce3SDavid Greenman if (after != NULL) 74924a1cce3SDavid Greenman *after = 0; 75026f9a767SRodney W. Grimes ix = offset / (SWB_NPAGES * PAGE_SIZE); 7512a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 75226f9a767SRodney W. Grimes return (FALSE); 75326f9a767SRodney W. Grimes } 7542a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 755170db9c6SJohn Dyson gix = offset / PAGE_SIZE; 756170db9c6SJohn Dyson ix = gix % SWB_NPAGES; 757170db9c6SJohn Dyson 75826f9a767SRodney W. Grimes if (swb->swb_block[ix] != SWB_EMPTY) { 759170db9c6SJohn Dyson 760170db9c6SJohn Dyson if (swb->swb_valid & (1 << ix)) { 761170db9c6SJohn Dyson int tix; 762170db9c6SJohn Dyson if (before) { 763170db9c6SJohn Dyson for(tix = ix - 1; tix >= 0; --tix) { 7642f82e604SDavid Greenman if ((swb->swb_valid & (1 << tix)) == 0) 7652f82e604SDavid Greenman break; 766ca56715fSJohn Dyson if ((swb->swb_block[tix] + 767170db9c6SJohn Dyson (ix - tix) * (PAGE_SIZE/DEV_BSIZE)) != 768170db9c6SJohn Dyson swb->swb_block[ix]) 769170db9c6SJohn Dyson break; 770170db9c6SJohn Dyson (*before)++; 771170db9c6SJohn Dyson } 772170db9c6SJohn Dyson } 773170db9c6SJohn Dyson 774170db9c6SJohn Dyson if (after) { 775170db9c6SJohn Dyson for(tix = ix + 1; tix < SWB_NPAGES; tix++) { 7762f82e604SDavid Greenman if ((swb->swb_valid & (1 << tix)) == 0) 7772f82e604SDavid Greenman break; 778ca56715fSJohn Dyson if ((swb->swb_block[tix] - 779170db9c6SJohn Dyson (tix - ix) * (PAGE_SIZE/DEV_BSIZE)) != 780170db9c6SJohn Dyson swb->swb_block[ix]) 781170db9c6SJohn Dyson break; 782170db9c6SJohn Dyson (*after)++; 783170db9c6SJohn Dyson } 784170db9c6SJohn Dyson } 785170db9c6SJohn Dyson 78626f9a767SRodney W. Grimes return TRUE; 78726f9a767SRodney W. Grimes } 788170db9c6SJohn Dyson } 78926f9a767SRodney W. Grimes return (FALSE); 79026f9a767SRodney W. Grimes } 79126f9a767SRodney W. Grimes 79226f9a767SRodney W. Grimes /* 79326f9a767SRodney W. Grimes * swap_pager_freepage is a convienience routine that clears the busy 79426f9a767SRodney W. Grimes * bit and deallocates a page. 795df8bae1dSRodney W. Grimes */ 79626f9a767SRodney W. Grimes static void 79726f9a767SRodney W. Grimes swap_pager_freepage(m) 79826f9a767SRodney W. Grimes vm_page_t m; 79926f9a767SRodney W. Grimes { 80026f9a767SRodney W. Grimes PAGE_WAKEUP(m); 80126f9a767SRodney W. Grimes vm_page_free(m); 80226f9a767SRodney W. Grimes } 80326f9a767SRodney W. Grimes 80426f9a767SRodney W. Grimes /* 80526f9a767SRodney W. Grimes * swap_pager_ridpages is a convienience routine that deallocates all 80626f9a767SRodney W. Grimes * but the required page. this is usually used in error returns that 80726f9a767SRodney W. Grimes * need to invalidate the "extra" readahead pages. 80826f9a767SRodney W. Grimes */ 80926f9a767SRodney W. Grimes static void 81026f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage) 81126f9a767SRodney W. Grimes vm_page_t *m; 81226f9a767SRodney W. Grimes int count; 81326f9a767SRodney W. Grimes int reqpage; 81426f9a767SRodney W. Grimes { 81526f9a767SRodney W. Grimes int i; 8160d94caffSDavid Greenman 81726f9a767SRodney W. Grimes for (i = 0; i < count; i++) 81826f9a767SRodney W. Grimes if (i != reqpage) 81926f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 82026f9a767SRodney W. Grimes } 82126f9a767SRodney W. Grimes 82226f9a767SRodney W. Grimes /* 82326f9a767SRodney W. Grimes * swap_pager_iodone1 is the completion routine for both reads and async writes 82426f9a767SRodney W. Grimes */ 825f5a12711SPoul-Henning Kamp static void 82626f9a767SRodney W. Grimes swap_pager_iodone1(bp) 82726f9a767SRodney W. Grimes struct buf *bp; 82826f9a767SRodney W. Grimes { 82926f9a767SRodney W. Grimes bp->b_flags |= B_DONE; 83026f9a767SRodney W. Grimes bp->b_flags &= ~B_ASYNC; 83124a1cce3SDavid Greenman wakeup(bp); 83226f9a767SRodney W. Grimes } 83326f9a767SRodney W. Grimes 83426f9a767SRodney W. Grimes int 83524a1cce3SDavid Greenman swap_pager_getpages(object, m, count, reqpage) 83624a1cce3SDavid Greenman vm_object_t object; 83726f9a767SRodney W. Grimes vm_page_t *m; 83826f9a767SRodney W. Grimes int count, reqpage; 839df8bae1dSRodney W. Grimes { 840df8bae1dSRodney W. Grimes register struct buf *bp; 84126f9a767SRodney W. Grimes sw_blk_t swb[count]; 842df8bae1dSRodney W. Grimes register int s; 84326f9a767SRodney W. Grimes int i; 844df8bae1dSRodney W. Grimes boolean_t rv; 84526f9a767SRodney W. Grimes vm_offset_t kva, off[count]; 846df8bae1dSRodney W. Grimes swp_clean_t spc; 84726f9a767SRodney W. Grimes vm_offset_t paging_offset; 84826f9a767SRodney W. Grimes int reqaddr[count]; 8496d40c3d3SDavid Greenman int sequential; 850df8bae1dSRodney W. Grimes 85126f9a767SRodney W. Grimes int first, last; 85226f9a767SRodney W. Grimes int failed; 85326f9a767SRodney W. Grimes int reqdskregion; 854df8bae1dSRodney W. Grimes 85526f9a767SRodney W. Grimes object = m[reqpage]->object; 85626f9a767SRodney W. Grimes paging_offset = object->paging_offset; 8576d40c3d3SDavid Greenman sequential = (m[reqpage]->offset == (object->last_read + PAGE_SIZE)); 8582a4895f4SDavid Greenman 85926f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 86026f9a767SRodney W. Grimes vm_offset_t foff = m[i]->offset + paging_offset; 8612a4895f4SDavid Greenman int ix = swap_pager_block_index(foff); 8620d94caffSDavid Greenman 8632a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 86426f9a767SRodney W. Grimes int j; 8650d94caffSDavid Greenman 86626f9a767SRodney W. Grimes if (i <= reqpage) { 86726f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 868df8bae1dSRodney W. Grimes return (VM_PAGER_FAIL); 86926f9a767SRodney W. Grimes } 87026f9a767SRodney W. Grimes for (j = i; j < count; j++) { 87126f9a767SRodney W. Grimes swap_pager_freepage(m[j]); 87226f9a767SRodney W. Grimes } 87326f9a767SRodney W. Grimes count = i; 87426f9a767SRodney W. Grimes break; 87526f9a767SRodney W. Grimes } 8762a4895f4SDavid Greenman swb[i] = &object->un_pager.swp.swp_blocks[ix]; 8772a4895f4SDavid Greenman off[i] = swap_pager_block_offset(foff); 87826f9a767SRodney W. Grimes reqaddr[i] = swb[i]->swb_block[off[i]]; 87926f9a767SRodney W. Grimes } 88026f9a767SRodney W. Grimes 88126f9a767SRodney W. Grimes /* make sure that our required input request is existant */ 88226f9a767SRodney W. Grimes 88326f9a767SRodney W. Grimes if (reqaddr[reqpage] == SWB_EMPTY || 88426f9a767SRodney W. Grimes (swb[reqpage]->swb_valid & (1 << off[reqpage])) == 0) { 88526f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 88626f9a767SRodney W. Grimes return (VM_PAGER_FAIL); 88726f9a767SRodney W. Grimes } 88826f9a767SRodney W. Grimes reqdskregion = reqaddr[reqpage] / dmmax; 889df8bae1dSRodney W. Grimes 890df8bae1dSRodney W. Grimes /* 89126f9a767SRodney W. Grimes * search backwards for the first contiguous page to transfer 892df8bae1dSRodney W. Grimes */ 89326f9a767SRodney W. Grimes failed = 0; 89426f9a767SRodney W. Grimes first = 0; 89526f9a767SRodney W. Grimes for (i = reqpage - 1; i >= 0; --i) { 8966d40c3d3SDavid Greenman if (sequential || failed || (reqaddr[i] == SWB_EMPTY) || 89726f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 89826f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 89926f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 90026f9a767SRodney W. Grimes failed = 1; 90126f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 90226f9a767SRodney W. Grimes if (first == 0) 90326f9a767SRodney W. Grimes first = i + 1; 90426f9a767SRodney W. Grimes } 905df8bae1dSRodney W. Grimes } 906df8bae1dSRodney W. Grimes /* 90726f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 908df8bae1dSRodney W. Grimes */ 90926f9a767SRodney W. Grimes failed = 0; 91026f9a767SRodney W. Grimes last = count; 91126f9a767SRodney W. Grimes for (i = reqpage + 1; i < count; i++) { 91226f9a767SRodney W. Grimes if (failed || (reqaddr[i] == SWB_EMPTY) || 91326f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 91426f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 91526f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 91626f9a767SRodney W. Grimes failed = 1; 91726f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 91826f9a767SRodney W. Grimes if (last == count) 91926f9a767SRodney W. Grimes last = i; 92026f9a767SRodney W. Grimes } 92126f9a767SRodney W. Grimes } 92226f9a767SRodney W. Grimes 92326f9a767SRodney W. Grimes count = last; 92426f9a767SRodney W. Grimes if (first != 0) { 92526f9a767SRodney W. Grimes for (i = first; i < count; i++) { 92626f9a767SRodney W. Grimes m[i - first] = m[i]; 92726f9a767SRodney W. Grimes reqaddr[i - first] = reqaddr[i]; 92826f9a767SRodney W. Grimes off[i - first] = off[i]; 92926f9a767SRodney W. Grimes } 93026f9a767SRodney W. Grimes count -= first; 93126f9a767SRodney W. Grimes reqpage -= first; 93226f9a767SRodney W. Grimes } 93326f9a767SRodney W. Grimes ++swb[reqpage]->swb_locked; 93426f9a767SRodney W. Grimes 93526f9a767SRodney W. Grimes /* 9360d94caffSDavid Greenman * at this point: "m" is a pointer to the array of vm_page_t for 9370d94caffSDavid Greenman * paging I/O "count" is the number of vm_page_t entries represented 9380d94caffSDavid Greenman * by "m" "object" is the vm_object_t for I/O "reqpage" is the index 9390d94caffSDavid Greenman * into "m" for the page actually faulted 94026f9a767SRodney W. Grimes */ 94126f9a767SRodney W. Grimes 94226f9a767SRodney W. Grimes spc = NULL; /* we might not use an spc data structure */ 94326f9a767SRodney W. Grimes 944a1f6d91cSDavid Greenman if ((count == 1) && (swap_pager_free.tqh_first != NULL)) { 94526f9a767SRodney W. Grimes /* 9460d94caffSDavid Greenman * if a kva has not been allocated, we can only do a one page 9470d94caffSDavid Greenman * transfer, so we free the other pages that might have been 9480d94caffSDavid Greenman * allocated by vm_fault. 94926f9a767SRodney W. Grimes */ 95026f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 95126f9a767SRodney W. Grimes m[0] = m[reqpage]; 95226f9a767SRodney W. Grimes reqaddr[0] = reqaddr[reqpage]; 95326f9a767SRodney W. Grimes 95426f9a767SRodney W. Grimes count = 1; 95526f9a767SRodney W. Grimes reqpage = 0; 95626f9a767SRodney W. Grimes /* 9570d94caffSDavid Greenman * get a swap pager clean data structure, block until we get 9580d94caffSDavid Greenman * it 95926f9a767SRodney W. Grimes */ 960df8bae1dSRodney W. Grimes if (swap_pager_free.tqh_first == NULL) { 961df8bae1dSRodney W. Grimes s = splbio(); 96226f9a767SRodney W. Grimes if (curproc == pageproc) 96324a1cce3SDavid Greenman swap_pager_sync(); 96426f9a767SRodney W. Grimes else 965f919ebdeSDavid Greenman pagedaemon_wakeup(); 96626f9a767SRodney W. Grimes while (swap_pager_free.tqh_first == NULL) { 96726f9a767SRodney W. Grimes swap_pager_needflags |= SWAP_FREE_NEEDED; 968a1f6d91cSDavid Greenman if (curproc == pageproc) 969a1f6d91cSDavid Greenman swap_pager_needflags |= SWAP_FREE_NEEDED_BY_PAGEOUT; 97024a1cce3SDavid Greenman tsleep(&swap_pager_free, 97126f9a767SRodney W. Grimes PVM, "swpfre", 0); 97226f9a767SRodney W. Grimes if (curproc == pageproc) 97324a1cce3SDavid Greenman swap_pager_sync(); 97426f9a767SRodney W. Grimes else 975f919ebdeSDavid Greenman pagedaemon_wakeup(); 976df8bae1dSRodney W. Grimes } 977df8bae1dSRodney W. Grimes splx(s); 97826f9a767SRodney W. Grimes } 97926f9a767SRodney W. Grimes spc = swap_pager_free.tqh_first; 98026f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 98126f9a767SRodney W. Grimes kva = spc->spc_kva; 98226f9a767SRodney W. Grimes bp = spc->spc_bp; 98326f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 98426f9a767SRodney W. Grimes bp->b_spc = spc; 9857609ab12SDavid Greenman bp->b_vnbufs.le_next = NOLIST; 98626f9a767SRodney W. Grimes } else { 98716f62314SDavid Greenman /* 98816f62314SDavid Greenman * Get a swap buffer header to perform the IO 98916f62314SDavid Greenman */ 99026f9a767SRodney W. Grimes bp = getpbuf(); 99116f62314SDavid Greenman kva = (vm_offset_t) bp->b_data; 99226f9a767SRodney W. Grimes } 99326f9a767SRodney W. Grimes 99416f62314SDavid Greenman /* 99516f62314SDavid Greenman * map our page(s) into kva for input 99616f62314SDavid Greenman */ 99716f62314SDavid Greenman pmap_qenter(kva, m, count); 99816f62314SDavid Greenman 999aba8f38eSDavid Greenman bp->b_flags = B_BUSY | B_READ | B_CALL | B_PAGING; 100026f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 1001df8bae1dSRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 100226f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 100326f9a767SRodney W. Grimes crhold(bp->b_rcred); 100426f9a767SRodney W. Grimes crhold(bp->b_wcred); 100526f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva; 100626f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 100726f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE * count; 100826f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE * count; 100926f9a767SRodney W. Grimes 10100d94caffSDavid Greenman pbgetvp(swapdev_vp, bp); 1011df8bae1dSRodney W. Grimes 1012976e77fcSDavid Greenman cnt.v_swapin++; 1013976e77fcSDavid Greenman cnt.v_swappgsin += count; 1014df8bae1dSRodney W. Grimes /* 101526f9a767SRodney W. Grimes * perform the I/O 1016df8bae1dSRodney W. Grimes */ 1017df8bae1dSRodney W. Grimes VOP_STRATEGY(bp); 101826f9a767SRodney W. Grimes 101926f9a767SRodney W. Grimes /* 102026f9a767SRodney W. Grimes * wait for the sync I/O to complete 102126f9a767SRodney W. Grimes */ 10227609ab12SDavid Greenman s = splbio(); 102326f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 102424a1cce3SDavid Greenman tsleep(bp, PVM, "swread", 0); 1025df8bae1dSRodney W. Grimes } 10261b119d9dSDavid Greenman 10271b119d9dSDavid Greenman if (bp->b_flags & B_ERROR) { 10281b119d9dSDavid Greenman printf("swap_pager: I/O error - pagein failed; blkno %d, size %d, error %d\n", 10291b119d9dSDavid Greenman bp->b_blkno, bp->b_bcount, bp->b_error); 1030a83c285cSDavid Greenman rv = VM_PAGER_ERROR; 10311b119d9dSDavid Greenman } else { 10321b119d9dSDavid Greenman rv = VM_PAGER_OK; 10331b119d9dSDavid Greenman } 103426f9a767SRodney W. Grimes 103526f9a767SRodney W. Grimes /* 10360d94caffSDavid Greenman * relpbuf does this, but we maintain our own buffer list also... 103726f9a767SRodney W. Grimes */ 1038df8bae1dSRodney W. Grimes if (bp->b_vp) 10390d94caffSDavid Greenman pbrelvp(bp); 104026f9a767SRodney W. Grimes 1041df8bae1dSRodney W. Grimes splx(s); 10422a4895f4SDavid Greenman swb[reqpage]->swb_locked--; 104326f9a767SRodney W. Grimes 104426f9a767SRodney W. Grimes /* 104526f9a767SRodney W. Grimes * remove the mapping for kernel virtual 104626f9a767SRodney W. Grimes */ 104716f62314SDavid Greenman pmap_qremove(kva, count); 104826f9a767SRodney W. Grimes 104926f9a767SRodney W. Grimes if (spc) { 10506d40c3d3SDavid Greenman m[reqpage]->object->last_read = m[reqpage]->offset; 10510d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 105224a1cce3SDavid Greenman wakeup(bp); 105326f9a767SRodney W. Grimes /* 105426f9a767SRodney W. Grimes * if we have used an spc, we need to free it. 105526f9a767SRodney W. Grimes */ 105626f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 105726f9a767SRodney W. Grimes crfree(bp->b_rcred); 105826f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 105926f9a767SRodney W. Grimes crfree(bp->b_wcred); 106026f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 106126f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 106224a1cce3SDavid Greenman wakeup(&swap_pager_free); 106326f9a767SRodney W. Grimes } 1064a1f6d91cSDavid Greenman if (swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1065f919ebdeSDavid Greenman pagedaemon_wakeup(); 1066a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 106726f9a767SRodney W. Grimes } else { 106826f9a767SRodney W. Grimes /* 106926f9a767SRodney W. Grimes * release the physical I/O buffer 107026f9a767SRodney W. Grimes */ 107126f9a767SRodney W. Grimes relpbuf(bp); 107226f9a767SRodney W. Grimes /* 107326f9a767SRodney W. Grimes * finish up input if everything is ok 107426f9a767SRodney W. Grimes */ 107526f9a767SRodney W. Grimes if (rv == VM_PAGER_OK) { 107626f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 107726f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 10780d94caffSDavid Greenman m[i]->dirty = 0; 1079894048d7SJohn Dyson m[i]->flags &= ~PG_ZERO; 108026f9a767SRodney W. Grimes if (i != reqpage) { 108126f9a767SRodney W. Grimes /* 10820d94caffSDavid Greenman * whether or not to leave the page 10830d94caffSDavid Greenman * activated is up in the air, but we 10840d94caffSDavid Greenman * should put the page on a page queue 10850d94caffSDavid Greenman * somewhere. (it already is in the 10860d94caffSDavid Greenman * object). After some emperical 10870d94caffSDavid Greenman * results, it is best to deactivate 10880d94caffSDavid Greenman * the readahead pages. 108926f9a767SRodney W. Grimes */ 109026f9a767SRodney W. Grimes vm_page_deactivate(m[i]); 109126f9a767SRodney W. Grimes 109226f9a767SRodney W. Grimes /* 10930d94caffSDavid Greenman * just in case someone was asking for 10940d94caffSDavid Greenman * this page we now tell them that it 10950d94caffSDavid Greenman * is ok to use 109626f9a767SRodney W. Grimes */ 10970d94caffSDavid Greenman m[i]->valid = VM_PAGE_BITS_ALL; 109826f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 109926f9a767SRodney W. Grimes } 110026f9a767SRodney W. Grimes } 11016d40c3d3SDavid Greenman 11026d40c3d3SDavid Greenman m[reqpage]->object->last_read = m[count-1]->offset; 11036d40c3d3SDavid Greenman 11042e1e24ddSDavid Greenman /* 11052e1e24ddSDavid Greenman * If we're out of swap space, then attempt to free 11062e1e24ddSDavid Greenman * some whenever pages are brought in. We must clear 11072e1e24ddSDavid Greenman * the clean flag so that the page contents will be 11082e1e24ddSDavid Greenman * preserved. 11092e1e24ddSDavid Greenman */ 111026f9a767SRodney W. Grimes if (swap_pager_full) { 11112e1e24ddSDavid Greenman for (i = 0; i < count; i++) { 11120d94caffSDavid Greenman m[i]->dirty = VM_PAGE_BITS_ALL; 11132e1e24ddSDavid Greenman } 111424a1cce3SDavid Greenman swap_pager_freespace(object, m[0]->offset + paging_offset, count * PAGE_SIZE); 111526f9a767SRodney W. Grimes } 111626f9a767SRodney W. Grimes } else { 111726f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 111826f9a767SRodney W. Grimes } 111926f9a767SRodney W. Grimes } 112023922ccaSDavid Greenman if (rv == VM_PAGER_OK) { 112123922ccaSDavid Greenman pmap_clear_modify(VM_PAGE_TO_PHYS(m[reqpage])); 112223922ccaSDavid Greenman m[reqpage]->valid = VM_PAGE_BITS_ALL; 112323922ccaSDavid Greenman m[reqpage]->dirty = 0; 112423922ccaSDavid Greenman } 1125df8bae1dSRodney W. Grimes return (rv); 1126df8bae1dSRodney W. Grimes } 1127df8bae1dSRodney W. Grimes 112826f9a767SRodney W. Grimes int 112924a1cce3SDavid Greenman swap_pager_putpages(object, m, count, sync, rtvals) 113024a1cce3SDavid Greenman vm_object_t object; 113126f9a767SRodney W. Grimes vm_page_t *m; 113226f9a767SRodney W. Grimes int count; 113324a1cce3SDavid Greenman boolean_t sync; 113426f9a767SRodney W. Grimes int *rtvals; 1135df8bae1dSRodney W. Grimes { 113626f9a767SRodney W. Grimes register struct buf *bp; 113726f9a767SRodney W. Grimes sw_blk_t swb[count]; 113826f9a767SRodney W. Grimes register int s; 113926f9a767SRodney W. Grimes int i, j, ix; 114026f9a767SRodney W. Grimes boolean_t rv; 114126f9a767SRodney W. Grimes vm_offset_t kva, off, foff; 114226f9a767SRodney W. Grimes swp_clean_t spc; 114326f9a767SRodney W. Grimes vm_offset_t paging_offset; 114426f9a767SRodney W. Grimes int reqaddr[count]; 114526f9a767SRodney W. Grimes int failed; 1146df8bae1dSRodney W. Grimes 114724ea4a96SDavid Greenman if (vm_swap_size) 114824ea4a96SDavid Greenman no_swap_space = 0; 114924ea4a96SDavid Greenman if (no_swap_space) { 11505663e6deSDavid Greenman for (i = 0; i < count; i++) 11515663e6deSDavid Greenman rtvals[i] = VM_PAGER_FAIL; 11525663e6deSDavid Greenman return VM_PAGER_FAIL; 11535663e6deSDavid Greenman } 115426f9a767SRodney W. Grimes spc = NULL; 115526f9a767SRodney W. Grimes 115626f9a767SRodney W. Grimes object = m[0]->object; 115726f9a767SRodney W. Grimes paging_offset = object->paging_offset; 115826f9a767SRodney W. Grimes 115926f9a767SRodney W. Grimes failed = 0; 116026f9a767SRodney W. Grimes for (j = 0; j < count; j++) { 116126f9a767SRodney W. Grimes foff = m[j]->offset + paging_offset; 11622a4895f4SDavid Greenman ix = swap_pager_block_index(foff); 116326f9a767SRodney W. Grimes swb[j] = 0; 11642a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 116526f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 116626f9a767SRodney W. Grimes failed = 1; 116726f9a767SRodney W. Grimes continue; 116826f9a767SRodney W. Grimes } else { 116926f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_OK; 117026f9a767SRodney W. Grimes } 11712a4895f4SDavid Greenman swb[j] = &object->un_pager.swp.swp_blocks[ix]; 11722a4895f4SDavid Greenman swb[j]->swb_locked++; 117326f9a767SRodney W. Grimes if (failed) { 117426f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 117526f9a767SRodney W. Grimes continue; 117626f9a767SRodney W. Grimes } 11772a4895f4SDavid Greenman off = swap_pager_block_offset(foff); 117826f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 117926f9a767SRodney W. Grimes if (reqaddr[j] == SWB_EMPTY) { 118026f9a767SRodney W. Grimes int blk; 118126f9a767SRodney W. Grimes int tries; 118226f9a767SRodney W. Grimes int ntoget; 11830d94caffSDavid Greenman 118426f9a767SRodney W. Grimes tries = 0; 1185df8bae1dSRodney W. Grimes s = splbio(); 118626f9a767SRodney W. Grimes 1187df8bae1dSRodney W. Grimes /* 11880d94caffSDavid Greenman * if any other pages have been allocated in this 11890d94caffSDavid Greenman * block, we only try to get one page. 1190df8bae1dSRodney W. Grimes */ 119126f9a767SRodney W. Grimes for (i = 0; i < SWB_NPAGES; i++) { 119226f9a767SRodney W. Grimes if (swb[j]->swb_block[i] != SWB_EMPTY) 1193df8bae1dSRodney W. Grimes break; 1194df8bae1dSRodney W. Grimes } 119526f9a767SRodney W. Grimes 119626f9a767SRodney W. Grimes ntoget = (i == SWB_NPAGES) ? SWB_NPAGES : 1; 119726f9a767SRodney W. Grimes /* 11980d94caffSDavid Greenman * this code is alittle conservative, but works (the 11990d94caffSDavid Greenman * intent of this code is to allocate small chunks for 12000d94caffSDavid Greenman * small objects) 120126f9a767SRodney W. Grimes */ 120211fda60bSJohn Dyson if ((foff == 0) && 120311fda60bSJohn Dyson ((ntoget * PAGE_SIZE) > object->size)) { 120411fda60bSJohn Dyson ntoget = (object->size + (PAGE_SIZE - 1)) / PAGE_SIZE; 120526f9a767SRodney W. Grimes } 120626f9a767SRodney W. Grimes retrygetspace: 120726f9a767SRodney W. Grimes if (!swap_pager_full && ntoget > 1 && 12082a4895f4SDavid Greenman swap_pager_getswapspace(object, ntoget * btodb(PAGE_SIZE), &blk)) { 120926f9a767SRodney W. Grimes 121026f9a767SRodney W. Grimes for (i = 0; i < ntoget; i++) { 121126f9a767SRodney W. Grimes swb[j]->swb_block[i] = blk + btodb(PAGE_SIZE) * i; 121226f9a767SRodney W. Grimes swb[j]->swb_valid = 0; 121326f9a767SRodney W. Grimes } 121426f9a767SRodney W. Grimes 121526f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 12162a4895f4SDavid Greenman } else if (!swap_pager_getswapspace(object, btodb(PAGE_SIZE), 121726f9a767SRodney W. Grimes &swb[j]->swb_block[off])) { 121826f9a767SRodney W. Grimes /* 12190d94caffSDavid Greenman * if the allocation has failed, we try to 12200d94caffSDavid Greenman * reclaim space and retry. 122126f9a767SRodney W. Grimes */ 122226f9a767SRodney W. Grimes if (++tries == 1) { 122326f9a767SRodney W. Grimes swap_pager_reclaim(); 122426f9a767SRodney W. Grimes goto retrygetspace; 122526f9a767SRodney W. Grimes } 122626f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_AGAIN; 122726f9a767SRodney W. Grimes failed = 1; 122824ea4a96SDavid Greenman swap_pager_full = 1; 122926f9a767SRodney W. Grimes } else { 123026f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 123126f9a767SRodney W. Grimes swb[j]->swb_valid &= ~(1 << off); 1232df8bae1dSRodney W. Grimes } 1233df8bae1dSRodney W. Grimes splx(s); 123426f9a767SRodney W. Grimes } 123526f9a767SRodney W. Grimes } 123626f9a767SRodney W. Grimes 123726f9a767SRodney W. Grimes /* 123826f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 123926f9a767SRodney W. Grimes */ 124026f9a767SRodney W. Grimes failed = 0; 124126f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 124226f9a767SRodney W. Grimes if (failed || (reqaddr[i] != reqaddr[0] + i * btodb(PAGE_SIZE)) || 124326f9a767SRodney W. Grimes (reqaddr[i] / dmmax) != (reqaddr[0] / dmmax) || 124426f9a767SRodney W. Grimes (rtvals[i] != VM_PAGER_OK)) { 124526f9a767SRodney W. Grimes failed = 1; 124626f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) 124726f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 124826f9a767SRodney W. Grimes } 124926f9a767SRodney W. Grimes } 125026f9a767SRodney W. Grimes 125126f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 125226f9a767SRodney W. Grimes if (rtvals[i] != VM_PAGER_OK) { 125326f9a767SRodney W. Grimes if (swb[i]) 125426f9a767SRodney W. Grimes --swb[i]->swb_locked; 125526f9a767SRodney W. Grimes } 125626f9a767SRodney W. Grimes } 125726f9a767SRodney W. Grimes 125826f9a767SRodney W. Grimes for (i = 0; i < count; i++) 125926f9a767SRodney W. Grimes if (rtvals[i] != VM_PAGER_OK) 126026f9a767SRodney W. Grimes break; 126126f9a767SRodney W. Grimes 126226f9a767SRodney W. Grimes if (i == 0) { 126326f9a767SRodney W. Grimes return VM_PAGER_AGAIN; 126426f9a767SRodney W. Grimes } 126526f9a767SRodney W. Grimes count = i; 126626f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 126726f9a767SRodney W. Grimes if (reqaddr[i] == SWB_EMPTY) 126826f9a767SRodney W. Grimes printf("I/O to empty block????\n"); 126926f9a767SRodney W. Grimes } 127026f9a767SRodney W. Grimes 127126f9a767SRodney W. Grimes /* 12720d94caffSDavid Greenman * For synchronous writes, we clean up all completed async pageouts. 127326f9a767SRodney W. Grimes */ 127424a1cce3SDavid Greenman if (sync == TRUE) { 127524a1cce3SDavid Greenman swap_pager_sync(); 127626f9a767SRodney W. Grimes } 127726f9a767SRodney W. Grimes kva = 0; 127826f9a767SRodney W. Grimes 127926f9a767SRodney W. Grimes /* 128026f9a767SRodney W. Grimes * get a swap pager clean data structure, block until we get it 128126f9a767SRodney W. Grimes */ 1282a1f6d91cSDavid Greenman if (swap_pager_free.tqh_first == NULL || 1283a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next == NULL || 1284a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { 128526f9a767SRodney W. Grimes s = splbio(); 12860d94caffSDavid Greenman if (curproc == pageproc) { 128724a1cce3SDavid Greenman swap_pager_sync(); 1288a1f6d91cSDavid Greenman #if 0 12890d94caffSDavid Greenman splx(s); 12900d94caffSDavid Greenman return VM_PAGER_AGAIN; 1291a1f6d91cSDavid Greenman #endif 12920d94caffSDavid Greenman } else 1293f919ebdeSDavid Greenman pagedaemon_wakeup(); 1294a1f6d91cSDavid Greenman while (swap_pager_free.tqh_first == NULL || 1295a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next == NULL || 1296a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { 1297a1f6d91cSDavid Greenman if (curproc == pageproc) { 1298a1f6d91cSDavid Greenman swap_pager_needflags |= SWAP_FREE_NEEDED_BY_PAGEOUT; 1299a1f6d91cSDavid Greenman if((cnt.v_free_count + cnt.v_cache_count) > cnt.v_free_reserved) 130024a1cce3SDavid Greenman wakeup(&cnt.v_free_count); 1301a1f6d91cSDavid Greenman } 13020d94caffSDavid Greenman 130326f9a767SRodney W. Grimes swap_pager_needflags |= SWAP_FREE_NEEDED; 130424a1cce3SDavid Greenman tsleep(&swap_pager_free, PVM, "swpfre", 0); 130526f9a767SRodney W. Grimes if (curproc == pageproc) 130624a1cce3SDavid Greenman swap_pager_sync(); 130726f9a767SRodney W. Grimes else 1308f919ebdeSDavid Greenman pagedaemon_wakeup(); 130926f9a767SRodney W. Grimes } 131026f9a767SRodney W. Grimes splx(s); 131126f9a767SRodney W. Grimes } 131226f9a767SRodney W. Grimes spc = swap_pager_free.tqh_first; 131326f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 1314fff93ab6SDavid Greenman 131526f9a767SRodney W. Grimes kva = spc->spc_kva; 131626f9a767SRodney W. Grimes 131726f9a767SRodney W. Grimes /* 131826f9a767SRodney W. Grimes * map our page(s) into kva for I/O 131926f9a767SRodney W. Grimes */ 132016f62314SDavid Greenman pmap_qenter(kva, m, count); 132126f9a767SRodney W. Grimes 132226f9a767SRodney W. Grimes /* 132326f9a767SRodney W. Grimes * get the base I/O offset into the swap file 132426f9a767SRodney W. Grimes */ 132526f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 132626f9a767SRodney W. Grimes foff = m[i]->offset + paging_offset; 13272a4895f4SDavid Greenman off = swap_pager_block_offset(foff); 132826f9a767SRodney W. Grimes /* 132926f9a767SRodney W. Grimes * set the valid bit 133026f9a767SRodney W. Grimes */ 133126f9a767SRodney W. Grimes swb[i]->swb_valid |= (1 << off); 133226f9a767SRodney W. Grimes /* 133326f9a767SRodney W. Grimes * and unlock the data structure 133426f9a767SRodney W. Grimes */ 13352a4895f4SDavid Greenman swb[i]->swb_locked--; 133626f9a767SRodney W. Grimes } 133726f9a767SRodney W. Grimes 133826f9a767SRodney W. Grimes /* 133926f9a767SRodney W. Grimes * Get a swap buffer header and perform the IO 134026f9a767SRodney W. Grimes */ 134126f9a767SRodney W. Grimes bp = spc->spc_bp; 134226f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 134326f9a767SRodney W. Grimes bp->b_spc = spc; 13447609ab12SDavid Greenman bp->b_vnbufs.le_next = NOLIST; 134526f9a767SRodney W. Grimes 1346aba8f38eSDavid Greenman bp->b_flags = B_BUSY | B_PAGING; 134726f9a767SRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 134826f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 1349a481f200SDavid Greenman if (bp->b_rcred != NOCRED) 135026f9a767SRodney W. Grimes crhold(bp->b_rcred); 1351a481f200SDavid Greenman if (bp->b_wcred != NOCRED) 135226f9a767SRodney W. Grimes crhold(bp->b_wcred); 1353a481f200SDavid Greenman bp->b_data = (caddr_t) kva; 135426f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 13550d94caffSDavid Greenman pbgetvp(swapdev_vp, bp); 135616f62314SDavid Greenman 135726f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE * count; 135826f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE * count; 135926f9a767SRodney W. Grimes swapdev_vp->v_numoutput++; 136026f9a767SRodney W. Grimes 136126f9a767SRodney W. Grimes /* 13620d94caffSDavid Greenman * If this is an async write we set up additional buffer fields and 13630d94caffSDavid Greenman * place a "cleaning" entry on the inuse queue. 136426f9a767SRodney W. Grimes */ 13657609ab12SDavid Greenman s = splbio(); 136624a1cce3SDavid Greenman if (sync == FALSE) { 136726f9a767SRodney W. Grimes spc->spc_flags = 0; 13682a4895f4SDavid Greenman spc->spc_object = object; 136926f9a767SRodney W. Grimes for (i = 0; i < count; i++) 137026f9a767SRodney W. Grimes spc->spc_m[i] = m[i]; 137126f9a767SRodney W. Grimes spc->spc_count = count; 137226f9a767SRodney W. Grimes /* 137326f9a767SRodney W. Grimes * the completion routine for async writes 137426f9a767SRodney W. Grimes */ 137526f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 137626f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone; 137726f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 137826f9a767SRodney W. Grimes bp->b_dirtyend = bp->b_bcount; 13792a4895f4SDavid Greenman object->un_pager.swp.swp_poip++; 138026f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list); 138126f9a767SRodney W. Grimes } else { 13822a4895f4SDavid Greenman object->un_pager.swp.swp_poip++; 138326f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 138426f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 138526f9a767SRodney W. Grimes } 1386976e77fcSDavid Greenman 1387976e77fcSDavid Greenman cnt.v_swapout++; 1388976e77fcSDavid Greenman cnt.v_swappgsout += count; 138926f9a767SRodney W. Grimes /* 139026f9a767SRodney W. Grimes * perform the I/O 139126f9a767SRodney W. Grimes */ 139226f9a767SRodney W. Grimes VOP_STRATEGY(bp); 139324a1cce3SDavid Greenman if (sync == FALSE) { 139426f9a767SRodney W. Grimes if ((bp->b_flags & B_DONE) == B_DONE) { 139524a1cce3SDavid Greenman swap_pager_sync(); 139626f9a767SRodney W. Grimes } 139726f9a767SRodney W. Grimes splx(s); 139826f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 139926f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_PEND; 140026f9a767SRodney W. Grimes } 140126f9a767SRodney W. Grimes return VM_PAGER_PEND; 140226f9a767SRodney W. Grimes } 140326f9a767SRodney W. Grimes /* 140426f9a767SRodney W. Grimes * wait for the sync I/O to complete 140526f9a767SRodney W. Grimes */ 140626f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 140724a1cce3SDavid Greenman tsleep(bp, PVM, "swwrt", 0); 140826f9a767SRodney W. Grimes } 14091b119d9dSDavid Greenman if (bp->b_flags & B_ERROR) { 14101b119d9dSDavid Greenman printf("swap_pager: I/O error - pageout failed; blkno %d, size %d, error %d\n", 14111b119d9dSDavid Greenman bp->b_blkno, bp->b_bcount, bp->b_error); 1412a83c285cSDavid Greenman rv = VM_PAGER_ERROR; 14131b119d9dSDavid Greenman } else { 14141b119d9dSDavid Greenman rv = VM_PAGER_OK; 14151b119d9dSDavid Greenman } 141626f9a767SRodney W. Grimes 14172a4895f4SDavid Greenman object->un_pager.swp.swp_poip--; 14182a4895f4SDavid Greenman if (object->un_pager.swp.swp_poip == 0) 14192a4895f4SDavid Greenman wakeup(object); 142026f9a767SRodney W. Grimes 142126f9a767SRodney W. Grimes if (bp->b_vp) 14220d94caffSDavid Greenman pbrelvp(bp); 14230d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 142424a1cce3SDavid Greenman wakeup(bp); 142526f9a767SRodney W. Grimes 142626f9a767SRodney W. Grimes splx(s); 142726f9a767SRodney W. Grimes 142826f9a767SRodney W. Grimes /* 142926f9a767SRodney W. Grimes * remove the mapping for kernel virtual 143026f9a767SRodney W. Grimes */ 143116f62314SDavid Greenman pmap_qremove(kva, count); 143226f9a767SRodney W. Grimes 143326f9a767SRodney W. Grimes /* 14340d94caffSDavid Greenman * if we have written the page, then indicate that the page is clean. 143526f9a767SRodney W. Grimes */ 143626f9a767SRodney W. Grimes if (rv == VM_PAGER_OK) { 143726f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 143826f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) { 143926f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 14400d94caffSDavid Greenman m[i]->dirty = 0; 144126f9a767SRodney W. Grimes /* 14420d94caffSDavid Greenman * optimization, if a page has been read 14430d94caffSDavid Greenman * during the pageout process, we activate it. 144426f9a767SRodney W. Grimes */ 144526f9a767SRodney W. Grimes if ((m[i]->flags & PG_ACTIVE) == 0 && 14467fb0c17eSDavid Greenman ((m[i]->flags & (PG_WANTED|PG_REFERENCED)) || 14477fb0c17eSDavid Greenman pmap_is_referenced(VM_PAGE_TO_PHYS(m[i])))) { 144826f9a767SRodney W. Grimes vm_page_activate(m[i]); 144926f9a767SRodney W. Grimes } 145026f9a767SRodney W. Grimes } 14517fb0c17eSDavid Greenman } 145226f9a767SRodney W. Grimes } else { 145326f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 145426f9a767SRodney W. Grimes rtvals[i] = rv; 145526f9a767SRodney W. Grimes } 145626f9a767SRodney W. Grimes } 145726f9a767SRodney W. Grimes 145826f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 145926f9a767SRodney W. Grimes crfree(bp->b_rcred); 146026f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 146126f9a767SRodney W. Grimes crfree(bp->b_wcred); 146226f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 146326f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 146424a1cce3SDavid Greenman wakeup(&swap_pager_free); 146526f9a767SRodney W. Grimes } 1466a1f6d91cSDavid Greenman if (swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1467f919ebdeSDavid Greenman pagedaemon_wakeup(); 1468a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 146926f9a767SRodney W. Grimes return (rv); 147026f9a767SRodney W. Grimes } 147126f9a767SRodney W. Grimes 147224a1cce3SDavid Greenman void 147324a1cce3SDavid Greenman swap_pager_sync() 147426f9a767SRodney W. Grimes { 147526f9a767SRodney W. Grimes register swp_clean_t spc, tspc; 147626f9a767SRodney W. Grimes register int s; 147726f9a767SRodney W. Grimes 147826f9a767SRodney W. Grimes tspc = NULL; 147926f9a767SRodney W. Grimes if (swap_pager_done.tqh_first == NULL) 148024a1cce3SDavid Greenman return; 148126f9a767SRodney W. Grimes for (;;) { 148226f9a767SRodney W. Grimes s = splbio(); 148326f9a767SRodney W. Grimes /* 14840d94caffSDavid Greenman * Look up and removal from done list must be done at splbio() 14850d94caffSDavid Greenman * to avoid conflicts with swap_pager_iodone. 148626f9a767SRodney W. Grimes */ 148705f0fdd2SPoul-Henning Kamp while ((spc = swap_pager_done.tqh_first) != 0) { 1488fff93ab6SDavid Greenman pmap_qremove(spc->spc_kva, spc->spc_count); 148926f9a767SRodney W. Grimes swap_pager_finish(spc); 149026f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_done, spc, spc_list); 149126f9a767SRodney W. Grimes goto doclean; 149226f9a767SRodney W. Grimes } 1493df8bae1dSRodney W. Grimes 1494df8bae1dSRodney W. Grimes /* 1495df8bae1dSRodney W. Grimes * No operations done, thats all we can do for now. 1496df8bae1dSRodney W. Grimes */ 149726f9a767SRodney W. Grimes 149826f9a767SRodney W. Grimes splx(s); 1499df8bae1dSRodney W. Grimes break; 1500df8bae1dSRodney W. Grimes 1501df8bae1dSRodney W. Grimes /* 15020d94caffSDavid Greenman * The desired page was found to be busy earlier in the scan 15030d94caffSDavid Greenman * but has since completed. 1504df8bae1dSRodney W. Grimes */ 150526f9a767SRodney W. Grimes doclean: 150626f9a767SRodney W. Grimes if (tspc && tspc == spc) { 150726f9a767SRodney W. Grimes tspc = NULL; 150826f9a767SRodney W. Grimes } 150926f9a767SRodney W. Grimes spc->spc_flags = 0; 151026f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 151126f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 151224a1cce3SDavid Greenman wakeup(&swap_pager_free); 151326f9a767SRodney W. Grimes } 1514a1f6d91cSDavid Greenman if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1515f919ebdeSDavid Greenman pagedaemon_wakeup(); 1516a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 151726f9a767SRodney W. Grimes splx(s); 151826f9a767SRodney W. Grimes } 151926f9a767SRodney W. Grimes 152024a1cce3SDavid Greenman return; 152126f9a767SRodney W. Grimes } 152226f9a767SRodney W. Grimes 152326f9a767SRodney W. Grimes void 152426f9a767SRodney W. Grimes swap_pager_finish(spc) 152526f9a767SRodney W. Grimes register swp_clean_t spc; 152626f9a767SRodney W. Grimes { 152726f9a767SRodney W. Grimes vm_object_t object = spc->spc_m[0]->object; 152826f9a767SRodney W. Grimes int i; 152926f9a767SRodney W. Grimes 1530c0503609SDavid Greenman object->paging_in_progress -= spc->spc_count; 1531c0503609SDavid Greenman if ((object->paging_in_progress == 0) && 1532c0503609SDavid Greenman (object->flags & OBJ_PIPWNT)) { 1533c0503609SDavid Greenman object->flags &= ~OBJ_PIPWNT; 153424a1cce3SDavid Greenman wakeup(object); 1535c0503609SDavid Greenman } 1536df8bae1dSRodney W. Grimes 1537df8bae1dSRodney W. Grimes /* 15385f55e841SDavid Greenman * If no error, mark as clean and inform the pmap system. If error, 15390d94caffSDavid Greenman * mark as dirty so we will try again. (XXX could get stuck doing 15400d94caffSDavid Greenman * this, should give up after awhile) 1541df8bae1dSRodney W. Grimes */ 1542df8bae1dSRodney W. Grimes if (spc->spc_flags & SPC_ERROR) { 154326f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 1544a83c285cSDavid Greenman printf("swap_pager_finish: I/O error, clean of page %lx failed\n", 154505f0fdd2SPoul-Henning Kamp (u_long) VM_PAGE_TO_PHYS(spc->spc_m[i])); 154626f9a767SRodney W. Grimes } 1547df8bae1dSRodney W. Grimes } else { 154826f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 154926f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m[i])); 15500d94caffSDavid Greenman spc->spc_m[i]->dirty = 0; 15510d94caffSDavid Greenman if ((spc->spc_m[i]->flags & PG_ACTIVE) == 0 && 15520d94caffSDavid Greenman ((spc->spc_m[i]->flags & PG_WANTED) || pmap_is_referenced(VM_PAGE_TO_PHYS(spc->spc_m[i])))) 15530d94caffSDavid Greenman vm_page_activate(spc->spc_m[i]); 1554df8bae1dSRodney W. Grimes } 1555df8bae1dSRodney W. Grimes } 1556df8bae1dSRodney W. Grimes 155726f9a767SRodney W. Grimes 155826f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 1559df8bae1dSRodney W. Grimes /* 15600d94caffSDavid Greenman * we wakeup any processes that are waiting on these pages. 1561df8bae1dSRodney W. Grimes */ 156226f9a767SRodney W. Grimes PAGE_WAKEUP(spc->spc_m[i]); 1563df8bae1dSRodney W. Grimes } 156426f9a767SRodney W. Grimes nswiodone -= spc->spc_count; 1565df8bae1dSRodney W. Grimes 1566df8bae1dSRodney W. Grimes return; 156726f9a767SRodney W. Grimes } 1568df8bae1dSRodney W. Grimes 156926f9a767SRodney W. Grimes /* 157026f9a767SRodney W. Grimes * swap_pager_iodone 157126f9a767SRodney W. Grimes */ 1572f5a12711SPoul-Henning Kamp static void 1573df8bae1dSRodney W. Grimes swap_pager_iodone(bp) 1574df8bae1dSRodney W. Grimes register struct buf *bp; 1575df8bae1dSRodney W. Grimes { 1576df8bae1dSRodney W. Grimes register swp_clean_t spc; 1577df8bae1dSRodney W. Grimes int s; 1578df8bae1dSRodney W. Grimes 1579df8bae1dSRodney W. Grimes s = splbio(); 158026f9a767SRodney W. Grimes spc = (swp_clean_t) bp->b_spc; 158126f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list); 158226f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_done, spc, spc_list); 158326f9a767SRodney W. Grimes if (bp->b_flags & B_ERROR) { 1584df8bae1dSRodney W. Grimes spc->spc_flags |= SPC_ERROR; 1585c3a1e425SDavid Greenman printf("swap_pager: I/O error - async %s failed; blkno %lu, size %ld, error %d\n", 15861b119d9dSDavid Greenman (bp->b_flags & B_READ) ? "pagein" : "pageout", 1587c3a1e425SDavid Greenman (u_long) bp->b_blkno, bp->b_bcount, bp->b_error); 1588df8bae1dSRodney W. Grimes } 158926f9a767SRodney W. Grimes 15900d94caffSDavid Greenman if (bp->b_vp) 15910d94caffSDavid Greenman pbrelvp(bp); 15920d94caffSDavid Greenman 15930d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 159424a1cce3SDavid Greenman wakeup(bp); 15950d94caffSDavid Greenman 159626f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 159726f9a767SRodney W. Grimes crfree(bp->b_rcred); 159826f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 159926f9a767SRodney W. Grimes crfree(bp->b_wcred); 160026f9a767SRodney W. Grimes 160126f9a767SRodney W. Grimes nswiodone += spc->spc_count; 16022a4895f4SDavid Greenman if (--spc->spc_object->un_pager.swp.swp_poip == 0) { 16032a4895f4SDavid Greenman wakeup(spc->spc_object); 160426f9a767SRodney W. Grimes } 160526f9a767SRodney W. Grimes if ((swap_pager_needflags & SWAP_FREE_NEEDED) || 160626f9a767SRodney W. Grimes swap_pager_inuse.tqh_first == 0) { 160726f9a767SRodney W. Grimes swap_pager_needflags &= ~SWAP_FREE_NEEDED; 160824a1cce3SDavid Greenman wakeup(&swap_pager_free); 1609a1f6d91cSDavid Greenman } 1610a1f6d91cSDavid Greenman 1611a1f6d91cSDavid Greenman if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) { 1612a1f6d91cSDavid Greenman swap_pager_needflags &= ~SWAP_FREE_NEEDED_BY_PAGEOUT; 1613f919ebdeSDavid Greenman pagedaemon_wakeup(); 161426f9a767SRodney W. Grimes } 1615a1f6d91cSDavid Greenman 161626f9a767SRodney W. Grimes if (vm_pageout_pages_needed) { 161724a1cce3SDavid Greenman wakeup(&vm_pageout_pages_needed); 1618a1f6d91cSDavid Greenman vm_pageout_pages_needed = 0; 161926f9a767SRodney W. Grimes } 162026f9a767SRodney W. Grimes if ((swap_pager_inuse.tqh_first == NULL) || 16210d94caffSDavid Greenman ((cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min && 16220d94caffSDavid Greenman nswiodone + cnt.v_free_count + cnt.v_cache_count >= cnt.v_free_min)) { 1623f919ebdeSDavid Greenman pagedaemon_wakeup(); 162426f9a767SRodney W. Grimes } 162526f9a767SRodney W. Grimes splx(s); 162626f9a767SRodney W. Grimes } 162726f9a767SRodney W. Grimes 162826f9a767SRodney W. Grimes /* 162926f9a767SRodney W. Grimes * return true if any swap control structures can be allocated 163026f9a767SRodney W. Grimes */ 1631cac597e4SBruce Evans static int 16320d94caffSDavid Greenman swap_pager_ready() 16330d94caffSDavid Greenman { 163426f9a767SRodney W. Grimes if (swap_pager_free.tqh_first) 163526f9a767SRodney W. Grimes return 1; 163626f9a767SRodney W. Grimes else 163726f9a767SRodney W. Grimes return 0; 163826f9a767SRodney W. Grimes } 1639