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 42ff98689dSBruce Evans * $Id: swap_pager.c,v 1.49 1995/11/14 20:53:20 phk Exp $ 43df8bae1dSRodney W. Grimes */ 44df8bae1dSRodney W. Grimes 45df8bae1dSRodney W. Grimes /* 46df8bae1dSRodney W. Grimes * Quick hack to page to dedicated partition(s). 47df8bae1dSRodney W. Grimes * TODO: 48df8bae1dSRodney W. Grimes * Add multiprocessor locks 49df8bae1dSRodney W. Grimes * Deal with async writes in a better fashion 50df8bae1dSRodney W. Grimes */ 51df8bae1dSRodney W. Grimes 52df8bae1dSRodney W. Grimes #include <sys/param.h> 53df8bae1dSRodney W. Grimes #include <sys/systm.h> 5464abb5a5SDavid Greenman #include <sys/kernel.h> 55df8bae1dSRodney W. Grimes #include <sys/proc.h> 56df8bae1dSRodney W. Grimes #include <sys/buf.h> 57df8bae1dSRodney W. Grimes #include <sys/vnode.h> 58df8bae1dSRodney W. Grimes #include <sys/malloc.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 6126f9a767SRodney W. Grimes #include <sys/rlist.h> 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes #include <vm/vm.h> 6426f9a767SRodney W. Grimes #include <vm/vm_pager.h> 65df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 66df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h> 67df8bae1dSRodney W. Grimes #include <vm/swap_pager.h> 6864abb5a5SDavid Greenman #include <vm/vm_kern.h> 69df8bae1dSRodney W. Grimes 70df8bae1dSRodney W. Grimes #ifndef NPENDINGIO 710d94caffSDavid Greenman #define NPENDINGIO 10 72df8bae1dSRodney W. Grimes #endif 73df8bae1dSRodney W. Grimes 7426f9a767SRodney W. Grimes int nswiodone; 7526f9a767SRodney W. Grimes int swap_pager_full; 7626f9a767SRodney W. Grimes extern int vm_swap_size; 77f5a12711SPoul-Henning Kamp static int no_swap_space = 1; 7835c10d22SDavid Greenman struct rlist *swaplist; 7935c10d22SDavid Greenman int nswaplist; 8026f9a767SRodney W. Grimes 8126f9a767SRodney W. Grimes #define MAX_PAGEOUT_CLUSTER 8 82df8bae1dSRodney W. Grimes 83df8bae1dSRodney W. Grimes TAILQ_HEAD(swpclean, swpagerclean); 84df8bae1dSRodney W. Grimes 8526f9a767SRodney W. Grimes typedef struct swpagerclean *swp_clean_t; 8626f9a767SRodney W. Grimes 87df8bae1dSRodney W. Grimes struct swpagerclean { 88df8bae1dSRodney W. Grimes TAILQ_ENTRY(swpagerclean) spc_list; 89df8bae1dSRodney W. Grimes int spc_flags; 90df8bae1dSRodney W. Grimes struct buf *spc_bp; 912a4895f4SDavid Greenman vm_object_t spc_object; 92df8bae1dSRodney W. Grimes vm_offset_t spc_kva; 9326f9a767SRodney W. Grimes int spc_count; 9426f9a767SRodney W. Grimes vm_page_t spc_m[MAX_PAGEOUT_CLUSTER]; 95df8bae1dSRodney W. Grimes } swcleanlist[NPENDINGIO]; 9626f9a767SRodney W. Grimes 9726f9a767SRodney W. Grimes 98df8bae1dSRodney W. Grimes /* spc_flags values */ 9926f9a767SRodney W. Grimes #define SPC_ERROR 0x01 100df8bae1dSRodney W. Grimes 10126f9a767SRodney W. Grimes #define SWB_EMPTY (-1) 102df8bae1dSRodney W. Grimes 103a401ebbeSDavid Greenman struct swpclean swap_pager_done; /* list of completed page cleans */ 104df8bae1dSRodney W. Grimes struct swpclean swap_pager_inuse; /* list of pending page cleans */ 105df8bae1dSRodney W. Grimes struct swpclean swap_pager_free; /* list of free pager clean structs */ 10624a1cce3SDavid Greenman struct pagerlst swap_pager_object_list; /* list of "named" anon region objects */ 10724a1cce3SDavid Greenman struct pagerlst swap_pager_un_object_list; /* list of "unnamed" anon region objects */ 108df8bae1dSRodney W. Grimes 10926f9a767SRodney W. Grimes #define SWAP_FREE_NEEDED 0x1 /* need a swap block */ 110a1f6d91cSDavid Greenman #define SWAP_FREE_NEEDED_BY_PAGEOUT 0x2 11126f9a767SRodney W. Grimes int swap_pager_needflags; 11226f9a767SRodney W. Grimes 113f5a12711SPoul-Henning Kamp static struct pagerlst *swp_qs[] = { 11424a1cce3SDavid Greenman &swap_pager_object_list, &swap_pager_un_object_list, (struct pagerlst *) 0 11526f9a767SRodney W. Grimes }; 11626f9a767SRodney W. Grimes 11724a1cce3SDavid Greenman /* 11824a1cce3SDavid Greenman * pagerops for OBJT_SWAP - "swap pager". 11924a1cce3SDavid Greenman */ 120ff98689dSBruce Evans static vm_object_t 121ff98689dSBruce Evans swap_pager_alloc __P((void *handle, vm_size_t size, 122ff98689dSBruce Evans vm_prot_t prot, vm_offset_t offset)); 123ff98689dSBruce Evans static void swap_pager_dealloc __P((vm_object_t object)); 124ff98689dSBruce Evans static boolean_t 125ff98689dSBruce Evans swap_pager_haspage __P((vm_object_t object, vm_offset_t offset, 126ff98689dSBruce Evans int *before, int *after)); 127ff98689dSBruce Evans static void swap_pager_init __P((void)); 128df8bae1dSRodney W. Grimes struct pagerops swappagerops = { 129df8bae1dSRodney W. Grimes swap_pager_init, 130df8bae1dSRodney W. Grimes swap_pager_alloc, 131df8bae1dSRodney W. Grimes swap_pager_dealloc, 13224a1cce3SDavid Greenman swap_pager_getpages, 13324a1cce3SDavid Greenman swap_pager_putpages, 13424a1cce3SDavid Greenman swap_pager_haspage, 13524a1cce3SDavid Greenman swap_pager_sync 136df8bae1dSRodney W. Grimes }; 137df8bae1dSRodney W. Grimes 138f5a12711SPoul-Henning Kamp static int npendingio = NPENDINGIO; 139f5a12711SPoul-Henning Kamp static void swap_pager_finish(); 14026f9a767SRodney W. Grimes int dmmin, dmmax; 14126f9a767SRodney W. Grimes 142ff98689dSBruce Evans static void swap_pager_iodone __P((struct buf *)); 14324a1cce3SDavid Greenman 1440d94caffSDavid Greenman static inline void 1450d94caffSDavid Greenman swapsizecheck() 1460d94caffSDavid Greenman { 14726f9a767SRodney W. Grimes if (vm_swap_size < 128 * btodb(PAGE_SIZE)) { 148a1f6d91cSDavid Greenman if (swap_pager_full == 0) 14926f9a767SRodney W. Grimes printf("swap_pager: out of space\n"); 15026f9a767SRodney W. Grimes swap_pager_full = 1; 15126f9a767SRodney W. Grimes } else if (vm_swap_size > 192 * btodb(PAGE_SIZE)) 15226f9a767SRodney W. Grimes swap_pager_full = 0; 15326f9a767SRodney W. Grimes } 15426f9a767SRodney W. Grimes 155f5a12711SPoul-Henning Kamp static void 156df8bae1dSRodney W. Grimes swap_pager_init() 157df8bae1dSRodney W. Grimes { 15824a1cce3SDavid Greenman TAILQ_INIT(&swap_pager_object_list); 15924a1cce3SDavid Greenman TAILQ_INIT(&swap_pager_un_object_list); 160df8bae1dSRodney W. Grimes 161df8bae1dSRodney W. Grimes /* 162df8bae1dSRodney W. Grimes * Initialize clean lists 163df8bae1dSRodney W. Grimes */ 164df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_inuse); 16526f9a767SRodney W. Grimes TAILQ_INIT(&swap_pager_done); 166df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_free); 16726f9a767SRodney W. Grimes 168df8bae1dSRodney W. Grimes /* 169df8bae1dSRodney W. Grimes * Calculate the swap allocation constants. 170df8bae1dSRodney W. Grimes */ 17126f9a767SRodney W. Grimes dmmin = CLBYTES / DEV_BSIZE; 17226f9a767SRodney W. Grimes dmmax = btodb(SWB_NPAGES * PAGE_SIZE) * 2; 173df8bae1dSRodney W. Grimes } 174df8bae1dSRodney W. Grimes 17524a1cce3SDavid Greenman void 17624a1cce3SDavid Greenman swap_pager_swap_init() 177df8bae1dSRodney W. Grimes { 17826f9a767SRodney W. Grimes swp_clean_t spc; 17926f9a767SRodney W. Grimes struct buf *bp; 18024a1cce3SDavid Greenman int i; 1810d94caffSDavid Greenman 18226f9a767SRodney W. Grimes /* 1830d94caffSDavid Greenman * kva's are allocated here so that we dont need to keep doing 1840d94caffSDavid Greenman * kmem_alloc pageables at runtime 18526f9a767SRodney W. Grimes */ 18626f9a767SRodney W. Grimes for (i = 0, spc = swcleanlist; i < npendingio; i++, spc++) { 187fff93ab6SDavid Greenman spc->spc_kva = kmem_alloc_pageable(pager_map, PAGE_SIZE * MAX_PAGEOUT_CLUSTER); 18826f9a767SRodney W. Grimes if (!spc->spc_kva) { 18926f9a767SRodney W. Grimes break; 19026f9a767SRodney W. Grimes } 191a1f6d91cSDavid Greenman spc->spc_bp = malloc(sizeof(*bp), M_TEMP, M_KERNEL); 19226f9a767SRodney W. Grimes if (!spc->spc_bp) { 19326f9a767SRodney W. Grimes kmem_free_wakeup(pager_map, spc->spc_kva, PAGE_SIZE); 19426f9a767SRodney W. Grimes break; 19526f9a767SRodney W. Grimes } 19626f9a767SRodney W. Grimes spc->spc_flags = 0; 19726f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 19826f9a767SRodney W. Grimes } 19926f9a767SRodney W. Grimes } 20024a1cce3SDavid Greenman 20124a1cce3SDavid Greenman int 20224a1cce3SDavid Greenman swap_pager_swp_alloc(object, wait) 20324a1cce3SDavid Greenman vm_object_t object; 20424a1cce3SDavid Greenman int wait; 20524a1cce3SDavid Greenman { 2062a4895f4SDavid Greenman sw_blk_t swb; 2072a4895f4SDavid Greenman int nblocks; 20824a1cce3SDavid Greenman int i, j; 20924a1cce3SDavid Greenman 2102a4895f4SDavid Greenman nblocks = (btodb(object->size) + btodb(SWB_NPAGES * PAGE_SIZE) - 1) / 2112a4895f4SDavid Greenman btodb(SWB_NPAGES * PAGE_SIZE); 21224a1cce3SDavid Greenman 2132a4895f4SDavid Greenman swb = malloc(nblocks * sizeof(*swb), M_VMPGDATA, wait); 2142a4895f4SDavid Greenman if (swb == NULL) 21524a1cce3SDavid Greenman return 1; 21624a1cce3SDavid Greenman 2172a4895f4SDavid Greenman for (i = 0; i < nblocks; i++) { 2182a4895f4SDavid Greenman swb[i].swb_valid = 0; 2192a4895f4SDavid Greenman swb[i].swb_locked = 0; 22026f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) 2212a4895f4SDavid Greenman swb[i].swb_block[j] = SWB_EMPTY; 22226f9a767SRodney W. Grimes } 22326f9a767SRodney W. Grimes 2242a4895f4SDavid Greenman object->un_pager.swp.swp_nblocks = nblocks; 2252a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize = 0; 2262a4895f4SDavid Greenman object->un_pager.swp.swp_blocks = swb; 2272a4895f4SDavid Greenman object->un_pager.swp.swp_poip = 0; 22824a1cce3SDavid Greenman 22924a1cce3SDavid Greenman if (object->handle != NULL) { 23024a1cce3SDavid Greenman TAILQ_INSERT_TAIL(&swap_pager_object_list, object, pager_object_list); 231df8bae1dSRodney W. Grimes } else { 23224a1cce3SDavid Greenman TAILQ_INSERT_TAIL(&swap_pager_un_object_list, object, pager_object_list); 233df8bae1dSRodney W. Grimes } 234df8bae1dSRodney W. Grimes 23524a1cce3SDavid Greenman return 0; 23624a1cce3SDavid Greenman } 23724a1cce3SDavid Greenman 23824a1cce3SDavid Greenman /* 2392a4895f4SDavid Greenman * Allocate an object and associated resources. 24024a1cce3SDavid Greenman * Note that if we are called from the pageout daemon (handle == NULL) 24124a1cce3SDavid Greenman * we should not wait for memory as it could resulting in deadlock. 24224a1cce3SDavid Greenman */ 243f5a12711SPoul-Henning Kamp static vm_object_t 24424a1cce3SDavid Greenman swap_pager_alloc(handle, size, prot, offset) 24524a1cce3SDavid Greenman void *handle; 24624a1cce3SDavid Greenman register vm_size_t size; 24724a1cce3SDavid Greenman vm_prot_t prot; 24824a1cce3SDavid Greenman vm_offset_t offset; 24924a1cce3SDavid Greenman { 25024a1cce3SDavid Greenman vm_object_t object; 25124a1cce3SDavid Greenman int i; 25224a1cce3SDavid Greenman 25324a1cce3SDavid Greenman /* 25424a1cce3SDavid Greenman * If this is a "named" anonymous region, look it up and use the 25524a1cce3SDavid Greenman * object if it exists, otherwise allocate a new one. 25624a1cce3SDavid Greenman */ 25724a1cce3SDavid Greenman if (handle) { 25824a1cce3SDavid Greenman object = vm_pager_object_lookup(&swap_pager_object_list, handle); 25924a1cce3SDavid Greenman if (object != NULL) { 26024a1cce3SDavid Greenman vm_object_reference(object); 26124a1cce3SDavid Greenman } else { 26224a1cce3SDavid Greenman /* 26324a1cce3SDavid Greenman * XXX - there is a race condition here. Two processes 26424a1cce3SDavid Greenman * can request the same named object simultaneuously, 26524a1cce3SDavid Greenman * and if one blocks for memory, the result is a disaster. 26624a1cce3SDavid Greenman * Probably quite rare, but is yet another reason to just 26724a1cce3SDavid Greenman * rip support of "named anonymous regions" out altogether. 26824a1cce3SDavid Greenman */ 26924a1cce3SDavid Greenman object = vm_object_allocate(OBJT_SWAP, offset + size); 27024a1cce3SDavid Greenman object->handle = handle; 27124a1cce3SDavid Greenman (void) swap_pager_swp_alloc(object, M_WAITOK); 27224a1cce3SDavid Greenman } 27324a1cce3SDavid Greenman } else { 27424a1cce3SDavid Greenman object = vm_object_allocate(OBJT_SWAP, offset + size); 27524a1cce3SDavid Greenman (void) swap_pager_swp_alloc(object, M_WAITOK); 27624a1cce3SDavid Greenman } 27724a1cce3SDavid Greenman 27824a1cce3SDavid Greenman return (object); 279df8bae1dSRodney W. Grimes } 280df8bae1dSRodney W. Grimes 28126f9a767SRodney W. Grimes /* 28226f9a767SRodney W. Grimes * returns disk block associated with pager and offset 28326f9a767SRodney W. Grimes * additionally, as a side effect returns a flag indicating 28426f9a767SRodney W. Grimes * if the block has been written 28526f9a767SRodney W. Grimes */ 28626f9a767SRodney W. Grimes 287a1f6d91cSDavid Greenman inline static int * 28824a1cce3SDavid Greenman swap_pager_diskaddr(object, offset, valid) 28924a1cce3SDavid Greenman vm_object_t object; 29026f9a767SRodney W. Grimes vm_offset_t offset; 29126f9a767SRodney W. Grimes int *valid; 29226f9a767SRodney W. Grimes { 29326f9a767SRodney W. Grimes register sw_blk_t swb; 29426f9a767SRodney W. Grimes int ix; 29526f9a767SRodney W. Grimes 29626f9a767SRodney W. Grimes if (valid) 29726f9a767SRodney W. Grimes *valid = 0; 29826f9a767SRodney W. Grimes ix = offset / (SWB_NPAGES * PAGE_SIZE); 2992a4895f4SDavid Greenman if ((ix >= object->un_pager.swp.swp_nblocks) || 30024a1cce3SDavid Greenman (offset >= object->size)) { 30126f9a767SRodney W. Grimes return (FALSE); 30226f9a767SRodney W. Grimes } 3032a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 30426f9a767SRodney W. Grimes ix = (offset % (SWB_NPAGES * PAGE_SIZE)) / PAGE_SIZE; 30526f9a767SRodney W. Grimes if (valid) 30626f9a767SRodney W. Grimes *valid = swb->swb_valid & (1 << ix); 30726f9a767SRodney W. Grimes return &swb->swb_block[ix]; 30826f9a767SRodney W. Grimes } 30926f9a767SRodney W. Grimes 31026f9a767SRodney W. Grimes /* 31126f9a767SRodney W. Grimes * Utility routine to set the valid (written) bit for 31226f9a767SRodney W. Grimes * a block associated with a pager and offset 31326f9a767SRodney W. Grimes */ 314df8bae1dSRodney W. Grimes static void 3152a4895f4SDavid Greenman swap_pager_setvalid(object, offset, valid) 3162a4895f4SDavid Greenman vm_object_t object; 31726f9a767SRodney W. Grimes vm_offset_t offset; 31826f9a767SRodney W. Grimes int valid; 31926f9a767SRodney W. Grimes { 32026f9a767SRodney W. Grimes register sw_blk_t swb; 32126f9a767SRodney W. Grimes int ix; 32226f9a767SRodney W. Grimes 32326f9a767SRodney W. Grimes ix = offset / (SWB_NPAGES * PAGE_SIZE); 3242a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) 32526f9a767SRodney W. Grimes return; 32626f9a767SRodney W. Grimes 3272a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 32826f9a767SRodney W. Grimes ix = (offset % (SWB_NPAGES * PAGE_SIZE)) / PAGE_SIZE; 32926f9a767SRodney W. Grimes if (valid) 33026f9a767SRodney W. Grimes swb->swb_valid |= (1 << ix); 33126f9a767SRodney W. Grimes else 33226f9a767SRodney W. Grimes swb->swb_valid &= ~(1 << ix); 33326f9a767SRodney W. Grimes return; 33426f9a767SRodney W. Grimes } 33526f9a767SRodney W. Grimes 33626f9a767SRodney W. Grimes /* 33726f9a767SRodney W. Grimes * this routine allocates swap space with a fragmentation 33826f9a767SRodney W. Grimes * minimization policy. 33926f9a767SRodney W. Grimes */ 340f5a12711SPoul-Henning Kamp static int 3412a4895f4SDavid Greenman swap_pager_getswapspace(object, amount, rtval) 3422a4895f4SDavid Greenman vm_object_t object; 3432a4895f4SDavid Greenman unsigned int amount; 3442a4895f4SDavid Greenman unsigned int *rtval; 3450d94caffSDavid Greenman { 34624ea4a96SDavid Greenman vm_swap_size -= amount; 34724ea4a96SDavid Greenman if (!rlist_alloc(&swaplist, amount, rtval)) { 34824ea4a96SDavid Greenman vm_swap_size += amount; 34926f9a767SRodney W. Grimes return 0; 35024ea4a96SDavid Greenman } else { 35124ea4a96SDavid Greenman swapsizecheck(); 3522a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize += amount; 35326f9a767SRodney W. Grimes return 1; 35426f9a767SRodney W. Grimes } 35526f9a767SRodney W. Grimes } 35626f9a767SRodney W. Grimes 35726f9a767SRodney W. Grimes /* 35826f9a767SRodney W. Grimes * this routine frees swap space with a fragmentation 35926f9a767SRodney W. Grimes * minimization policy. 36026f9a767SRodney W. Grimes */ 361f5a12711SPoul-Henning Kamp static void 3622a4895f4SDavid Greenman swap_pager_freeswapspace(object, from, to) 3632a4895f4SDavid Greenman vm_object_t object; 3642a4895f4SDavid Greenman unsigned int from; 3652a4895f4SDavid Greenman unsigned int to; 3660d94caffSDavid Greenman { 36735c10d22SDavid Greenman rlist_free(&swaplist, from, to); 36824ea4a96SDavid Greenman vm_swap_size += (to - from) + 1; 3692a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize -= (to - from) + 1; 37024ea4a96SDavid Greenman swapsizecheck(); 37126f9a767SRodney W. Grimes } 37226f9a767SRodney W. Grimes /* 37326f9a767SRodney W. Grimes * this routine frees swap blocks from a specified pager 37426f9a767SRodney W. Grimes */ 37526f9a767SRodney W. Grimes void 37624a1cce3SDavid Greenman swap_pager_freespace(object, start, size) 37724a1cce3SDavid Greenman vm_object_t object; 37826f9a767SRodney W. Grimes vm_offset_t start; 37926f9a767SRodney W. Grimes vm_offset_t size; 38026f9a767SRodney W. Grimes { 38126f9a767SRodney W. Grimes vm_offset_t i; 38226f9a767SRodney W. Grimes int s; 38326f9a767SRodney W. Grimes 38426f9a767SRodney W. Grimes s = splbio(); 3856f7bc393SDavid Greenman for (i = start; i < round_page(start + size); i += PAGE_SIZE) { 38626f9a767SRodney W. Grimes int valid; 38724a1cce3SDavid Greenman int *addr = swap_pager_diskaddr(object, i, &valid); 3880d94caffSDavid Greenman 38926f9a767SRodney W. Grimes if (addr && *addr != SWB_EMPTY) { 3902a4895f4SDavid Greenman swap_pager_freeswapspace(object, *addr, *addr + btodb(PAGE_SIZE) - 1); 39126f9a767SRodney W. Grimes if (valid) { 3922a4895f4SDavid Greenman swap_pager_setvalid(object, i, 0); 39326f9a767SRodney W. Grimes } 39426f9a767SRodney W. Grimes *addr = SWB_EMPTY; 39526f9a767SRodney W. Grimes } 39626f9a767SRodney W. Grimes } 39726f9a767SRodney W. Grimes splx(s); 39826f9a767SRodney W. Grimes } 39926f9a767SRodney W. Grimes 400a1f6d91cSDavid Greenman static void 4012a4895f4SDavid Greenman swap_pager_free_swap(object) 4022a4895f4SDavid Greenman vm_object_t object; 403a1f6d91cSDavid Greenman { 404a1f6d91cSDavid Greenman register int i, j; 4052a4895f4SDavid Greenman register sw_blk_t swb; 406a1f6d91cSDavid Greenman int first_block=0, block_count=0; 407a1f6d91cSDavid Greenman int s; 408a1f6d91cSDavid Greenman /* 409a1f6d91cSDavid Greenman * Free left over swap blocks 410a1f6d91cSDavid Greenman */ 411a1f6d91cSDavid Greenman s = splbio(); 4122a4895f4SDavid Greenman for (i = 0, swb = object->un_pager.swp.swp_blocks; 4132a4895f4SDavid Greenman i < object->un_pager.swp.swp_nblocks; i++, swb++) { 414a1f6d91cSDavid Greenman for (j = 0; j < SWB_NPAGES; j++) { 4152a4895f4SDavid Greenman if (swb->swb_block[j] != SWB_EMPTY) { 416a1f6d91cSDavid Greenman /* 417a1f6d91cSDavid Greenman * initially the length of the run is zero 418a1f6d91cSDavid Greenman */ 419a1f6d91cSDavid Greenman if (block_count == 0) { 4202a4895f4SDavid Greenman first_block = swb->swb_block[j]; 421a1f6d91cSDavid Greenman block_count = btodb(PAGE_SIZE); 4222a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 423a1f6d91cSDavid Greenman /* 424a1f6d91cSDavid Greenman * if the new block can be included into the current run 425a1f6d91cSDavid Greenman */ 4262a4895f4SDavid Greenman } else if (swb->swb_block[j] == first_block + block_count) { 427a1f6d91cSDavid Greenman block_count += btodb(PAGE_SIZE); 4282a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 429a1f6d91cSDavid Greenman /* 430a1f6d91cSDavid Greenman * terminate the previous run, and start a new one 431a1f6d91cSDavid Greenman */ 432a1f6d91cSDavid Greenman } else { 4332a4895f4SDavid Greenman swap_pager_freeswapspace(object, first_block, 434a1f6d91cSDavid Greenman (unsigned) first_block + block_count - 1); 4352a4895f4SDavid Greenman first_block = swb->swb_block[j]; 436a1f6d91cSDavid Greenman block_count = btodb(PAGE_SIZE); 4372a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 438a1f6d91cSDavid Greenman } 439a1f6d91cSDavid Greenman } 440a1f6d91cSDavid Greenman } 441a1f6d91cSDavid Greenman } 442a1f6d91cSDavid Greenman 443a1f6d91cSDavid Greenman if (block_count) { 4442a4895f4SDavid Greenman swap_pager_freeswapspace(object, first_block, 445a1f6d91cSDavid Greenman (unsigned) first_block + block_count - 1); 446a1f6d91cSDavid Greenman } 447a1f6d91cSDavid Greenman splx(s); 448a1f6d91cSDavid Greenman } 449a1f6d91cSDavid Greenman 450a1f6d91cSDavid Greenman 45126f9a767SRodney W. Grimes /* 45226f9a767SRodney W. Grimes * swap_pager_reclaim frees up over-allocated space from all pagers 45326f9a767SRodney W. Grimes * this eliminates internal fragmentation due to allocation of space 45426f9a767SRodney W. Grimes * for segments that are never swapped to. It has been written so that 45526f9a767SRodney W. Grimes * it does not block until the rlist_free operation occurs; it keeps 45626f9a767SRodney W. Grimes * the queues consistant. 45726f9a767SRodney W. Grimes */ 45826f9a767SRodney W. Grimes 45926f9a767SRodney W. Grimes /* 46026f9a767SRodney W. Grimes * Maximum number of blocks (pages) to reclaim per pass 46126f9a767SRodney W. Grimes */ 462a1f6d91cSDavid Greenman #define MAXRECLAIM 128 46326f9a767SRodney W. Grimes 464f5a12711SPoul-Henning Kamp static void 46526f9a767SRodney W. Grimes swap_pager_reclaim() 46626f9a767SRodney W. Grimes { 46724a1cce3SDavid Greenman vm_object_t object; 46826f9a767SRodney W. Grimes int i, j, k; 46926f9a767SRodney W. Grimes int s; 47026f9a767SRodney W. Grimes int reclaimcount; 471a1f6d91cSDavid Greenman static struct { 472a1f6d91cSDavid Greenman int address; 4732a4895f4SDavid Greenman vm_object_t object; 474a1f6d91cSDavid Greenman } reclaims[MAXRECLAIM]; 47526f9a767SRodney W. Grimes static int in_reclaim; 47626f9a767SRodney W. Grimes 47726f9a767SRodney W. Grimes /* 47826f9a767SRodney W. Grimes * allow only one process to be in the swap_pager_reclaim subroutine 47926f9a767SRodney W. Grimes */ 48026f9a767SRodney W. Grimes s = splbio(); 48126f9a767SRodney W. Grimes if (in_reclaim) { 48224a1cce3SDavid Greenman tsleep(&in_reclaim, PSWP, "swrclm", 0); 48326f9a767SRodney W. Grimes splx(s); 48426f9a767SRodney W. Grimes return; 48526f9a767SRodney W. Grimes } 48626f9a767SRodney W. Grimes in_reclaim = 1; 48726f9a767SRodney W. Grimes reclaimcount = 0; 48826f9a767SRodney W. Grimes 48926f9a767SRodney W. Grimes /* for each pager queue */ 49026f9a767SRodney W. Grimes for (k = 0; swp_qs[k]; k++) { 49126f9a767SRodney W. Grimes 49224a1cce3SDavid Greenman object = swp_qs[k]->tqh_first; 49324a1cce3SDavid Greenman while (object && (reclaimcount < MAXRECLAIM)) { 49426f9a767SRodney W. Grimes 49526f9a767SRodney W. Grimes /* 49626f9a767SRodney W. Grimes * see if any blocks associated with a pager has been 49726f9a767SRodney W. Grimes * allocated but not used (written) 49826f9a767SRodney W. Grimes */ 4992a4895f4SDavid Greenman for (i = 0; i < object->un_pager.swp.swp_nblocks; i++) { 5002a4895f4SDavid Greenman sw_blk_t swb = &object->un_pager.swp.swp_blocks[i]; 5010d94caffSDavid Greenman 50226f9a767SRodney W. Grimes if (swb->swb_locked) 50326f9a767SRodney W. Grimes continue; 50426f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) { 50526f9a767SRodney W. Grimes if (swb->swb_block[j] != SWB_EMPTY && 50626f9a767SRodney W. Grimes (swb->swb_valid & (1 << j)) == 0) { 507a1f6d91cSDavid Greenman reclaims[reclaimcount].address = swb->swb_block[j]; 5082a4895f4SDavid Greenman reclaims[reclaimcount++].object = object; 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 } 51524a1cce3SDavid Greenman object = object->pager_object_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++) { 5252a4895f4SDavid Greenman swap_pager_freeswapspace(reclaims[i].object, 5262a4895f4SDavid Greenman reclaims[i].address, reclaims[i].address + btodb(PAGE_SIZE) - 1); 52726f9a767SRodney W. Grimes } 52826f9a767SRodney W. Grimes splx(s); 52926f9a767SRodney W. Grimes in_reclaim = 0; 53024a1cce3SDavid Greenman wakeup(&in_reclaim); 53126f9a767SRodney W. Grimes } 53226f9a767SRodney W. Grimes 53326f9a767SRodney W. Grimes 53426f9a767SRodney W. Grimes /* 53526f9a767SRodney W. Grimes * swap_pager_copy copies blocks from one pager to another and 53626f9a767SRodney W. Grimes * destroys the source pager 53726f9a767SRodney W. Grimes */ 53826f9a767SRodney W. Grimes 53926f9a767SRodney W. Grimes void 54024a1cce3SDavid Greenman swap_pager_copy(srcobject, srcoffset, dstobject, dstoffset, offset) 54124a1cce3SDavid Greenman vm_object_t srcobject; 54226f9a767SRodney W. Grimes vm_offset_t srcoffset; 54324a1cce3SDavid Greenman vm_object_t dstobject; 54426f9a767SRodney W. Grimes vm_offset_t dstoffset; 54526f9a767SRodney W. Grimes vm_offset_t offset; 54626f9a767SRodney W. Grimes { 54726f9a767SRodney W. Grimes vm_offset_t i; 548a1f6d91cSDavid Greenman int origsize; 54926f9a767SRodney W. Grimes int s; 55026f9a767SRodney W. Grimes 55124ea4a96SDavid Greenman if (vm_swap_size) 55224ea4a96SDavid Greenman no_swap_space = 0; 55324ea4a96SDavid Greenman 5542a4895f4SDavid Greenman origsize = srcobject->un_pager.swp.swp_allocsize; 55526f9a767SRodney W. Grimes 55626f9a767SRodney W. Grimes /* 55724a1cce3SDavid Greenman * remove the source object from the swap_pager internal queue 55826f9a767SRodney W. Grimes */ 55924a1cce3SDavid Greenman if (srcobject->handle == NULL) { 56024a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_un_object_list, srcobject, pager_object_list); 56126f9a767SRodney W. Grimes } else { 56224a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_object_list, srcobject, pager_object_list); 56326f9a767SRodney W. Grimes } 56426f9a767SRodney W. Grimes 56524a1cce3SDavid Greenman s = splbio(); 5662a4895f4SDavid Greenman while (srcobject->un_pager.swp.swp_poip) { 5672a4895f4SDavid Greenman tsleep(srcobject, PVM, "spgout", 0); 56826f9a767SRodney W. Grimes } 56926f9a767SRodney W. Grimes splx(s); 57026f9a767SRodney W. Grimes 57126f9a767SRodney W. Grimes /* 57226f9a767SRodney W. Grimes * clean all of the pages that are currently active and finished 57326f9a767SRodney W. Grimes */ 57424a1cce3SDavid Greenman swap_pager_sync(); 57526f9a767SRodney W. Grimes 57626f9a767SRodney W. Grimes s = splbio(); 57726f9a767SRodney W. Grimes /* 57826f9a767SRodney W. Grimes * transfer source to destination 57926f9a767SRodney W. Grimes */ 58024a1cce3SDavid Greenman for (i = 0; i < dstobject->size; i += PAGE_SIZE) { 58126f9a767SRodney W. Grimes int srcvalid, dstvalid; 58224a1cce3SDavid Greenman int *srcaddrp = swap_pager_diskaddr(srcobject, i + offset + srcoffset, 58326f9a767SRodney W. Grimes &srcvalid); 58426f9a767SRodney W. Grimes int *dstaddrp; 5850d94caffSDavid Greenman 58626f9a767SRodney W. Grimes /* 58726f9a767SRodney W. Grimes * see if the source has space allocated 58826f9a767SRodney W. Grimes */ 58926f9a767SRodney W. Grimes if (srcaddrp && *srcaddrp != SWB_EMPTY) { 59026f9a767SRodney W. Grimes /* 5910d94caffSDavid Greenman * if the source is valid and the dest has no space, 5920d94caffSDavid Greenman * then copy the allocation from the srouce to the 5930d94caffSDavid Greenman * dest. 59426f9a767SRodney W. Grimes */ 59526f9a767SRodney W. Grimes if (srcvalid) { 59624a1cce3SDavid Greenman dstaddrp = swap_pager_diskaddr(dstobject, i + dstoffset, 597a1f6d91cSDavid Greenman &dstvalid); 59826f9a767SRodney W. Grimes /* 5990d94caffSDavid Greenman * if the dest already has a valid block, 6000d94caffSDavid Greenman * deallocate the source block without 6010d94caffSDavid Greenman * copying. 60226f9a767SRodney W. Grimes */ 60326f9a767SRodney W. Grimes if (!dstvalid && dstaddrp && *dstaddrp != SWB_EMPTY) { 6042a4895f4SDavid Greenman swap_pager_freeswapspace(dstobject, *dstaddrp, 605a1f6d91cSDavid Greenman *dstaddrp + btodb(PAGE_SIZE) - 1); 60626f9a767SRodney W. Grimes *dstaddrp = SWB_EMPTY; 60726f9a767SRodney W. Grimes } 60826f9a767SRodney W. Grimes if (dstaddrp && *dstaddrp == SWB_EMPTY) { 60926f9a767SRodney W. Grimes *dstaddrp = *srcaddrp; 61026f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 6112a4895f4SDavid Greenman dstobject->un_pager.swp.swp_allocsize += btodb(PAGE_SIZE); 6122a4895f4SDavid Greenman srcobject->un_pager.swp.swp_allocsize -= btodb(PAGE_SIZE); 6132a4895f4SDavid Greenman swap_pager_setvalid(dstobject, i + dstoffset, 1); 61426f9a767SRodney W. Grimes } 61526f9a767SRodney W. Grimes } 61626f9a767SRodney W. Grimes /* 6170d94caffSDavid Greenman * if the source is not empty at this point, then 6180d94caffSDavid Greenman * deallocate the space. 61926f9a767SRodney W. Grimes */ 62026f9a767SRodney W. Grimes if (*srcaddrp != SWB_EMPTY) { 6212a4895f4SDavid Greenman swap_pager_freeswapspace(srcobject, *srcaddrp, 622a1f6d91cSDavid Greenman *srcaddrp + btodb(PAGE_SIZE) - 1); 62326f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 62426f9a767SRodney W. Grimes } 62526f9a767SRodney W. Grimes } 62626f9a767SRodney W. Grimes } 62726f9a767SRodney W. Grimes splx(s); 62826f9a767SRodney W. Grimes 629a1f6d91cSDavid Greenman /* 630a1f6d91cSDavid Greenman * Free left over swap blocks 631a1f6d91cSDavid Greenman */ 6322a4895f4SDavid Greenman swap_pager_free_swap(srcobject); 633a1f6d91cSDavid Greenman 6342a4895f4SDavid Greenman if (srcobject->un_pager.swp.swp_allocsize) { 6352a4895f4SDavid Greenman printf("swap_pager_copy: *warning* pager with %d blocks (orig: %d)\n", 6362a4895f4SDavid Greenman srcobject->un_pager.swp.swp_allocsize, origsize); 6372a4895f4SDavid Greenman } 6382a4895f4SDavid Greenman 6392a4895f4SDavid Greenman free(srcobject->un_pager.swp.swp_blocks, M_VMPGDATA); 6402a4895f4SDavid Greenman srcobject->un_pager.swp.swp_blocks = NULL; 64126f9a767SRodney W. Grimes 64226f9a767SRodney W. Grimes return; 64326f9a767SRodney W. Grimes } 64426f9a767SRodney W. Grimes 645f5a12711SPoul-Henning Kamp static void 64624a1cce3SDavid Greenman swap_pager_dealloc(object) 64724a1cce3SDavid Greenman vm_object_t object; 648df8bae1dSRodney W. Grimes { 649df8bae1dSRodney W. Grimes int s; 650df8bae1dSRodney W. Grimes 651df8bae1dSRodney W. Grimes /* 6520d94caffSDavid Greenman * Remove from list right away so lookups will fail if we block for 6530d94caffSDavid Greenman * pageout completion. 654df8bae1dSRodney W. Grimes */ 65524a1cce3SDavid Greenman if (object->handle == NULL) { 65624a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_un_object_list, object, pager_object_list); 65726f9a767SRodney W. Grimes } else { 65824a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_object_list, object, pager_object_list); 659df8bae1dSRodney W. Grimes } 66024a1cce3SDavid Greenman 661df8bae1dSRodney W. Grimes /* 6620d94caffSDavid Greenman * Wait for all pageouts to finish and remove all entries from 6630d94caffSDavid Greenman * cleaning list. 664df8bae1dSRodney W. Grimes */ 66526f9a767SRodney W. Grimes 66624a1cce3SDavid Greenman s = splbio(); 6672a4895f4SDavid Greenman while (object->un_pager.swp.swp_poip) { 6682a4895f4SDavid Greenman tsleep(object, PVM, "swpout", 0); 669df8bae1dSRodney W. Grimes } 670df8bae1dSRodney W. Grimes splx(s); 67126f9a767SRodney W. Grimes 67226f9a767SRodney W. Grimes 67324a1cce3SDavid Greenman swap_pager_sync(); 674df8bae1dSRodney W. Grimes 675df8bae1dSRodney W. Grimes /* 676df8bae1dSRodney W. Grimes * Free left over swap blocks 677df8bae1dSRodney W. Grimes */ 6782a4895f4SDavid Greenman swap_pager_free_swap(object); 67926f9a767SRodney W. Grimes 6802a4895f4SDavid Greenman if (object->un_pager.swp.swp_allocsize) { 6812a4895f4SDavid Greenman printf("swap_pager_dealloc: *warning* freeing pager with %d blocks\n", 6822a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize); 6832a4895f4SDavid Greenman } 684df8bae1dSRodney W. Grimes /* 685df8bae1dSRodney W. Grimes * Free swap management resources 686df8bae1dSRodney W. Grimes */ 6872a4895f4SDavid Greenman free(object->un_pager.swp.swp_blocks, M_VMPGDATA); 6882a4895f4SDavid Greenman object->un_pager.swp.swp_blocks = NULL; 68926f9a767SRodney W. Grimes } 69026f9a767SRodney W. Grimes 69126f9a767SRodney W. Grimes static inline int 6920d94caffSDavid Greenman const 6932a4895f4SDavid Greenman swap_pager_block_index(offset) 69426f9a767SRodney W. Grimes vm_offset_t offset; 69526f9a767SRodney W. Grimes { 69626f9a767SRodney W. Grimes return (offset / (SWB_NPAGES * PAGE_SIZE)); 69726f9a767SRodney W. Grimes } 69826f9a767SRodney W. Grimes 69926f9a767SRodney W. Grimes static inline int 7000d94caffSDavid Greenman const 7012a4895f4SDavid Greenman swap_pager_block_offset(offset) 70226f9a767SRodney W. Grimes vm_offset_t offset; 70326f9a767SRodney W. Grimes { 70426f9a767SRodney W. Grimes return ((offset % (PAGE_SIZE * SWB_NPAGES)) / PAGE_SIZE); 70526f9a767SRodney W. Grimes } 70626f9a767SRodney W. Grimes 70726f9a767SRodney W. Grimes /* 70824a1cce3SDavid Greenman * swap_pager_haspage returns TRUE if the pager has data that has 70926f9a767SRodney W. Grimes * been written out. 71026f9a767SRodney W. Grimes */ 711f5a12711SPoul-Henning Kamp static boolean_t 71224a1cce3SDavid Greenman swap_pager_haspage(object, offset, before, after) 71324a1cce3SDavid Greenman vm_object_t object; 71426f9a767SRodney W. Grimes vm_offset_t offset; 71524a1cce3SDavid Greenman int *before; 71624a1cce3SDavid Greenman int *after; 71726f9a767SRodney W. Grimes { 71826f9a767SRodney W. Grimes register sw_blk_t swb; 71926f9a767SRodney W. Grimes int ix; 720170db9c6SJohn Dyson int gix; 72126f9a767SRodney W. Grimes 72224a1cce3SDavid Greenman if (before != NULL) 72324a1cce3SDavid Greenman *before = 0; 72424a1cce3SDavid Greenman if (after != NULL) 72524a1cce3SDavid Greenman *after = 0; 72626f9a767SRodney W. Grimes ix = offset / (SWB_NPAGES * PAGE_SIZE); 7272a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 72826f9a767SRodney W. Grimes return (FALSE); 72926f9a767SRodney W. Grimes } 7302a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 731170db9c6SJohn Dyson gix = offset / PAGE_SIZE; 732170db9c6SJohn Dyson ix = gix % SWB_NPAGES; 733170db9c6SJohn Dyson 73426f9a767SRodney W. Grimes if (swb->swb_block[ix] != SWB_EMPTY) { 735170db9c6SJohn Dyson 736170db9c6SJohn Dyson if (swb->swb_valid & (1 << ix)) { 737170db9c6SJohn Dyson int tix; 738170db9c6SJohn Dyson if (before) { 739170db9c6SJohn Dyson for(tix = ix - 1; tix >= 0; --tix) { 7402f82e604SDavid Greenman if ((swb->swb_valid & (1 << tix)) == 0) 7412f82e604SDavid Greenman break; 742ca56715fSJohn Dyson if ((swb->swb_block[tix] + 743170db9c6SJohn Dyson (ix - tix) * (PAGE_SIZE/DEV_BSIZE)) != 744170db9c6SJohn Dyson swb->swb_block[ix]) 745170db9c6SJohn Dyson break; 746170db9c6SJohn Dyson (*before)++; 747170db9c6SJohn Dyson } 748170db9c6SJohn Dyson } 749170db9c6SJohn Dyson 750170db9c6SJohn Dyson if (after) { 751170db9c6SJohn Dyson for(tix = ix + 1; tix < SWB_NPAGES; tix++) { 7522f82e604SDavid Greenman if ((swb->swb_valid & (1 << tix)) == 0) 7532f82e604SDavid Greenman break; 754ca56715fSJohn Dyson if ((swb->swb_block[tix] - 755170db9c6SJohn Dyson (tix - ix) * (PAGE_SIZE/DEV_BSIZE)) != 756170db9c6SJohn Dyson swb->swb_block[ix]) 757170db9c6SJohn Dyson break; 758170db9c6SJohn Dyson (*after)++; 759170db9c6SJohn Dyson } 760170db9c6SJohn Dyson } 761170db9c6SJohn Dyson 76226f9a767SRodney W. Grimes return TRUE; 76326f9a767SRodney W. Grimes } 764170db9c6SJohn Dyson } 76526f9a767SRodney W. Grimes return (FALSE); 76626f9a767SRodney W. Grimes } 76726f9a767SRodney W. Grimes 76826f9a767SRodney W. Grimes /* 76926f9a767SRodney W. Grimes * swap_pager_freepage is a convienience routine that clears the busy 77026f9a767SRodney W. Grimes * bit and deallocates a page. 771df8bae1dSRodney W. Grimes */ 77226f9a767SRodney W. Grimes static void 77326f9a767SRodney W. Grimes swap_pager_freepage(m) 77426f9a767SRodney W. Grimes vm_page_t m; 77526f9a767SRodney W. Grimes { 77626f9a767SRodney W. Grimes PAGE_WAKEUP(m); 77726f9a767SRodney W. Grimes vm_page_free(m); 77826f9a767SRodney W. Grimes } 77926f9a767SRodney W. Grimes 78026f9a767SRodney W. Grimes /* 78126f9a767SRodney W. Grimes * swap_pager_ridpages is a convienience routine that deallocates all 78226f9a767SRodney W. Grimes * but the required page. this is usually used in error returns that 78326f9a767SRodney W. Grimes * need to invalidate the "extra" readahead pages. 78426f9a767SRodney W. Grimes */ 78526f9a767SRodney W. Grimes static void 78626f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage) 78726f9a767SRodney W. Grimes vm_page_t *m; 78826f9a767SRodney W. Grimes int count; 78926f9a767SRodney W. Grimes int reqpage; 79026f9a767SRodney W. Grimes { 79126f9a767SRodney W. Grimes int i; 7920d94caffSDavid Greenman 79326f9a767SRodney W. Grimes for (i = 0; i < count; i++) 79426f9a767SRodney W. Grimes if (i != reqpage) 79526f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 79626f9a767SRodney W. Grimes } 79726f9a767SRodney W. Grimes 79826f9a767SRodney W. Grimes /* 79926f9a767SRodney W. Grimes * swap_pager_iodone1 is the completion routine for both reads and async writes 80026f9a767SRodney W. Grimes */ 801f5a12711SPoul-Henning Kamp static void 80226f9a767SRodney W. Grimes swap_pager_iodone1(bp) 80326f9a767SRodney W. Grimes struct buf *bp; 80426f9a767SRodney W. Grimes { 80526f9a767SRodney W. Grimes bp->b_flags |= B_DONE; 80626f9a767SRodney W. Grimes bp->b_flags &= ~B_ASYNC; 80724a1cce3SDavid Greenman wakeup(bp); 80826f9a767SRodney W. Grimes } 80926f9a767SRodney W. Grimes 81026f9a767SRodney W. Grimes int 81124a1cce3SDavid Greenman swap_pager_getpages(object, m, count, reqpage) 81224a1cce3SDavid Greenman vm_object_t object; 81326f9a767SRodney W. Grimes vm_page_t *m; 81426f9a767SRodney W. Grimes int count, reqpage; 815df8bae1dSRodney W. Grimes { 816df8bae1dSRodney W. Grimes register struct buf *bp; 81726f9a767SRodney W. Grimes sw_blk_t swb[count]; 818df8bae1dSRodney W. Grimes register int s; 81926f9a767SRodney W. Grimes int i; 820df8bae1dSRodney W. Grimes boolean_t rv; 82126f9a767SRodney W. Grimes vm_offset_t kva, off[count]; 822df8bae1dSRodney W. Grimes swp_clean_t spc; 82326f9a767SRodney W. Grimes vm_offset_t paging_offset; 82426f9a767SRodney W. Grimes int reqaddr[count]; 8256d40c3d3SDavid Greenman int sequential; 826df8bae1dSRodney W. Grimes 82726f9a767SRodney W. Grimes int first, last; 82826f9a767SRodney W. Grimes int failed; 82926f9a767SRodney W. Grimes int reqdskregion; 830df8bae1dSRodney W. Grimes 83126f9a767SRodney W. Grimes object = m[reqpage]->object; 83226f9a767SRodney W. Grimes paging_offset = object->paging_offset; 8336d40c3d3SDavid Greenman sequential = (m[reqpage]->offset == (object->last_read + PAGE_SIZE)); 8342a4895f4SDavid Greenman 83526f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 83626f9a767SRodney W. Grimes vm_offset_t foff = m[i]->offset + paging_offset; 8372a4895f4SDavid Greenman int ix = swap_pager_block_index(foff); 8380d94caffSDavid Greenman 8392a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 84026f9a767SRodney W. Grimes int j; 8410d94caffSDavid Greenman 84226f9a767SRodney W. Grimes if (i <= reqpage) { 84326f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 844df8bae1dSRodney W. Grimes return (VM_PAGER_FAIL); 84526f9a767SRodney W. Grimes } 84626f9a767SRodney W. Grimes for (j = i; j < count; j++) { 84726f9a767SRodney W. Grimes swap_pager_freepage(m[j]); 84826f9a767SRodney W. Grimes } 84926f9a767SRodney W. Grimes count = i; 85026f9a767SRodney W. Grimes break; 85126f9a767SRodney W. Grimes } 8522a4895f4SDavid Greenman swb[i] = &object->un_pager.swp.swp_blocks[ix]; 8532a4895f4SDavid Greenman off[i] = swap_pager_block_offset(foff); 85426f9a767SRodney W. Grimes reqaddr[i] = swb[i]->swb_block[off[i]]; 85526f9a767SRodney W. Grimes } 85626f9a767SRodney W. Grimes 85726f9a767SRodney W. Grimes /* make sure that our required input request is existant */ 85826f9a767SRodney W. Grimes 85926f9a767SRodney W. Grimes if (reqaddr[reqpage] == SWB_EMPTY || 86026f9a767SRodney W. Grimes (swb[reqpage]->swb_valid & (1 << off[reqpage])) == 0) { 86126f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 86226f9a767SRodney W. Grimes return (VM_PAGER_FAIL); 86326f9a767SRodney W. Grimes } 86426f9a767SRodney W. Grimes reqdskregion = reqaddr[reqpage] / dmmax; 865df8bae1dSRodney W. Grimes 866df8bae1dSRodney W. Grimes /* 86726f9a767SRodney W. Grimes * search backwards for the first contiguous page to transfer 868df8bae1dSRodney W. Grimes */ 86926f9a767SRodney W. Grimes failed = 0; 87026f9a767SRodney W. Grimes first = 0; 87126f9a767SRodney W. Grimes for (i = reqpage - 1; i >= 0; --i) { 8726d40c3d3SDavid Greenman if (sequential || failed || (reqaddr[i] == SWB_EMPTY) || 87326f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 87426f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 87526f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 87626f9a767SRodney W. Grimes failed = 1; 87726f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 87826f9a767SRodney W. Grimes if (first == 0) 87926f9a767SRodney W. Grimes first = i + 1; 88026f9a767SRodney W. Grimes } 881df8bae1dSRodney W. Grimes } 882df8bae1dSRodney W. Grimes /* 88326f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 884df8bae1dSRodney W. Grimes */ 88526f9a767SRodney W. Grimes failed = 0; 88626f9a767SRodney W. Grimes last = count; 88726f9a767SRodney W. Grimes for (i = reqpage + 1; i < count; i++) { 88826f9a767SRodney W. Grimes if (failed || (reqaddr[i] == SWB_EMPTY) || 88926f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 89026f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 89126f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 89226f9a767SRodney W. Grimes failed = 1; 89326f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 89426f9a767SRodney W. Grimes if (last == count) 89526f9a767SRodney W. Grimes last = i; 89626f9a767SRodney W. Grimes } 89726f9a767SRodney W. Grimes } 89826f9a767SRodney W. Grimes 89926f9a767SRodney W. Grimes count = last; 90026f9a767SRodney W. Grimes if (first != 0) { 90126f9a767SRodney W. Grimes for (i = first; i < count; i++) { 90226f9a767SRodney W. Grimes m[i - first] = m[i]; 90326f9a767SRodney W. Grimes reqaddr[i - first] = reqaddr[i]; 90426f9a767SRodney W. Grimes off[i - first] = off[i]; 90526f9a767SRodney W. Grimes } 90626f9a767SRodney W. Grimes count -= first; 90726f9a767SRodney W. Grimes reqpage -= first; 90826f9a767SRodney W. Grimes } 90926f9a767SRodney W. Grimes ++swb[reqpage]->swb_locked; 91026f9a767SRodney W. Grimes 91126f9a767SRodney W. Grimes /* 9120d94caffSDavid Greenman * at this point: "m" is a pointer to the array of vm_page_t for 9130d94caffSDavid Greenman * paging I/O "count" is the number of vm_page_t entries represented 9140d94caffSDavid Greenman * by "m" "object" is the vm_object_t for I/O "reqpage" is the index 9150d94caffSDavid Greenman * into "m" for the page actually faulted 91626f9a767SRodney W. Grimes */ 91726f9a767SRodney W. Grimes 91826f9a767SRodney W. Grimes spc = NULL; /* we might not use an spc data structure */ 91926f9a767SRodney W. Grimes 920a1f6d91cSDavid Greenman if ((count == 1) && (swap_pager_free.tqh_first != NULL)) { 92126f9a767SRodney W. Grimes /* 9220d94caffSDavid Greenman * if a kva has not been allocated, we can only do a one page 9230d94caffSDavid Greenman * transfer, so we free the other pages that might have been 9240d94caffSDavid Greenman * allocated by vm_fault. 92526f9a767SRodney W. Grimes */ 92626f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 92726f9a767SRodney W. Grimes m[0] = m[reqpage]; 92826f9a767SRodney W. Grimes reqaddr[0] = reqaddr[reqpage]; 92926f9a767SRodney W. Grimes 93026f9a767SRodney W. Grimes count = 1; 93126f9a767SRodney W. Grimes reqpage = 0; 93226f9a767SRodney W. Grimes /* 9330d94caffSDavid Greenman * get a swap pager clean data structure, block until we get 9340d94caffSDavid Greenman * it 93526f9a767SRodney W. Grimes */ 936df8bae1dSRodney W. Grimes if (swap_pager_free.tqh_first == NULL) { 937df8bae1dSRodney W. Grimes s = splbio(); 93826f9a767SRodney W. Grimes if (curproc == pageproc) 93924a1cce3SDavid Greenman swap_pager_sync(); 94026f9a767SRodney W. Grimes else 941f919ebdeSDavid Greenman pagedaemon_wakeup(); 94226f9a767SRodney W. Grimes while (swap_pager_free.tqh_first == NULL) { 94326f9a767SRodney W. Grimes swap_pager_needflags |= SWAP_FREE_NEEDED; 944a1f6d91cSDavid Greenman if (curproc == pageproc) 945a1f6d91cSDavid Greenman swap_pager_needflags |= SWAP_FREE_NEEDED_BY_PAGEOUT; 94624a1cce3SDavid Greenman tsleep(&swap_pager_free, 94726f9a767SRodney W. Grimes PVM, "swpfre", 0); 94826f9a767SRodney W. Grimes if (curproc == pageproc) 94924a1cce3SDavid Greenman swap_pager_sync(); 95026f9a767SRodney W. Grimes else 951f919ebdeSDavid Greenman pagedaemon_wakeup(); 952df8bae1dSRodney W. Grimes } 953df8bae1dSRodney W. Grimes splx(s); 95426f9a767SRodney W. Grimes } 95526f9a767SRodney W. Grimes spc = swap_pager_free.tqh_first; 95626f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 95726f9a767SRodney W. Grimes kva = spc->spc_kva; 95826f9a767SRodney W. Grimes bp = spc->spc_bp; 95926f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 96026f9a767SRodney W. Grimes bp->b_spc = spc; 9617609ab12SDavid Greenman bp->b_vnbufs.le_next = NOLIST; 96226f9a767SRodney W. Grimes } else { 96316f62314SDavid Greenman /* 96416f62314SDavid Greenman * Get a swap buffer header to perform the IO 96516f62314SDavid Greenman */ 96626f9a767SRodney W. Grimes bp = getpbuf(); 96716f62314SDavid Greenman kva = (vm_offset_t) bp->b_data; 96826f9a767SRodney W. Grimes } 96926f9a767SRodney W. Grimes 97016f62314SDavid Greenman /* 97116f62314SDavid Greenman * map our page(s) into kva for input 97216f62314SDavid Greenman */ 97316f62314SDavid Greenman pmap_qenter(kva, m, count); 97416f62314SDavid Greenman 975aba8f38eSDavid Greenman bp->b_flags = B_BUSY | B_READ | B_CALL | B_PAGING; 97626f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 977df8bae1dSRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 97826f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 97926f9a767SRodney W. Grimes crhold(bp->b_rcred); 98026f9a767SRodney W. Grimes crhold(bp->b_wcred); 98126f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva; 98226f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 98326f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE * count; 98426f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE * count; 98526f9a767SRodney W. Grimes 9860d94caffSDavid Greenman pbgetvp(swapdev_vp, bp); 987df8bae1dSRodney W. Grimes 988976e77fcSDavid Greenman cnt.v_swapin++; 989976e77fcSDavid Greenman cnt.v_swappgsin += count; 990df8bae1dSRodney W. Grimes /* 99126f9a767SRodney W. Grimes * perform the I/O 992df8bae1dSRodney W. Grimes */ 993df8bae1dSRodney W. Grimes VOP_STRATEGY(bp); 99426f9a767SRodney W. Grimes 99526f9a767SRodney W. Grimes /* 99626f9a767SRodney W. Grimes * wait for the sync I/O to complete 99726f9a767SRodney W. Grimes */ 9987609ab12SDavid Greenman s = splbio(); 99926f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 100024a1cce3SDavid Greenman tsleep(bp, PVM, "swread", 0); 1001df8bae1dSRodney W. Grimes } 10021b119d9dSDavid Greenman 10031b119d9dSDavid Greenman if (bp->b_flags & B_ERROR) { 10041b119d9dSDavid Greenman printf("swap_pager: I/O error - pagein failed; blkno %d, size %d, error %d\n", 10051b119d9dSDavid Greenman bp->b_blkno, bp->b_bcount, bp->b_error); 1006a83c285cSDavid Greenman rv = VM_PAGER_ERROR; 10071b119d9dSDavid Greenman } else { 10081b119d9dSDavid Greenman rv = VM_PAGER_OK; 10091b119d9dSDavid Greenman } 101026f9a767SRodney W. Grimes 101126f9a767SRodney W. Grimes /* 10120d94caffSDavid Greenman * relpbuf does this, but we maintain our own buffer list also... 101326f9a767SRodney W. Grimes */ 1014df8bae1dSRodney W. Grimes if (bp->b_vp) 10150d94caffSDavid Greenman pbrelvp(bp); 101626f9a767SRodney W. Grimes 1017df8bae1dSRodney W. Grimes splx(s); 10182a4895f4SDavid Greenman swb[reqpage]->swb_locked--; 101926f9a767SRodney W. Grimes 102026f9a767SRodney W. Grimes /* 102126f9a767SRodney W. Grimes * remove the mapping for kernel virtual 102226f9a767SRodney W. Grimes */ 102316f62314SDavid Greenman pmap_qremove(kva, count); 102426f9a767SRodney W. Grimes 102526f9a767SRodney W. Grimes if (spc) { 10266d40c3d3SDavid Greenman m[reqpage]->object->last_read = m[reqpage]->offset; 10270d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 102824a1cce3SDavid Greenman wakeup(bp); 102926f9a767SRodney W. Grimes /* 103026f9a767SRodney W. Grimes * if we have used an spc, we need to free it. 103126f9a767SRodney W. Grimes */ 103226f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 103326f9a767SRodney W. Grimes crfree(bp->b_rcred); 103426f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 103526f9a767SRodney W. Grimes crfree(bp->b_wcred); 103626f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 103726f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 103824a1cce3SDavid Greenman wakeup(&swap_pager_free); 103926f9a767SRodney W. Grimes } 1040a1f6d91cSDavid Greenman if (swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1041f919ebdeSDavid Greenman pagedaemon_wakeup(); 1042a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 104326f9a767SRodney W. Grimes } else { 104426f9a767SRodney W. Grimes /* 104526f9a767SRodney W. Grimes * release the physical I/O buffer 104626f9a767SRodney W. Grimes */ 104726f9a767SRodney W. Grimes relpbuf(bp); 104826f9a767SRodney W. Grimes /* 104926f9a767SRodney W. Grimes * finish up input if everything is ok 105026f9a767SRodney W. Grimes */ 105126f9a767SRodney W. Grimes if (rv == VM_PAGER_OK) { 105226f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 105326f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 10540d94caffSDavid Greenman m[i]->dirty = 0; 1055894048d7SJohn Dyson m[i]->flags &= ~PG_ZERO; 105626f9a767SRodney W. Grimes if (i != reqpage) { 105726f9a767SRodney W. Grimes /* 10580d94caffSDavid Greenman * whether or not to leave the page 10590d94caffSDavid Greenman * activated is up in the air, but we 10600d94caffSDavid Greenman * should put the page on a page queue 10610d94caffSDavid Greenman * somewhere. (it already is in the 10620d94caffSDavid Greenman * object). After some emperical 10630d94caffSDavid Greenman * results, it is best to deactivate 10640d94caffSDavid Greenman * the readahead pages. 106526f9a767SRodney W. Grimes */ 106626f9a767SRodney W. Grimes vm_page_deactivate(m[i]); 106726f9a767SRodney W. Grimes 106826f9a767SRodney W. Grimes /* 10690d94caffSDavid Greenman * just in case someone was asking for 10700d94caffSDavid Greenman * this page we now tell them that it 10710d94caffSDavid Greenman * is ok to use 107226f9a767SRodney W. Grimes */ 10730d94caffSDavid Greenman m[i]->valid = VM_PAGE_BITS_ALL; 107426f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 107526f9a767SRodney W. Grimes } 107626f9a767SRodney W. Grimes } 10776d40c3d3SDavid Greenman 10786d40c3d3SDavid Greenman m[reqpage]->object->last_read = m[count-1]->offset; 10796d40c3d3SDavid Greenman 10802e1e24ddSDavid Greenman /* 10812e1e24ddSDavid Greenman * If we're out of swap space, then attempt to free 10822e1e24ddSDavid Greenman * some whenever pages are brought in. We must clear 10832e1e24ddSDavid Greenman * the clean flag so that the page contents will be 10842e1e24ddSDavid Greenman * preserved. 10852e1e24ddSDavid Greenman */ 108626f9a767SRodney W. Grimes if (swap_pager_full) { 10872e1e24ddSDavid Greenman for (i = 0; i < count; i++) { 10880d94caffSDavid Greenman m[i]->dirty = VM_PAGE_BITS_ALL; 10892e1e24ddSDavid Greenman } 109024a1cce3SDavid Greenman swap_pager_freespace(object, m[0]->offset + paging_offset, count * PAGE_SIZE); 109126f9a767SRodney W. Grimes } 109226f9a767SRodney W. Grimes } else { 109326f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 109426f9a767SRodney W. Grimes } 109526f9a767SRodney W. Grimes } 109623922ccaSDavid Greenman if (rv == VM_PAGER_OK) { 109723922ccaSDavid Greenman pmap_clear_modify(VM_PAGE_TO_PHYS(m[reqpage])); 109823922ccaSDavid Greenman m[reqpage]->valid = VM_PAGE_BITS_ALL; 109923922ccaSDavid Greenman m[reqpage]->dirty = 0; 110023922ccaSDavid Greenman } 1101df8bae1dSRodney W. Grimes return (rv); 1102df8bae1dSRodney W. Grimes } 1103df8bae1dSRodney W. Grimes 110426f9a767SRodney W. Grimes int 110524a1cce3SDavid Greenman swap_pager_putpages(object, m, count, sync, rtvals) 110624a1cce3SDavid Greenman vm_object_t object; 110726f9a767SRodney W. Grimes vm_page_t *m; 110826f9a767SRodney W. Grimes int count; 110924a1cce3SDavid Greenman boolean_t sync; 111026f9a767SRodney W. Grimes int *rtvals; 1111df8bae1dSRodney W. Grimes { 111226f9a767SRodney W. Grimes register struct buf *bp; 111326f9a767SRodney W. Grimes sw_blk_t swb[count]; 111426f9a767SRodney W. Grimes register int s; 111526f9a767SRodney W. Grimes int i, j, ix; 111626f9a767SRodney W. Grimes boolean_t rv; 111726f9a767SRodney W. Grimes vm_offset_t kva, off, foff; 111826f9a767SRodney W. Grimes swp_clean_t spc; 111926f9a767SRodney W. Grimes vm_offset_t paging_offset; 112026f9a767SRodney W. Grimes int reqaddr[count]; 112126f9a767SRodney W. Grimes int failed; 1122df8bae1dSRodney W. Grimes 112324ea4a96SDavid Greenman if (vm_swap_size) 112424ea4a96SDavid Greenman no_swap_space = 0; 112524ea4a96SDavid Greenman if (no_swap_space) { 11265663e6deSDavid Greenman for (i = 0; i < count; i++) 11275663e6deSDavid Greenman rtvals[i] = VM_PAGER_FAIL; 11285663e6deSDavid Greenman return VM_PAGER_FAIL; 11295663e6deSDavid Greenman } 113026f9a767SRodney W. Grimes spc = NULL; 113126f9a767SRodney W. Grimes 113226f9a767SRodney W. Grimes object = m[0]->object; 113326f9a767SRodney W. Grimes paging_offset = object->paging_offset; 113426f9a767SRodney W. Grimes 113526f9a767SRodney W. Grimes failed = 0; 113626f9a767SRodney W. Grimes for (j = 0; j < count; j++) { 113726f9a767SRodney W. Grimes foff = m[j]->offset + paging_offset; 11382a4895f4SDavid Greenman ix = swap_pager_block_index(foff); 113926f9a767SRodney W. Grimes swb[j] = 0; 11402a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 114126f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 114226f9a767SRodney W. Grimes failed = 1; 114326f9a767SRodney W. Grimes continue; 114426f9a767SRodney W. Grimes } else { 114526f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_OK; 114626f9a767SRodney W. Grimes } 11472a4895f4SDavid Greenman swb[j] = &object->un_pager.swp.swp_blocks[ix]; 11482a4895f4SDavid Greenman swb[j]->swb_locked++; 114926f9a767SRodney W. Grimes if (failed) { 115026f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 115126f9a767SRodney W. Grimes continue; 115226f9a767SRodney W. Grimes } 11532a4895f4SDavid Greenman off = swap_pager_block_offset(foff); 115426f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 115526f9a767SRodney W. Grimes if (reqaddr[j] == SWB_EMPTY) { 115626f9a767SRodney W. Grimes int blk; 115726f9a767SRodney W. Grimes int tries; 115826f9a767SRodney W. Grimes int ntoget; 11590d94caffSDavid Greenman 116026f9a767SRodney W. Grimes tries = 0; 1161df8bae1dSRodney W. Grimes s = splbio(); 116226f9a767SRodney W. Grimes 1163df8bae1dSRodney W. Grimes /* 11640d94caffSDavid Greenman * if any other pages have been allocated in this 11650d94caffSDavid Greenman * block, we only try to get one page. 1166df8bae1dSRodney W. Grimes */ 116726f9a767SRodney W. Grimes for (i = 0; i < SWB_NPAGES; i++) { 116826f9a767SRodney W. Grimes if (swb[j]->swb_block[i] != SWB_EMPTY) 1169df8bae1dSRodney W. Grimes break; 1170df8bae1dSRodney W. Grimes } 117126f9a767SRodney W. Grimes 117226f9a767SRodney W. Grimes ntoget = (i == SWB_NPAGES) ? SWB_NPAGES : 1; 117326f9a767SRodney W. Grimes /* 11740d94caffSDavid Greenman * this code is alittle conservative, but works (the 11750d94caffSDavid Greenman * intent of this code is to allocate small chunks for 11760d94caffSDavid Greenman * small objects) 117726f9a767SRodney W. Grimes */ 117811fda60bSJohn Dyson if ((foff == 0) && 117911fda60bSJohn Dyson ((ntoget * PAGE_SIZE) > object->size)) { 118011fda60bSJohn Dyson ntoget = (object->size + (PAGE_SIZE - 1)) / PAGE_SIZE; 118126f9a767SRodney W. Grimes } 118226f9a767SRodney W. Grimes retrygetspace: 118326f9a767SRodney W. Grimes if (!swap_pager_full && ntoget > 1 && 11842a4895f4SDavid Greenman swap_pager_getswapspace(object, ntoget * btodb(PAGE_SIZE), &blk)) { 118526f9a767SRodney W. Grimes 118626f9a767SRodney W. Grimes for (i = 0; i < ntoget; i++) { 118726f9a767SRodney W. Grimes swb[j]->swb_block[i] = blk + btodb(PAGE_SIZE) * i; 118826f9a767SRodney W. Grimes swb[j]->swb_valid = 0; 118926f9a767SRodney W. Grimes } 119026f9a767SRodney W. Grimes 119126f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 11922a4895f4SDavid Greenman } else if (!swap_pager_getswapspace(object, btodb(PAGE_SIZE), 119326f9a767SRodney W. Grimes &swb[j]->swb_block[off])) { 119426f9a767SRodney W. Grimes /* 11950d94caffSDavid Greenman * if the allocation has failed, we try to 11960d94caffSDavid Greenman * reclaim space and retry. 119726f9a767SRodney W. Grimes */ 119826f9a767SRodney W. Grimes if (++tries == 1) { 119926f9a767SRodney W. Grimes swap_pager_reclaim(); 120026f9a767SRodney W. Grimes goto retrygetspace; 120126f9a767SRodney W. Grimes } 120226f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_AGAIN; 120326f9a767SRodney W. Grimes failed = 1; 120424ea4a96SDavid Greenman swap_pager_full = 1; 120526f9a767SRodney W. Grimes } else { 120626f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 120726f9a767SRodney W. Grimes swb[j]->swb_valid &= ~(1 << off); 1208df8bae1dSRodney W. Grimes } 1209df8bae1dSRodney W. Grimes splx(s); 121026f9a767SRodney W. Grimes } 121126f9a767SRodney W. Grimes } 121226f9a767SRodney W. Grimes 121326f9a767SRodney W. Grimes /* 121426f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 121526f9a767SRodney W. Grimes */ 121626f9a767SRodney W. Grimes failed = 0; 121726f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 121826f9a767SRodney W. Grimes if (failed || (reqaddr[i] != reqaddr[0] + i * btodb(PAGE_SIZE)) || 121926f9a767SRodney W. Grimes (reqaddr[i] / dmmax) != (reqaddr[0] / dmmax) || 122026f9a767SRodney W. Grimes (rtvals[i] != VM_PAGER_OK)) { 122126f9a767SRodney W. Grimes failed = 1; 122226f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) 122326f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 122426f9a767SRodney W. Grimes } 122526f9a767SRodney W. Grimes } 122626f9a767SRodney W. Grimes 122726f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 122826f9a767SRodney W. Grimes if (rtvals[i] != VM_PAGER_OK) { 122926f9a767SRodney W. Grimes if (swb[i]) 123026f9a767SRodney W. Grimes --swb[i]->swb_locked; 123126f9a767SRodney W. Grimes } 123226f9a767SRodney W. Grimes } 123326f9a767SRodney W. Grimes 123426f9a767SRodney W. Grimes for (i = 0; i < count; i++) 123526f9a767SRodney W. Grimes if (rtvals[i] != VM_PAGER_OK) 123626f9a767SRodney W. Grimes break; 123726f9a767SRodney W. Grimes 123826f9a767SRodney W. Grimes if (i == 0) { 123926f9a767SRodney W. Grimes return VM_PAGER_AGAIN; 124026f9a767SRodney W. Grimes } 124126f9a767SRodney W. Grimes count = i; 124226f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 124326f9a767SRodney W. Grimes if (reqaddr[i] == SWB_EMPTY) 124426f9a767SRodney W. Grimes printf("I/O to empty block????\n"); 124526f9a767SRodney W. Grimes } 124626f9a767SRodney W. Grimes 124726f9a767SRodney W. Grimes /* 12480d94caffSDavid Greenman * For synchronous writes, we clean up all completed async pageouts. 124926f9a767SRodney W. Grimes */ 125024a1cce3SDavid Greenman if (sync == TRUE) { 125124a1cce3SDavid Greenman swap_pager_sync(); 125226f9a767SRodney W. Grimes } 125326f9a767SRodney W. Grimes kva = 0; 125426f9a767SRodney W. Grimes 125526f9a767SRodney W. Grimes /* 125626f9a767SRodney W. Grimes * get a swap pager clean data structure, block until we get it 125726f9a767SRodney W. Grimes */ 1258a1f6d91cSDavid Greenman if (swap_pager_free.tqh_first == NULL || 1259a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next == NULL || 1260a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { 126126f9a767SRodney W. Grimes s = splbio(); 12620d94caffSDavid Greenman if (curproc == pageproc) { 126324a1cce3SDavid Greenman swap_pager_sync(); 1264a1f6d91cSDavid Greenman #if 0 12650d94caffSDavid Greenman splx(s); 12660d94caffSDavid Greenman return VM_PAGER_AGAIN; 1267a1f6d91cSDavid Greenman #endif 12680d94caffSDavid Greenman } else 1269f919ebdeSDavid Greenman pagedaemon_wakeup(); 1270a1f6d91cSDavid Greenman while (swap_pager_free.tqh_first == NULL || 1271a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next == NULL || 1272a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { 1273a1f6d91cSDavid Greenman if (curproc == pageproc) { 1274a1f6d91cSDavid Greenman swap_pager_needflags |= SWAP_FREE_NEEDED_BY_PAGEOUT; 1275a1f6d91cSDavid Greenman if((cnt.v_free_count + cnt.v_cache_count) > cnt.v_free_reserved) 127624a1cce3SDavid Greenman wakeup(&cnt.v_free_count); 1277a1f6d91cSDavid Greenman } 12780d94caffSDavid Greenman 127926f9a767SRodney W. Grimes swap_pager_needflags |= SWAP_FREE_NEEDED; 128024a1cce3SDavid Greenman tsleep(&swap_pager_free, PVM, "swpfre", 0); 128126f9a767SRodney W. Grimes if (curproc == pageproc) 128224a1cce3SDavid Greenman swap_pager_sync(); 128326f9a767SRodney W. Grimes else 1284f919ebdeSDavid Greenman pagedaemon_wakeup(); 128526f9a767SRodney W. Grimes } 128626f9a767SRodney W. Grimes splx(s); 128726f9a767SRodney W. Grimes } 128826f9a767SRodney W. Grimes spc = swap_pager_free.tqh_first; 128926f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 1290fff93ab6SDavid Greenman 129126f9a767SRodney W. Grimes kva = spc->spc_kva; 129226f9a767SRodney W. Grimes 129326f9a767SRodney W. Grimes /* 129426f9a767SRodney W. Grimes * map our page(s) into kva for I/O 129526f9a767SRodney W. Grimes */ 129616f62314SDavid Greenman pmap_qenter(kva, m, count); 129726f9a767SRodney W. Grimes 129826f9a767SRodney W. Grimes /* 129926f9a767SRodney W. Grimes * get the base I/O offset into the swap file 130026f9a767SRodney W. Grimes */ 130126f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 130226f9a767SRodney W. Grimes foff = m[i]->offset + paging_offset; 13032a4895f4SDavid Greenman off = swap_pager_block_offset(foff); 130426f9a767SRodney W. Grimes /* 130526f9a767SRodney W. Grimes * set the valid bit 130626f9a767SRodney W. Grimes */ 130726f9a767SRodney W. Grimes swb[i]->swb_valid |= (1 << off); 130826f9a767SRodney W. Grimes /* 130926f9a767SRodney W. Grimes * and unlock the data structure 131026f9a767SRodney W. Grimes */ 13112a4895f4SDavid Greenman swb[i]->swb_locked--; 131226f9a767SRodney W. Grimes } 131326f9a767SRodney W. Grimes 131426f9a767SRodney W. Grimes /* 131526f9a767SRodney W. Grimes * Get a swap buffer header and perform the IO 131626f9a767SRodney W. Grimes */ 131726f9a767SRodney W. Grimes bp = spc->spc_bp; 131826f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 131926f9a767SRodney W. Grimes bp->b_spc = spc; 13207609ab12SDavid Greenman bp->b_vnbufs.le_next = NOLIST; 132126f9a767SRodney W. Grimes 1322aba8f38eSDavid Greenman bp->b_flags = B_BUSY | B_PAGING; 132326f9a767SRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 132426f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 1325a481f200SDavid Greenman if (bp->b_rcred != NOCRED) 132626f9a767SRodney W. Grimes crhold(bp->b_rcred); 1327a481f200SDavid Greenman if (bp->b_wcred != NOCRED) 132826f9a767SRodney W. Grimes crhold(bp->b_wcred); 1329a481f200SDavid Greenman bp->b_data = (caddr_t) kva; 133026f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 13310d94caffSDavid Greenman pbgetvp(swapdev_vp, bp); 133216f62314SDavid Greenman 133326f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE * count; 133426f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE * count; 133526f9a767SRodney W. Grimes swapdev_vp->v_numoutput++; 133626f9a767SRodney W. Grimes 133726f9a767SRodney W. Grimes /* 13380d94caffSDavid Greenman * If this is an async write we set up additional buffer fields and 13390d94caffSDavid Greenman * place a "cleaning" entry on the inuse queue. 134026f9a767SRodney W. Grimes */ 13417609ab12SDavid Greenman s = splbio(); 134224a1cce3SDavid Greenman if (sync == FALSE) { 134326f9a767SRodney W. Grimes spc->spc_flags = 0; 13442a4895f4SDavid Greenman spc->spc_object = object; 134526f9a767SRodney W. Grimes for (i = 0; i < count; i++) 134626f9a767SRodney W. Grimes spc->spc_m[i] = m[i]; 134726f9a767SRodney W. Grimes spc->spc_count = count; 134826f9a767SRodney W. Grimes /* 134926f9a767SRodney W. Grimes * the completion routine for async writes 135026f9a767SRodney W. Grimes */ 135126f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 135226f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone; 135326f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 135426f9a767SRodney W. Grimes bp->b_dirtyend = bp->b_bcount; 13552a4895f4SDavid Greenman object->un_pager.swp.swp_poip++; 135626f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list); 135726f9a767SRodney W. Grimes } else { 13582a4895f4SDavid Greenman object->un_pager.swp.swp_poip++; 135926f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 136026f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 136126f9a767SRodney W. Grimes } 1362976e77fcSDavid Greenman 1363976e77fcSDavid Greenman cnt.v_swapout++; 1364976e77fcSDavid Greenman cnt.v_swappgsout += count; 136526f9a767SRodney W. Grimes /* 136626f9a767SRodney W. Grimes * perform the I/O 136726f9a767SRodney W. Grimes */ 136826f9a767SRodney W. Grimes VOP_STRATEGY(bp); 136924a1cce3SDavid Greenman if (sync == FALSE) { 137026f9a767SRodney W. Grimes if ((bp->b_flags & B_DONE) == B_DONE) { 137124a1cce3SDavid Greenman swap_pager_sync(); 137226f9a767SRodney W. Grimes } 137326f9a767SRodney W. Grimes splx(s); 137426f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 137526f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_PEND; 137626f9a767SRodney W. Grimes } 137726f9a767SRodney W. Grimes return VM_PAGER_PEND; 137826f9a767SRodney W. Grimes } 137926f9a767SRodney W. Grimes /* 138026f9a767SRodney W. Grimes * wait for the sync I/O to complete 138126f9a767SRodney W. Grimes */ 138226f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 138324a1cce3SDavid Greenman tsleep(bp, PVM, "swwrt", 0); 138426f9a767SRodney W. Grimes } 13851b119d9dSDavid Greenman if (bp->b_flags & B_ERROR) { 13861b119d9dSDavid Greenman printf("swap_pager: I/O error - pageout failed; blkno %d, size %d, error %d\n", 13871b119d9dSDavid Greenman bp->b_blkno, bp->b_bcount, bp->b_error); 1388a83c285cSDavid Greenman rv = VM_PAGER_ERROR; 13891b119d9dSDavid Greenman } else { 13901b119d9dSDavid Greenman rv = VM_PAGER_OK; 13911b119d9dSDavid Greenman } 139226f9a767SRodney W. Grimes 13932a4895f4SDavid Greenman object->un_pager.swp.swp_poip--; 13942a4895f4SDavid Greenman if (object->un_pager.swp.swp_poip == 0) 13952a4895f4SDavid Greenman wakeup(object); 139626f9a767SRodney W. Grimes 139726f9a767SRodney W. Grimes if (bp->b_vp) 13980d94caffSDavid Greenman pbrelvp(bp); 13990d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 140024a1cce3SDavid Greenman wakeup(bp); 140126f9a767SRodney W. Grimes 140226f9a767SRodney W. Grimes splx(s); 140326f9a767SRodney W. Grimes 140426f9a767SRodney W. Grimes /* 140526f9a767SRodney W. Grimes * remove the mapping for kernel virtual 140626f9a767SRodney W. Grimes */ 140716f62314SDavid Greenman pmap_qremove(kva, count); 140826f9a767SRodney W. Grimes 140926f9a767SRodney W. Grimes /* 14100d94caffSDavid Greenman * if we have written the page, then indicate that the page is clean. 141126f9a767SRodney W. Grimes */ 141226f9a767SRodney W. Grimes if (rv == VM_PAGER_OK) { 141326f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 141426f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) { 141526f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 14160d94caffSDavid Greenman m[i]->dirty = 0; 141726f9a767SRodney W. Grimes /* 14180d94caffSDavid Greenman * optimization, if a page has been read 14190d94caffSDavid Greenman * during the pageout process, we activate it. 142026f9a767SRodney W. Grimes */ 142126f9a767SRodney W. Grimes if ((m[i]->flags & PG_ACTIVE) == 0 && 14227fb0c17eSDavid Greenman ((m[i]->flags & (PG_WANTED|PG_REFERENCED)) || 14237fb0c17eSDavid Greenman pmap_is_referenced(VM_PAGE_TO_PHYS(m[i])))) { 142426f9a767SRodney W. Grimes vm_page_activate(m[i]); 142526f9a767SRodney W. Grimes } 142626f9a767SRodney W. Grimes } 14277fb0c17eSDavid Greenman } 142826f9a767SRodney W. Grimes } else { 142926f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 143026f9a767SRodney W. Grimes rtvals[i] = rv; 143126f9a767SRodney W. Grimes } 143226f9a767SRodney W. Grimes } 143326f9a767SRodney W. Grimes 143426f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 143526f9a767SRodney W. Grimes crfree(bp->b_rcred); 143626f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 143726f9a767SRodney W. Grimes crfree(bp->b_wcred); 143826f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 143926f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 144024a1cce3SDavid Greenman wakeup(&swap_pager_free); 144126f9a767SRodney W. Grimes } 1442a1f6d91cSDavid Greenman if (swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1443f919ebdeSDavid Greenman pagedaemon_wakeup(); 1444a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 144526f9a767SRodney W. Grimes return (rv); 144626f9a767SRodney W. Grimes } 144726f9a767SRodney W. Grimes 144824a1cce3SDavid Greenman void 144924a1cce3SDavid Greenman swap_pager_sync() 145026f9a767SRodney W. Grimes { 145126f9a767SRodney W. Grimes register swp_clean_t spc, tspc; 145226f9a767SRodney W. Grimes register int s; 145326f9a767SRodney W. Grimes 145426f9a767SRodney W. Grimes tspc = NULL; 145526f9a767SRodney W. Grimes if (swap_pager_done.tqh_first == NULL) 145624a1cce3SDavid Greenman return; 145726f9a767SRodney W. Grimes for (;;) { 145826f9a767SRodney W. Grimes s = splbio(); 145926f9a767SRodney W. Grimes /* 14600d94caffSDavid Greenman * Look up and removal from done list must be done at splbio() 14610d94caffSDavid Greenman * to avoid conflicts with swap_pager_iodone. 146226f9a767SRodney W. Grimes */ 146305f0fdd2SPoul-Henning Kamp while ((spc = swap_pager_done.tqh_first) != 0) { 1464fff93ab6SDavid Greenman pmap_qremove(spc->spc_kva, spc->spc_count); 146526f9a767SRodney W. Grimes swap_pager_finish(spc); 146626f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_done, spc, spc_list); 146726f9a767SRodney W. Grimes goto doclean; 146826f9a767SRodney W. Grimes } 1469df8bae1dSRodney W. Grimes 1470df8bae1dSRodney W. Grimes /* 1471df8bae1dSRodney W. Grimes * No operations done, thats all we can do for now. 1472df8bae1dSRodney W. Grimes */ 147326f9a767SRodney W. Grimes 147426f9a767SRodney W. Grimes splx(s); 1475df8bae1dSRodney W. Grimes break; 1476df8bae1dSRodney W. Grimes 1477df8bae1dSRodney W. Grimes /* 14780d94caffSDavid Greenman * The desired page was found to be busy earlier in the scan 14790d94caffSDavid Greenman * but has since completed. 1480df8bae1dSRodney W. Grimes */ 148126f9a767SRodney W. Grimes doclean: 148226f9a767SRodney W. Grimes if (tspc && tspc == spc) { 148326f9a767SRodney W. Grimes tspc = NULL; 148426f9a767SRodney W. Grimes } 148526f9a767SRodney W. Grimes spc->spc_flags = 0; 148626f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 148726f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 148824a1cce3SDavid Greenman wakeup(&swap_pager_free); 148926f9a767SRodney W. Grimes } 1490a1f6d91cSDavid Greenman if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1491f919ebdeSDavid Greenman pagedaemon_wakeup(); 1492a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 149326f9a767SRodney W. Grimes splx(s); 149426f9a767SRodney W. Grimes } 149526f9a767SRodney W. Grimes 149624a1cce3SDavid Greenman return; 149726f9a767SRodney W. Grimes } 149826f9a767SRodney W. Grimes 149926f9a767SRodney W. Grimes void 150026f9a767SRodney W. Grimes swap_pager_finish(spc) 150126f9a767SRodney W. Grimes register swp_clean_t spc; 150226f9a767SRodney W. Grimes { 150326f9a767SRodney W. Grimes vm_object_t object = spc->spc_m[0]->object; 150426f9a767SRodney W. Grimes int i; 150526f9a767SRodney W. Grimes 1506c0503609SDavid Greenman object->paging_in_progress -= spc->spc_count; 1507c0503609SDavid Greenman if ((object->paging_in_progress == 0) && 1508c0503609SDavid Greenman (object->flags & OBJ_PIPWNT)) { 1509c0503609SDavid Greenman object->flags &= ~OBJ_PIPWNT; 151024a1cce3SDavid Greenman wakeup(object); 1511c0503609SDavid Greenman } 1512df8bae1dSRodney W. Grimes 1513df8bae1dSRodney W. Grimes /* 15145f55e841SDavid Greenman * If no error, mark as clean and inform the pmap system. If error, 15150d94caffSDavid Greenman * mark as dirty so we will try again. (XXX could get stuck doing 15160d94caffSDavid Greenman * this, should give up after awhile) 1517df8bae1dSRodney W. Grimes */ 1518df8bae1dSRodney W. Grimes if (spc->spc_flags & SPC_ERROR) { 151926f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 1520a83c285cSDavid Greenman printf("swap_pager_finish: I/O error, clean of page %lx failed\n", 152105f0fdd2SPoul-Henning Kamp (u_long) VM_PAGE_TO_PHYS(spc->spc_m[i])); 152226f9a767SRodney W. Grimes } 1523df8bae1dSRodney W. Grimes } else { 152426f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 152526f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m[i])); 15260d94caffSDavid Greenman spc->spc_m[i]->dirty = 0; 15270d94caffSDavid Greenman if ((spc->spc_m[i]->flags & PG_ACTIVE) == 0 && 15280d94caffSDavid Greenman ((spc->spc_m[i]->flags & PG_WANTED) || pmap_is_referenced(VM_PAGE_TO_PHYS(spc->spc_m[i])))) 15290d94caffSDavid Greenman vm_page_activate(spc->spc_m[i]); 1530df8bae1dSRodney W. Grimes } 1531df8bae1dSRodney W. Grimes } 1532df8bae1dSRodney W. Grimes 153326f9a767SRodney W. Grimes 153426f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 1535df8bae1dSRodney W. Grimes /* 15360d94caffSDavid Greenman * we wakeup any processes that are waiting on these pages. 1537df8bae1dSRodney W. Grimes */ 153826f9a767SRodney W. Grimes PAGE_WAKEUP(spc->spc_m[i]); 1539df8bae1dSRodney W. Grimes } 154026f9a767SRodney W. Grimes nswiodone -= spc->spc_count; 1541df8bae1dSRodney W. Grimes 1542df8bae1dSRodney W. Grimes return; 154326f9a767SRodney W. Grimes } 1544df8bae1dSRodney W. Grimes 154526f9a767SRodney W. Grimes /* 154626f9a767SRodney W. Grimes * swap_pager_iodone 154726f9a767SRodney W. Grimes */ 1548f5a12711SPoul-Henning Kamp static void 1549df8bae1dSRodney W. Grimes swap_pager_iodone(bp) 1550df8bae1dSRodney W. Grimes register struct buf *bp; 1551df8bae1dSRodney W. Grimes { 1552df8bae1dSRodney W. Grimes register swp_clean_t spc; 1553df8bae1dSRodney W. Grimes int s; 1554df8bae1dSRodney W. Grimes 1555df8bae1dSRodney W. Grimes s = splbio(); 155626f9a767SRodney W. Grimes spc = (swp_clean_t) bp->b_spc; 155726f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list); 155826f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_done, spc, spc_list); 155926f9a767SRodney W. Grimes if (bp->b_flags & B_ERROR) { 1560df8bae1dSRodney W. Grimes spc->spc_flags |= SPC_ERROR; 1561c3a1e425SDavid Greenman printf("swap_pager: I/O error - async %s failed; blkno %lu, size %ld, error %d\n", 15621b119d9dSDavid Greenman (bp->b_flags & B_READ) ? "pagein" : "pageout", 1563c3a1e425SDavid Greenman (u_long) bp->b_blkno, bp->b_bcount, bp->b_error); 1564df8bae1dSRodney W. Grimes } 156526f9a767SRodney W. Grimes 15660d94caffSDavid Greenman if (bp->b_vp) 15670d94caffSDavid Greenman pbrelvp(bp); 15680d94caffSDavid Greenman 15690d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 157024a1cce3SDavid Greenman wakeup(bp); 15710d94caffSDavid Greenman 157226f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 157326f9a767SRodney W. Grimes crfree(bp->b_rcred); 157426f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 157526f9a767SRodney W. Grimes crfree(bp->b_wcred); 157626f9a767SRodney W. Grimes 157726f9a767SRodney W. Grimes nswiodone += spc->spc_count; 15782a4895f4SDavid Greenman if (--spc->spc_object->un_pager.swp.swp_poip == 0) { 15792a4895f4SDavid Greenman wakeup(spc->spc_object); 158026f9a767SRodney W. Grimes } 158126f9a767SRodney W. Grimes if ((swap_pager_needflags & SWAP_FREE_NEEDED) || 158226f9a767SRodney W. Grimes swap_pager_inuse.tqh_first == 0) { 158326f9a767SRodney W. Grimes swap_pager_needflags &= ~SWAP_FREE_NEEDED; 158424a1cce3SDavid Greenman wakeup(&swap_pager_free); 1585a1f6d91cSDavid Greenman } 1586a1f6d91cSDavid Greenman 1587a1f6d91cSDavid Greenman if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) { 1588a1f6d91cSDavid Greenman swap_pager_needflags &= ~SWAP_FREE_NEEDED_BY_PAGEOUT; 1589f919ebdeSDavid Greenman pagedaemon_wakeup(); 159026f9a767SRodney W. Grimes } 1591a1f6d91cSDavid Greenman 159226f9a767SRodney W. Grimes if (vm_pageout_pages_needed) { 159324a1cce3SDavid Greenman wakeup(&vm_pageout_pages_needed); 1594a1f6d91cSDavid Greenman vm_pageout_pages_needed = 0; 159526f9a767SRodney W. Grimes } 159626f9a767SRodney W. Grimes if ((swap_pager_inuse.tqh_first == NULL) || 15970d94caffSDavid Greenman ((cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min && 15980d94caffSDavid Greenman nswiodone + cnt.v_free_count + cnt.v_cache_count >= cnt.v_free_min)) { 1599f919ebdeSDavid Greenman pagedaemon_wakeup(); 160026f9a767SRodney W. Grimes } 160126f9a767SRodney W. Grimes splx(s); 160226f9a767SRodney W. Grimes } 160326f9a767SRodney W. Grimes 160426f9a767SRodney W. Grimes /* 160526f9a767SRodney W. Grimes * return true if any swap control structures can be allocated 160626f9a767SRodney W. Grimes */ 160726f9a767SRodney W. Grimes int 16080d94caffSDavid Greenman swap_pager_ready() 16090d94caffSDavid Greenman { 161026f9a767SRodney W. Grimes if (swap_pager_free.tqh_first) 161126f9a767SRodney W. Grimes return 1; 161226f9a767SRodney W. Grimes else 161326f9a767SRodney W. Grimes return 0; 161426f9a767SRodney W. Grimes } 1615