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 42df8bae1dSRodney W. Grimes */ 43df8bae1dSRodney W. Grimes 44df8bae1dSRodney W. Grimes /* 45df8bae1dSRodney W. Grimes * Quick hack to page to dedicated partition(s). 46df8bae1dSRodney W. Grimes * TODO: 47df8bae1dSRodney W. Grimes * Add multiprocessor locks 48df8bae1dSRodney W. Grimes * Deal with async writes in a better fashion 49df8bae1dSRodney W. Grimes */ 50df8bae1dSRodney W. Grimes 51df8bae1dSRodney W. Grimes #include <sys/param.h> 52df8bae1dSRodney W. Grimes #include <sys/systm.h> 53df8bae1dSRodney W. Grimes #include <sys/proc.h> 54df8bae1dSRodney W. Grimes #include <sys/buf.h> 55df8bae1dSRodney W. Grimes #include <sys/vnode.h> 56df8bae1dSRodney W. Grimes #include <sys/malloc.h> 57df8bae1dSRodney W. Grimes 58df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 5926f9a767SRodney W. Grimes #include <sys/rlist.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes #include <vm/vm.h> 6226f9a767SRodney W. Grimes #include <vm/vm_pager.h> 63df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 64df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h> 65df8bae1dSRodney W. Grimes #include <vm/swap_pager.h> 66df8bae1dSRodney W. Grimes 67df8bae1dSRodney W. Grimes #ifndef NPENDINGIO 6826f9a767SRodney W. Grimes #define NPENDINGIO 16 69df8bae1dSRodney W. Grimes #endif 70df8bae1dSRodney W. Grimes 7126f9a767SRodney W. Grimes extern int nswbuf; 7226f9a767SRodney W. Grimes int nswiodone; 7326f9a767SRodney W. Grimes extern int vm_pageout_rate_limit; 7426f9a767SRodney W. Grimes static int cleandone; 7526f9a767SRodney W. Grimes extern int hz; 7626f9a767SRodney W. Grimes int swap_pager_full; 7726f9a767SRodney W. Grimes extern vm_map_t pager_map; 7826f9a767SRodney W. Grimes extern int vm_pageout_pages_needed; 7926f9a767SRodney W. Grimes extern int vm_swap_size; 8026f9a767SRodney W. Grimes extern struct vnode *swapdev_vp; 8126f9a767SRodney W. Grimes 8226f9a767SRodney W. Grimes #define MAX_PAGEOUT_CLUSTER 8 83df8bae1dSRodney W. Grimes 84df8bae1dSRodney W. Grimes TAILQ_HEAD(swpclean, swpagerclean); 85df8bae1dSRodney W. Grimes 8626f9a767SRodney W. Grimes typedef struct swpagerclean *swp_clean_t; 8726f9a767SRodney W. Grimes 88df8bae1dSRodney W. Grimes struct swpagerclean { 89df8bae1dSRodney W. Grimes TAILQ_ENTRY(swpagerclean) spc_list; 90df8bae1dSRodney W. Grimes int spc_flags; 91df8bae1dSRodney W. Grimes struct buf *spc_bp; 92df8bae1dSRodney W. Grimes sw_pager_t spc_swp; 93df8bae1dSRodney W. Grimes vm_offset_t spc_kva; 9426f9a767SRodney W. Grimes vm_offset_t spc_altkva; 9526f9a767SRodney W. Grimes int spc_count; 9626f9a767SRodney W. Grimes vm_page_t spc_m[MAX_PAGEOUT_CLUSTER]; 97df8bae1dSRodney W. Grimes } swcleanlist [NPENDINGIO] ; 9826f9a767SRodney W. Grimes 9926f9a767SRodney W. Grimes 10026f9a767SRodney W. Grimes extern vm_map_t kernel_map; 101df8bae1dSRodney 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 10726f9a767SRodney W. Grimes void swap_pager_init(void); 10826f9a767SRodney W. Grimes vm_pager_t swap_pager_alloc(caddr_t, vm_size_t, vm_prot_t, vm_offset_t); 10926f9a767SRodney W. Grimes void swap_pager_dealloc(vm_pager_t); 11026f9a767SRodney W. Grimes boolean_t swap_pager_getpage(vm_pager_t, vm_page_t, boolean_t); 11126f9a767SRodney W. Grimes boolean_t swap_pager_putpage(vm_pager_t, vm_page_t, boolean_t); 11226f9a767SRodney W. Grimes boolean_t swap_pager_getmulti(vm_pager_t, vm_page_t *, int, int, boolean_t); 11326f9a767SRodney W. Grimes boolean_t swap_pager_haspage(vm_pager_t, vm_offset_t); 11426f9a767SRodney W. Grimes int swap_pager_io(sw_pager_t, vm_page_t *, int, int, int); 11526f9a767SRodney W. Grimes void swap_pager_iodone(struct buf *); 11626f9a767SRodney W. Grimes boolean_t swap_pager_clean(); 117df8bae1dSRodney W. Grimes 11826f9a767SRodney W. Grimes extern struct pagerops swappagerops; 119df8bae1dSRodney W. Grimes 12026f9a767SRodney W. Grimes struct swpclean swap_pager_done; /* list of compileted page cleans */ 121df8bae1dSRodney W. Grimes struct swpclean swap_pager_inuse; /* list of pending page cleans */ 122df8bae1dSRodney W. Grimes struct swpclean swap_pager_free; /* list of free pager clean structs */ 123df8bae1dSRodney W. Grimes struct pagerlst swap_pager_list; /* list of "named" anon regions */ 12426f9a767SRodney W. Grimes struct pagerlst swap_pager_un_list; /* list of "unnamed" anon pagers */ 125df8bae1dSRodney W. Grimes 12626f9a767SRodney W. Grimes #define SWAP_FREE_NEEDED 0x1 /* need a swap block */ 12726f9a767SRodney W. Grimes int swap_pager_needflags; 12826f9a767SRodney W. Grimes struct rlist *swapfrag; 12926f9a767SRodney W. Grimes 13026f9a767SRodney W. Grimes struct pagerlst *swp_qs[]={ 13126f9a767SRodney W. Grimes &swap_pager_list, &swap_pager_un_list, (struct pagerlst *) 0 13226f9a767SRodney W. Grimes }; 13326f9a767SRodney W. Grimes 13426f9a767SRodney W. Grimes int swap_pager_putmulti(); 135df8bae1dSRodney W. Grimes 136df8bae1dSRodney W. Grimes struct pagerops swappagerops = { 137df8bae1dSRodney W. Grimes swap_pager_init, 138df8bae1dSRodney W. Grimes swap_pager_alloc, 139df8bae1dSRodney W. Grimes swap_pager_dealloc, 140df8bae1dSRodney W. Grimes swap_pager_getpage, 14126f9a767SRodney W. Grimes swap_pager_getmulti, 142df8bae1dSRodney W. Grimes swap_pager_putpage, 14326f9a767SRodney W. Grimes swap_pager_putmulti, 14426f9a767SRodney W. Grimes swap_pager_haspage 145df8bae1dSRodney W. Grimes }; 146df8bae1dSRodney W. Grimes 14726f9a767SRodney W. Grimes extern int nswbuf; 14826f9a767SRodney W. Grimes 14926f9a767SRodney W. Grimes int npendingio = NPENDINGIO; 15026f9a767SRodney W. Grimes int pendingiowait; 15126f9a767SRodney W. Grimes int require_swap_init; 15226f9a767SRodney W. Grimes void swap_pager_finish(); 15326f9a767SRodney W. Grimes int dmmin, dmmax; 15426f9a767SRodney W. Grimes extern int vm_page_count; 15526f9a767SRodney W. Grimes 15626f9a767SRodney W. Grimes struct buf * getpbuf() ; 15726f9a767SRodney W. Grimes void relpbuf(struct buf *bp) ; 15826f9a767SRodney W. Grimes 15926f9a767SRodney W. Grimes static inline void swapsizecheck() { 16026f9a767SRodney W. Grimes if( vm_swap_size < 128*btodb(PAGE_SIZE)) { 16126f9a767SRodney W. Grimes if( swap_pager_full) 16226f9a767SRodney W. Grimes printf("swap_pager: out of space\n"); 16326f9a767SRodney W. Grimes swap_pager_full = 1; 16426f9a767SRodney W. Grimes } else if( vm_swap_size > 192*btodb(PAGE_SIZE)) 16526f9a767SRodney W. Grimes swap_pager_full = 0; 16626f9a767SRodney W. Grimes } 16726f9a767SRodney W. Grimes 16826f9a767SRodney W. Grimes void 169df8bae1dSRodney W. Grimes swap_pager_init() 170df8bae1dSRodney W. Grimes { 171df8bae1dSRodney W. Grimes extern int dmmin, dmmax; 172df8bae1dSRodney W. Grimes 173df8bae1dSRodney W. Grimes dfltpagerops = &swappagerops; 174df8bae1dSRodney W. Grimes 17526f9a767SRodney W. Grimes TAILQ_INIT(&swap_pager_list); 17626f9a767SRodney W. Grimes TAILQ_INIT(&swap_pager_un_list); 177df8bae1dSRodney W. Grimes 178df8bae1dSRodney W. Grimes /* 179df8bae1dSRodney W. Grimes * Initialize clean lists 180df8bae1dSRodney W. Grimes */ 181df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_inuse); 18226f9a767SRodney W. Grimes TAILQ_INIT(&swap_pager_done); 183df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_free); 18426f9a767SRodney W. Grimes 18526f9a767SRodney W. Grimes require_swap_init = 1; 186df8bae1dSRodney W. Grimes 187df8bae1dSRodney W. Grimes /* 188df8bae1dSRodney W. Grimes * Calculate the swap allocation constants. 189df8bae1dSRodney W. Grimes */ 190df8bae1dSRodney W. Grimes 19126f9a767SRodney W. Grimes dmmin = CLBYTES/DEV_BSIZE; 19226f9a767SRodney W. Grimes dmmax = btodb(SWB_NPAGES*PAGE_SIZE)*2; 19326f9a767SRodney W. Grimes 194df8bae1dSRodney W. Grimes } 195df8bae1dSRodney W. Grimes 196df8bae1dSRodney W. Grimes /* 197df8bae1dSRodney W. Grimes * Allocate a pager structure and associated resources. 198df8bae1dSRodney W. Grimes * Note that if we are called from the pageout daemon (handle == NULL) 199df8bae1dSRodney W. Grimes * we should not wait for memory as it could resulting in deadlock. 200df8bae1dSRodney W. Grimes */ 20126f9a767SRodney W. Grimes vm_pager_t 20226f9a767SRodney W. Grimes swap_pager_alloc(handle, size, prot, offset) 203df8bae1dSRodney W. Grimes caddr_t handle; 204df8bae1dSRodney W. Grimes register vm_size_t size; 205df8bae1dSRodney W. Grimes vm_prot_t prot; 20626f9a767SRodney W. Grimes vm_offset_t offset; 207df8bae1dSRodney W. Grimes { 208df8bae1dSRodney W. Grimes register vm_pager_t pager; 209df8bae1dSRodney W. Grimes register sw_pager_t swp; 210df8bae1dSRodney W. Grimes int waitok; 21126f9a767SRodney W. Grimes int i,j; 212df8bae1dSRodney W. Grimes 21326f9a767SRodney W. Grimes if (require_swap_init) { 21426f9a767SRodney W. Grimes swp_clean_t spc; 21526f9a767SRodney W. Grimes struct buf *bp; 21626f9a767SRodney W. Grimes /* 21726f9a767SRodney W. Grimes * kva's are allocated here so that we dont need to keep 21826f9a767SRodney W. Grimes * doing kmem_alloc pageables at runtime 21926f9a767SRodney W. Grimes */ 22026f9a767SRodney W. Grimes for (i = 0, spc = swcleanlist; i < npendingio ; i++, spc++) { 22126f9a767SRodney W. Grimes spc->spc_kva = kmem_alloc_pageable(pager_map, PAGE_SIZE); 22226f9a767SRodney W. Grimes if (!spc->spc_kva) { 22326f9a767SRodney W. Grimes break; 22426f9a767SRodney W. Grimes } 22526f9a767SRodney W. Grimes spc->spc_bp = malloc( sizeof( *bp), M_TEMP, M_NOWAIT); 22626f9a767SRodney W. Grimes if (!spc->spc_bp) { 22726f9a767SRodney W. Grimes kmem_free_wakeup(pager_map, spc->spc_kva, PAGE_SIZE); 22826f9a767SRodney W. Grimes break; 22926f9a767SRodney W. Grimes } 23026f9a767SRodney W. Grimes spc->spc_flags = 0; 23126f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 23226f9a767SRodney W. Grimes } 23326f9a767SRodney W. Grimes require_swap_init = 0; 23426f9a767SRodney W. Grimes if( size == 0) 23526f9a767SRodney W. Grimes return(NULL); 23626f9a767SRodney W. Grimes } 23726f9a767SRodney W. Grimes 238df8bae1dSRodney W. Grimes /* 239df8bae1dSRodney W. Grimes * If this is a "named" anonymous region, look it up and 240df8bae1dSRodney W. Grimes * return the appropriate pager if it exists. 241df8bae1dSRodney W. Grimes */ 242df8bae1dSRodney W. Grimes if (handle) { 243df8bae1dSRodney W. Grimes pager = vm_pager_lookup(&swap_pager_list, handle); 244df8bae1dSRodney W. Grimes if (pager != NULL) { 245df8bae1dSRodney W. Grimes /* 246df8bae1dSRodney W. Grimes * Use vm_object_lookup to gain a reference 247df8bae1dSRodney W. Grimes * to the object and also to remove from the 248df8bae1dSRodney W. Grimes * object cache. 249df8bae1dSRodney W. Grimes */ 250df8bae1dSRodney W. Grimes if (vm_object_lookup(pager) == NULL) 251df8bae1dSRodney W. Grimes panic("swap_pager_alloc: bad object"); 252df8bae1dSRodney W. Grimes return(pager); 253df8bae1dSRodney W. Grimes } 254df8bae1dSRodney W. Grimes } 25526f9a767SRodney W. Grimes 25626f9a767SRodney W. Grimes if (swap_pager_full) { 25726f9a767SRodney W. Grimes return(NULL); 25826f9a767SRodney W. Grimes } 25926f9a767SRodney W. Grimes 260df8bae1dSRodney W. Grimes /* 261df8bae1dSRodney W. Grimes * Pager doesn't exist, allocate swap management resources 262df8bae1dSRodney W. Grimes * and initialize. 263df8bae1dSRodney W. Grimes */ 264df8bae1dSRodney W. Grimes waitok = handle ? M_WAITOK : M_NOWAIT; 265df8bae1dSRodney W. Grimes pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok); 266df8bae1dSRodney W. Grimes if (pager == NULL) 267df8bae1dSRodney W. Grimes return(NULL); 268df8bae1dSRodney W. Grimes swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok); 269df8bae1dSRodney W. Grimes if (swp == NULL) { 270df8bae1dSRodney W. Grimes free((caddr_t)pager, M_VMPAGER); 271df8bae1dSRodney W. Grimes return(NULL); 272df8bae1dSRodney W. Grimes } 273df8bae1dSRodney W. Grimes size = round_page(size); 274df8bae1dSRodney W. Grimes swp->sw_osize = size; 27526f9a767SRodney W. Grimes swp->sw_nblocks = (btodb(size) + btodb(SWB_NPAGES * PAGE_SIZE) - 1) / btodb(SWB_NPAGES*PAGE_SIZE); 276df8bae1dSRodney W. Grimes swp->sw_blocks = (sw_blk_t) 277df8bae1dSRodney W. Grimes malloc(swp->sw_nblocks*sizeof(*swp->sw_blocks), 27826f9a767SRodney W. Grimes M_VMPGDATA, waitok); 279df8bae1dSRodney W. Grimes if (swp->sw_blocks == NULL) { 280df8bae1dSRodney W. Grimes free((caddr_t)swp, M_VMPGDATA); 281df8bae1dSRodney W. Grimes free((caddr_t)pager, M_VMPAGER); 28226f9a767SRodney W. Grimes return(NULL); 283df8bae1dSRodney W. Grimes } 28426f9a767SRodney W. Grimes 28526f9a767SRodney W. Grimes for (i = 0; i < swp->sw_nblocks; i++) { 28626f9a767SRodney W. Grimes swp->sw_blocks[i].swb_valid = 0; 28726f9a767SRodney W. Grimes swp->sw_blocks[i].swb_locked = 0; 28826f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) 28926f9a767SRodney W. Grimes swp->sw_blocks[i].swb_block[j] = SWB_EMPTY; 29026f9a767SRodney W. Grimes } 29126f9a767SRodney W. Grimes 292df8bae1dSRodney W. Grimes swp->sw_poip = 0; 293df8bae1dSRodney W. Grimes if (handle) { 294df8bae1dSRodney W. Grimes vm_object_t object; 295df8bae1dSRodney W. Grimes 296df8bae1dSRodney W. Grimes swp->sw_flags = SW_NAMED; 297df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_list, pager, pg_list); 298df8bae1dSRodney W. Grimes /* 299df8bae1dSRodney W. Grimes * Consistant with other pagers: return with object 300df8bae1dSRodney W. Grimes * referenced. Can't do this with handle == NULL 301df8bae1dSRodney W. Grimes * since it might be the pageout daemon calling. 302df8bae1dSRodney W. Grimes */ 303df8bae1dSRodney W. Grimes object = vm_object_allocate(size); 304df8bae1dSRodney W. Grimes vm_object_enter(object, pager); 305df8bae1dSRodney W. Grimes vm_object_setpager(object, pager, 0, FALSE); 306df8bae1dSRodney W. Grimes } else { 307df8bae1dSRodney W. Grimes swp->sw_flags = 0; 30826f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_un_list, pager, pg_list); 309df8bae1dSRodney W. Grimes } 310df8bae1dSRodney W. Grimes pager->pg_handle = handle; 311df8bae1dSRodney W. Grimes pager->pg_ops = &swappagerops; 312df8bae1dSRodney W. Grimes pager->pg_type = PG_SWAP; 31326f9a767SRodney W. Grimes pager->pg_data = (caddr_t)swp; 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes return(pager); 316df8bae1dSRodney W. Grimes } 317df8bae1dSRodney W. Grimes 31826f9a767SRodney W. Grimes /* 31926f9a767SRodney W. Grimes * returns disk block associated with pager and offset 32026f9a767SRodney W. Grimes * additionally, as a side effect returns a flag indicating 32126f9a767SRodney W. Grimes * if the block has been written 32226f9a767SRodney W. Grimes */ 32326f9a767SRodney W. Grimes 32426f9a767SRodney W. Grimes static int * 32526f9a767SRodney W. Grimes swap_pager_diskaddr(swp, offset, valid) 32626f9a767SRodney W. Grimes sw_pager_t swp; 32726f9a767SRodney W. Grimes vm_offset_t offset; 32826f9a767SRodney W. Grimes int *valid; 32926f9a767SRodney W. Grimes { 33026f9a767SRodney W. Grimes register sw_blk_t swb; 33126f9a767SRodney W. Grimes int ix; 33226f9a767SRodney W. Grimes 33326f9a767SRodney W. Grimes if (valid) 33426f9a767SRodney W. Grimes *valid = 0; 33526f9a767SRodney W. Grimes ix = offset / (SWB_NPAGES*PAGE_SIZE); 33626f9a767SRodney W. Grimes if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) { 33726f9a767SRodney W. Grimes return(FALSE); 33826f9a767SRodney W. Grimes } 33926f9a767SRodney W. Grimes swb = &swp->sw_blocks[ix]; 34026f9a767SRodney W. Grimes ix = (offset % (SWB_NPAGES*PAGE_SIZE)) / PAGE_SIZE; 34126f9a767SRodney W. Grimes if (valid) 34226f9a767SRodney W. Grimes *valid = swb->swb_valid & (1<<ix); 34326f9a767SRodney W. Grimes return &swb->swb_block[ix]; 34426f9a767SRodney W. Grimes } 34526f9a767SRodney W. Grimes 34626f9a767SRodney W. Grimes /* 34726f9a767SRodney W. Grimes * Utility routine to set the valid (written) bit for 34826f9a767SRodney W. Grimes * a block associated with a pager and offset 34926f9a767SRodney W. Grimes */ 350df8bae1dSRodney W. Grimes static void 35126f9a767SRodney W. Grimes swap_pager_setvalid(swp, offset, valid) 35226f9a767SRodney W. Grimes sw_pager_t swp; 35326f9a767SRodney W. Grimes vm_offset_t offset; 35426f9a767SRodney W. Grimes int valid; 35526f9a767SRodney W. Grimes { 35626f9a767SRodney W. Grimes register sw_blk_t swb; 35726f9a767SRodney W. Grimes int ix; 35826f9a767SRodney W. Grimes 35926f9a767SRodney W. Grimes ix = offset / (SWB_NPAGES*PAGE_SIZE); 36026f9a767SRodney W. Grimes if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) 36126f9a767SRodney W. Grimes return; 36226f9a767SRodney W. Grimes 36326f9a767SRodney W. Grimes swb = &swp->sw_blocks[ix]; 36426f9a767SRodney W. Grimes ix = (offset % (SWB_NPAGES*PAGE_SIZE)) / PAGE_SIZE; 36526f9a767SRodney W. Grimes if (valid) 36626f9a767SRodney W. Grimes swb->swb_valid |= (1 << ix); 36726f9a767SRodney W. Grimes else 36826f9a767SRodney W. Grimes swb->swb_valid &= ~(1 << ix); 36926f9a767SRodney W. Grimes return; 37026f9a767SRodney W. Grimes } 37126f9a767SRodney W. Grimes 37226f9a767SRodney W. Grimes /* 37326f9a767SRodney W. Grimes * this routine allocates swap space with a fragmentation 37426f9a767SRodney W. Grimes * minimization policy. 37526f9a767SRodney W. Grimes */ 37626f9a767SRodney W. Grimes int 37726f9a767SRodney W. Grimes swap_pager_getswapspace( unsigned amount, unsigned *rtval) { 37826f9a767SRodney W. Grimes unsigned tmpalloc; 37926f9a767SRodney W. Grimes unsigned nblocksfrag = btodb(SWB_NPAGES*PAGE_SIZE); 38026f9a767SRodney W. Grimes if( amount < nblocksfrag) { 38126f9a767SRodney W. Grimes if( rlist_alloc(&swapfrag, amount, rtval)) 38226f9a767SRodney W. Grimes return 1; 38326f9a767SRodney W. Grimes if( !rlist_alloc(&swapmap, nblocksfrag, &tmpalloc)) 38426f9a767SRodney W. Grimes return 0; 38526f9a767SRodney W. Grimes rlist_free( &swapfrag, tmpalloc+amount, tmpalloc + nblocksfrag - 1); 38626f9a767SRodney W. Grimes *rtval = tmpalloc; 38726f9a767SRodney W. Grimes return 1; 38826f9a767SRodney W. Grimes } 38926f9a767SRodney W. Grimes if( !rlist_alloc(&swapmap, amount, rtval)) 39026f9a767SRodney W. Grimes return 0; 39126f9a767SRodney W. Grimes else 39226f9a767SRodney W. Grimes return 1; 39326f9a767SRodney W. Grimes } 39426f9a767SRodney W. Grimes 39526f9a767SRodney W. Grimes /* 39626f9a767SRodney W. Grimes * this routine frees swap space with a fragmentation 39726f9a767SRodney W. Grimes * minimization policy. 39826f9a767SRodney W. Grimes */ 39926f9a767SRodney W. Grimes void 40026f9a767SRodney W. Grimes swap_pager_freeswapspace( unsigned from, unsigned to) { 40126f9a767SRodney W. Grimes unsigned nblocksfrag = btodb(SWB_NPAGES*PAGE_SIZE); 40226f9a767SRodney W. Grimes unsigned tmpalloc; 40326f9a767SRodney W. Grimes if( ((to + 1) - from) >= nblocksfrag) { 40426f9a767SRodney W. Grimes while( (from + nblocksfrag) <= to + 1) { 40526f9a767SRodney W. Grimes rlist_free(&swapmap, from, from + nblocksfrag - 1); 40626f9a767SRodney W. Grimes from += nblocksfrag; 40726f9a767SRodney W. Grimes } 40826f9a767SRodney W. Grimes } 40926f9a767SRodney W. Grimes if( from >= to) 41026f9a767SRodney W. Grimes return; 41126f9a767SRodney W. Grimes rlist_free(&swapfrag, from, to); 41226f9a767SRodney W. Grimes while( rlist_alloc(&swapfrag, nblocksfrag, &tmpalloc)) { 41326f9a767SRodney W. Grimes rlist_free(&swapmap, tmpalloc, tmpalloc + nblocksfrag-1); 41426f9a767SRodney W. Grimes } 41526f9a767SRodney W. Grimes } 41626f9a767SRodney W. Grimes /* 41726f9a767SRodney W. Grimes * this routine frees swap blocks from a specified pager 41826f9a767SRodney W. Grimes */ 41926f9a767SRodney W. Grimes void 42026f9a767SRodney W. Grimes _swap_pager_freespace(swp, start, size) 42126f9a767SRodney W. Grimes sw_pager_t swp; 42226f9a767SRodney W. Grimes vm_offset_t start; 42326f9a767SRodney W. Grimes vm_offset_t size; 42426f9a767SRodney W. Grimes { 42526f9a767SRodney W. Grimes vm_offset_t i; 42626f9a767SRodney W. Grimes int s; 42726f9a767SRodney W. Grimes 42826f9a767SRodney W. Grimes s = splbio(); 42926f9a767SRodney W. Grimes for (i = start; i < round_page(start + size - 1); i += PAGE_SIZE) { 43026f9a767SRodney W. Grimes int valid; 43126f9a767SRodney W. Grimes int *addr = swap_pager_diskaddr(swp, i, &valid); 43226f9a767SRodney W. Grimes if (addr && *addr != SWB_EMPTY) { 43326f9a767SRodney W. Grimes swap_pager_freeswapspace(*addr, *addr+btodb(PAGE_SIZE) - 1); 43426f9a767SRodney W. Grimes if( valid) { 43526f9a767SRodney W. Grimes vm_swap_size += btodb(PAGE_SIZE); 43626f9a767SRodney W. Grimes swap_pager_setvalid(swp, i, 0); 43726f9a767SRodney W. Grimes } 43826f9a767SRodney W. Grimes *addr = SWB_EMPTY; 43926f9a767SRodney W. Grimes } 44026f9a767SRodney W. Grimes } 44126f9a767SRodney W. Grimes swapsizecheck(); 44226f9a767SRodney W. Grimes splx(s); 44326f9a767SRodney W. Grimes } 44426f9a767SRodney W. Grimes 44526f9a767SRodney W. Grimes void 44626f9a767SRodney W. Grimes swap_pager_freespace(pager, start, size) 44726f9a767SRodney W. Grimes vm_pager_t pager; 44826f9a767SRodney W. Grimes vm_offset_t start; 44926f9a767SRodney W. Grimes vm_offset_t size; 45026f9a767SRodney W. Grimes { 45126f9a767SRodney W. Grimes _swap_pager_freespace((sw_pager_t) pager->pg_data, start, size); 45226f9a767SRodney W. Grimes } 45326f9a767SRodney W. Grimes 45426f9a767SRodney W. Grimes /* 45526f9a767SRodney W. Grimes * swap_pager_reclaim frees up over-allocated space from all pagers 45626f9a767SRodney W. Grimes * this eliminates internal fragmentation due to allocation of space 45726f9a767SRodney W. Grimes * for segments that are never swapped to. It has been written so that 45826f9a767SRodney W. Grimes * it does not block until the rlist_free operation occurs; it keeps 45926f9a767SRodney W. Grimes * the queues consistant. 46026f9a767SRodney W. Grimes */ 46126f9a767SRodney W. Grimes 46226f9a767SRodney W. Grimes /* 46326f9a767SRodney W. Grimes * Maximum number of blocks (pages) to reclaim per pass 46426f9a767SRodney W. Grimes */ 46526f9a767SRodney W. Grimes #define MAXRECLAIM 256 46626f9a767SRodney W. Grimes 46726f9a767SRodney W. Grimes void 46826f9a767SRodney W. Grimes swap_pager_reclaim() 46926f9a767SRodney W. Grimes { 47026f9a767SRodney W. Grimes vm_pager_t p; 47126f9a767SRodney W. Grimes sw_pager_t swp; 47226f9a767SRodney W. Grimes int i, j, k; 47326f9a767SRodney W. Grimes int s; 47426f9a767SRodney W. Grimes int reclaimcount; 47526f9a767SRodney W. Grimes static int reclaims[MAXRECLAIM]; 47626f9a767SRodney W. Grimes static int in_reclaim; 47726f9a767SRodney W. Grimes 47826f9a767SRodney W. Grimes /* 47926f9a767SRodney W. Grimes * allow only one process to be in the swap_pager_reclaim subroutine 48026f9a767SRodney W. Grimes */ 48126f9a767SRodney W. Grimes s = splbio(); 48226f9a767SRodney W. Grimes if (in_reclaim) { 48326f9a767SRodney W. Grimes tsleep((caddr_t) &in_reclaim, PSWP, "swrclm", 0); 48426f9a767SRodney W. Grimes splx(s); 48526f9a767SRodney W. Grimes return; 48626f9a767SRodney W. Grimes } 48726f9a767SRodney W. Grimes in_reclaim = 1; 48826f9a767SRodney W. Grimes reclaimcount = 0; 48926f9a767SRodney W. Grimes 49026f9a767SRodney W. Grimes /* for each pager queue */ 49126f9a767SRodney W. Grimes for (k = 0; swp_qs[k]; k++) { 49226f9a767SRodney W. Grimes 49326f9a767SRodney W. Grimes p = swp_qs[k]->tqh_first; 49426f9a767SRodney W. Grimes while (p && (reclaimcount < MAXRECLAIM)) { 49526f9a767SRodney W. Grimes 49626f9a767SRodney W. Grimes /* 49726f9a767SRodney W. Grimes * see if any blocks associated with a pager has been 49826f9a767SRodney W. Grimes * allocated but not used (written) 49926f9a767SRodney W. Grimes */ 50026f9a767SRodney W. Grimes swp = (sw_pager_t) p->pg_data; 50126f9a767SRodney W. Grimes for (i = 0; i < swp->sw_nblocks; i++) { 50226f9a767SRodney W. Grimes sw_blk_t swb = &swp->sw_blocks[i]; 50326f9a767SRodney W. Grimes if( swb->swb_locked) 50426f9a767SRodney W. Grimes continue; 50526f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) { 50626f9a767SRodney W. Grimes if (swb->swb_block[j] != SWB_EMPTY && 50726f9a767SRodney W. Grimes (swb->swb_valid & (1 << j)) == 0) { 50826f9a767SRodney W. Grimes reclaims[reclaimcount++] = swb->swb_block[j]; 50926f9a767SRodney W. Grimes swb->swb_block[j] = SWB_EMPTY; 51026f9a767SRodney W. Grimes if (reclaimcount >= MAXRECLAIM) 51126f9a767SRodney W. Grimes goto rfinished; 51226f9a767SRodney W. Grimes } 51326f9a767SRodney W. Grimes } 51426f9a767SRodney W. Grimes } 51526f9a767SRodney W. Grimes p = p->pg_list.tqe_next; 51626f9a767SRodney W. Grimes } 51726f9a767SRodney W. Grimes } 51826f9a767SRodney W. Grimes 51926f9a767SRodney W. Grimes rfinished: 52026f9a767SRodney W. Grimes 52126f9a767SRodney W. Grimes /* 52226f9a767SRodney W. Grimes * free the blocks that have been added to the reclaim list 52326f9a767SRodney W. Grimes */ 52426f9a767SRodney W. Grimes for (i = 0; i < reclaimcount; i++) { 52526f9a767SRodney W. Grimes swap_pager_freeswapspace(reclaims[i], reclaims[i]+btodb(PAGE_SIZE) - 1); 52626f9a767SRodney W. Grimes swapsizecheck(); 52726f9a767SRodney W. Grimes wakeup((caddr_t) &in_reclaim); 52826f9a767SRodney W. Grimes } 52926f9a767SRodney W. Grimes 53026f9a767SRodney W. Grimes splx(s); 53126f9a767SRodney W. Grimes in_reclaim = 0; 53226f9a767SRodney W. Grimes wakeup((caddr_t) &in_reclaim); 53326f9a767SRodney W. Grimes } 53426f9a767SRodney W. Grimes 53526f9a767SRodney W. Grimes 53626f9a767SRodney W. Grimes /* 53726f9a767SRodney W. Grimes * swap_pager_copy copies blocks from one pager to another and 53826f9a767SRodney W. Grimes * destroys the source pager 53926f9a767SRodney W. Grimes */ 54026f9a767SRodney W. Grimes 54126f9a767SRodney W. Grimes void 54226f9a767SRodney W. Grimes swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset) 54326f9a767SRodney W. Grimes vm_pager_t srcpager; 54426f9a767SRodney W. Grimes vm_offset_t srcoffset; 54526f9a767SRodney W. Grimes vm_pager_t dstpager; 54626f9a767SRodney W. Grimes vm_offset_t dstoffset; 54726f9a767SRodney W. Grimes vm_offset_t offset; 54826f9a767SRodney W. Grimes { 54926f9a767SRodney W. Grimes sw_pager_t srcswp, dstswp; 55026f9a767SRodney W. Grimes vm_offset_t i; 55126f9a767SRodney W. Grimes int s; 55226f9a767SRodney W. Grimes 55326f9a767SRodney W. Grimes srcswp = (sw_pager_t) srcpager->pg_data; 55426f9a767SRodney W. Grimes dstswp = (sw_pager_t) dstpager->pg_data; 55526f9a767SRodney W. Grimes 55626f9a767SRodney W. Grimes /* 55726f9a767SRodney W. Grimes * remove the source pager from the swap_pager internal queue 55826f9a767SRodney W. Grimes */ 55926f9a767SRodney W. Grimes s = splbio(); 56026f9a767SRodney W. Grimes if (srcswp->sw_flags & SW_NAMED) { 56126f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_list, srcpager, pg_list); 56226f9a767SRodney W. Grimes srcswp->sw_flags &= ~SW_NAMED; 56326f9a767SRodney W. Grimes } else { 56426f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_un_list, srcpager, pg_list); 56526f9a767SRodney W. Grimes } 56626f9a767SRodney W. Grimes 56726f9a767SRodney W. Grimes while (srcswp->sw_poip) { 56826f9a767SRodney W. Grimes tsleep((caddr_t)srcswp, PVM, "spgout", 0); 56926f9a767SRodney W. Grimes } 57026f9a767SRodney W. Grimes splx(s); 57126f9a767SRodney W. Grimes 57226f9a767SRodney W. Grimes /* 57326f9a767SRodney W. Grimes * clean all of the pages that are currently active and finished 57426f9a767SRodney W. Grimes */ 57526f9a767SRodney W. Grimes (void) swap_pager_clean(); 57626f9a767SRodney W. Grimes 57726f9a767SRodney W. Grimes s = splbio(); 57826f9a767SRodney W. Grimes /* 57926f9a767SRodney W. Grimes * clear source block before destination object 58026f9a767SRodney W. Grimes * (release allocated space) 58126f9a767SRodney W. Grimes */ 58226f9a767SRodney W. Grimes for (i = 0; i < offset + srcoffset; i += PAGE_SIZE) { 58326f9a767SRodney W. Grimes int valid; 58426f9a767SRodney W. Grimes int *addr = swap_pager_diskaddr(srcswp, i, &valid); 58526f9a767SRodney W. Grimes if (addr && *addr != SWB_EMPTY) { 58626f9a767SRodney W. Grimes swap_pager_freeswapspace(*addr, *addr+btodb(PAGE_SIZE) - 1); 58726f9a767SRodney W. Grimes if( valid) 58826f9a767SRodney W. Grimes vm_swap_size += btodb(PAGE_SIZE); 58926f9a767SRodney W. Grimes swapsizecheck(); 59026f9a767SRodney W. Grimes *addr = SWB_EMPTY; 59126f9a767SRodney W. Grimes } 59226f9a767SRodney W. Grimes } 59326f9a767SRodney W. Grimes /* 59426f9a767SRodney W. Grimes * transfer source to destination 59526f9a767SRodney W. Grimes */ 59626f9a767SRodney W. Grimes for (i = 0; i < dstswp->sw_osize; i += PAGE_SIZE) { 59726f9a767SRodney W. Grimes int srcvalid, dstvalid; 59826f9a767SRodney W. Grimes int *srcaddrp = swap_pager_diskaddr(srcswp, i + offset + srcoffset, 59926f9a767SRodney W. Grimes &srcvalid); 60026f9a767SRodney W. Grimes int *dstaddrp; 60126f9a767SRodney W. Grimes /* 60226f9a767SRodney W. Grimes * see if the source has space allocated 60326f9a767SRodney W. Grimes */ 60426f9a767SRodney W. Grimes if (srcaddrp && *srcaddrp != SWB_EMPTY) { 60526f9a767SRodney W. Grimes /* 60626f9a767SRodney W. Grimes * if the source is valid and the dest has no space, then 60726f9a767SRodney W. Grimes * copy the allocation from the srouce to the dest. 60826f9a767SRodney W. Grimes */ 60926f9a767SRodney W. Grimes if (srcvalid) { 61026f9a767SRodney W. Grimes dstaddrp = swap_pager_diskaddr(dstswp, i + dstoffset, &dstvalid); 61126f9a767SRodney W. Grimes /* 61226f9a767SRodney W. Grimes * if the dest already has a valid block, deallocate the 61326f9a767SRodney W. Grimes * source block without copying. 61426f9a767SRodney W. Grimes */ 61526f9a767SRodney W. Grimes if (!dstvalid && dstaddrp && *dstaddrp != SWB_EMPTY) { 61626f9a767SRodney W. Grimes swap_pager_freeswapspace(*dstaddrp, *dstaddrp+btodb(PAGE_SIZE) - 1); 61726f9a767SRodney W. Grimes *dstaddrp = SWB_EMPTY; 61826f9a767SRodney W. Grimes } 61926f9a767SRodney W. Grimes if (dstaddrp && *dstaddrp == SWB_EMPTY) { 62026f9a767SRodney W. Grimes *dstaddrp = *srcaddrp; 62126f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 62226f9a767SRodney W. Grimes swap_pager_setvalid(dstswp, i + dstoffset, 1); 62326f9a767SRodney W. Grimes vm_swap_size -= btodb(PAGE_SIZE); 62426f9a767SRodney W. Grimes } 62526f9a767SRodney W. Grimes } 62626f9a767SRodney W. Grimes /* 62726f9a767SRodney W. Grimes * if the source is not empty at this point, then deallocate the space. 62826f9a767SRodney W. Grimes */ 62926f9a767SRodney W. Grimes if (*srcaddrp != SWB_EMPTY) { 63026f9a767SRodney W. Grimes swap_pager_freeswapspace(*srcaddrp, *srcaddrp+btodb(PAGE_SIZE) - 1); 63126f9a767SRodney W. Grimes if( srcvalid) 63226f9a767SRodney W. Grimes vm_swap_size += btodb(PAGE_SIZE); 63326f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 63426f9a767SRodney W. Grimes } 63526f9a767SRodney W. Grimes } 63626f9a767SRodney W. Grimes } 63726f9a767SRodney W. Grimes 63826f9a767SRodney W. Grimes /* 63926f9a767SRodney W. Grimes * deallocate the rest of the source object 64026f9a767SRodney W. Grimes */ 64126f9a767SRodney W. Grimes for (i = dstswp->sw_osize + offset + srcoffset; i < srcswp->sw_osize; i += PAGE_SIZE) { 64226f9a767SRodney W. Grimes int valid; 64326f9a767SRodney W. Grimes int *srcaddrp = swap_pager_diskaddr(srcswp, i, &valid); 64426f9a767SRodney W. Grimes if (srcaddrp && *srcaddrp != SWB_EMPTY) { 64526f9a767SRodney W. Grimes swap_pager_freeswapspace(*srcaddrp, *srcaddrp+btodb(PAGE_SIZE) - 1); 64626f9a767SRodney W. Grimes if( valid) 64726f9a767SRodney W. Grimes vm_swap_size += btodb(PAGE_SIZE); 64826f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 64926f9a767SRodney W. Grimes } 65026f9a767SRodney W. Grimes } 65126f9a767SRodney W. Grimes 65226f9a767SRodney W. Grimes swapsizecheck(); 65326f9a767SRodney W. Grimes splx(s); 65426f9a767SRodney W. Grimes 65526f9a767SRodney W. Grimes free((caddr_t)srcswp->sw_blocks, M_VMPGDATA); 65626f9a767SRodney W. Grimes srcswp->sw_blocks = 0; 65726f9a767SRodney W. Grimes free((caddr_t)srcswp, M_VMPGDATA); 65826f9a767SRodney W. Grimes srcpager->pg_data = 0; 65926f9a767SRodney W. Grimes free((caddr_t)srcpager, M_VMPAGER); 66026f9a767SRodney W. Grimes 66126f9a767SRodney W. Grimes return; 66226f9a767SRodney W. Grimes } 66326f9a767SRodney W. Grimes 66426f9a767SRodney W. Grimes 66526f9a767SRodney W. Grimes void 666df8bae1dSRodney W. Grimes swap_pager_dealloc(pager) 667df8bae1dSRodney W. Grimes vm_pager_t pager; 668df8bae1dSRodney W. Grimes { 66926f9a767SRodney W. Grimes register int i,j; 670df8bae1dSRodney W. Grimes register sw_blk_t bp; 671df8bae1dSRodney W. Grimes register sw_pager_t swp; 672df8bae1dSRodney W. Grimes int s; 673df8bae1dSRodney W. Grimes 674df8bae1dSRodney W. Grimes /* 675df8bae1dSRodney W. Grimes * Remove from list right away so lookups will fail if we 676df8bae1dSRodney W. Grimes * block for pageout completion. 677df8bae1dSRodney W. Grimes */ 67826f9a767SRodney W. Grimes s = splbio(); 679df8bae1dSRodney W. Grimes swp = (sw_pager_t) pager->pg_data; 680df8bae1dSRodney W. Grimes if (swp->sw_flags & SW_NAMED) { 681df8bae1dSRodney W. Grimes TAILQ_REMOVE(&swap_pager_list, pager, pg_list); 682df8bae1dSRodney W. Grimes swp->sw_flags &= ~SW_NAMED; 68326f9a767SRodney W. Grimes } else { 68426f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_un_list, pager, pg_list); 685df8bae1dSRodney W. Grimes } 686df8bae1dSRodney W. Grimes /* 687df8bae1dSRodney W. Grimes * Wait for all pageouts to finish and remove 688df8bae1dSRodney W. Grimes * all entries from cleaning list. 689df8bae1dSRodney W. Grimes */ 69026f9a767SRodney W. Grimes 691df8bae1dSRodney W. Grimes while (swp->sw_poip) { 69226f9a767SRodney W. Grimes tsleep((caddr_t)swp, PVM, "swpout", 0); 693df8bae1dSRodney W. Grimes } 694df8bae1dSRodney W. Grimes splx(s); 69526f9a767SRodney W. Grimes 69626f9a767SRodney W. Grimes 69726f9a767SRodney W. Grimes (void) swap_pager_clean(); 698df8bae1dSRodney W. Grimes 699df8bae1dSRodney W. Grimes /* 700df8bae1dSRodney W. Grimes * Free left over swap blocks 701df8bae1dSRodney W. Grimes */ 70226f9a767SRodney W. Grimes s = splbio(); 70326f9a767SRodney W. Grimes for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++) { 70426f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) 70526f9a767SRodney W. Grimes if (bp->swb_block[j] != SWB_EMPTY) { 70626f9a767SRodney W. Grimes swap_pager_freeswapspace((unsigned)bp->swb_block[j], 70726f9a767SRodney W. Grimes (unsigned)bp->swb_block[j] + btodb(PAGE_SIZE) - 1); 70826f9a767SRodney W. Grimes if( bp->swb_valid & (1<<j)) 70926f9a767SRodney W. Grimes vm_swap_size += btodb(PAGE_SIZE); 71026f9a767SRodney W. Grimes bp->swb_block[j] = SWB_EMPTY; 711df8bae1dSRodney W. Grimes } 71226f9a767SRodney W. Grimes } 71326f9a767SRodney W. Grimes splx(s); 71426f9a767SRodney W. Grimes swapsizecheck(); 71526f9a767SRodney W. Grimes 716df8bae1dSRodney W. Grimes /* 717df8bae1dSRodney W. Grimes * Free swap management resources 718df8bae1dSRodney W. Grimes */ 719df8bae1dSRodney W. Grimes free((caddr_t)swp->sw_blocks, M_VMPGDATA); 72026f9a767SRodney W. Grimes swp->sw_blocks = 0; 721df8bae1dSRodney W. Grimes free((caddr_t)swp, M_VMPGDATA); 72226f9a767SRodney W. Grimes pager->pg_data = 0; 723df8bae1dSRodney W. Grimes free((caddr_t)pager, M_VMPAGER); 724df8bae1dSRodney W. Grimes } 725df8bae1dSRodney W. Grimes 72626f9a767SRodney W. Grimes /* 72726f9a767SRodney W. Grimes * swap_pager_getmulti can get multiple pages. 72826f9a767SRodney W. Grimes */ 72926f9a767SRodney W. Grimes int 73026f9a767SRodney W. Grimes swap_pager_getmulti(pager, m, count, reqpage, sync) 731df8bae1dSRodney W. Grimes vm_pager_t pager; 73226f9a767SRodney W. Grimes vm_page_t *m; 73326f9a767SRodney W. Grimes int count; 73426f9a767SRodney W. Grimes int reqpage; 735df8bae1dSRodney W. Grimes boolean_t sync; 736df8bae1dSRodney W. Grimes { 73726f9a767SRodney W. Grimes if( reqpage >= count) 73826f9a767SRodney W. Grimes panic("swap_pager_getmulti: reqpage >= count\n"); 73926f9a767SRodney W. Grimes return swap_pager_input((sw_pager_t) pager->pg_data, m, count, reqpage); 740df8bae1dSRodney W. Grimes } 741df8bae1dSRodney W. Grimes 74226f9a767SRodney W. Grimes /* 74326f9a767SRodney W. Grimes * swap_pager_getpage gets individual pages 74426f9a767SRodney W. Grimes */ 74526f9a767SRodney W. Grimes int 74626f9a767SRodney W. Grimes swap_pager_getpage(pager, m, sync) 747df8bae1dSRodney W. Grimes vm_pager_t pager; 74826f9a767SRodney W. Grimes vm_page_t m; 749df8bae1dSRodney W. Grimes boolean_t sync; 750df8bae1dSRodney W. Grimes { 75126f9a767SRodney W. Grimes vm_page_t marray[1]; 75226f9a767SRodney W. Grimes 75326f9a767SRodney W. Grimes marray[0] = m; 75426f9a767SRodney W. Grimes return swap_pager_input((sw_pager_t)pager->pg_data, marray, 1, 0); 75526f9a767SRodney W. Grimes } 75626f9a767SRodney W. Grimes 75726f9a767SRodney W. Grimes int 75826f9a767SRodney W. Grimes swap_pager_putmulti(pager, m, c, sync, rtvals) 75926f9a767SRodney W. Grimes vm_pager_t pager; 76026f9a767SRodney W. Grimes vm_page_t *m; 76126f9a767SRodney W. Grimes int c; 76226f9a767SRodney W. Grimes boolean_t sync; 76326f9a767SRodney W. Grimes int *rtvals; 76426f9a767SRodney W. Grimes { 765df8bae1dSRodney W. Grimes int flags; 766df8bae1dSRodney W. Grimes 767df8bae1dSRodney W. Grimes if (pager == NULL) { 76826f9a767SRodney W. Grimes (void) swap_pager_clean(); 76926f9a767SRodney W. Grimes return VM_PAGER_OK; 770df8bae1dSRodney W. Grimes } 77126f9a767SRodney W. Grimes 772df8bae1dSRodney W. Grimes flags = B_WRITE; 773df8bae1dSRodney W. Grimes if (!sync) 774df8bae1dSRodney W. Grimes flags |= B_ASYNC; 77526f9a767SRodney W. Grimes 77626f9a767SRodney W. Grimes return swap_pager_output((sw_pager_t)pager->pg_data, m, c, flags, rtvals); 777df8bae1dSRodney W. Grimes } 778df8bae1dSRodney W. Grimes 77926f9a767SRodney W. Grimes /* 78026f9a767SRodney W. Grimes * swap_pager_putpage writes individual pages 78126f9a767SRodney W. Grimes */ 78226f9a767SRodney W. Grimes int 78326f9a767SRodney W. Grimes swap_pager_putpage(pager, m, sync) 78426f9a767SRodney W. Grimes vm_pager_t pager; 78526f9a767SRodney W. Grimes vm_page_t m; 78626f9a767SRodney W. Grimes boolean_t sync; 78726f9a767SRodney W. Grimes { 78826f9a767SRodney W. Grimes int flags; 78926f9a767SRodney W. Grimes vm_page_t marray[1]; 79026f9a767SRodney W. Grimes int rtvals[1]; 79126f9a767SRodney W. Grimes 79226f9a767SRodney W. Grimes 79326f9a767SRodney W. Grimes if (pager == NULL) { 79426f9a767SRodney W. Grimes (void) swap_pager_clean(); 79526f9a767SRodney W. Grimes return VM_PAGER_OK; 79626f9a767SRodney W. Grimes } 79726f9a767SRodney W. Grimes 79826f9a767SRodney W. Grimes marray[0] = m; 79926f9a767SRodney W. Grimes flags = B_WRITE; 80026f9a767SRodney W. Grimes if (!sync) 80126f9a767SRodney W. Grimes flags |= B_ASYNC; 80226f9a767SRodney W. Grimes 80326f9a767SRodney W. Grimes swap_pager_output((sw_pager_t)pager->pg_data, marray, 1, flags, rtvals); 80426f9a767SRodney W. Grimes 80526f9a767SRodney W. Grimes return rtvals[0]; 80626f9a767SRodney W. Grimes } 80726f9a767SRodney W. Grimes 80826f9a767SRodney W. Grimes static inline int 80926f9a767SRodney W. Grimes const swap_pager_block_index(swp, offset) 81026f9a767SRodney W. Grimes sw_pager_t swp; 81126f9a767SRodney W. Grimes vm_offset_t offset; 81226f9a767SRodney W. Grimes { 81326f9a767SRodney W. Grimes return (offset / (SWB_NPAGES*PAGE_SIZE)); 81426f9a767SRodney W. Grimes } 81526f9a767SRodney W. Grimes 81626f9a767SRodney W. Grimes static inline int 81726f9a767SRodney W. Grimes const swap_pager_block_offset(swp, offset) 81826f9a767SRodney W. Grimes sw_pager_t swp; 81926f9a767SRodney W. Grimes vm_offset_t offset; 82026f9a767SRodney W. Grimes { 82126f9a767SRodney W. Grimes return ((offset % (PAGE_SIZE*SWB_NPAGES)) / PAGE_SIZE); 82226f9a767SRodney W. Grimes } 82326f9a767SRodney W. Grimes 82426f9a767SRodney W. Grimes /* 82526f9a767SRodney W. Grimes * _swap_pager_haspage returns TRUE if the pager has data that has 82626f9a767SRodney W. Grimes * been written out. 82726f9a767SRodney W. Grimes */ 828df8bae1dSRodney W. Grimes static boolean_t 82926f9a767SRodney W. Grimes _swap_pager_haspage(swp, offset) 83026f9a767SRodney W. Grimes sw_pager_t swp; 83126f9a767SRodney W. Grimes vm_offset_t offset; 83226f9a767SRodney W. Grimes { 83326f9a767SRodney W. Grimes register sw_blk_t swb; 83426f9a767SRodney W. Grimes int ix; 83526f9a767SRodney W. Grimes 83626f9a767SRodney W. Grimes ix = offset / (SWB_NPAGES*PAGE_SIZE); 83726f9a767SRodney W. Grimes if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) { 83826f9a767SRodney W. Grimes return(FALSE); 83926f9a767SRodney W. Grimes } 84026f9a767SRodney W. Grimes swb = &swp->sw_blocks[ix]; 84126f9a767SRodney W. Grimes ix = (offset % (SWB_NPAGES*PAGE_SIZE)) / PAGE_SIZE; 84226f9a767SRodney W. Grimes if (swb->swb_block[ix] != SWB_EMPTY) { 84326f9a767SRodney W. Grimes if (swb->swb_valid & (1 << ix)) 84426f9a767SRodney W. Grimes return TRUE; 84526f9a767SRodney W. Grimes } 84626f9a767SRodney W. Grimes 84726f9a767SRodney W. Grimes return(FALSE); 84826f9a767SRodney W. Grimes } 84926f9a767SRodney W. Grimes 85026f9a767SRodney W. Grimes /* 85126f9a767SRodney W. Grimes * swap_pager_haspage is the externally accessible version of 85226f9a767SRodney W. Grimes * _swap_pager_haspage above. this routine takes a vm_pager_t 85326f9a767SRodney W. Grimes * for an argument instead of sw_pager_t. 85426f9a767SRodney W. Grimes */ 85526f9a767SRodney W. Grimes boolean_t 856df8bae1dSRodney W. Grimes swap_pager_haspage(pager, offset) 857df8bae1dSRodney W. Grimes vm_pager_t pager; 858df8bae1dSRodney W. Grimes vm_offset_t offset; 859df8bae1dSRodney W. Grimes { 86026f9a767SRodney W. Grimes return _swap_pager_haspage((sw_pager_t) pager->pg_data, offset); 861df8bae1dSRodney W. Grimes } 862df8bae1dSRodney W. Grimes 863df8bae1dSRodney W. Grimes /* 86426f9a767SRodney W. Grimes * swap_pager_freepage is a convienience routine that clears the busy 86526f9a767SRodney W. Grimes * bit and deallocates a page. 866df8bae1dSRodney W. Grimes */ 86726f9a767SRodney W. Grimes static void 86826f9a767SRodney W. Grimes swap_pager_freepage(m) 86926f9a767SRodney W. Grimes vm_page_t m; 87026f9a767SRodney W. Grimes { 87126f9a767SRodney W. Grimes PAGE_WAKEUP(m); 87226f9a767SRodney W. Grimes vm_page_free(m); 87326f9a767SRodney W. Grimes } 87426f9a767SRodney W. Grimes 87526f9a767SRodney W. Grimes /* 87626f9a767SRodney W. Grimes * swap_pager_ridpages is a convienience routine that deallocates all 87726f9a767SRodney W. Grimes * but the required page. this is usually used in error returns that 87826f9a767SRodney W. Grimes * need to invalidate the "extra" readahead pages. 87926f9a767SRodney W. Grimes */ 88026f9a767SRodney W. Grimes static void 88126f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage) 88226f9a767SRodney W. Grimes vm_page_t *m; 88326f9a767SRodney W. Grimes int count; 88426f9a767SRodney W. Grimes int reqpage; 88526f9a767SRodney W. Grimes { 88626f9a767SRodney W. Grimes int i; 88726f9a767SRodney W. Grimes for (i = 0; i < count; i++) 88826f9a767SRodney W. Grimes if (i != reqpage) 88926f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 89026f9a767SRodney W. Grimes } 89126f9a767SRodney W. Grimes 89226f9a767SRodney W. Grimes int swapwritecount=0; 89326f9a767SRodney W. Grimes 89426f9a767SRodney W. Grimes /* 89526f9a767SRodney W. Grimes * swap_pager_iodone1 is the completion routine for both reads and async writes 89626f9a767SRodney W. Grimes */ 89726f9a767SRodney W. Grimes void 89826f9a767SRodney W. Grimes swap_pager_iodone1(bp) 89926f9a767SRodney W. Grimes struct buf *bp; 90026f9a767SRodney W. Grimes { 90126f9a767SRodney W. Grimes bp->b_flags |= B_DONE; 90226f9a767SRodney W. Grimes bp->b_flags &= ~B_ASYNC; 90326f9a767SRodney W. Grimes wakeup((caddr_t)bp); 90426f9a767SRodney W. Grimes /* 90526f9a767SRodney W. Grimes if ((bp->b_flags & B_READ) == 0) 90626f9a767SRodney W. Grimes vwakeup(bp); 90726f9a767SRodney W. Grimes */ 90826f9a767SRodney W. Grimes } 90926f9a767SRodney W. Grimes 91026f9a767SRodney W. Grimes 91126f9a767SRodney W. Grimes int 91226f9a767SRodney W. Grimes swap_pager_input(swp, m, count, reqpage) 913df8bae1dSRodney W. Grimes register sw_pager_t swp; 91426f9a767SRodney W. Grimes vm_page_t *m; 91526f9a767SRodney W. Grimes int count, reqpage; 916df8bae1dSRodney W. Grimes { 917df8bae1dSRodney W. Grimes register struct buf *bp; 91826f9a767SRodney W. Grimes sw_blk_t swb[count]; 919df8bae1dSRodney W. Grimes register int s; 92026f9a767SRodney W. Grimes int i; 921df8bae1dSRodney W. Grimes boolean_t rv; 92226f9a767SRodney W. Grimes vm_offset_t kva, off[count]; 923df8bae1dSRodney W. Grimes swp_clean_t spc; 92426f9a767SRodney W. Grimes vm_offset_t paging_offset; 92526f9a767SRodney W. Grimes vm_object_t object; 92626f9a767SRodney W. Grimes int reqaddr[count]; 927df8bae1dSRodney W. Grimes 92826f9a767SRodney W. Grimes int first, last; 92926f9a767SRodney W. Grimes int failed; 93026f9a767SRodney W. Grimes int reqdskregion; 931df8bae1dSRodney W. Grimes 93226f9a767SRodney W. Grimes object = m[reqpage]->object; 93326f9a767SRodney W. Grimes paging_offset = object->paging_offset; 934df8bae1dSRodney W. Grimes /* 935df8bae1dSRodney W. Grimes * First determine if the page exists in the pager if this is 936df8bae1dSRodney W. Grimes * a sync read. This quickly handles cases where we are 937df8bae1dSRodney W. Grimes * following shadow chains looking for the top level object 938df8bae1dSRodney W. Grimes * with the page. 939df8bae1dSRodney W. Grimes */ 94026f9a767SRodney W. Grimes if (swp->sw_blocks == NULL) { 94126f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 942df8bae1dSRodney W. Grimes return(VM_PAGER_FAIL); 943df8bae1dSRodney W. Grimes } 94426f9a767SRodney W. Grimes 94526f9a767SRodney W. Grimes for(i = 0; i < count; i++) { 94626f9a767SRodney W. Grimes vm_offset_t foff = m[i]->offset + paging_offset; 94726f9a767SRodney W. Grimes int ix = swap_pager_block_index(swp, foff); 94826f9a767SRodney W. Grimes if (ix >= swp->sw_nblocks) { 94926f9a767SRodney W. Grimes int j; 95026f9a767SRodney W. Grimes if( i <= reqpage) { 95126f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 952df8bae1dSRodney W. Grimes return(VM_PAGER_FAIL); 95326f9a767SRodney W. Grimes } 95426f9a767SRodney W. Grimes for(j = i; j < count; j++) { 95526f9a767SRodney W. Grimes swap_pager_freepage(m[j]); 95626f9a767SRodney W. Grimes } 95726f9a767SRodney W. Grimes count = i; 95826f9a767SRodney W. Grimes break; 95926f9a767SRodney W. Grimes } 96026f9a767SRodney W. Grimes 96126f9a767SRodney W. Grimes swb[i] = &swp->sw_blocks[ix]; 96226f9a767SRodney W. Grimes off[i] = swap_pager_block_offset(swp, foff); 96326f9a767SRodney W. Grimes reqaddr[i] = swb[i]->swb_block[off[i]]; 96426f9a767SRodney W. Grimes } 96526f9a767SRodney W. Grimes 96626f9a767SRodney W. Grimes /* make sure that our required input request is existant */ 96726f9a767SRodney W. Grimes 96826f9a767SRodney W. Grimes if (reqaddr[reqpage] == SWB_EMPTY || 96926f9a767SRodney W. Grimes (swb[reqpage]->swb_valid & (1 << off[reqpage])) == 0) { 97026f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 97126f9a767SRodney W. Grimes return(VM_PAGER_FAIL); 97226f9a767SRodney W. Grimes } 97326f9a767SRodney W. Grimes 97426f9a767SRodney W. Grimes 97526f9a767SRodney W. Grimes reqdskregion = reqaddr[reqpage] / dmmax; 976df8bae1dSRodney W. Grimes 977df8bae1dSRodney W. Grimes /* 97826f9a767SRodney W. Grimes * search backwards for the first contiguous page to transfer 979df8bae1dSRodney W. Grimes */ 98026f9a767SRodney W. Grimes failed = 0; 98126f9a767SRodney W. Grimes first = 0; 98226f9a767SRodney W. Grimes for (i = reqpage - 1; i >= 0; --i) { 98326f9a767SRodney W. Grimes if ( failed || (reqaddr[i] == SWB_EMPTY) || 98426f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 98526f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 98626f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 98726f9a767SRodney W. Grimes failed = 1; 98826f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 98926f9a767SRodney W. Grimes if (first == 0) 99026f9a767SRodney W. Grimes first = i + 1; 99126f9a767SRodney W. Grimes } 992df8bae1dSRodney W. Grimes } 993df8bae1dSRodney W. Grimes /* 99426f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 995df8bae1dSRodney W. Grimes */ 99626f9a767SRodney W. Grimes failed = 0; 99726f9a767SRodney W. Grimes last = count; 99826f9a767SRodney W. Grimes for (i = reqpage + 1; i < count; i++) { 99926f9a767SRodney W. Grimes if ( failed || (reqaddr[i] == SWB_EMPTY) || 100026f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 100126f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 100226f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 100326f9a767SRodney W. Grimes failed = 1; 100426f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 100526f9a767SRodney W. Grimes if (last == count) 100626f9a767SRodney W. Grimes last = i; 100726f9a767SRodney W. Grimes } 100826f9a767SRodney W. Grimes } 100926f9a767SRodney W. Grimes 101026f9a767SRodney W. Grimes count = last; 101126f9a767SRodney W. Grimes if (first != 0) { 101226f9a767SRodney W. Grimes for (i = first; i < count; i++) { 101326f9a767SRodney W. Grimes m[i-first] = m[i]; 101426f9a767SRodney W. Grimes reqaddr[i-first] = reqaddr[i]; 101526f9a767SRodney W. Grimes off[i-first] = off[i]; 101626f9a767SRodney W. Grimes } 101726f9a767SRodney W. Grimes count -= first; 101826f9a767SRodney W. Grimes reqpage -= first; 101926f9a767SRodney W. Grimes } 102026f9a767SRodney W. Grimes 102126f9a767SRodney W. Grimes ++swb[reqpage]->swb_locked; 102226f9a767SRodney W. Grimes 102326f9a767SRodney W. Grimes /* 102426f9a767SRodney W. Grimes * at this point: 102526f9a767SRodney W. Grimes * "m" is a pointer to the array of vm_page_t for paging I/O 102626f9a767SRodney W. Grimes * "count" is the number of vm_page_t entries represented by "m" 102726f9a767SRodney W. Grimes * "object" is the vm_object_t for I/O 102826f9a767SRodney W. Grimes * "reqpage" is the index into "m" for the page actually faulted 102926f9a767SRodney W. Grimes */ 103026f9a767SRodney W. Grimes 103126f9a767SRodney W. Grimes spc = NULL; /* we might not use an spc data structure */ 103226f9a767SRodney W. Grimes kva = 0; 103326f9a767SRodney W. Grimes 103426f9a767SRodney W. Grimes /* 103526f9a767SRodney W. Grimes * we allocate a new kva for transfers > 1 page 103626f9a767SRodney W. Grimes * but for transfers == 1 page, the swap_pager_free list contains 103726f9a767SRodney W. Grimes * entries that have pre-allocated kva's (for efficiency). 103826f9a767SRodney W. Grimes */ 103926f9a767SRodney W. Grimes if (count > 1) { 104026f9a767SRodney W. Grimes kva = kmem_alloc_pageable(pager_map, count*PAGE_SIZE); 104126f9a767SRodney W. Grimes } 104226f9a767SRodney W. Grimes 104326f9a767SRodney W. Grimes 104426f9a767SRodney W. Grimes if (!kva) { 104526f9a767SRodney W. Grimes /* 104626f9a767SRodney W. Grimes * if a kva has not been allocated, we can only do a one page transfer, 104726f9a767SRodney W. Grimes * so we free the other pages that might have been allocated by 104826f9a767SRodney W. Grimes * vm_fault. 104926f9a767SRodney W. Grimes */ 105026f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 105126f9a767SRodney W. Grimes m[0] = m[reqpage]; 105226f9a767SRodney W. Grimes reqaddr[0] = reqaddr[reqpage]; 105326f9a767SRodney W. Grimes 105426f9a767SRodney W. Grimes count = 1; 105526f9a767SRodney W. Grimes reqpage = 0; 105626f9a767SRodney W. Grimes /* 105726f9a767SRodney W. Grimes * get a swap pager clean data structure, block until we get it 105826f9a767SRodney W. Grimes */ 1059df8bae1dSRodney W. Grimes if (swap_pager_free.tqh_first == NULL) { 1060df8bae1dSRodney W. Grimes s = splbio(); 106126f9a767SRodney W. Grimes if( curproc == pageproc) 106226f9a767SRodney W. Grimes (void) swap_pager_clean(); 106326f9a767SRodney W. Grimes else 106426f9a767SRodney W. Grimes wakeup((caddr_t) &vm_pages_needed); 106526f9a767SRodney W. Grimes while (swap_pager_free.tqh_first == NULL) { 106626f9a767SRodney W. Grimes swap_pager_needflags |= SWAP_FREE_NEEDED; 106726f9a767SRodney W. Grimes tsleep((caddr_t)&swap_pager_free, 106826f9a767SRodney W. Grimes PVM, "swpfre", 0); 106926f9a767SRodney W. Grimes if( curproc == pageproc) 107026f9a767SRodney W. Grimes (void) swap_pager_clean(); 107126f9a767SRodney W. Grimes else 107226f9a767SRodney W. Grimes wakeup((caddr_t) &vm_pages_needed); 1073df8bae1dSRodney W. Grimes } 1074df8bae1dSRodney W. Grimes splx(s); 107526f9a767SRodney W. Grimes } 107626f9a767SRodney W. Grimes spc = swap_pager_free.tqh_first; 107726f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 107826f9a767SRodney W. Grimes kva = spc->spc_kva; 107926f9a767SRodney W. Grimes } 108026f9a767SRodney W. Grimes 108126f9a767SRodney W. Grimes 108226f9a767SRodney W. Grimes /* 108326f9a767SRodney W. Grimes * map our page(s) into kva for input 108426f9a767SRodney W. Grimes */ 108526f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 108626f9a767SRodney W. Grimes pmap_kenter( kva + PAGE_SIZE * i, VM_PAGE_TO_PHYS(m[i])); 108726f9a767SRodney W. Grimes } 108826f9a767SRodney W. Grimes pmap_update(); 108926f9a767SRodney W. Grimes 109026f9a767SRodney W. Grimes 109126f9a767SRodney W. Grimes /* 109226f9a767SRodney W. Grimes * Get a swap buffer header and perform the IO 109326f9a767SRodney W. Grimes */ 109426f9a767SRodney W. Grimes if( spc) { 109526f9a767SRodney W. Grimes bp = spc->spc_bp; 109626f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 109726f9a767SRodney W. Grimes bp->b_spc = spc; 109826f9a767SRodney W. Grimes } else { 109926f9a767SRodney W. Grimes bp = getpbuf(); 110026f9a767SRodney W. Grimes } 110126f9a767SRodney W. Grimes 110226f9a767SRodney W. Grimes s = splbio(); 110326f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_READ | B_CALL; 110426f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 1105df8bae1dSRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 110626f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 110726f9a767SRodney W. Grimes crhold(bp->b_rcred); 110826f9a767SRodney W. Grimes crhold(bp->b_wcred); 110926f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva; 111026f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 111126f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE*count; 111226f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE*count; 111326f9a767SRodney W. Grimes 111426f9a767SRodney W. Grimes /* 1115df8bae1dSRodney W. Grimes VHOLD(swapdev_vp); 1116df8bae1dSRodney W. Grimes bp->b_vp = swapdev_vp; 1117df8bae1dSRodney W. Grimes if (swapdev_vp->v_type == VBLK) 1118df8bae1dSRodney W. Grimes bp->b_dev = swapdev_vp->v_rdev; 111926f9a767SRodney W. Grimes */ 112026f9a767SRodney W. Grimes bgetvp( swapdev_vp, bp); 112126f9a767SRodney W. Grimes 112226f9a767SRodney W. Grimes swp->sw_piip++; 1123df8bae1dSRodney W. Grimes 1124df8bae1dSRodney W. Grimes /* 112526f9a767SRodney W. Grimes * perform the I/O 1126df8bae1dSRodney W. Grimes */ 1127df8bae1dSRodney W. Grimes VOP_STRATEGY(bp); 112826f9a767SRodney W. Grimes 112926f9a767SRodney W. Grimes /* 113026f9a767SRodney W. Grimes * wait for the sync I/O to complete 113126f9a767SRodney W. Grimes */ 113226f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 113326f9a767SRodney W. Grimes tsleep((caddr_t)bp, PVM, "swread", 0); 1134df8bae1dSRodney W. Grimes } 113526f9a767SRodney W. Grimes rv = (bp->b_flags & B_ERROR) ? VM_PAGER_FAIL : VM_PAGER_OK; 113626f9a767SRodney W. Grimes bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_DIRTY|B_CALL|B_DONE); 113726f9a767SRodney W. Grimes 113826f9a767SRodney W. Grimes --swp->sw_piip; 113926f9a767SRodney W. Grimes if (swp->sw_piip == 0) 114026f9a767SRodney W. Grimes wakeup((caddr_t) swp); 114126f9a767SRodney W. Grimes 114226f9a767SRodney W. Grimes /* 114326f9a767SRodney W. Grimes * relpbuf does this, but we maintain our own buffer 114426f9a767SRodney W. Grimes * list also... 114526f9a767SRodney W. Grimes */ 1146df8bae1dSRodney W. Grimes if (bp->b_vp) 1147df8bae1dSRodney W. Grimes brelvp(bp); 114826f9a767SRodney W. Grimes 1149df8bae1dSRodney W. Grimes splx(s); 115026f9a767SRodney W. Grimes --swb[reqpage]->swb_locked; 115126f9a767SRodney W. Grimes 115226f9a767SRodney W. Grimes /* 115326f9a767SRodney W. Grimes * remove the mapping for kernel virtual 115426f9a767SRodney W. Grimes */ 115526f9a767SRodney W. Grimes pmap_remove(vm_map_pmap(pager_map), kva, kva + count * PAGE_SIZE); 115626f9a767SRodney W. Grimes 115726f9a767SRodney W. Grimes if (spc) { 115826f9a767SRodney W. Grimes /* 115926f9a767SRodney W. Grimes * if we have used an spc, we need to free it. 116026f9a767SRodney W. Grimes */ 116126f9a767SRodney W. Grimes if( bp->b_rcred != NOCRED) 116226f9a767SRodney W. Grimes crfree(bp->b_rcred); 116326f9a767SRodney W. Grimes if( bp->b_wcred != NOCRED) 116426f9a767SRodney W. Grimes crfree(bp->b_wcred); 116526f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 116626f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 116726f9a767SRodney W. Grimes swap_pager_needflags &= ~SWAP_FREE_NEEDED; 116826f9a767SRodney W. Grimes wakeup((caddr_t)&swap_pager_free); 116926f9a767SRodney W. Grimes } 117026f9a767SRodney W. Grimes } else { 117126f9a767SRodney W. Grimes /* 117226f9a767SRodney W. Grimes * free the kernel virtual addresses 117326f9a767SRodney W. Grimes */ 117426f9a767SRodney W. Grimes kmem_free_wakeup(pager_map, kva, count * PAGE_SIZE); 117526f9a767SRodney W. Grimes /* 117626f9a767SRodney W. Grimes * release the physical I/O buffer 117726f9a767SRodney W. Grimes */ 117826f9a767SRodney W. Grimes relpbuf(bp); 117926f9a767SRodney W. Grimes /* 118026f9a767SRodney W. Grimes * finish up input if everything is ok 118126f9a767SRodney W. Grimes */ 118226f9a767SRodney W. Grimes if( rv == VM_PAGER_OK) { 118326f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 118426f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 118526f9a767SRodney W. Grimes m[i]->flags |= PG_CLEAN; 118626f9a767SRodney W. Grimes m[i]->flags &= ~PG_LAUNDRY; 118726f9a767SRodney W. Grimes if (i != reqpage) { 118826f9a767SRodney W. Grimes /* 118926f9a767SRodney W. Grimes * whether or not to leave the page activated 119026f9a767SRodney W. Grimes * is up in the air, but we should put the page 119126f9a767SRodney W. Grimes * on a page queue somewhere. (it already is in 119226f9a767SRodney W. Grimes * the object). 119326f9a767SRodney W. Grimes * After some emperical results, it is best 119426f9a767SRodney W. Grimes * to deactivate the readahead pages. 119526f9a767SRodney W. Grimes */ 119626f9a767SRodney W. Grimes vm_page_deactivate(m[i]); 119726f9a767SRodney W. Grimes m[i]->act_count = 2; 119826f9a767SRodney W. Grimes 119926f9a767SRodney W. Grimes /* 120026f9a767SRodney W. Grimes * just in case someone was asking for this 120126f9a767SRodney W. Grimes * page we now tell them that it is ok to use 120226f9a767SRodney W. Grimes */ 120326f9a767SRodney W. Grimes m[i]->flags &= ~PG_FAKE; 120426f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 120526f9a767SRodney W. Grimes } 120626f9a767SRodney W. Grimes } 120726f9a767SRodney W. Grimes if( swap_pager_full) { 120826f9a767SRodney W. Grimes _swap_pager_freespace( swp, m[0]->offset+paging_offset, count*PAGE_SIZE); 120926f9a767SRodney W. Grimes } 121026f9a767SRodney W. Grimes } else { 121126f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 121226f9a767SRodney W. Grimes } 121326f9a767SRodney W. Grimes } 1214df8bae1dSRodney W. Grimes return(rv); 1215df8bae1dSRodney W. Grimes } 1216df8bae1dSRodney W. Grimes 121726f9a767SRodney W. Grimes int 121826f9a767SRodney W. Grimes swap_pager_output(swp, m, count, flags, rtvals) 121926f9a767SRodney W. Grimes register sw_pager_t swp; 122026f9a767SRodney W. Grimes vm_page_t *m; 122126f9a767SRodney W. Grimes int count; 122226f9a767SRodney W. Grimes int flags; 122326f9a767SRodney W. Grimes int *rtvals; 1224df8bae1dSRodney W. Grimes { 122526f9a767SRodney W. Grimes register struct buf *bp; 122626f9a767SRodney W. Grimes sw_blk_t swb[count]; 122726f9a767SRodney W. Grimes register int s; 122826f9a767SRodney W. Grimes int i, j, ix; 122926f9a767SRodney W. Grimes boolean_t rv; 123026f9a767SRodney W. Grimes vm_offset_t kva, off, foff; 123126f9a767SRodney W. Grimes swp_clean_t spc; 123226f9a767SRodney W. Grimes vm_offset_t paging_offset; 1233df8bae1dSRodney W. Grimes vm_object_t object; 123426f9a767SRodney W. Grimes int reqaddr[count]; 123526f9a767SRodney W. Grimes int failed; 1236df8bae1dSRodney W. Grimes 1237df8bae1dSRodney W. Grimes /* 123826f9a767SRodney W. Grimes if( count > 1) 123926f9a767SRodney W. Grimes printf("off: 0x%x, count: %d\n", m[0]->offset, count); 1240df8bae1dSRodney W. Grimes */ 124126f9a767SRodney W. Grimes spc = NULL; 124226f9a767SRodney W. Grimes 124326f9a767SRodney W. Grimes object = m[0]->object; 124426f9a767SRodney W. Grimes paging_offset = object->paging_offset; 124526f9a767SRodney W. Grimes 124626f9a767SRodney W. Grimes failed = 0; 124726f9a767SRodney W. Grimes for(j=0;j<count;j++) { 124826f9a767SRodney W. Grimes foff = m[j]->offset + paging_offset; 124926f9a767SRodney W. Grimes ix = swap_pager_block_index(swp, foff); 125026f9a767SRodney W. Grimes swb[j] = 0; 125126f9a767SRodney W. Grimes if( swp->sw_blocks == NULL || ix >= swp->sw_nblocks) { 125226f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 125326f9a767SRodney W. Grimes failed = 1; 125426f9a767SRodney W. Grimes continue; 125526f9a767SRodney W. Grimes } else { 125626f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_OK; 125726f9a767SRodney W. Grimes } 125826f9a767SRodney W. Grimes swb[j] = &swp->sw_blocks[ix]; 125926f9a767SRodney W. Grimes ++swb[j]->swb_locked; 126026f9a767SRodney W. Grimes if( failed) { 126126f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 126226f9a767SRodney W. Grimes continue; 126326f9a767SRodney W. Grimes } 126426f9a767SRodney W. Grimes off = swap_pager_block_offset(swp, foff); 126526f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 126626f9a767SRodney W. Grimes if( reqaddr[j] == SWB_EMPTY) { 126726f9a767SRodney W. Grimes int blk; 126826f9a767SRodney W. Grimes int tries; 126926f9a767SRodney W. Grimes int ntoget; 127026f9a767SRodney W. Grimes tries = 0; 1271df8bae1dSRodney W. Grimes s = splbio(); 127226f9a767SRodney W. Grimes 1273df8bae1dSRodney W. Grimes /* 127426f9a767SRodney W. Grimes * if any other pages have been allocated in this block, we 127526f9a767SRodney W. Grimes * only try to get one page. 1276df8bae1dSRodney W. Grimes */ 127726f9a767SRodney W. Grimes for (i = 0; i < SWB_NPAGES; i++) { 127826f9a767SRodney W. Grimes if (swb[j]->swb_block[i] != SWB_EMPTY) 1279df8bae1dSRodney W. Grimes break; 1280df8bae1dSRodney W. Grimes } 128126f9a767SRodney W. Grimes 128226f9a767SRodney W. Grimes 128326f9a767SRodney W. Grimes ntoget = (i == SWB_NPAGES) ? SWB_NPAGES : 1; 128426f9a767SRodney W. Grimes /* 128526f9a767SRodney W. Grimes * this code is alittle conservative, but works 128626f9a767SRodney W. Grimes * (the intent of this code is to allocate small chunks 128726f9a767SRodney W. Grimes * for small objects) 128826f9a767SRodney W. Grimes */ 128926f9a767SRodney W. Grimes if( (m[j]->offset == 0) && (ntoget*PAGE_SIZE > object->size)) { 129026f9a767SRodney W. Grimes ntoget = (object->size + (PAGE_SIZE-1))/PAGE_SIZE; 129126f9a767SRodney W. Grimes } 129226f9a767SRodney W. Grimes 129326f9a767SRodney W. Grimes retrygetspace: 129426f9a767SRodney W. Grimes if (!swap_pager_full && ntoget > 1 && 129526f9a767SRodney W. Grimes swap_pager_getswapspace(ntoget * btodb(PAGE_SIZE), &blk)) { 129626f9a767SRodney W. Grimes 129726f9a767SRodney W. Grimes for (i = 0; i < ntoget; i++) { 129826f9a767SRodney W. Grimes swb[j]->swb_block[i] = blk + btodb(PAGE_SIZE) * i; 129926f9a767SRodney W. Grimes swb[j]->swb_valid = 0; 130026f9a767SRodney W. Grimes } 130126f9a767SRodney W. Grimes 130226f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 130326f9a767SRodney W. Grimes } else if (!swap_pager_getswapspace(btodb(PAGE_SIZE), 130426f9a767SRodney W. Grimes &swb[j]->swb_block[off])) { 130526f9a767SRodney W. Grimes /* 130626f9a767SRodney W. Grimes * if the allocation has failed, we try to reclaim space and 130726f9a767SRodney W. Grimes * retry. 130826f9a767SRodney W. Grimes */ 130926f9a767SRodney W. Grimes if (++tries == 1) { 131026f9a767SRodney W. Grimes swap_pager_reclaim(); 131126f9a767SRodney W. Grimes goto retrygetspace; 131226f9a767SRodney W. Grimes } 131326f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_AGAIN; 131426f9a767SRodney W. Grimes failed = 1; 131526f9a767SRodney W. Grimes } else { 131626f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 131726f9a767SRodney W. Grimes swb[j]->swb_valid &= ~(1<<off); 1318df8bae1dSRodney W. Grimes } 1319df8bae1dSRodney W. Grimes splx(s); 132026f9a767SRodney W. Grimes } 132126f9a767SRodney W. Grimes } 132226f9a767SRodney W. Grimes 132326f9a767SRodney W. Grimes /* 132426f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 132526f9a767SRodney W. Grimes */ 132626f9a767SRodney W. Grimes failed = 0; 132726f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 132826f9a767SRodney W. Grimes if( failed || (reqaddr[i] != reqaddr[0] + i*btodb(PAGE_SIZE)) || 132926f9a767SRodney W. Grimes (reqaddr[i] / dmmax) != (reqaddr[0] / dmmax) || 133026f9a767SRodney W. Grimes (rtvals[i] != VM_PAGER_OK)) { 133126f9a767SRodney W. Grimes failed = 1; 133226f9a767SRodney W. Grimes if( rtvals[i] == VM_PAGER_OK) 133326f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 133426f9a767SRodney W. Grimes } 133526f9a767SRodney W. Grimes } 133626f9a767SRodney W. Grimes 133726f9a767SRodney W. Grimes for(i = 0; i < count; i++) { 133826f9a767SRodney W. Grimes if( rtvals[i] != VM_PAGER_OK) { 133926f9a767SRodney W. Grimes if( swb[i]) 134026f9a767SRodney W. Grimes --swb[i]->swb_locked; 134126f9a767SRodney W. Grimes } 134226f9a767SRodney W. Grimes } 134326f9a767SRodney W. Grimes 134426f9a767SRodney W. Grimes for(i = 0; i < count; i++) 134526f9a767SRodney W. Grimes if( rtvals[i] != VM_PAGER_OK) 134626f9a767SRodney W. Grimes break; 134726f9a767SRodney W. Grimes 134826f9a767SRodney W. Grimes if( i == 0) { 134926f9a767SRodney W. Grimes return VM_PAGER_AGAIN; 135026f9a767SRodney W. Grimes } 135126f9a767SRodney W. Grimes 135226f9a767SRodney W. Grimes count = i; 135326f9a767SRodney W. Grimes for(i=0;i<count;i++) { 135426f9a767SRodney W. Grimes if( reqaddr[i] == SWB_EMPTY) 135526f9a767SRodney W. Grimes printf("I/O to empty block????\n"); 135626f9a767SRodney W. Grimes } 135726f9a767SRodney W. Grimes 135826f9a767SRodney W. Grimes /* 135926f9a767SRodney W. Grimes */ 136026f9a767SRodney W. Grimes 136126f9a767SRodney W. Grimes /* 136226f9a767SRodney W. Grimes * For synchronous writes, we clean up 136326f9a767SRodney W. Grimes * all completed async pageouts. 136426f9a767SRodney W. Grimes */ 136526f9a767SRodney W. Grimes if ((flags & B_ASYNC) == 0) { 136626f9a767SRodney W. Grimes swap_pager_clean(); 136726f9a767SRodney W. Grimes } 136826f9a767SRodney W. Grimes 136926f9a767SRodney W. Grimes kva = 0; 137026f9a767SRodney W. Grimes 137126f9a767SRodney W. Grimes /* 137226f9a767SRodney W. Grimes * we allocate a new kva for transfers > 1 page 137326f9a767SRodney W. Grimes * but for transfers == 1 page, the swap_pager_free list contains 137426f9a767SRodney W. Grimes * entries that have pre-allocated kva's (for efficiency). 137526f9a767SRodney W. Grimes */ 137626f9a767SRodney W. Grimes if ( count > 1) { 137726f9a767SRodney W. Grimes kva = kmem_alloc_pageable(pager_map, count*PAGE_SIZE); 137826f9a767SRodney W. Grimes if( !kva) { 137926f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 138026f9a767SRodney W. Grimes if( swb[i]) 138126f9a767SRodney W. Grimes --swb[i]->swb_locked; 138226f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 138326f9a767SRodney W. Grimes } 138426f9a767SRodney W. Grimes return VM_PAGER_AGAIN; 138526f9a767SRodney W. Grimes } 138626f9a767SRodney W. Grimes } 138726f9a767SRodney W. Grimes 138826f9a767SRodney W. Grimes /* 138926f9a767SRodney W. Grimes * get a swap pager clean data structure, block until we get it 139026f9a767SRodney W. Grimes */ 139126f9a767SRodney W. Grimes if (swap_pager_free.tqh_first == NULL) { 139226f9a767SRodney W. Grimes /* 139326f9a767SRodney W. Grimes if (flags & B_ASYNC) { 139426f9a767SRodney W. Grimes for(i=0;i<count;i++) { 139526f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 139626f9a767SRodney W. Grimes if( swb[i]) 139726f9a767SRodney W. Grimes --swb[i]->swb_locked; 139826f9a767SRodney W. Grimes } 139926f9a767SRodney W. Grimes return VM_PAGER_AGAIN; 140026f9a767SRodney W. Grimes } 140126f9a767SRodney W. Grimes */ 140226f9a767SRodney W. Grimes 140326f9a767SRodney W. Grimes s = splbio(); 140426f9a767SRodney W. Grimes if( curproc == pageproc) 140526f9a767SRodney W. Grimes (void) swap_pager_clean(); 140626f9a767SRodney W. Grimes else 140726f9a767SRodney W. Grimes wakeup((caddr_t) &vm_pages_needed); 140826f9a767SRodney W. Grimes while (swap_pager_free.tqh_first == NULL) { 140926f9a767SRodney W. Grimes swap_pager_needflags |= SWAP_FREE_NEEDED; 141026f9a767SRodney W. Grimes tsleep((caddr_t)&swap_pager_free, 141126f9a767SRodney W. Grimes PVM, "swpfre", 0); 141226f9a767SRodney W. Grimes if( curproc == pageproc) 141326f9a767SRodney W. Grimes (void) swap_pager_clean(); 141426f9a767SRodney W. Grimes else 141526f9a767SRodney W. Grimes wakeup((caddr_t) &vm_pages_needed); 141626f9a767SRodney W. Grimes } 141726f9a767SRodney W. Grimes splx(s); 141826f9a767SRodney W. Grimes } 141926f9a767SRodney W. Grimes 142026f9a767SRodney W. Grimes spc = swap_pager_free.tqh_first; 142126f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 142226f9a767SRodney W. Grimes if( !kva) { 142326f9a767SRodney W. Grimes kva = spc->spc_kva; 142426f9a767SRodney W. Grimes spc->spc_altkva = 0; 142526f9a767SRodney W. Grimes } else { 142626f9a767SRodney W. Grimes spc->spc_altkva = kva; 142726f9a767SRodney W. Grimes } 142826f9a767SRodney W. Grimes 142926f9a767SRodney W. Grimes /* 143026f9a767SRodney W. Grimes * map our page(s) into kva for I/O 143126f9a767SRodney W. Grimes */ 143226f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 143326f9a767SRodney W. Grimes pmap_kenter( kva + PAGE_SIZE * i, VM_PAGE_TO_PHYS(m[i])); 143426f9a767SRodney W. Grimes } 143526f9a767SRodney W. Grimes pmap_update(); 143626f9a767SRodney W. Grimes 143726f9a767SRodney W. Grimes /* 143826f9a767SRodney W. Grimes * get the base I/O offset into the swap file 143926f9a767SRodney W. Grimes */ 144026f9a767SRodney W. Grimes for(i=0;i<count;i++) { 144126f9a767SRodney W. Grimes foff = m[i]->offset + paging_offset; 144226f9a767SRodney W. Grimes off = swap_pager_block_offset(swp, foff); 144326f9a767SRodney W. Grimes /* 144426f9a767SRodney W. Grimes * if we are setting the valid bit anew, 144526f9a767SRodney W. Grimes * then diminish the swap free space 144626f9a767SRodney W. Grimes */ 144726f9a767SRodney W. Grimes if( (swb[i]->swb_valid & (1 << off)) == 0) 144826f9a767SRodney W. Grimes vm_swap_size -= btodb(PAGE_SIZE); 144926f9a767SRodney W. Grimes 145026f9a767SRodney W. Grimes /* 145126f9a767SRodney W. Grimes * set the valid bit 145226f9a767SRodney W. Grimes */ 145326f9a767SRodney W. Grimes swb[i]->swb_valid |= (1 << off); 145426f9a767SRodney W. Grimes /* 145526f9a767SRodney W. Grimes * and unlock the data structure 145626f9a767SRodney W. Grimes */ 145726f9a767SRodney W. Grimes --swb[i]->swb_locked; 145826f9a767SRodney W. Grimes } 145926f9a767SRodney W. Grimes 146026f9a767SRodney W. Grimes s = splbio(); 146126f9a767SRodney W. Grimes /* 146226f9a767SRodney W. Grimes * Get a swap buffer header and perform the IO 146326f9a767SRodney W. Grimes */ 146426f9a767SRodney W. Grimes bp = spc->spc_bp; 146526f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 146626f9a767SRodney W. Grimes bp->b_spc = spc; 146726f9a767SRodney W. Grimes 146826f9a767SRodney W. Grimes bp->b_flags = B_BUSY; 146926f9a767SRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 147026f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 147126f9a767SRodney W. Grimes crhold(bp->b_rcred); 147226f9a767SRodney W. Grimes crhold(bp->b_wcred); 147326f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva; 147426f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 147526f9a767SRodney W. Grimes bgetvp( swapdev_vp, bp); 147626f9a767SRodney W. Grimes /* 147726f9a767SRodney W. Grimes VHOLD(swapdev_vp); 147826f9a767SRodney W. Grimes bp->b_vp = swapdev_vp; 147926f9a767SRodney W. Grimes if (swapdev_vp->v_type == VBLK) 148026f9a767SRodney W. Grimes bp->b_dev = swapdev_vp->v_rdev; 148126f9a767SRodney W. Grimes */ 148226f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE*count; 148326f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE*count; 148426f9a767SRodney W. Grimes swapdev_vp->v_numoutput++; 148526f9a767SRodney W. Grimes 148626f9a767SRodney W. Grimes /* 148726f9a767SRodney W. Grimes * If this is an async write we set up additional buffer fields 148826f9a767SRodney W. Grimes * and place a "cleaning" entry on the inuse queue. 148926f9a767SRodney W. Grimes */ 149026f9a767SRodney W. Grimes if ( flags & B_ASYNC ) { 149126f9a767SRodney W. Grimes spc->spc_flags = 0; 149226f9a767SRodney W. Grimes spc->spc_swp = swp; 149326f9a767SRodney W. Grimes for(i=0;i<count;i++) 149426f9a767SRodney W. Grimes spc->spc_m[i] = m[i]; 149526f9a767SRodney W. Grimes spc->spc_count = count; 149626f9a767SRodney W. Grimes /* 149726f9a767SRodney W. Grimes * the completion routine for async writes 149826f9a767SRodney W. Grimes */ 149926f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 150026f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone; 150126f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 150226f9a767SRodney W. Grimes bp->b_dirtyend = bp->b_bcount; 150326f9a767SRodney W. Grimes swp->sw_poip++; 150426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list); 150526f9a767SRodney W. Grimes } else { 150626f9a767SRodney W. Grimes swp->sw_poip++; 150726f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 150826f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 150926f9a767SRodney W. Grimes } 151026f9a767SRodney W. Grimes /* 151126f9a767SRodney W. Grimes * perform the I/O 151226f9a767SRodney W. Grimes */ 151326f9a767SRodney W. Grimes VOP_STRATEGY(bp); 151426f9a767SRodney W. Grimes if ((flags & (B_READ|B_ASYNC)) == B_ASYNC ) { 151526f9a767SRodney W. Grimes if ((bp->b_flags & B_DONE) == B_DONE) { 151626f9a767SRodney W. Grimes swap_pager_clean(); 151726f9a767SRodney W. Grimes } 151826f9a767SRodney W. Grimes splx(s); 151926f9a767SRodney W. Grimes for(i=0;i<count;i++) { 152026f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_PEND; 152126f9a767SRodney W. Grimes } 152226f9a767SRodney W. Grimes return VM_PAGER_PEND; 152326f9a767SRodney W. Grimes } 152426f9a767SRodney W. Grimes 152526f9a767SRodney W. Grimes /* 152626f9a767SRodney W. Grimes * wait for the sync I/O to complete 152726f9a767SRodney W. Grimes */ 152826f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 152926f9a767SRodney W. Grimes tsleep((caddr_t)bp, PVM, "swwrt", 0); 153026f9a767SRodney W. Grimes } 153126f9a767SRodney W. Grimes rv = (bp->b_flags & B_ERROR) ? VM_PAGER_FAIL : VM_PAGER_OK; 153226f9a767SRodney W. Grimes bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_DIRTY|B_CALL|B_DONE); 153326f9a767SRodney W. Grimes 153426f9a767SRodney W. Grimes --swp->sw_poip; 153526f9a767SRodney W. Grimes if (swp->sw_poip == 0) 153626f9a767SRodney W. Grimes wakeup((caddr_t) swp); 153726f9a767SRodney W. Grimes 153826f9a767SRodney W. Grimes if (bp->b_vp) 153926f9a767SRodney W. Grimes brelvp(bp); 154026f9a767SRodney W. Grimes 154126f9a767SRodney W. Grimes splx(s); 154226f9a767SRodney W. Grimes 154326f9a767SRodney W. Grimes /* 154426f9a767SRodney W. Grimes * remove the mapping for kernel virtual 154526f9a767SRodney W. Grimes */ 154626f9a767SRodney W. Grimes pmap_remove(vm_map_pmap(pager_map), kva, kva + count * PAGE_SIZE); 154726f9a767SRodney W. Grimes 154826f9a767SRodney W. Grimes /* 154926f9a767SRodney W. Grimes * if we have written the page, then indicate that the page 155026f9a767SRodney W. Grimes * is clean. 155126f9a767SRodney W. Grimes */ 155226f9a767SRodney W. Grimes if (rv == VM_PAGER_OK) { 155326f9a767SRodney W. Grimes for(i=0;i<count;i++) { 155426f9a767SRodney W. Grimes if( rtvals[i] == VM_PAGER_OK) { 155526f9a767SRodney W. Grimes m[i]->flags |= PG_CLEAN; 155626f9a767SRodney W. Grimes m[i]->flags &= ~PG_LAUNDRY; 155726f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 155826f9a767SRodney W. Grimes /* 155926f9a767SRodney W. Grimes * optimization, if a page has been read during the 156026f9a767SRodney W. Grimes * pageout process, we activate it. 156126f9a767SRodney W. Grimes */ 156226f9a767SRodney W. Grimes if ( (m[i]->flags & PG_ACTIVE) == 0 && 156326f9a767SRodney W. Grimes pmap_is_referenced(VM_PAGE_TO_PHYS(m[i]))) 156426f9a767SRodney W. Grimes vm_page_activate(m[i]); 156526f9a767SRodney W. Grimes } 156626f9a767SRodney W. Grimes } 156726f9a767SRodney W. Grimes } else { 156826f9a767SRodney W. Grimes for(i=0;i<count;i++) { 156926f9a767SRodney W. Grimes rtvals[i] = rv; 157026f9a767SRodney W. Grimes m[i]->flags |= PG_LAUNDRY; 157126f9a767SRodney W. Grimes } 157226f9a767SRodney W. Grimes } 157326f9a767SRodney W. Grimes 157426f9a767SRodney W. Grimes if( spc->spc_altkva) 157526f9a767SRodney W. Grimes kmem_free_wakeup(pager_map, kva, count * PAGE_SIZE); 157626f9a767SRodney W. Grimes 157726f9a767SRodney W. Grimes if( bp->b_rcred != NOCRED) 157826f9a767SRodney W. Grimes crfree(bp->b_rcred); 157926f9a767SRodney W. Grimes if( bp->b_wcred != NOCRED) 158026f9a767SRodney W. Grimes crfree(bp->b_wcred); 158126f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 158226f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 158326f9a767SRodney W. Grimes swap_pager_needflags &= ~SWAP_FREE_NEEDED; 158426f9a767SRodney W. Grimes wakeup((caddr_t)&swap_pager_free); 158526f9a767SRodney W. Grimes } 158626f9a767SRodney W. Grimes 158726f9a767SRodney W. Grimes return(rv); 158826f9a767SRodney W. Grimes } 158926f9a767SRodney W. Grimes 159026f9a767SRodney W. Grimes boolean_t 159126f9a767SRodney W. Grimes swap_pager_clean() 159226f9a767SRodney W. Grimes { 159326f9a767SRodney W. Grimes register swp_clean_t spc, tspc; 159426f9a767SRodney W. Grimes register int s; 159526f9a767SRodney W. Grimes 159626f9a767SRodney W. Grimes tspc = NULL; 159726f9a767SRodney W. Grimes if (swap_pager_done.tqh_first == NULL) 159826f9a767SRodney W. Grimes return FALSE; 159926f9a767SRodney W. Grimes for (;;) { 160026f9a767SRodney W. Grimes s = splbio(); 160126f9a767SRodney W. Grimes /* 160226f9a767SRodney W. Grimes * Look up and removal from done list must be done 160326f9a767SRodney W. Grimes * at splbio() to avoid conflicts with swap_pager_iodone. 160426f9a767SRodney W. Grimes */ 160526f9a767SRodney W. Grimes while (spc = swap_pager_done.tqh_first) { 160626f9a767SRodney W. Grimes if( spc->spc_altkva) { 160726f9a767SRodney W. Grimes pmap_remove(vm_map_pmap(pager_map), spc->spc_altkva, spc->spc_altkva + spc->spc_count * PAGE_SIZE); 160826f9a767SRodney W. Grimes kmem_free_wakeup(pager_map, spc->spc_altkva, spc->spc_count * PAGE_SIZE); 160926f9a767SRodney W. Grimes spc->spc_altkva = 0; 161026f9a767SRodney W. Grimes } else { 161126f9a767SRodney W. Grimes pmap_remove(vm_map_pmap(pager_map), spc->spc_kva, spc->spc_kva + PAGE_SIZE); 161226f9a767SRodney W. Grimes } 161326f9a767SRodney W. Grimes swap_pager_finish(spc); 161426f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_done, spc, spc_list); 161526f9a767SRodney W. Grimes goto doclean; 161626f9a767SRodney W. Grimes } 1617df8bae1dSRodney W. Grimes 1618df8bae1dSRodney W. Grimes /* 1619df8bae1dSRodney W. Grimes * No operations done, thats all we can do for now. 1620df8bae1dSRodney W. Grimes */ 162126f9a767SRodney W. Grimes 162226f9a767SRodney W. Grimes splx(s); 1623df8bae1dSRodney W. Grimes break; 1624df8bae1dSRodney W. Grimes 1625df8bae1dSRodney W. Grimes /* 162626f9a767SRodney W. Grimes * The desired page was found to be busy earlier in 162726f9a767SRodney W. Grimes * the scan but has since completed. 1628df8bae1dSRodney W. Grimes */ 162926f9a767SRodney W. Grimes doclean: 163026f9a767SRodney W. Grimes if (tspc && tspc == spc) { 163126f9a767SRodney W. Grimes tspc = NULL; 163226f9a767SRodney W. Grimes } 163326f9a767SRodney W. Grimes spc->spc_flags = 0; 163426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 163526f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 163626f9a767SRodney W. Grimes swap_pager_needflags &= ~SWAP_FREE_NEEDED; 163726f9a767SRodney W. Grimes wakeup((caddr_t)&swap_pager_free); 163826f9a767SRodney W. Grimes } 163926f9a767SRodney W. Grimes ++cleandone; 164026f9a767SRodney W. Grimes splx(s); 164126f9a767SRodney W. Grimes } 164226f9a767SRodney W. Grimes 164326f9a767SRodney W. Grimes return(tspc ? TRUE : FALSE); 164426f9a767SRodney W. Grimes } 164526f9a767SRodney W. Grimes 164626f9a767SRodney W. Grimes void 164726f9a767SRodney W. Grimes swap_pager_finish(spc) 164826f9a767SRodney W. Grimes register swp_clean_t spc; 164926f9a767SRodney W. Grimes { 165026f9a767SRodney W. Grimes vm_object_t object = spc->spc_m[0]->object; 165126f9a767SRodney W. Grimes int i; 165226f9a767SRodney W. Grimes 165326f9a767SRodney W. Grimes if ((object->paging_in_progress -= spc->spc_count) == 0) 165426f9a767SRodney W. Grimes thread_wakeup((int) object); 1655df8bae1dSRodney W. Grimes 1656df8bae1dSRodney W. Grimes /* 165726f9a767SRodney W. Grimes * If no error mark as clean and inform the pmap system. 165826f9a767SRodney W. Grimes * If error, mark as dirty so we will try again. 165926f9a767SRodney W. Grimes * (XXX could get stuck doing this, should give up after awhile) 1660df8bae1dSRodney W. Grimes */ 1661df8bae1dSRodney W. Grimes if (spc->spc_flags & SPC_ERROR) { 166226f9a767SRodney W. Grimes for(i=0;i<spc->spc_count;i++) { 166326f9a767SRodney W. Grimes printf("swap_pager_finish: clean of page %x failed\n", 166426f9a767SRodney W. Grimes VM_PAGE_TO_PHYS(spc->spc_m[i])); 166526f9a767SRodney W. Grimes spc->spc_m[i]->flags |= PG_LAUNDRY; 166626f9a767SRodney W. Grimes } 1667df8bae1dSRodney W. Grimes } else { 166826f9a767SRodney W. Grimes for(i=0;i<spc->spc_count;i++) { 166926f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m[i])); 167026f9a767SRodney W. Grimes spc->spc_m[i]->flags |= PG_CLEAN; 1671df8bae1dSRodney W. Grimes } 1672df8bae1dSRodney W. Grimes } 1673df8bae1dSRodney W. Grimes 167426f9a767SRodney W. Grimes 167526f9a767SRodney W. Grimes for(i=0;i<spc->spc_count;i++) { 1676df8bae1dSRodney W. Grimes /* 167726f9a767SRodney W. Grimes * we wakeup any processes that are waiting on 167826f9a767SRodney W. Grimes * these pages. 1679df8bae1dSRodney W. Grimes */ 168026f9a767SRodney W. Grimes PAGE_WAKEUP(spc->spc_m[i]); 1681df8bae1dSRodney W. Grimes } 168226f9a767SRodney W. Grimes nswiodone -= spc->spc_count; 1683df8bae1dSRodney W. Grimes 1684df8bae1dSRodney W. Grimes return; 168526f9a767SRodney W. Grimes } 1686df8bae1dSRodney W. Grimes 168726f9a767SRodney W. Grimes /* 168826f9a767SRodney W. Grimes * swap_pager_iodone 168926f9a767SRodney W. Grimes */ 169026f9a767SRodney W. Grimes void 1691df8bae1dSRodney W. Grimes swap_pager_iodone(bp) 1692df8bae1dSRodney W. Grimes register struct buf *bp; 1693df8bae1dSRodney W. Grimes { 1694df8bae1dSRodney W. Grimes register swp_clean_t spc; 1695df8bae1dSRodney W. Grimes int s; 1696df8bae1dSRodney W. Grimes 1697df8bae1dSRodney W. Grimes s = splbio(); 169826f9a767SRodney W. Grimes spc = (swp_clean_t) bp->b_spc; 169926f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list); 170026f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_done, spc, spc_list); 170126f9a767SRodney W. Grimes if (bp->b_flags & B_ERROR) { 1702df8bae1dSRodney W. Grimes spc->spc_flags |= SPC_ERROR; 170326f9a767SRodney W. Grimes printf("error %d blkno %d sz %d ", 170426f9a767SRodney W. Grimes bp->b_error, bp->b_blkno, bp->b_bcount); 1705df8bae1dSRodney W. Grimes } 1706df8bae1dSRodney W. Grimes 170726f9a767SRodney W. Grimes /* 170826f9a767SRodney W. Grimes if ((bp->b_flags & B_READ) == 0) 170926f9a767SRodney W. Grimes vwakeup(bp); 171026f9a767SRodney W. Grimes */ 171126f9a767SRodney W. Grimes 171226f9a767SRodney W. Grimes bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_DIRTY|B_ASYNC); 171326f9a767SRodney W. Grimes if (bp->b_vp) { 171426f9a767SRodney W. Grimes brelvp(bp); 171526f9a767SRodney W. Grimes } 171626f9a767SRodney W. Grimes if( bp->b_rcred != NOCRED) 171726f9a767SRodney W. Grimes crfree(bp->b_rcred); 171826f9a767SRodney W. Grimes if( bp->b_wcred != NOCRED) 171926f9a767SRodney W. Grimes crfree(bp->b_wcred); 172026f9a767SRodney W. Grimes 172126f9a767SRodney W. Grimes nswiodone += spc->spc_count; 172226f9a767SRodney W. Grimes if (--spc->spc_swp->sw_poip == 0) { 172326f9a767SRodney W. Grimes wakeup((caddr_t)spc->spc_swp); 172426f9a767SRodney W. Grimes } 172526f9a767SRodney W. Grimes 172626f9a767SRodney W. Grimes if ((swap_pager_needflags & SWAP_FREE_NEEDED) || 172726f9a767SRodney W. Grimes swap_pager_inuse.tqh_first == 0) { 172826f9a767SRodney W. Grimes swap_pager_needflags &= ~SWAP_FREE_NEEDED; 172926f9a767SRodney W. Grimes wakeup((caddr_t)&swap_pager_free); 173026f9a767SRodney W. Grimes wakeup((caddr_t)&vm_pages_needed); 173126f9a767SRodney W. Grimes } 173226f9a767SRodney W. Grimes 173326f9a767SRodney W. Grimes if (vm_pageout_pages_needed) { 173426f9a767SRodney W. Grimes wakeup((caddr_t)&vm_pageout_pages_needed); 173526f9a767SRodney W. Grimes } 173626f9a767SRodney W. Grimes 173726f9a767SRodney W. Grimes if ((swap_pager_inuse.tqh_first == NULL) || 173826f9a767SRodney W. Grimes (cnt.v_free_count < cnt.v_free_min && 173926f9a767SRodney W. Grimes nswiodone + cnt.v_free_count >= cnt.v_free_min) ) { 174026f9a767SRodney W. Grimes wakeup((caddr_t)&vm_pages_needed); 174126f9a767SRodney W. Grimes } 174226f9a767SRodney W. Grimes splx(s); 174326f9a767SRodney W. Grimes } 174426f9a767SRodney W. Grimes 174526f9a767SRodney W. Grimes int bswneeded; 174626f9a767SRodney W. Grimes /* TAILQ_HEAD(swqueue, buf) bswlist; */ 174726f9a767SRodney W. Grimes /* 174826f9a767SRodney W. Grimes * allocate a physical buffer 174926f9a767SRodney W. Grimes */ 175026f9a767SRodney W. Grimes struct buf * 175126f9a767SRodney W. Grimes getpbuf() { 175226f9a767SRodney W. Grimes int s; 175326f9a767SRodney W. Grimes struct buf *bp; 175426f9a767SRodney W. Grimes 175526f9a767SRodney W. Grimes s = splbio(); 175626f9a767SRodney W. Grimes /* get a bp from the swap buffer header pool */ 175726f9a767SRodney W. Grimes while ((bp = bswlist.tqh_first) == NULL) { 175826f9a767SRodney W. Grimes bswneeded = 1; 175926f9a767SRodney W. Grimes tsleep((caddr_t)&bswneeded, PVM, "wswbuf", 0); 176026f9a767SRodney W. Grimes } 176126f9a767SRodney W. Grimes TAILQ_REMOVE(&bswlist, bp, b_freelist); 176226f9a767SRodney W. Grimes 176326f9a767SRodney W. Grimes splx(s); 176426f9a767SRodney W. Grimes 176526f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 176626f9a767SRodney W. Grimes bp->b_rcred = NOCRED; 176726f9a767SRodney W. Grimes bp->b_wcred = NOCRED; 176826f9a767SRodney W. Grimes return bp; 176926f9a767SRodney W. Grimes } 177026f9a767SRodney W. Grimes 177126f9a767SRodney W. Grimes /* 177226f9a767SRodney W. Grimes * allocate a physical buffer, if one is available 177326f9a767SRodney W. Grimes */ 177426f9a767SRodney W. Grimes struct buf * 177526f9a767SRodney W. Grimes trypbuf() { 177626f9a767SRodney W. Grimes int s; 177726f9a767SRodney W. Grimes struct buf *bp; 177826f9a767SRodney W. Grimes 177926f9a767SRodney W. Grimes s = splbio(); 178026f9a767SRodney W. Grimes if ((bp = bswlist.tqh_first) == NULL) { 178126f9a767SRodney W. Grimes splx(s); 178226f9a767SRodney W. Grimes return NULL; 178326f9a767SRodney W. Grimes } 178426f9a767SRodney W. Grimes TAILQ_REMOVE(&bswlist, bp, b_freelist); 178526f9a767SRodney W. Grimes splx(s); 178626f9a767SRodney W. Grimes 178726f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 178826f9a767SRodney W. Grimes bp->b_rcred = NOCRED; 178926f9a767SRodney W. Grimes bp->b_wcred = NOCRED; 179026f9a767SRodney W. Grimes return bp; 179126f9a767SRodney W. Grimes } 179226f9a767SRodney W. Grimes 179326f9a767SRodney W. Grimes /* 179426f9a767SRodney W. Grimes * release a physical buffer 179526f9a767SRodney W. Grimes */ 179626f9a767SRodney W. Grimes void 179726f9a767SRodney W. Grimes relpbuf(bp) 179826f9a767SRodney W. Grimes struct buf *bp; 179926f9a767SRodney W. Grimes { 180026f9a767SRodney W. Grimes int s; 180126f9a767SRodney W. Grimes 180226f9a767SRodney W. Grimes s = splbio(); 180326f9a767SRodney W. Grimes 180426f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) { 180526f9a767SRodney W. Grimes crfree(bp->b_rcred); 180626f9a767SRodney W. Grimes bp->b_rcred = NOCRED; 180726f9a767SRodney W. Grimes } 180826f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) { 180926f9a767SRodney W. Grimes crfree(bp->b_wcred); 181026f9a767SRodney W. Grimes bp->b_wcred = NOCRED; 181126f9a767SRodney W. Grimes } 181226f9a767SRodney W. Grimes 1813df8bae1dSRodney W. Grimes if (bp->b_vp) 1814df8bae1dSRodney W. Grimes brelvp(bp); 181526f9a767SRodney W. Grimes 181626f9a767SRodney W. Grimes TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist); 181726f9a767SRodney W. Grimes 181826f9a767SRodney W. Grimes if (bswneeded) { 181926f9a767SRodney W. Grimes bswneeded = 0; 182026f9a767SRodney W. Grimes wakeup((caddr_t)&bswlist); 1821df8bae1dSRodney W. Grimes } 1822df8bae1dSRodney W. Grimes splx(s); 1823df8bae1dSRodney W. Grimes } 182426f9a767SRodney W. Grimes 182526f9a767SRodney W. Grimes /* 182626f9a767SRodney W. Grimes * return true if any swap control structures can be allocated 182726f9a767SRodney W. Grimes */ 182826f9a767SRodney W. Grimes int 182926f9a767SRodney W. Grimes swap_pager_ready() { 183026f9a767SRodney W. Grimes if( swap_pager_free.tqh_first) 183126f9a767SRodney W. Grimes return 1; 183226f9a767SRodney W. Grimes else 183326f9a767SRodney W. Grimes return 0; 183426f9a767SRodney W. Grimes } 1835