1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1990 University of Utah. 3df8bae1dSRodney W. Grimes * Copyright (c) 1991, 1993 4df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 5df8bae1dSRodney W. Grimes * 6df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 7df8bae1dSRodney W. Grimes * the Systems Programming Group of the University of Utah Computer 8df8bae1dSRodney W. Grimes * Science Department. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$ 39df8bae1dSRodney W. Grimes * 40df8bae1dSRodney W. Grimes * @(#)swap_pager.c 8.9 (Berkeley) 3/21/94 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 43df8bae1dSRodney W. Grimes /* 44df8bae1dSRodney W. Grimes * Quick hack to page to dedicated partition(s). 45df8bae1dSRodney W. Grimes * TODO: 46df8bae1dSRodney W. Grimes * Add multiprocessor locks 47df8bae1dSRodney W. Grimes * Deal with async writes in a better fashion 48df8bae1dSRodney W. Grimes */ 49df8bae1dSRodney W. Grimes 50df8bae1dSRodney W. Grimes #include <sys/param.h> 51df8bae1dSRodney W. Grimes #include <sys/systm.h> 52df8bae1dSRodney W. Grimes #include <sys/proc.h> 53df8bae1dSRodney W. Grimes #include <sys/buf.h> 54df8bae1dSRodney W. Grimes #include <sys/map.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> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <vm/vm.h> 61df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 62df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h> 63df8bae1dSRodney W. Grimes #include <vm/swap_pager.h> 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes #define NSWSIZES 16 /* size of swtab */ 66df8bae1dSRodney W. Grimes #define MAXDADDRS 64 /* max # of disk addrs for fixed allocations */ 67df8bae1dSRodney W. Grimes #ifndef NPENDINGIO 68df8bae1dSRodney W. Grimes #define NPENDINGIO 64 /* max # of pending cleans */ 69df8bae1dSRodney W. Grimes #endif 70df8bae1dSRodney W. Grimes 71df8bae1dSRodney W. Grimes #ifdef DEBUG 72df8bae1dSRodney W. Grimes int swpagerdebug = 0x100; 73df8bae1dSRodney W. Grimes #define SDB_FOLLOW 0x001 74df8bae1dSRodney W. Grimes #define SDB_INIT 0x002 75df8bae1dSRodney W. Grimes #define SDB_ALLOC 0x004 76df8bae1dSRodney W. Grimes #define SDB_IO 0x008 77df8bae1dSRodney W. Grimes #define SDB_WRITE 0x010 78df8bae1dSRodney W. Grimes #define SDB_FAIL 0x020 79df8bae1dSRodney W. Grimes #define SDB_ALLOCBLK 0x040 80df8bae1dSRodney W. Grimes #define SDB_FULL 0x080 81df8bae1dSRodney W. Grimes #define SDB_ANOM 0x100 82df8bae1dSRodney W. Grimes #define SDB_ANOMPANIC 0x200 83df8bae1dSRodney W. Grimes #define SDB_CLUSTER 0x400 84df8bae1dSRodney W. Grimes #define SDB_PARANOIA 0x800 85df8bae1dSRodney W. Grimes #endif 86df8bae1dSRodney W. Grimes 87df8bae1dSRodney W. Grimes TAILQ_HEAD(swpclean, swpagerclean); 88df8bae1dSRodney W. Grimes 89df8bae1dSRodney W. Grimes struct swpagerclean { 90df8bae1dSRodney W. Grimes TAILQ_ENTRY(swpagerclean) spc_list; 91df8bae1dSRodney W. Grimes int spc_flags; 92df8bae1dSRodney W. Grimes struct buf *spc_bp; 93df8bae1dSRodney W. Grimes sw_pager_t spc_swp; 94df8bae1dSRodney W. Grimes vm_offset_t spc_kva; 95df8bae1dSRodney W. Grimes vm_page_t spc_m; 96df8bae1dSRodney W. Grimes int spc_npages; 97df8bae1dSRodney W. Grimes } swcleanlist[NPENDINGIO]; 98df8bae1dSRodney W. Grimes typedef struct swpagerclean *swp_clean_t; 99df8bae1dSRodney W. Grimes 100df8bae1dSRodney W. Grimes /* spc_flags values */ 101df8bae1dSRodney W. Grimes #define SPC_FREE 0x00 102df8bae1dSRodney W. Grimes #define SPC_BUSY 0x01 103df8bae1dSRodney W. Grimes #define SPC_DONE 0x02 104df8bae1dSRodney W. Grimes #define SPC_ERROR 0x04 105df8bae1dSRodney W. Grimes 106df8bae1dSRodney W. Grimes struct swtab { 107df8bae1dSRodney W. Grimes vm_size_t st_osize; /* size of object (bytes) */ 108df8bae1dSRodney W. Grimes int st_bsize; /* vs. size of swap block (DEV_BSIZE units) */ 109df8bae1dSRodney W. Grimes #ifdef DEBUG 110df8bae1dSRodney W. Grimes u_long st_inuse; /* number in this range in use */ 111df8bae1dSRodney W. Grimes u_long st_usecnt; /* total used of this size */ 112df8bae1dSRodney W. Grimes #endif 113df8bae1dSRodney W. Grimes } swtab[NSWSIZES+1]; 114df8bae1dSRodney W. Grimes 115df8bae1dSRodney W. Grimes #ifdef DEBUG 116df8bae1dSRodney W. Grimes int swap_pager_poip; /* pageouts in progress */ 117df8bae1dSRodney W. Grimes int swap_pager_piip; /* pageins in progress */ 118df8bae1dSRodney W. Grimes #endif 119df8bae1dSRodney W. Grimes 120df8bae1dSRodney W. Grimes int swap_pager_maxcluster; /* maximum cluster size */ 121df8bae1dSRodney W. Grimes int swap_pager_npendingio; /* number of pager clean structs */ 122df8bae1dSRodney W. Grimes 123df8bae1dSRodney W. Grimes struct swpclean swap_pager_inuse; /* list of pending page cleans */ 124df8bae1dSRodney W. Grimes struct swpclean swap_pager_free; /* list of free pager clean structs */ 125df8bae1dSRodney W. Grimes struct pagerlst swap_pager_list; /* list of "named" anon regions */ 126df8bae1dSRodney W. Grimes 127df8bae1dSRodney W. Grimes static void swap_pager_init __P((void)); 128df8bae1dSRodney W. Grimes static vm_pager_t swap_pager_alloc 129df8bae1dSRodney W. Grimes __P((caddr_t, vm_size_t, vm_prot_t, vm_offset_t)); 130df8bae1dSRodney W. Grimes static void swap_pager_clean __P((int)); 131df8bae1dSRodney W. Grimes #ifdef DEBUG 132df8bae1dSRodney W. Grimes static void swap_pager_clean_check __P((vm_page_t *, int, int)); 133df8bae1dSRodney W. Grimes #endif 134df8bae1dSRodney W. Grimes static void swap_pager_cluster 135df8bae1dSRodney W. Grimes __P((vm_pager_t, vm_offset_t, 136df8bae1dSRodney W. Grimes vm_offset_t *, vm_offset_t *)); 137df8bae1dSRodney W. Grimes static void swap_pager_dealloc __P((vm_pager_t)); 138df8bae1dSRodney W. Grimes static int swap_pager_getpage 139df8bae1dSRodney W. Grimes __P((vm_pager_t, vm_page_t *, int, boolean_t)); 140df8bae1dSRodney W. Grimes static boolean_t swap_pager_haspage __P((vm_pager_t, vm_offset_t)); 141df8bae1dSRodney W. Grimes static int swap_pager_io __P((sw_pager_t, vm_page_t *, int, int)); 142df8bae1dSRodney W. Grimes static void swap_pager_iodone __P((struct buf *)); 143df8bae1dSRodney W. Grimes static int swap_pager_putpage 144df8bae1dSRodney W. Grimes __P((vm_pager_t, vm_page_t *, int, boolean_t)); 145df8bae1dSRodney W. Grimes 146df8bae1dSRodney W. Grimes struct pagerops swappagerops = { 147df8bae1dSRodney W. Grimes swap_pager_init, 148df8bae1dSRodney W. Grimes swap_pager_alloc, 149df8bae1dSRodney W. Grimes swap_pager_dealloc, 150df8bae1dSRodney W. Grimes swap_pager_getpage, 151df8bae1dSRodney W. Grimes swap_pager_putpage, 152df8bae1dSRodney W. Grimes swap_pager_haspage, 153df8bae1dSRodney W. Grimes swap_pager_cluster 154df8bae1dSRodney W. Grimes }; 155df8bae1dSRodney W. Grimes 156df8bae1dSRodney W. Grimes static void 157df8bae1dSRodney W. Grimes swap_pager_init() 158df8bae1dSRodney W. Grimes { 159df8bae1dSRodney W. Grimes register swp_clean_t spc; 160df8bae1dSRodney W. Grimes register int i, bsize; 161df8bae1dSRodney W. Grimes extern int dmmin, dmmax; 162df8bae1dSRodney W. Grimes int maxbsize; 163df8bae1dSRodney W. Grimes 164df8bae1dSRodney W. Grimes #ifdef DEBUG 165df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FOLLOW|SDB_INIT)) 166df8bae1dSRodney W. Grimes printf("swpg_init()\n"); 167df8bae1dSRodney W. Grimes #endif 168df8bae1dSRodney W. Grimes dfltpagerops = &swappagerops; 169df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_list); 170df8bae1dSRodney W. Grimes 171df8bae1dSRodney W. Grimes /* 172df8bae1dSRodney W. Grimes * Allocate async IO structures. 173df8bae1dSRodney W. Grimes * 174df8bae1dSRodney W. Grimes * XXX it would be nice if we could do this dynamically based on 175df8bae1dSRodney W. Grimes * the value of nswbuf (since we are ultimately limited by that) 176df8bae1dSRodney W. Grimes * but neither nswbuf or malloc has been initialized yet. So the 177df8bae1dSRodney W. Grimes * structs are statically allocated above. 178df8bae1dSRodney W. Grimes */ 179df8bae1dSRodney W. Grimes swap_pager_npendingio = NPENDINGIO; 180df8bae1dSRodney W. Grimes 181df8bae1dSRodney W. Grimes /* 182df8bae1dSRodney W. Grimes * Initialize clean lists 183df8bae1dSRodney W. Grimes */ 184df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_inuse); 185df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_free); 186df8bae1dSRodney W. Grimes for (i = 0, spc = swcleanlist; i < swap_pager_npendingio; i++, spc++) { 187df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 188df8bae1dSRodney W. Grimes spc->spc_flags = SPC_FREE; 189df8bae1dSRodney W. Grimes } 190df8bae1dSRodney W. Grimes 191df8bae1dSRodney W. Grimes /* 192df8bae1dSRodney W. Grimes * Calculate the swap allocation constants. 193df8bae1dSRodney W. Grimes */ 194df8bae1dSRodney W. Grimes if (dmmin == 0) { 195df8bae1dSRodney W. Grimes dmmin = DMMIN; 196df8bae1dSRodney W. Grimes if (dmmin < CLBYTES/DEV_BSIZE) 197df8bae1dSRodney W. Grimes dmmin = CLBYTES/DEV_BSIZE; 198df8bae1dSRodney W. Grimes } 199df8bae1dSRodney W. Grimes if (dmmax == 0) 200df8bae1dSRodney W. Grimes dmmax = DMMAX; 201df8bae1dSRodney W. Grimes 202df8bae1dSRodney W. Grimes /* 203df8bae1dSRodney W. Grimes * Fill in our table of object size vs. allocation size 204df8bae1dSRodney W. Grimes */ 205df8bae1dSRodney W. Grimes bsize = btodb(PAGE_SIZE); 206df8bae1dSRodney W. Grimes if (bsize < dmmin) 207df8bae1dSRodney W. Grimes bsize = dmmin; 208df8bae1dSRodney W. Grimes maxbsize = btodb(sizeof(sw_bm_t) * NBBY * PAGE_SIZE); 209df8bae1dSRodney W. Grimes if (maxbsize > dmmax) 210df8bae1dSRodney W. Grimes maxbsize = dmmax; 211df8bae1dSRodney W. Grimes for (i = 0; i < NSWSIZES; i++) { 212df8bae1dSRodney W. Grimes swtab[i].st_osize = (vm_size_t) (MAXDADDRS * dbtob(bsize)); 213df8bae1dSRodney W. Grimes swtab[i].st_bsize = bsize; 214df8bae1dSRodney W. Grimes if (bsize <= btodb(MAXPHYS)) 215df8bae1dSRodney W. Grimes swap_pager_maxcluster = dbtob(bsize); 216df8bae1dSRodney W. Grimes #ifdef DEBUG 217df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_INIT) 218df8bae1dSRodney W. Grimes printf("swpg_init: ix %d, size %x, bsize %x\n", 219df8bae1dSRodney W. Grimes i, swtab[i].st_osize, swtab[i].st_bsize); 220df8bae1dSRodney W. Grimes #endif 221df8bae1dSRodney W. Grimes if (bsize >= maxbsize) 222df8bae1dSRodney W. Grimes break; 223df8bae1dSRodney W. Grimes bsize *= 2; 224df8bae1dSRodney W. Grimes } 225df8bae1dSRodney W. Grimes swtab[i].st_osize = 0; 226df8bae1dSRodney W. Grimes swtab[i].st_bsize = bsize; 227df8bae1dSRodney W. Grimes } 228df8bae1dSRodney W. Grimes 229df8bae1dSRodney W. Grimes /* 230df8bae1dSRodney W. Grimes * Allocate a pager structure and associated resources. 231df8bae1dSRodney W. Grimes * Note that if we are called from the pageout daemon (handle == NULL) 232df8bae1dSRodney W. Grimes * we should not wait for memory as it could resulting in deadlock. 233df8bae1dSRodney W. Grimes */ 234df8bae1dSRodney W. Grimes static vm_pager_t 235df8bae1dSRodney W. Grimes swap_pager_alloc(handle, size, prot, foff) 236df8bae1dSRodney W. Grimes caddr_t handle; 237df8bae1dSRodney W. Grimes register vm_size_t size; 238df8bae1dSRodney W. Grimes vm_prot_t prot; 239df8bae1dSRodney W. Grimes vm_offset_t foff; 240df8bae1dSRodney W. Grimes { 241df8bae1dSRodney W. Grimes register vm_pager_t pager; 242df8bae1dSRodney W. Grimes register sw_pager_t swp; 243df8bae1dSRodney W. Grimes struct swtab *swt; 244df8bae1dSRodney W. Grimes int waitok; 245df8bae1dSRodney W. Grimes 246df8bae1dSRodney W. Grimes #ifdef DEBUG 247df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC)) 248df8bae1dSRodney W. Grimes printf("swpg_alloc(%x, %x, %x)\n", handle, size, prot); 249df8bae1dSRodney W. Grimes #endif 250df8bae1dSRodney W. Grimes /* 251df8bae1dSRodney W. Grimes * If this is a "named" anonymous region, look it up and 252df8bae1dSRodney W. Grimes * return the appropriate pager if it exists. 253df8bae1dSRodney W. Grimes */ 254df8bae1dSRodney W. Grimes if (handle) { 255df8bae1dSRodney W. Grimes pager = vm_pager_lookup(&swap_pager_list, handle); 256df8bae1dSRodney W. Grimes if (pager != NULL) { 257df8bae1dSRodney W. Grimes /* 258df8bae1dSRodney W. Grimes * Use vm_object_lookup to gain a reference 259df8bae1dSRodney W. Grimes * to the object and also to remove from the 260df8bae1dSRodney W. Grimes * object cache. 261df8bae1dSRodney W. Grimes */ 262df8bae1dSRodney W. Grimes if (vm_object_lookup(pager) == NULL) 263df8bae1dSRodney W. Grimes panic("swap_pager_alloc: bad object"); 264df8bae1dSRodney W. Grimes return(pager); 265df8bae1dSRodney W. Grimes } 266df8bae1dSRodney W. Grimes } 267df8bae1dSRodney W. Grimes /* 268df8bae1dSRodney W. Grimes * Pager doesn't exist, allocate swap management resources 269df8bae1dSRodney W. Grimes * and initialize. 270df8bae1dSRodney W. Grimes */ 271df8bae1dSRodney W. Grimes waitok = handle ? M_WAITOK : M_NOWAIT; 272df8bae1dSRodney W. Grimes pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok); 273df8bae1dSRodney W. Grimes if (pager == NULL) 274df8bae1dSRodney W. Grimes return(NULL); 275df8bae1dSRodney W. Grimes swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok); 276df8bae1dSRodney W. Grimes if (swp == NULL) { 277df8bae1dSRodney W. Grimes #ifdef DEBUG 278df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_FAIL) 279df8bae1dSRodney W. Grimes printf("swpg_alloc: swpager malloc failed\n"); 280df8bae1dSRodney W. Grimes #endif 281df8bae1dSRodney W. Grimes free((caddr_t)pager, M_VMPAGER); 282df8bae1dSRodney W. Grimes return(NULL); 283df8bae1dSRodney W. Grimes } 284df8bae1dSRodney W. Grimes size = round_page(size); 285df8bae1dSRodney W. Grimes for (swt = swtab; swt->st_osize; swt++) 286df8bae1dSRodney W. Grimes if (size <= swt->st_osize) 287df8bae1dSRodney W. Grimes break; 288df8bae1dSRodney W. Grimes #ifdef DEBUG 289df8bae1dSRodney W. Grimes swt->st_inuse++; 290df8bae1dSRodney W. Grimes swt->st_usecnt++; 291df8bae1dSRodney W. Grimes #endif 292df8bae1dSRodney W. Grimes swp->sw_osize = size; 293df8bae1dSRodney W. Grimes swp->sw_bsize = swt->st_bsize; 294df8bae1dSRodney W. Grimes swp->sw_nblocks = (btodb(size) + swp->sw_bsize - 1) / swp->sw_bsize; 295df8bae1dSRodney W. Grimes swp->sw_blocks = (sw_blk_t) 296df8bae1dSRodney W. Grimes malloc(swp->sw_nblocks*sizeof(*swp->sw_blocks), 297df8bae1dSRodney W. Grimes M_VMPGDATA, M_NOWAIT); 298df8bae1dSRodney W. Grimes if (swp->sw_blocks == NULL) { 299df8bae1dSRodney W. Grimes free((caddr_t)swp, M_VMPGDATA); 300df8bae1dSRodney W. Grimes free((caddr_t)pager, M_VMPAGER); 301df8bae1dSRodney W. Grimes #ifdef DEBUG 302df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_FAIL) 303df8bae1dSRodney W. Grimes printf("swpg_alloc: sw_blocks malloc failed\n"); 304df8bae1dSRodney W. Grimes swt->st_inuse--; 305df8bae1dSRodney W. Grimes swt->st_usecnt--; 306df8bae1dSRodney W. Grimes #endif 307df8bae1dSRodney W. Grimes return(FALSE); 308df8bae1dSRodney W. Grimes } 309df8bae1dSRodney W. Grimes bzero((caddr_t)swp->sw_blocks, 310df8bae1dSRodney W. Grimes swp->sw_nblocks * sizeof(*swp->sw_blocks)); 311df8bae1dSRodney W. Grimes swp->sw_poip = 0; 312df8bae1dSRodney W. Grimes if (handle) { 313df8bae1dSRodney W. Grimes vm_object_t object; 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes swp->sw_flags = SW_NAMED; 316df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_list, pager, pg_list); 317df8bae1dSRodney W. Grimes /* 318df8bae1dSRodney W. Grimes * Consistant with other pagers: return with object 319df8bae1dSRodney W. Grimes * referenced. Can't do this with handle == NULL 320df8bae1dSRodney W. Grimes * since it might be the pageout daemon calling. 321df8bae1dSRodney W. Grimes */ 322df8bae1dSRodney W. Grimes object = vm_object_allocate(size); 323df8bae1dSRodney W. Grimes vm_object_enter(object, pager); 324df8bae1dSRodney W. Grimes vm_object_setpager(object, pager, 0, FALSE); 325df8bae1dSRodney W. Grimes } else { 326df8bae1dSRodney W. Grimes swp->sw_flags = 0; 327df8bae1dSRodney W. Grimes pager->pg_list.tqe_next = NULL; 328df8bae1dSRodney W. Grimes pager->pg_list.tqe_prev = NULL; 329df8bae1dSRodney W. Grimes } 330df8bae1dSRodney W. Grimes pager->pg_handle = handle; 331df8bae1dSRodney W. Grimes pager->pg_ops = &swappagerops; 332df8bae1dSRodney W. Grimes pager->pg_type = PG_SWAP; 333df8bae1dSRodney W. Grimes pager->pg_flags = PG_CLUSTERPUT; 334df8bae1dSRodney W. Grimes pager->pg_data = swp; 335df8bae1dSRodney W. Grimes 336df8bae1dSRodney W. Grimes #ifdef DEBUG 337df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_ALLOC) 338df8bae1dSRodney W. Grimes printf("swpg_alloc: pg_data %x, %x of %x at %x\n", 339df8bae1dSRodney W. Grimes swp, swp->sw_nblocks, swp->sw_bsize, swp->sw_blocks); 340df8bae1dSRodney W. Grimes #endif 341df8bae1dSRodney W. Grimes return(pager); 342df8bae1dSRodney W. Grimes } 343df8bae1dSRodney W. Grimes 344df8bae1dSRodney W. Grimes static void 345df8bae1dSRodney W. Grimes swap_pager_dealloc(pager) 346df8bae1dSRodney W. Grimes vm_pager_t pager; 347df8bae1dSRodney W. Grimes { 348df8bae1dSRodney W. Grimes register int i; 349df8bae1dSRodney W. Grimes register sw_blk_t bp; 350df8bae1dSRodney W. Grimes register sw_pager_t swp; 351df8bae1dSRodney W. Grimes struct swtab *swt; 352df8bae1dSRodney W. Grimes int s; 353df8bae1dSRodney W. Grimes 354df8bae1dSRodney W. Grimes #ifdef DEBUG 355df8bae1dSRodney W. Grimes /* save panic time state */ 356df8bae1dSRodney W. Grimes if ((swpagerdebug & SDB_ANOMPANIC) && panicstr) 357df8bae1dSRodney W. Grimes return; 358df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC)) 359df8bae1dSRodney W. Grimes printf("swpg_dealloc(%x)\n", pager); 360df8bae1dSRodney W. Grimes #endif 361df8bae1dSRodney W. Grimes /* 362df8bae1dSRodney W. Grimes * Remove from list right away so lookups will fail if we 363df8bae1dSRodney W. Grimes * block for pageout completion. 364df8bae1dSRodney W. Grimes */ 365df8bae1dSRodney W. Grimes swp = (sw_pager_t) pager->pg_data; 366df8bae1dSRodney W. Grimes if (swp->sw_flags & SW_NAMED) { 367df8bae1dSRodney W. Grimes TAILQ_REMOVE(&swap_pager_list, pager, pg_list); 368df8bae1dSRodney W. Grimes swp->sw_flags &= ~SW_NAMED; 369df8bae1dSRodney W. Grimes } 370df8bae1dSRodney W. Grimes #ifdef DEBUG 371df8bae1dSRodney W. Grimes for (swt = swtab; swt->st_osize; swt++) 372df8bae1dSRodney W. Grimes if (swp->sw_osize <= swt->st_osize) 373df8bae1dSRodney W. Grimes break; 374df8bae1dSRodney W. Grimes swt->st_inuse--; 375df8bae1dSRodney W. Grimes #endif 376df8bae1dSRodney W. Grimes 377df8bae1dSRodney W. Grimes /* 378df8bae1dSRodney W. Grimes * Wait for all pageouts to finish and remove 379df8bae1dSRodney W. Grimes * all entries from cleaning list. 380df8bae1dSRodney W. Grimes */ 381df8bae1dSRodney W. Grimes s = splbio(); 382df8bae1dSRodney W. Grimes while (swp->sw_poip) { 383df8bae1dSRodney W. Grimes swp->sw_flags |= SW_WANTED; 384df8bae1dSRodney W. Grimes (void) tsleep(swp, PVM, "swpgdealloc", 0); 385df8bae1dSRodney W. Grimes } 386df8bae1dSRodney W. Grimes splx(s); 387df8bae1dSRodney W. Grimes swap_pager_clean(B_WRITE); 388df8bae1dSRodney W. Grimes 389df8bae1dSRodney W. Grimes /* 390df8bae1dSRodney W. Grimes * Free left over swap blocks 391df8bae1dSRodney W. Grimes */ 392df8bae1dSRodney W. Grimes for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++) 393df8bae1dSRodney W. Grimes if (bp->swb_block) { 394df8bae1dSRodney W. Grimes #ifdef DEBUG 395df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_ALLOCBLK|SDB_FULL)) 396df8bae1dSRodney W. Grimes printf("swpg_dealloc: blk %x\n", 397df8bae1dSRodney W. Grimes bp->swb_block); 398df8bae1dSRodney W. Grimes #endif 399df8bae1dSRodney W. Grimes rmfree(swapmap, swp->sw_bsize, bp->swb_block); 400df8bae1dSRodney W. Grimes } 401df8bae1dSRodney W. Grimes /* 402df8bae1dSRodney W. Grimes * Free swap management resources 403df8bae1dSRodney W. Grimes */ 404df8bae1dSRodney W. Grimes free((caddr_t)swp->sw_blocks, M_VMPGDATA); 405df8bae1dSRodney W. Grimes free((caddr_t)swp, M_VMPGDATA); 406df8bae1dSRodney W. Grimes free((caddr_t)pager, M_VMPAGER); 407df8bae1dSRodney W. Grimes } 408df8bae1dSRodney W. Grimes 409df8bae1dSRodney W. Grimes static int 410df8bae1dSRodney W. Grimes swap_pager_getpage(pager, mlist, npages, sync) 411df8bae1dSRodney W. Grimes vm_pager_t pager; 412df8bae1dSRodney W. Grimes vm_page_t *mlist; 413df8bae1dSRodney W. Grimes int npages; 414df8bae1dSRodney W. Grimes boolean_t sync; 415df8bae1dSRodney W. Grimes { 416df8bae1dSRodney W. Grimes #ifdef DEBUG 417df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_FOLLOW) 418df8bae1dSRodney W. Grimes printf("swpg_getpage(%x, %x, %x, %x)\n", 419df8bae1dSRodney W. Grimes pager, mlist, npages, sync); 420df8bae1dSRodney W. Grimes #endif 421df8bae1dSRodney W. Grimes return(swap_pager_io((sw_pager_t)pager->pg_data, 422df8bae1dSRodney W. Grimes mlist, npages, B_READ)); 423df8bae1dSRodney W. Grimes } 424df8bae1dSRodney W. Grimes 425df8bae1dSRodney W. Grimes static int 426df8bae1dSRodney W. Grimes swap_pager_putpage(pager, mlist, npages, sync) 427df8bae1dSRodney W. Grimes vm_pager_t pager; 428df8bae1dSRodney W. Grimes vm_page_t *mlist; 429df8bae1dSRodney W. Grimes int npages; 430df8bae1dSRodney W. Grimes boolean_t sync; 431df8bae1dSRodney W. Grimes { 432df8bae1dSRodney W. Grimes int flags; 433df8bae1dSRodney W. Grimes 434df8bae1dSRodney W. Grimes #ifdef DEBUG 435df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_FOLLOW) 436df8bae1dSRodney W. Grimes printf("swpg_putpage(%x, %x, %x, %x)\n", 437df8bae1dSRodney W. Grimes pager, mlist, npages, sync); 438df8bae1dSRodney W. Grimes #endif 439df8bae1dSRodney W. Grimes if (pager == NULL) { 440df8bae1dSRodney W. Grimes swap_pager_clean(B_WRITE); 441df8bae1dSRodney W. Grimes return (VM_PAGER_OK); /* ??? */ 442df8bae1dSRodney W. Grimes } 443df8bae1dSRodney W. Grimes flags = B_WRITE; 444df8bae1dSRodney W. Grimes if (!sync) 445df8bae1dSRodney W. Grimes flags |= B_ASYNC; 446df8bae1dSRodney W. Grimes return(swap_pager_io((sw_pager_t)pager->pg_data, 447df8bae1dSRodney W. Grimes mlist, npages, flags)); 448df8bae1dSRodney W. Grimes } 449df8bae1dSRodney W. Grimes 450df8bae1dSRodney W. Grimes static boolean_t 451df8bae1dSRodney W. Grimes swap_pager_haspage(pager, offset) 452df8bae1dSRodney W. Grimes vm_pager_t pager; 453df8bae1dSRodney W. Grimes vm_offset_t offset; 454df8bae1dSRodney W. Grimes { 455df8bae1dSRodney W. Grimes register sw_pager_t swp; 456df8bae1dSRodney W. Grimes register sw_blk_t swb; 457df8bae1dSRodney W. Grimes int ix; 458df8bae1dSRodney W. Grimes 459df8bae1dSRodney W. Grimes #ifdef DEBUG 460df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK)) 461df8bae1dSRodney W. Grimes printf("swpg_haspage(%x, %x) ", pager, offset); 462df8bae1dSRodney W. Grimes #endif 463df8bae1dSRodney W. Grimes swp = (sw_pager_t) pager->pg_data; 464df8bae1dSRodney W. Grimes ix = offset / dbtob(swp->sw_bsize); 465df8bae1dSRodney W. Grimes if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) { 466df8bae1dSRodney W. Grimes #ifdef DEBUG 467df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FAIL|SDB_FOLLOW|SDB_ALLOCBLK)) 468df8bae1dSRodney W. Grimes printf("swpg_haspage: %x bad offset %x, ix %x\n", 469df8bae1dSRodney W. Grimes swp->sw_blocks, offset, ix); 470df8bae1dSRodney W. Grimes #endif 471df8bae1dSRodney W. Grimes return(FALSE); 472df8bae1dSRodney W. Grimes } 473df8bae1dSRodney W. Grimes swb = &swp->sw_blocks[ix]; 474df8bae1dSRodney W. Grimes if (swb->swb_block) 475df8bae1dSRodney W. Grimes ix = atop(offset % dbtob(swp->sw_bsize)); 476df8bae1dSRodney W. Grimes #ifdef DEBUG 477df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_ALLOCBLK) 478df8bae1dSRodney W. Grimes printf("%x blk %x+%x ", swp->sw_blocks, swb->swb_block, ix); 479df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK)) 480df8bae1dSRodney W. Grimes printf("-> %c\n", 481df8bae1dSRodney W. Grimes "FT"[swb->swb_block && (swb->swb_mask & (1 << ix))]); 482df8bae1dSRodney W. Grimes #endif 483df8bae1dSRodney W. Grimes if (swb->swb_block && (swb->swb_mask & (1 << ix))) 484df8bae1dSRodney W. Grimes return(TRUE); 485df8bae1dSRodney W. Grimes return(FALSE); 486df8bae1dSRodney W. Grimes } 487df8bae1dSRodney W. Grimes 488df8bae1dSRodney W. Grimes static void 489df8bae1dSRodney W. Grimes swap_pager_cluster(pager, offset, loffset, hoffset) 490df8bae1dSRodney W. Grimes vm_pager_t pager; 491df8bae1dSRodney W. Grimes vm_offset_t offset; 492df8bae1dSRodney W. Grimes vm_offset_t *loffset; 493df8bae1dSRodney W. Grimes vm_offset_t *hoffset; 494df8bae1dSRodney W. Grimes { 495df8bae1dSRodney W. Grimes sw_pager_t swp; 496df8bae1dSRodney W. Grimes register int bsize; 497df8bae1dSRodney W. Grimes vm_offset_t loff, hoff; 498df8bae1dSRodney W. Grimes 499df8bae1dSRodney W. Grimes #ifdef DEBUG 500df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FOLLOW|SDB_CLUSTER)) 501df8bae1dSRodney W. Grimes printf("swpg_cluster(%x, %x) ", pager, offset); 502df8bae1dSRodney W. Grimes #endif 503df8bae1dSRodney W. Grimes swp = (sw_pager_t) pager->pg_data; 504df8bae1dSRodney W. Grimes bsize = dbtob(swp->sw_bsize); 505df8bae1dSRodney W. Grimes if (bsize > swap_pager_maxcluster) 506df8bae1dSRodney W. Grimes bsize = swap_pager_maxcluster; 507df8bae1dSRodney W. Grimes 508df8bae1dSRodney W. Grimes loff = offset - (offset % bsize); 509df8bae1dSRodney W. Grimes if (loff >= swp->sw_osize) 510df8bae1dSRodney W. Grimes panic("swap_pager_cluster: bad offset"); 511df8bae1dSRodney W. Grimes 512df8bae1dSRodney W. Grimes hoff = loff + bsize; 513df8bae1dSRodney W. Grimes if (hoff > swp->sw_osize) 514df8bae1dSRodney W. Grimes hoff = swp->sw_osize; 515df8bae1dSRodney W. Grimes 516df8bae1dSRodney W. Grimes *loffset = loff; 517df8bae1dSRodney W. Grimes *hoffset = hoff; 518df8bae1dSRodney W. Grimes #ifdef DEBUG 519df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FOLLOW|SDB_CLUSTER)) 520df8bae1dSRodney W. Grimes printf("returns [%x-%x]\n", loff, hoff); 521df8bae1dSRodney W. Grimes #endif 522df8bae1dSRodney W. Grimes } 523df8bae1dSRodney W. Grimes 524df8bae1dSRodney W. Grimes /* 525df8bae1dSRodney W. Grimes * Scaled down version of swap(). 526df8bae1dSRodney W. Grimes * Assumes that PAGE_SIZE < MAXPHYS; i.e. only one operation needed. 527df8bae1dSRodney W. Grimes * BOGUS: lower level IO routines expect a KVA so we have to map our 528df8bae1dSRodney W. Grimes * provided physical page into the KVA to keep them happy. 529df8bae1dSRodney W. Grimes */ 530df8bae1dSRodney W. Grimes static int 531df8bae1dSRodney W. Grimes swap_pager_io(swp, mlist, npages, flags) 532df8bae1dSRodney W. Grimes register sw_pager_t swp; 533df8bae1dSRodney W. Grimes vm_page_t *mlist; 534df8bae1dSRodney W. Grimes int npages; 535df8bae1dSRodney W. Grimes int flags; 536df8bae1dSRodney W. Grimes { 537df8bae1dSRodney W. Grimes register struct buf *bp; 538df8bae1dSRodney W. Grimes register sw_blk_t swb; 539df8bae1dSRodney W. Grimes register int s; 540df8bae1dSRodney W. Grimes int ix, mask; 541df8bae1dSRodney W. Grimes boolean_t rv; 542df8bae1dSRodney W. Grimes vm_offset_t kva, off; 543df8bae1dSRodney W. Grimes swp_clean_t spc; 544df8bae1dSRodney W. Grimes vm_page_t m; 545df8bae1dSRodney W. Grimes 546df8bae1dSRodney W. Grimes #ifdef DEBUG 547df8bae1dSRodney W. Grimes /* save panic time state */ 548df8bae1dSRodney W. Grimes if ((swpagerdebug & SDB_ANOMPANIC) && panicstr) 549df8bae1dSRodney W. Grimes return (VM_PAGER_FAIL); /* XXX: correct return? */ 550df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FOLLOW|SDB_IO)) 551df8bae1dSRodney W. Grimes printf("swpg_io(%x, %x, %x, %x)\n", swp, mlist, npages, flags); 552df8bae1dSRodney W. Grimes if (flags & B_READ) { 553df8bae1dSRodney W. Grimes if (flags & B_ASYNC) 554df8bae1dSRodney W. Grimes panic("swap_pager_io: cannot do ASYNC reads"); 555df8bae1dSRodney W. Grimes if (npages != 1) 556df8bae1dSRodney W. Grimes panic("swap_pager_io: cannot do clustered reads"); 557df8bae1dSRodney W. Grimes } 558df8bae1dSRodney W. Grimes #endif 559df8bae1dSRodney W. Grimes 560df8bae1dSRodney W. Grimes /* 561df8bae1dSRodney W. Grimes * First determine if the page exists in the pager if this is 562df8bae1dSRodney W. Grimes * a sync read. This quickly handles cases where we are 563df8bae1dSRodney W. Grimes * following shadow chains looking for the top level object 564df8bae1dSRodney W. Grimes * with the page. 565df8bae1dSRodney W. Grimes */ 566df8bae1dSRodney W. Grimes m = *mlist; 567df8bae1dSRodney W. Grimes off = m->offset + m->object->paging_offset; 568df8bae1dSRodney W. Grimes ix = off / dbtob(swp->sw_bsize); 569df8bae1dSRodney W. Grimes if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) { 570df8bae1dSRodney W. Grimes #ifdef DEBUG 571df8bae1dSRodney W. Grimes if ((flags & B_READ) == 0 && (swpagerdebug & SDB_ANOM)) { 572df8bae1dSRodney W. Grimes printf("swap_pager_io: no swap block on write\n"); 573df8bae1dSRodney W. Grimes return(VM_PAGER_BAD); 574df8bae1dSRodney W. Grimes } 575df8bae1dSRodney W. Grimes #endif 576df8bae1dSRodney W. Grimes return(VM_PAGER_FAIL); 577df8bae1dSRodney W. Grimes } 578df8bae1dSRodney W. Grimes swb = &swp->sw_blocks[ix]; 579df8bae1dSRodney W. Grimes off = off % dbtob(swp->sw_bsize); 580df8bae1dSRodney W. Grimes if ((flags & B_READ) && 581df8bae1dSRodney W. Grimes (swb->swb_block == 0 || (swb->swb_mask & (1 << atop(off))) == 0)) 582df8bae1dSRodney W. Grimes return(VM_PAGER_FAIL); 583df8bae1dSRodney W. Grimes 584df8bae1dSRodney W. Grimes /* 585df8bae1dSRodney W. Grimes * For reads (pageins) and synchronous writes, we clean up 586df8bae1dSRodney W. Grimes * all completed async pageouts. 587df8bae1dSRodney W. Grimes */ 588df8bae1dSRodney W. Grimes if ((flags & B_ASYNC) == 0) { 589df8bae1dSRodney W. Grimes s = splbio(); 590df8bae1dSRodney W. Grimes swap_pager_clean(flags&B_READ); 591df8bae1dSRodney W. Grimes #ifdef DEBUG 592df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_PARANOIA) 593df8bae1dSRodney W. Grimes swap_pager_clean_check(mlist, npages, flags&B_READ); 594df8bae1dSRodney W. Grimes #endif 595df8bae1dSRodney W. Grimes splx(s); 596df8bae1dSRodney W. Grimes } 597df8bae1dSRodney W. Grimes /* 598df8bae1dSRodney W. Grimes * For async writes (pageouts), we cleanup completed pageouts so 599df8bae1dSRodney W. Grimes * that all available resources are freed. Also tells us if this 600df8bae1dSRodney W. Grimes * page is already being cleaned. If it is, or no resources 601df8bae1dSRodney W. Grimes * are available, we try again later. 602df8bae1dSRodney W. Grimes */ 603df8bae1dSRodney W. Grimes else { 604df8bae1dSRodney W. Grimes swap_pager_clean(B_WRITE); 605df8bae1dSRodney W. Grimes #ifdef DEBUG 606df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_PARANOIA) 607df8bae1dSRodney W. Grimes swap_pager_clean_check(mlist, npages, B_WRITE); 608df8bae1dSRodney W. Grimes #endif 609df8bae1dSRodney W. Grimes if (swap_pager_free.tqh_first == NULL) { 610df8bae1dSRodney W. Grimes #ifdef DEBUG 611df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_FAIL) 612df8bae1dSRodney W. Grimes printf("%s: no available io headers\n", 613df8bae1dSRodney W. Grimes "swap_pager_io"); 614df8bae1dSRodney W. Grimes #endif 615df8bae1dSRodney W. Grimes return(VM_PAGER_AGAIN); 616df8bae1dSRodney W. Grimes } 617df8bae1dSRodney W. Grimes } 618df8bae1dSRodney W. Grimes 619df8bae1dSRodney W. Grimes /* 620df8bae1dSRodney W. Grimes * Allocate a swap block if necessary. 621df8bae1dSRodney W. Grimes */ 622df8bae1dSRodney W. Grimes if (swb->swb_block == 0) { 623df8bae1dSRodney W. Grimes swb->swb_block = rmalloc(swapmap, swp->sw_bsize); 624df8bae1dSRodney W. Grimes if (swb->swb_block == 0) { 625df8bae1dSRodney W. Grimes #ifdef DEBUG 626df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_FAIL) 627df8bae1dSRodney W. Grimes printf("swpg_io: rmalloc of %x failed\n", 628df8bae1dSRodney W. Grimes swp->sw_bsize); 629df8bae1dSRodney W. Grimes #endif 630df8bae1dSRodney W. Grimes /* 631df8bae1dSRodney W. Grimes * XXX this is technically a resource shortage that 632df8bae1dSRodney W. Grimes * should return AGAIN, but the situation isn't likely 633df8bae1dSRodney W. Grimes * to be remedied just by delaying a little while and 634df8bae1dSRodney W. Grimes * trying again (the pageout daemon's current response 635df8bae1dSRodney W. Grimes * to AGAIN) so we just return FAIL. 636df8bae1dSRodney W. Grimes */ 637df8bae1dSRodney W. Grimes return(VM_PAGER_FAIL); 638df8bae1dSRodney W. Grimes } 639df8bae1dSRodney W. Grimes #ifdef DEBUG 640df8bae1dSRodney W. Grimes if (swpagerdebug & (SDB_FULL|SDB_ALLOCBLK)) 641df8bae1dSRodney W. Grimes printf("swpg_io: %x alloc blk %x at ix %x\n", 642df8bae1dSRodney W. Grimes swp->sw_blocks, swb->swb_block, ix); 643df8bae1dSRodney W. Grimes #endif 644df8bae1dSRodney W. Grimes } 645df8bae1dSRodney W. Grimes 646df8bae1dSRodney W. Grimes /* 647df8bae1dSRodney W. Grimes * Allocate a kernel virtual address and initialize so that PTE 648df8bae1dSRodney W. Grimes * is available for lower level IO drivers. 649df8bae1dSRodney W. Grimes */ 650df8bae1dSRodney W. Grimes kva = vm_pager_map_pages(mlist, npages, !(flags & B_ASYNC)); 651df8bae1dSRodney W. Grimes if (kva == NULL) { 652df8bae1dSRodney W. Grimes #ifdef DEBUG 653df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_FAIL) 654df8bae1dSRodney W. Grimes printf("%s: no KVA space to map pages\n", 655df8bae1dSRodney W. Grimes "swap_pager_io"); 656df8bae1dSRodney W. Grimes #endif 657df8bae1dSRodney W. Grimes return(VM_PAGER_AGAIN); 658df8bae1dSRodney W. Grimes } 659df8bae1dSRodney W. Grimes 660df8bae1dSRodney W. Grimes /* 661df8bae1dSRodney W. Grimes * Get a swap buffer header and initialize it. 662df8bae1dSRodney W. Grimes */ 663df8bae1dSRodney W. Grimes s = splbio(); 664df8bae1dSRodney W. Grimes while (bswlist.b_actf == NULL) { 665df8bae1dSRodney W. Grimes #ifdef DEBUG 666df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_ANOM) 667df8bae1dSRodney W. Grimes printf("swap_pager_io: wait on swbuf for %x (%d)\n", 668df8bae1dSRodney W. Grimes m, flags); 669df8bae1dSRodney W. Grimes #endif 670df8bae1dSRodney W. Grimes bswlist.b_flags |= B_WANTED; 671df8bae1dSRodney W. Grimes tsleep((caddr_t)&bswlist, PSWP+1, "swpgiobuf", 0); 672df8bae1dSRodney W. Grimes } 673df8bae1dSRodney W. Grimes bp = bswlist.b_actf; 674df8bae1dSRodney W. Grimes bswlist.b_actf = bp->b_actf; 675df8bae1dSRodney W. Grimes splx(s); 676df8bae1dSRodney W. Grimes bp->b_flags = B_BUSY | (flags & B_READ); 677df8bae1dSRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 678df8bae1dSRodney W. Grimes bp->b_data = (caddr_t)kva; 679df8bae1dSRodney W. Grimes bp->b_blkno = swb->swb_block + btodb(off); 680df8bae1dSRodney W. Grimes VHOLD(swapdev_vp); 681df8bae1dSRodney W. Grimes bp->b_vp = swapdev_vp; 682df8bae1dSRodney W. Grimes if (swapdev_vp->v_type == VBLK) 683df8bae1dSRodney W. Grimes bp->b_dev = swapdev_vp->v_rdev; 684df8bae1dSRodney W. Grimes bp->b_bcount = npages * PAGE_SIZE; 685df8bae1dSRodney W. Grimes 686df8bae1dSRodney W. Grimes /* 687df8bae1dSRodney W. Grimes * For writes we set up additional buffer fields, record a pageout 688df8bae1dSRodney W. Grimes * in progress and mark that these swap blocks are now allocated. 689df8bae1dSRodney W. Grimes */ 690df8bae1dSRodney W. Grimes if ((bp->b_flags & B_READ) == 0) { 691df8bae1dSRodney W. Grimes bp->b_dirtyoff = 0; 692df8bae1dSRodney W. Grimes bp->b_dirtyend = npages * PAGE_SIZE; 693df8bae1dSRodney W. Grimes swapdev_vp->v_numoutput++; 694df8bae1dSRodney W. Grimes s = splbio(); 695df8bae1dSRodney W. Grimes swp->sw_poip++; 696df8bae1dSRodney W. Grimes splx(s); 697df8bae1dSRodney W. Grimes mask = (~(~0 << npages)) << atop(off); 698df8bae1dSRodney W. Grimes #ifdef DEBUG 699df8bae1dSRodney W. Grimes swap_pager_poip++; 700df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_WRITE) 701df8bae1dSRodney W. Grimes printf("swpg_io: write: bp=%x swp=%x poip=%d\n", 702df8bae1dSRodney W. Grimes bp, swp, swp->sw_poip); 703df8bae1dSRodney W. Grimes if ((swpagerdebug & SDB_ALLOCBLK) && 704df8bae1dSRodney W. Grimes (swb->swb_mask & mask) != mask) 705df8bae1dSRodney W. Grimes printf("swpg_io: %x write %d pages at %x+%x\n", 706df8bae1dSRodney W. Grimes swp->sw_blocks, npages, swb->swb_block, 707df8bae1dSRodney W. Grimes atop(off)); 708df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_CLUSTER) 709df8bae1dSRodney W. Grimes printf("swpg_io: off=%x, npg=%x, mask=%x, bmask=%x\n", 710df8bae1dSRodney W. Grimes off, npages, mask, swb->swb_mask); 711df8bae1dSRodney W. Grimes #endif 712df8bae1dSRodney W. Grimes swb->swb_mask |= mask; 713df8bae1dSRodney W. Grimes } 714df8bae1dSRodney W. Grimes /* 715df8bae1dSRodney W. Grimes * If this is an async write we set up still more buffer fields 716df8bae1dSRodney W. Grimes * and place a "cleaning" entry on the inuse queue. 717df8bae1dSRodney W. Grimes */ 718df8bae1dSRodney W. Grimes if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) { 719df8bae1dSRodney W. Grimes #ifdef DEBUG 720df8bae1dSRodney W. Grimes if (swap_pager_free.tqh_first == NULL) 721df8bae1dSRodney W. Grimes panic("swpg_io: lost spc"); 722df8bae1dSRodney W. Grimes #endif 723df8bae1dSRodney W. Grimes spc = swap_pager_free.tqh_first; 724df8bae1dSRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 725df8bae1dSRodney W. Grimes #ifdef DEBUG 726df8bae1dSRodney W. Grimes if (spc->spc_flags != SPC_FREE) 727df8bae1dSRodney W. Grimes panic("swpg_io: bad free spc"); 728df8bae1dSRodney W. Grimes #endif 729df8bae1dSRodney W. Grimes spc->spc_flags = SPC_BUSY; 730df8bae1dSRodney W. Grimes spc->spc_bp = bp; 731df8bae1dSRodney W. Grimes spc->spc_swp = swp; 732df8bae1dSRodney W. Grimes spc->spc_kva = kva; 733df8bae1dSRodney W. Grimes /* 734df8bae1dSRodney W. Grimes * Record the first page. This allows swap_pager_clean 735df8bae1dSRodney W. Grimes * to efficiently handle the common case of a single page. 736df8bae1dSRodney W. Grimes * For clusters, it allows us to locate the object easily 737df8bae1dSRodney W. Grimes * and we then reconstruct the rest of the mlist from spc_kva. 738df8bae1dSRodney W. Grimes */ 739df8bae1dSRodney W. Grimes spc->spc_m = m; 740df8bae1dSRodney W. Grimes spc->spc_npages = npages; 741df8bae1dSRodney W. Grimes bp->b_flags |= B_CALL; 742df8bae1dSRodney W. Grimes bp->b_iodone = swap_pager_iodone; 743df8bae1dSRodney W. Grimes s = splbio(); 744df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list); 745df8bae1dSRodney W. Grimes splx(s); 746df8bae1dSRodney W. Grimes } 747df8bae1dSRodney W. Grimes 748df8bae1dSRodney W. Grimes /* 749df8bae1dSRodney W. Grimes * Finally, start the IO operation. 750df8bae1dSRodney W. Grimes * If it is async we are all done, otherwise we must wait for 751df8bae1dSRodney W. Grimes * completion and cleanup afterwards. 752df8bae1dSRodney W. Grimes */ 753df8bae1dSRodney W. Grimes #ifdef DEBUG 754df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_IO) 755df8bae1dSRodney W. Grimes printf("swpg_io: IO start: bp %x, db %x, va %x, pa %x\n", 756df8bae1dSRodney W. Grimes bp, swb->swb_block+btodb(off), kva, VM_PAGE_TO_PHYS(m)); 757df8bae1dSRodney W. Grimes #endif 758df8bae1dSRodney W. Grimes VOP_STRATEGY(bp); 759df8bae1dSRodney W. Grimes if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) { 760df8bae1dSRodney W. Grimes #ifdef DEBUG 761df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_IO) 762df8bae1dSRodney W. Grimes printf("swpg_io: IO started: bp %x\n", bp); 763df8bae1dSRodney W. Grimes #endif 764df8bae1dSRodney W. Grimes return(VM_PAGER_PEND); 765df8bae1dSRodney W. Grimes } 766df8bae1dSRodney W. Grimes s = splbio(); 767df8bae1dSRodney W. Grimes #ifdef DEBUG 768df8bae1dSRodney W. Grimes if (flags & B_READ) 769df8bae1dSRodney W. Grimes swap_pager_piip++; 770df8bae1dSRodney W. Grimes else 771df8bae1dSRodney W. Grimes swap_pager_poip++; 772df8bae1dSRodney W. Grimes #endif 773df8bae1dSRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) 774df8bae1dSRodney W. Grimes (void) tsleep(bp, PVM, "swpgio", 0); 775df8bae1dSRodney W. Grimes if ((flags & B_READ) == 0) 776df8bae1dSRodney W. Grimes --swp->sw_poip; 777df8bae1dSRodney W. Grimes #ifdef DEBUG 778df8bae1dSRodney W. Grimes if (flags & B_READ) 779df8bae1dSRodney W. Grimes --swap_pager_piip; 780df8bae1dSRodney W. Grimes else 781df8bae1dSRodney W. Grimes --swap_pager_poip; 782df8bae1dSRodney W. Grimes #endif 783df8bae1dSRodney W. Grimes rv = (bp->b_flags & B_ERROR) ? VM_PAGER_ERROR : VM_PAGER_OK; 784df8bae1dSRodney W. Grimes bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY); 785df8bae1dSRodney W. Grimes bp->b_actf = bswlist.b_actf; 786df8bae1dSRodney W. Grimes bswlist.b_actf = bp; 787df8bae1dSRodney W. Grimes if (bp->b_vp) 788df8bae1dSRodney W. Grimes brelvp(bp); 789df8bae1dSRodney W. Grimes if (bswlist.b_flags & B_WANTED) { 790df8bae1dSRodney W. Grimes bswlist.b_flags &= ~B_WANTED; 791df8bae1dSRodney W. Grimes wakeup(&bswlist); 792df8bae1dSRodney W. Grimes } 793df8bae1dSRodney W. Grimes if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) { 794df8bae1dSRodney W. Grimes m->flags |= PG_CLEAN; 795df8bae1dSRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 796df8bae1dSRodney W. Grimes } 797df8bae1dSRodney W. Grimes splx(s); 798df8bae1dSRodney W. Grimes #ifdef DEBUG 799df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_IO) 800df8bae1dSRodney W. Grimes printf("swpg_io: IO done: bp %x, rv %d\n", bp, rv); 801df8bae1dSRodney W. Grimes if ((swpagerdebug & SDB_FAIL) && rv == VM_PAGER_ERROR) 802df8bae1dSRodney W. Grimes printf("swpg_io: IO error\n"); 803df8bae1dSRodney W. Grimes #endif 804df8bae1dSRodney W. Grimes vm_pager_unmap_pages(kva, npages); 805df8bae1dSRodney W. Grimes return(rv); 806df8bae1dSRodney W. Grimes } 807df8bae1dSRodney W. Grimes 808df8bae1dSRodney W. Grimes static void 809df8bae1dSRodney W. Grimes swap_pager_clean(rw) 810df8bae1dSRodney W. Grimes int rw; 811df8bae1dSRodney W. Grimes { 812df8bae1dSRodney W. Grimes register swp_clean_t spc; 813df8bae1dSRodney W. Grimes register int s, i; 814df8bae1dSRodney W. Grimes vm_object_t object; 815df8bae1dSRodney W. Grimes vm_page_t m; 816df8bae1dSRodney W. Grimes 817df8bae1dSRodney W. Grimes #ifdef DEBUG 818df8bae1dSRodney W. Grimes /* save panic time state */ 819df8bae1dSRodney W. Grimes if ((swpagerdebug & SDB_ANOMPANIC) && panicstr) 820df8bae1dSRodney W. Grimes return; 821df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_FOLLOW) 822df8bae1dSRodney W. Grimes printf("swpg_clean(%x)\n", rw); 823df8bae1dSRodney W. Grimes #endif 824df8bae1dSRodney W. Grimes 825df8bae1dSRodney W. Grimes for (;;) { 826df8bae1dSRodney W. Grimes /* 827df8bae1dSRodney W. Grimes * Look up and removal from inuse list must be done 828df8bae1dSRodney W. Grimes * at splbio() to avoid conflicts with swap_pager_iodone. 829df8bae1dSRodney W. Grimes */ 830df8bae1dSRodney W. Grimes s = splbio(); 831df8bae1dSRodney W. Grimes for (spc = swap_pager_inuse.tqh_first; 832df8bae1dSRodney W. Grimes spc != NULL; 833df8bae1dSRodney W. Grimes spc = spc->spc_list.tqe_next) { 834df8bae1dSRodney W. Grimes /* 835df8bae1dSRodney W. Grimes * If the operation is done, remove it from the 836df8bae1dSRodney W. Grimes * list and process it. 837df8bae1dSRodney W. Grimes * 838df8bae1dSRodney W. Grimes * XXX if we can't get the object lock we also 839df8bae1dSRodney W. Grimes * leave it on the list and try again later. 840df8bae1dSRodney W. Grimes * Is there something better we could do? 841df8bae1dSRodney W. Grimes */ 842df8bae1dSRodney W. Grimes if ((spc->spc_flags & SPC_DONE) && 843df8bae1dSRodney W. Grimes vm_object_lock_try(spc->spc_m->object)) { 844df8bae1dSRodney W. Grimes TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list); 845df8bae1dSRodney W. Grimes break; 846df8bae1dSRodney W. Grimes } 847df8bae1dSRodney W. Grimes } 848df8bae1dSRodney W. Grimes splx(s); 849df8bae1dSRodney W. Grimes 850df8bae1dSRodney W. Grimes /* 851df8bae1dSRodney W. Grimes * No operations done, thats all we can do for now. 852df8bae1dSRodney W. Grimes */ 853df8bae1dSRodney W. Grimes if (spc == NULL) 854df8bae1dSRodney W. Grimes break; 855df8bae1dSRodney W. Grimes 856df8bae1dSRodney W. Grimes /* 857df8bae1dSRodney W. Grimes * Found a completed operation so finish it off. 858df8bae1dSRodney W. Grimes * Note: no longer at splbio since entry is off the list. 859df8bae1dSRodney W. Grimes */ 860df8bae1dSRodney W. Grimes m = spc->spc_m; 861df8bae1dSRodney W. Grimes object = m->object; 862df8bae1dSRodney W. Grimes 863df8bae1dSRodney W. Grimes /* 864df8bae1dSRodney W. Grimes * Process each page in the cluster. 865df8bae1dSRodney W. Grimes * The first page is explicitly kept in the cleaning 866df8bae1dSRodney W. Grimes * entry, others must be reconstructed from the KVA. 867df8bae1dSRodney W. Grimes */ 868df8bae1dSRodney W. Grimes for (i = 0; i < spc->spc_npages; i++) { 869df8bae1dSRodney W. Grimes if (i) 870df8bae1dSRodney W. Grimes m = vm_pager_atop(spc->spc_kva + ptoa(i)); 871df8bae1dSRodney W. Grimes /* 872df8bae1dSRodney W. Grimes * If no error mark as clean and inform the pmap 873df8bae1dSRodney W. Grimes * system. If there was an error, mark as dirty 874df8bae1dSRodney W. Grimes * so we will try again. 875df8bae1dSRodney W. Grimes * 876df8bae1dSRodney W. Grimes * XXX could get stuck doing this, should give up 877df8bae1dSRodney W. Grimes * after awhile. 878df8bae1dSRodney W. Grimes */ 879df8bae1dSRodney W. Grimes if (spc->spc_flags & SPC_ERROR) { 880df8bae1dSRodney W. Grimes printf("%s: clean of page %x failed\n", 881df8bae1dSRodney W. Grimes "swap_pager_clean", 882df8bae1dSRodney W. Grimes VM_PAGE_TO_PHYS(m)); 883df8bae1dSRodney W. Grimes m->flags |= PG_LAUNDRY; 884df8bae1dSRodney W. Grimes } else { 885df8bae1dSRodney W. Grimes m->flags |= PG_CLEAN; 886df8bae1dSRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 887df8bae1dSRodney W. Grimes } 888df8bae1dSRodney W. Grimes m->flags &= ~PG_BUSY; 889df8bae1dSRodney W. Grimes PAGE_WAKEUP(m); 890df8bae1dSRodney W. Grimes } 891df8bae1dSRodney W. Grimes 892df8bae1dSRodney W. Grimes /* 893df8bae1dSRodney W. Grimes * Done with the object, decrement the paging count 894df8bae1dSRodney W. Grimes * and unlock it. 895df8bae1dSRodney W. Grimes */ 896df8bae1dSRodney W. Grimes if (--object->paging_in_progress == 0) 897df8bae1dSRodney W. Grimes wakeup(object); 898df8bae1dSRodney W. Grimes vm_object_unlock(object); 899df8bae1dSRodney W. Grimes 900df8bae1dSRodney W. Grimes /* 901df8bae1dSRodney W. Grimes * Free up KVM used and put the entry back on the list. 902df8bae1dSRodney W. Grimes */ 903df8bae1dSRodney W. Grimes vm_pager_unmap_pages(spc->spc_kva, spc->spc_npages); 904df8bae1dSRodney W. Grimes spc->spc_flags = SPC_FREE; 905df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 906df8bae1dSRodney W. Grimes #ifdef DEBUG 907df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_WRITE) 908df8bae1dSRodney W. Grimes printf("swpg_clean: free spc %x\n", spc); 909df8bae1dSRodney W. Grimes #endif 910df8bae1dSRodney W. Grimes } 911df8bae1dSRodney W. Grimes } 912df8bae1dSRodney W. Grimes 913df8bae1dSRodney W. Grimes #ifdef DEBUG 914df8bae1dSRodney W. Grimes static void 915df8bae1dSRodney W. Grimes swap_pager_clean_check(mlist, npages, rw) 916df8bae1dSRodney W. Grimes vm_page_t *mlist; 917df8bae1dSRodney W. Grimes int npages; 918df8bae1dSRodney W. Grimes int rw; 919df8bae1dSRodney W. Grimes { 920df8bae1dSRodney W. Grimes register swp_clean_t spc; 921df8bae1dSRodney W. Grimes boolean_t bad; 922df8bae1dSRodney W. Grimes int i, j, s; 923df8bae1dSRodney W. Grimes vm_page_t m; 924df8bae1dSRodney W. Grimes 925df8bae1dSRodney W. Grimes if (panicstr) 926df8bae1dSRodney W. Grimes return; 927df8bae1dSRodney W. Grimes 928df8bae1dSRodney W. Grimes bad = FALSE; 929df8bae1dSRodney W. Grimes s = splbio(); 930df8bae1dSRodney W. Grimes for (spc = swap_pager_inuse.tqh_first; 931df8bae1dSRodney W. Grimes spc != NULL; 932df8bae1dSRodney W. Grimes spc = spc->spc_list.tqe_next) { 933df8bae1dSRodney W. Grimes for (j = 0; j < spc->spc_npages; j++) { 934df8bae1dSRodney W. Grimes m = vm_pager_atop(spc->spc_kva + ptoa(j)); 935df8bae1dSRodney W. Grimes for (i = 0; i < npages; i++) 936df8bae1dSRodney W. Grimes if (m == mlist[i]) { 937df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_ANOM) 938df8bae1dSRodney W. Grimes printf( 939df8bae1dSRodney W. Grimes "swpg_clean_check: %s: page %x on list, flags %x\n", 940df8bae1dSRodney W. Grimes rw == B_WRITE ? "write" : "read", mlist[i], spc->spc_flags); 941df8bae1dSRodney W. Grimes bad = TRUE; 942df8bae1dSRodney W. Grimes } 943df8bae1dSRodney W. Grimes } 944df8bae1dSRodney W. Grimes } 945df8bae1dSRodney W. Grimes splx(s); 946df8bae1dSRodney W. Grimes if (bad) 947df8bae1dSRodney W. Grimes panic("swpg_clean_check"); 948df8bae1dSRodney W. Grimes } 949df8bae1dSRodney W. Grimes #endif 950df8bae1dSRodney W. Grimes 951df8bae1dSRodney W. Grimes static void 952df8bae1dSRodney W. Grimes swap_pager_iodone(bp) 953df8bae1dSRodney W. Grimes register struct buf *bp; 954df8bae1dSRodney W. Grimes { 955df8bae1dSRodney W. Grimes register swp_clean_t spc; 956df8bae1dSRodney W. Grimes daddr_t blk; 957df8bae1dSRodney W. Grimes int s; 958df8bae1dSRodney W. Grimes 959df8bae1dSRodney W. Grimes #ifdef DEBUG 960df8bae1dSRodney W. Grimes /* save panic time state */ 961df8bae1dSRodney W. Grimes if ((swpagerdebug & SDB_ANOMPANIC) && panicstr) 962df8bae1dSRodney W. Grimes return; 963df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_FOLLOW) 964df8bae1dSRodney W. Grimes printf("swpg_iodone(%x)\n", bp); 965df8bae1dSRodney W. Grimes #endif 966df8bae1dSRodney W. Grimes s = splbio(); 967df8bae1dSRodney W. Grimes for (spc = swap_pager_inuse.tqh_first; 968df8bae1dSRodney W. Grimes spc != NULL; 969df8bae1dSRodney W. Grimes spc = spc->spc_list.tqe_next) 970df8bae1dSRodney W. Grimes if (spc->spc_bp == bp) 971df8bae1dSRodney W. Grimes break; 972df8bae1dSRodney W. Grimes #ifdef DEBUG 973df8bae1dSRodney W. Grimes if (spc == NULL) 974df8bae1dSRodney W. Grimes panic("swap_pager_iodone: bp not found"); 975df8bae1dSRodney W. Grimes #endif 976df8bae1dSRodney W. Grimes 977df8bae1dSRodney W. Grimes spc->spc_flags &= ~SPC_BUSY; 978df8bae1dSRodney W. Grimes spc->spc_flags |= SPC_DONE; 979df8bae1dSRodney W. Grimes if (bp->b_flags & B_ERROR) 980df8bae1dSRodney W. Grimes spc->spc_flags |= SPC_ERROR; 981df8bae1dSRodney W. Grimes spc->spc_bp = NULL; 982df8bae1dSRodney W. Grimes blk = bp->b_blkno; 983df8bae1dSRodney W. Grimes 984df8bae1dSRodney W. Grimes #ifdef DEBUG 985df8bae1dSRodney W. Grimes --swap_pager_poip; 986df8bae1dSRodney W. Grimes if (swpagerdebug & SDB_WRITE) 987df8bae1dSRodney W. Grimes printf("swpg_iodone: bp=%x swp=%x flags=%x spc=%x poip=%x\n", 988df8bae1dSRodney W. Grimes bp, spc->spc_swp, spc->spc_swp->sw_flags, 989df8bae1dSRodney W. Grimes spc, spc->spc_swp->sw_poip); 990df8bae1dSRodney W. Grimes #endif 991df8bae1dSRodney W. Grimes 992df8bae1dSRodney W. Grimes spc->spc_swp->sw_poip--; 993df8bae1dSRodney W. Grimes if (spc->spc_swp->sw_flags & SW_WANTED) { 994df8bae1dSRodney W. Grimes spc->spc_swp->sw_flags &= ~SW_WANTED; 995df8bae1dSRodney W. Grimes wakeup(spc->spc_swp); 996df8bae1dSRodney W. Grimes } 997df8bae1dSRodney W. Grimes 998df8bae1dSRodney W. Grimes bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY); 999df8bae1dSRodney W. Grimes bp->b_actf = bswlist.b_actf; 1000df8bae1dSRodney W. Grimes bswlist.b_actf = bp; 1001df8bae1dSRodney W. Grimes if (bp->b_vp) 1002df8bae1dSRodney W. Grimes brelvp(bp); 1003df8bae1dSRodney W. Grimes if (bswlist.b_flags & B_WANTED) { 1004df8bae1dSRodney W. Grimes bswlist.b_flags &= ~B_WANTED; 1005df8bae1dSRodney W. Grimes wakeup(&bswlist); 1006df8bae1dSRodney W. Grimes } 1007df8bae1dSRodney W. Grimes wakeup(&vm_pages_needed); 1008df8bae1dSRodney W. Grimes splx(s); 1009df8bae1dSRodney W. Grimes } 1010