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 421af87c92SDavid Greenman * $Id: swap_pager.c,v 1.59 1996/01/19 03:59:41 dyson Exp $ 43df8bae1dSRodney W. Grimes */ 44df8bae1dSRodney W. Grimes 45df8bae1dSRodney W. Grimes /* 46df8bae1dSRodney W. Grimes * Quick hack to page to dedicated partition(s). 47df8bae1dSRodney W. Grimes * TODO: 48df8bae1dSRodney W. Grimes * Add multiprocessor locks 49df8bae1dSRodney W. Grimes * Deal with async writes in a better fashion 50df8bae1dSRodney W. Grimes */ 51df8bae1dSRodney W. Grimes 52df8bae1dSRodney W. Grimes #include <sys/param.h> 53df8bae1dSRodney W. Grimes #include <sys/systm.h> 5464abb5a5SDavid Greenman #include <sys/kernel.h> 55df8bae1dSRodney W. Grimes #include <sys/proc.h> 56df8bae1dSRodney W. Grimes #include <sys/buf.h> 57df8bae1dSRodney W. Grimes #include <sys/vnode.h> 58df8bae1dSRodney W. Grimes #include <sys/malloc.h> 59efeaf95aSDavid Greenman #include <sys/vmmeter.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 6226f9a767SRodney W. Grimes #include <sys/rlist.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #include <vm/vm.h> 65efeaf95aSDavid Greenman #include <vm/vm_param.h> 66efeaf95aSDavid Greenman #include <vm/vm_prot.h> 67efeaf95aSDavid Greenman #include <vm/vm_object.h> 68df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 69efeaf95aSDavid Greenman #include <vm/vm_pager.h> 70df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h> 71df8bae1dSRodney W. Grimes #include <vm/swap_pager.h> 7264abb5a5SDavid Greenman #include <vm/vm_kern.h> 73efeaf95aSDavid Greenman #include <vm/vm_extern.h> 74df8bae1dSRodney W. Grimes 75df8bae1dSRodney W. Grimes #ifndef NPENDINGIO 760d94caffSDavid Greenman #define NPENDINGIO 10 77df8bae1dSRodney W. Grimes #endif 78df8bae1dSRodney W. Grimes 79f708ef1bSPoul-Henning Kamp static int nswiodone; 8026f9a767SRodney W. Grimes int swap_pager_full; 8126f9a767SRodney W. Grimes extern int vm_swap_size; 82f5a12711SPoul-Henning Kamp static int no_swap_space = 1; 8335c10d22SDavid Greenman struct rlist *swaplist; 8426f9a767SRodney W. Grimes 85a316d390SJohn Dyson #define MAX_PAGEOUT_CLUSTER 16 86df8bae1dSRodney W. Grimes 87df8bae1dSRodney W. Grimes TAILQ_HEAD(swpclean, swpagerclean); 88df8bae1dSRodney W. Grimes 8926f9a767SRodney W. Grimes typedef struct swpagerclean *swp_clean_t; 9026f9a767SRodney W. Grimes 91f708ef1bSPoul-Henning Kamp static struct swpagerclean { 92df8bae1dSRodney W. Grimes TAILQ_ENTRY(swpagerclean) spc_list; 93df8bae1dSRodney W. Grimes int spc_flags; 94df8bae1dSRodney W. Grimes struct buf *spc_bp; 952a4895f4SDavid Greenman vm_object_t spc_object; 96df8bae1dSRodney W. Grimes vm_offset_t spc_kva; 9726f9a767SRodney W. Grimes int spc_count; 9826f9a767SRodney W. Grimes vm_page_t spc_m[MAX_PAGEOUT_CLUSTER]; 99df8bae1dSRodney W. Grimes } swcleanlist[NPENDINGIO]; 10026f9a767SRodney W. Grimes 10126f9a767SRodney W. Grimes 102df8bae1dSRodney W. Grimes /* spc_flags values */ 10326f9a767SRodney W. Grimes #define SPC_ERROR 0x01 104df8bae1dSRodney W. Grimes 10526f9a767SRodney W. Grimes #define SWB_EMPTY (-1) 106df8bae1dSRodney W. Grimes 107f708ef1bSPoul-Henning Kamp /* list of completed page cleans */ 108f708ef1bSPoul-Henning Kamp static struct swpclean swap_pager_done; 109f708ef1bSPoul-Henning Kamp 110f708ef1bSPoul-Henning Kamp /* list of pending page cleans */ 111f708ef1bSPoul-Henning Kamp static struct swpclean swap_pager_inuse; 112f708ef1bSPoul-Henning Kamp 113f708ef1bSPoul-Henning Kamp /* list of free pager clean structs */ 114f708ef1bSPoul-Henning Kamp static struct swpclean swap_pager_free; 115f708ef1bSPoul-Henning Kamp 116f708ef1bSPoul-Henning Kamp /* list of "named" anon region objects */ 117f708ef1bSPoul-Henning Kamp static struct pagerlst swap_pager_object_list; 118f708ef1bSPoul-Henning Kamp 119f708ef1bSPoul-Henning Kamp /* list of "unnamed" anon region objects */ 120f708ef1bSPoul-Henning Kamp struct pagerlst swap_pager_un_object_list; 121df8bae1dSRodney W. Grimes 12226f9a767SRodney W. Grimes #define SWAP_FREE_NEEDED 0x1 /* need a swap block */ 123a1f6d91cSDavid Greenman #define SWAP_FREE_NEEDED_BY_PAGEOUT 0x2 124f708ef1bSPoul-Henning Kamp static int swap_pager_needflags; 12526f9a767SRodney W. Grimes 126f5a12711SPoul-Henning Kamp static struct pagerlst *swp_qs[] = { 12724a1cce3SDavid Greenman &swap_pager_object_list, &swap_pager_un_object_list, (struct pagerlst *) 0 12826f9a767SRodney W. Grimes }; 12926f9a767SRodney W. Grimes 13024a1cce3SDavid Greenman /* 13124a1cce3SDavid Greenman * pagerops for OBJT_SWAP - "swap pager". 13224a1cce3SDavid Greenman */ 133ff98689dSBruce Evans static vm_object_t 134ff98689dSBruce Evans swap_pager_alloc __P((void *handle, vm_size_t size, 135a316d390SJohn Dyson vm_prot_t prot, vm_ooffset_t offset)); 136ff98689dSBruce Evans static void swap_pager_dealloc __P((vm_object_t object)); 137ff98689dSBruce Evans static boolean_t 138a316d390SJohn Dyson swap_pager_haspage __P((vm_object_t object, vm_pindex_t pindex, 139ff98689dSBruce Evans int *before, int *after)); 140f708ef1bSPoul-Henning Kamp static int swap_pager_getpages __P((vm_object_t, vm_page_t *, int, int)); 141ff98689dSBruce Evans static void swap_pager_init __P((void)); 142f708ef1bSPoul-Henning Kamp static void swap_pager_sync __P((void)); 143f708ef1bSPoul-Henning Kamp 144df8bae1dSRodney W. Grimes struct pagerops swappagerops = { 145df8bae1dSRodney W. Grimes swap_pager_init, 146df8bae1dSRodney W. Grimes swap_pager_alloc, 147df8bae1dSRodney W. Grimes swap_pager_dealloc, 14824a1cce3SDavid Greenman swap_pager_getpages, 14924a1cce3SDavid Greenman swap_pager_putpages, 15024a1cce3SDavid Greenman swap_pager_haspage, 15124a1cce3SDavid Greenman swap_pager_sync 152df8bae1dSRodney W. Grimes }; 153df8bae1dSRodney W. Grimes 154f5a12711SPoul-Henning Kamp static int npendingio = NPENDINGIO; 155f708ef1bSPoul-Henning Kamp static int dmmin; 156f708ef1bSPoul-Henning Kamp int dmmax; 15726f9a767SRodney W. Grimes 158cac597e4SBruce Evans static __pure int 159f2c6b65bSBruce Evans swap_pager_block_index __P((vm_pindex_t pindex)) __pure2; 160cac597e4SBruce Evans static __pure int 161f2c6b65bSBruce Evans swap_pager_block_offset __P((vm_pindex_t pindex)) __pure2; 162a316d390SJohn Dyson static daddr_t *swap_pager_diskaddr __P((vm_object_t object, 163a316d390SJohn Dyson vm_pindex_t pindex, int *valid)); 164cac597e4SBruce Evans static void swap_pager_finish __P((swp_clean_t spc)); 165cac597e4SBruce Evans static void swap_pager_freepage __P((vm_page_t m)); 166cac597e4SBruce Evans static void swap_pager_free_swap __P((vm_object_t object)); 167cac597e4SBruce Evans static void swap_pager_freeswapspace __P((vm_object_t object, 168cac597e4SBruce Evans unsigned int from, 169cac597e4SBruce Evans unsigned int to)); 170cac597e4SBruce Evans static int swap_pager_getswapspace __P((vm_object_t object, 171cac597e4SBruce Evans unsigned int amount, 172a316d390SJohn Dyson daddr_t *rtval)); 173ff98689dSBruce Evans static void swap_pager_iodone __P((struct buf *)); 174cac597e4SBruce Evans static void swap_pager_iodone1 __P((struct buf *bp)); 175cac597e4SBruce Evans static void swap_pager_reclaim __P((void)); 176cac597e4SBruce Evans static void swap_pager_ridpages __P((vm_page_t *m, int count, 177cac597e4SBruce Evans int reqpage)); 178cac597e4SBruce Evans static void swap_pager_setvalid __P((vm_object_t object, 179cac597e4SBruce Evans vm_offset_t offset, int valid)); 180cac597e4SBruce Evans static void swapsizecheck __P((void)); 18124a1cce3SDavid Greenman 1820d94caffSDavid Greenman static inline void 1830d94caffSDavid Greenman swapsizecheck() 1840d94caffSDavid Greenman { 18526f9a767SRodney W. Grimes if (vm_swap_size < 128 * btodb(PAGE_SIZE)) { 186a1f6d91cSDavid Greenman if (swap_pager_full == 0) 1871af87c92SDavid Greenman printf("swap_pager: out of swap space\n"); 18826f9a767SRodney W. Grimes swap_pager_full = 1; 18926f9a767SRodney W. Grimes } else if (vm_swap_size > 192 * btodb(PAGE_SIZE)) 19026f9a767SRodney W. Grimes swap_pager_full = 0; 19126f9a767SRodney W. Grimes } 19226f9a767SRodney W. Grimes 193f5a12711SPoul-Henning Kamp static void 194df8bae1dSRodney W. Grimes swap_pager_init() 195df8bae1dSRodney W. Grimes { 19624a1cce3SDavid Greenman TAILQ_INIT(&swap_pager_object_list); 19724a1cce3SDavid Greenman TAILQ_INIT(&swap_pager_un_object_list); 198df8bae1dSRodney W. Grimes 199df8bae1dSRodney W. Grimes /* 200df8bae1dSRodney W. Grimes * Initialize clean lists 201df8bae1dSRodney W. Grimes */ 202df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_inuse); 20326f9a767SRodney W. Grimes TAILQ_INIT(&swap_pager_done); 204df8bae1dSRodney W. Grimes TAILQ_INIT(&swap_pager_free); 20526f9a767SRodney W. Grimes 206df8bae1dSRodney W. Grimes /* 207df8bae1dSRodney W. Grimes * Calculate the swap allocation constants. 208df8bae1dSRodney W. Grimes */ 20926f9a767SRodney W. Grimes dmmin = CLBYTES / DEV_BSIZE; 21026f9a767SRodney W. Grimes dmmax = btodb(SWB_NPAGES * PAGE_SIZE) * 2; 211df8bae1dSRodney W. Grimes } 212df8bae1dSRodney W. Grimes 21324a1cce3SDavid Greenman void 21424a1cce3SDavid Greenman swap_pager_swap_init() 215df8bae1dSRodney W. Grimes { 21626f9a767SRodney W. Grimes swp_clean_t spc; 21726f9a767SRodney W. Grimes struct buf *bp; 21824a1cce3SDavid Greenman int i; 2190d94caffSDavid Greenman 22026f9a767SRodney W. Grimes /* 2210d94caffSDavid Greenman * kva's are allocated here so that we dont need to keep doing 2220d94caffSDavid Greenman * kmem_alloc pageables at runtime 22326f9a767SRodney W. Grimes */ 22426f9a767SRodney W. Grimes for (i = 0, spc = swcleanlist; i < npendingio; i++, spc++) { 225fff93ab6SDavid Greenman spc->spc_kva = kmem_alloc_pageable(pager_map, PAGE_SIZE * MAX_PAGEOUT_CLUSTER); 22626f9a767SRodney W. Grimes if (!spc->spc_kva) { 22726f9a767SRodney W. Grimes break; 22826f9a767SRodney W. Grimes } 229a1f6d91cSDavid Greenman spc->spc_bp = malloc(sizeof(*bp), M_TEMP, M_KERNEL); 23026f9a767SRodney W. Grimes if (!spc->spc_bp) { 23126f9a767SRodney W. Grimes kmem_free_wakeup(pager_map, spc->spc_kva, PAGE_SIZE); 23226f9a767SRodney W. Grimes break; 23326f9a767SRodney W. Grimes } 23426f9a767SRodney W. Grimes spc->spc_flags = 0; 23526f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 23626f9a767SRodney W. Grimes } 23726f9a767SRodney W. Grimes } 23824a1cce3SDavid Greenman 23924a1cce3SDavid Greenman int 24024a1cce3SDavid Greenman swap_pager_swp_alloc(object, wait) 24124a1cce3SDavid Greenman vm_object_t object; 24224a1cce3SDavid Greenman int wait; 24324a1cce3SDavid Greenman { 2442a4895f4SDavid Greenman sw_blk_t swb; 2452a4895f4SDavid Greenman int nblocks; 24624a1cce3SDavid Greenman int i, j; 24724a1cce3SDavid Greenman 248a316d390SJohn Dyson nblocks = (object->size + SWB_NPAGES - 1) / SWB_NPAGES; 2492a4895f4SDavid Greenman swb = malloc(nblocks * sizeof(*swb), M_VMPGDATA, wait); 2502a4895f4SDavid Greenman if (swb == NULL) 25124a1cce3SDavid Greenman return 1; 25224a1cce3SDavid Greenman 2532a4895f4SDavid Greenman for (i = 0; i < nblocks; i++) { 2542a4895f4SDavid Greenman swb[i].swb_valid = 0; 2552a4895f4SDavid Greenman swb[i].swb_locked = 0; 25626f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) 2572a4895f4SDavid Greenman swb[i].swb_block[j] = SWB_EMPTY; 25826f9a767SRodney W. Grimes } 25926f9a767SRodney W. Grimes 2602a4895f4SDavid Greenman object->un_pager.swp.swp_nblocks = nblocks; 2612a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize = 0; 2622a4895f4SDavid Greenman object->un_pager.swp.swp_blocks = swb; 2632a4895f4SDavid Greenman object->un_pager.swp.swp_poip = 0; 26424a1cce3SDavid Greenman 26524a1cce3SDavid Greenman if (object->handle != NULL) { 26624a1cce3SDavid Greenman TAILQ_INSERT_TAIL(&swap_pager_object_list, object, pager_object_list); 267df8bae1dSRodney W. Grimes } else { 26824a1cce3SDavid Greenman TAILQ_INSERT_TAIL(&swap_pager_un_object_list, object, pager_object_list); 269df8bae1dSRodney W. Grimes } 270df8bae1dSRodney W. Grimes 27124a1cce3SDavid Greenman return 0; 27224a1cce3SDavid Greenman } 27324a1cce3SDavid Greenman 27424a1cce3SDavid Greenman /* 2752a4895f4SDavid Greenman * Allocate an object and associated resources. 27624a1cce3SDavid Greenman * Note that if we are called from the pageout daemon (handle == NULL) 27724a1cce3SDavid Greenman * we should not wait for memory as it could resulting in deadlock. 27824a1cce3SDavid Greenman */ 279f5a12711SPoul-Henning Kamp static vm_object_t 28024a1cce3SDavid Greenman swap_pager_alloc(handle, size, prot, offset) 28124a1cce3SDavid Greenman void *handle; 28224a1cce3SDavid Greenman register vm_size_t size; 28324a1cce3SDavid Greenman vm_prot_t prot; 284a316d390SJohn Dyson vm_ooffset_t offset; 28524a1cce3SDavid Greenman { 28624a1cce3SDavid Greenman vm_object_t object; 28724a1cce3SDavid Greenman 28824a1cce3SDavid Greenman /* 28924a1cce3SDavid Greenman * If this is a "named" anonymous region, look it up and use the 29024a1cce3SDavid Greenman * object if it exists, otherwise allocate a new one. 29124a1cce3SDavid Greenman */ 29224a1cce3SDavid Greenman if (handle) { 29324a1cce3SDavid Greenman object = vm_pager_object_lookup(&swap_pager_object_list, handle); 29424a1cce3SDavid Greenman if (object != NULL) { 29524a1cce3SDavid Greenman vm_object_reference(object); 29624a1cce3SDavid Greenman } else { 29724a1cce3SDavid Greenman /* 29824a1cce3SDavid Greenman * XXX - there is a race condition here. Two processes 29924a1cce3SDavid Greenman * can request the same named object simultaneuously, 30024a1cce3SDavid Greenman * and if one blocks for memory, the result is a disaster. 30124a1cce3SDavid Greenman * Probably quite rare, but is yet another reason to just 30224a1cce3SDavid Greenman * rip support of "named anonymous regions" out altogether. 30324a1cce3SDavid Greenman */ 304a316d390SJohn Dyson object = vm_object_allocate(OBJT_SWAP, 305bd7e5f99SJohn Dyson OFF_TO_IDX(offset + PAGE_SIZE - 1) + size); 30624a1cce3SDavid Greenman object->handle = handle; 30724a1cce3SDavid Greenman (void) swap_pager_swp_alloc(object, M_WAITOK); 30824a1cce3SDavid Greenman } 30924a1cce3SDavid Greenman } else { 310a316d390SJohn Dyson object = vm_object_allocate(OBJT_SWAP, 311bd7e5f99SJohn Dyson OFF_TO_IDX(offset + PAGE_SIZE - 1) + size); 31224a1cce3SDavid Greenman (void) swap_pager_swp_alloc(object, M_WAITOK); 31324a1cce3SDavid Greenman } 31424a1cce3SDavid Greenman 31524a1cce3SDavid Greenman return (object); 316df8bae1dSRodney W. Grimes } 317df8bae1dSRodney W. Grimes 31826f9a767SRodney W. Grimes /* 31926f9a767SRodney W. Grimes * returns disk block associated with pager and offset 32026f9a767SRodney W. Grimes * additionally, as a side effect returns a flag indicating 32126f9a767SRodney W. Grimes * if the block has been written 32226f9a767SRodney W. Grimes */ 32326f9a767SRodney W. Grimes 324a316d390SJohn Dyson inline static daddr_t * 325a316d390SJohn Dyson swap_pager_diskaddr(object, pindex, valid) 32624a1cce3SDavid Greenman vm_object_t object; 327a316d390SJohn Dyson vm_pindex_t pindex; 32826f9a767SRodney W. Grimes int *valid; 32926f9a767SRodney W. Grimes { 33026f9a767SRodney W. Grimes register sw_blk_t swb; 33126f9a767SRodney W. Grimes int ix; 33226f9a767SRodney W. Grimes 33326f9a767SRodney W. Grimes if (valid) 33426f9a767SRodney W. Grimes *valid = 0; 335a316d390SJohn Dyson ix = pindex / SWB_NPAGES; 3362a4895f4SDavid Greenman if ((ix >= object->un_pager.swp.swp_nblocks) || 337a316d390SJohn Dyson (pindex >= object->size)) { 33826f9a767SRodney W. Grimes return (FALSE); 33926f9a767SRodney W. Grimes } 3402a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 341a316d390SJohn Dyson ix = pindex % SWB_NPAGES; 34226f9a767SRodney W. Grimes if (valid) 34326f9a767SRodney W. Grimes *valid = swb->swb_valid & (1 << ix); 34426f9a767SRodney W. Grimes return &swb->swb_block[ix]; 34526f9a767SRodney W. Grimes } 34626f9a767SRodney W. Grimes 34726f9a767SRodney W. Grimes /* 34826f9a767SRodney W. Grimes * Utility routine to set the valid (written) bit for 34926f9a767SRodney W. Grimes * a block associated with a pager and offset 35026f9a767SRodney W. Grimes */ 351df8bae1dSRodney W. Grimes static void 3522a4895f4SDavid Greenman swap_pager_setvalid(object, offset, valid) 3532a4895f4SDavid Greenman vm_object_t object; 35426f9a767SRodney W. Grimes vm_offset_t offset; 35526f9a767SRodney W. Grimes int valid; 35626f9a767SRodney W. Grimes { 35726f9a767SRodney W. Grimes register sw_blk_t swb; 35826f9a767SRodney W. Grimes int ix; 35926f9a767SRodney W. Grimes 360a316d390SJohn Dyson ix = offset / SWB_NPAGES; 3612a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) 36226f9a767SRodney W. Grimes return; 36326f9a767SRodney W. Grimes 3642a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 365a316d390SJohn Dyson ix = offset % SWB_NPAGES; 36626f9a767SRodney W. Grimes if (valid) 36726f9a767SRodney W. Grimes swb->swb_valid |= (1 << ix); 36826f9a767SRodney W. Grimes else 36926f9a767SRodney W. Grimes swb->swb_valid &= ~(1 << ix); 37026f9a767SRodney W. Grimes return; 37126f9a767SRodney W. Grimes } 37226f9a767SRodney W. Grimes 37326f9a767SRodney W. Grimes /* 37426f9a767SRodney W. Grimes * this routine allocates swap space with a fragmentation 37526f9a767SRodney W. Grimes * minimization policy. 37626f9a767SRodney W. Grimes */ 377f5a12711SPoul-Henning Kamp static int 3782a4895f4SDavid Greenman swap_pager_getswapspace(object, amount, rtval) 3792a4895f4SDavid Greenman vm_object_t object; 3802a4895f4SDavid Greenman unsigned int amount; 381a316d390SJohn Dyson daddr_t *rtval; 3820d94caffSDavid Greenman { 383a316d390SJohn Dyson unsigned location; 38424ea4a96SDavid Greenman vm_swap_size -= amount; 385a316d390SJohn Dyson if (!rlist_alloc(&swaplist, amount, &location)) { 38624ea4a96SDavid Greenman vm_swap_size += amount; 38726f9a767SRodney W. Grimes return 0; 38824ea4a96SDavid Greenman } else { 38924ea4a96SDavid Greenman swapsizecheck(); 3902a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize += amount; 391a316d390SJohn Dyson *rtval = location; 39226f9a767SRodney W. Grimes return 1; 39326f9a767SRodney W. Grimes } 39426f9a767SRodney W. Grimes } 39526f9a767SRodney W. Grimes 39626f9a767SRodney W. Grimes /* 39726f9a767SRodney W. Grimes * this routine frees swap space with a fragmentation 39826f9a767SRodney W. Grimes * minimization policy. 39926f9a767SRodney W. Grimes */ 400f5a12711SPoul-Henning Kamp static void 4012a4895f4SDavid Greenman swap_pager_freeswapspace(object, from, to) 4022a4895f4SDavid Greenman vm_object_t object; 4032a4895f4SDavid Greenman unsigned int from; 4042a4895f4SDavid Greenman unsigned int to; 4050d94caffSDavid Greenman { 40635c10d22SDavid Greenman rlist_free(&swaplist, from, to); 40724ea4a96SDavid Greenman vm_swap_size += (to - from) + 1; 4082a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize -= (to - from) + 1; 40924ea4a96SDavid Greenman swapsizecheck(); 41026f9a767SRodney W. Grimes } 41126f9a767SRodney W. Grimes /* 41226f9a767SRodney W. Grimes * this routine frees swap blocks from a specified pager 41326f9a767SRodney W. Grimes */ 41426f9a767SRodney W. Grimes void 41524a1cce3SDavid Greenman swap_pager_freespace(object, start, size) 41624a1cce3SDavid Greenman vm_object_t object; 417a316d390SJohn Dyson vm_pindex_t start; 418a316d390SJohn Dyson vm_size_t size; 41926f9a767SRodney W. Grimes { 420a316d390SJohn Dyson vm_pindex_t i; 42126f9a767SRodney W. Grimes int s; 42226f9a767SRodney W. Grimes 42326f9a767SRodney W. Grimes s = splbio(); 424a316d390SJohn Dyson for (i = start; i < start + size; i += 1) { 42526f9a767SRodney W. Grimes int valid; 426a316d390SJohn Dyson daddr_t *addr = swap_pager_diskaddr(object, i, &valid); 4270d94caffSDavid Greenman 42826f9a767SRodney W. Grimes if (addr && *addr != SWB_EMPTY) { 4292a4895f4SDavid Greenman swap_pager_freeswapspace(object, *addr, *addr + btodb(PAGE_SIZE) - 1); 43026f9a767SRodney W. Grimes if (valid) { 4312a4895f4SDavid Greenman swap_pager_setvalid(object, i, 0); 43226f9a767SRodney W. Grimes } 43326f9a767SRodney W. Grimes *addr = SWB_EMPTY; 43426f9a767SRodney W. Grimes } 43526f9a767SRodney W. Grimes } 43626f9a767SRodney W. Grimes splx(s); 43726f9a767SRodney W. Grimes } 43826f9a767SRodney W. Grimes 439a1f6d91cSDavid Greenman static void 4402a4895f4SDavid Greenman swap_pager_free_swap(object) 4412a4895f4SDavid Greenman vm_object_t object; 442a1f6d91cSDavid Greenman { 443a1f6d91cSDavid Greenman register int i, j; 4442a4895f4SDavid Greenman register sw_blk_t swb; 445a1f6d91cSDavid Greenman int first_block=0, block_count=0; 446a1f6d91cSDavid Greenman int s; 447a1f6d91cSDavid Greenman /* 448a1f6d91cSDavid Greenman * Free left over swap blocks 449a1f6d91cSDavid Greenman */ 450a1f6d91cSDavid Greenman s = splbio(); 4512a4895f4SDavid Greenman for (i = 0, swb = object->un_pager.swp.swp_blocks; 4522a4895f4SDavid Greenman i < object->un_pager.swp.swp_nblocks; i++, swb++) { 453a1f6d91cSDavid Greenman for (j = 0; j < SWB_NPAGES; j++) { 4542a4895f4SDavid Greenman if (swb->swb_block[j] != SWB_EMPTY) { 455a1f6d91cSDavid Greenman /* 456a1f6d91cSDavid Greenman * initially the length of the run is zero 457a1f6d91cSDavid Greenman */ 458a1f6d91cSDavid Greenman if (block_count == 0) { 4592a4895f4SDavid Greenman first_block = swb->swb_block[j]; 460a1f6d91cSDavid Greenman block_count = btodb(PAGE_SIZE); 4612a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 462a1f6d91cSDavid Greenman /* 463a1f6d91cSDavid Greenman * if the new block can be included into the current run 464a1f6d91cSDavid Greenman */ 4652a4895f4SDavid Greenman } else if (swb->swb_block[j] == first_block + block_count) { 466a1f6d91cSDavid Greenman block_count += btodb(PAGE_SIZE); 4672a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 468a1f6d91cSDavid Greenman /* 469a1f6d91cSDavid Greenman * terminate the previous run, and start a new one 470a1f6d91cSDavid Greenman */ 471a1f6d91cSDavid Greenman } else { 4722a4895f4SDavid Greenman swap_pager_freeswapspace(object, first_block, 473a1f6d91cSDavid Greenman (unsigned) first_block + block_count - 1); 4742a4895f4SDavid Greenman first_block = swb->swb_block[j]; 475a1f6d91cSDavid Greenman block_count = btodb(PAGE_SIZE); 4762a4895f4SDavid Greenman swb->swb_block[j] = SWB_EMPTY; 477a1f6d91cSDavid Greenman } 478a1f6d91cSDavid Greenman } 479a1f6d91cSDavid Greenman } 480a1f6d91cSDavid Greenman } 481a1f6d91cSDavid Greenman 482a1f6d91cSDavid Greenman if (block_count) { 4832a4895f4SDavid Greenman swap_pager_freeswapspace(object, first_block, 484a1f6d91cSDavid Greenman (unsigned) first_block + block_count - 1); 485a1f6d91cSDavid Greenman } 486a1f6d91cSDavid Greenman splx(s); 487a1f6d91cSDavid Greenman } 488a1f6d91cSDavid Greenman 489a1f6d91cSDavid Greenman 49026f9a767SRodney W. Grimes /* 49126f9a767SRodney W. Grimes * swap_pager_reclaim frees up over-allocated space from all pagers 49226f9a767SRodney W. Grimes * this eliminates internal fragmentation due to allocation of space 49326f9a767SRodney W. Grimes * for segments that are never swapped to. It has been written so that 49426f9a767SRodney W. Grimes * it does not block until the rlist_free operation occurs; it keeps 49526f9a767SRodney W. Grimes * the queues consistant. 49626f9a767SRodney W. Grimes */ 49726f9a767SRodney W. Grimes 49826f9a767SRodney W. Grimes /* 49926f9a767SRodney W. Grimes * Maximum number of blocks (pages) to reclaim per pass 50026f9a767SRodney W. Grimes */ 501a1f6d91cSDavid Greenman #define MAXRECLAIM 128 50226f9a767SRodney W. Grimes 503f5a12711SPoul-Henning Kamp static void 50426f9a767SRodney W. Grimes swap_pager_reclaim() 50526f9a767SRodney W. Grimes { 50624a1cce3SDavid Greenman vm_object_t object; 50726f9a767SRodney W. Grimes int i, j, k; 50826f9a767SRodney W. Grimes int s; 50926f9a767SRodney W. Grimes int reclaimcount; 510a1f6d91cSDavid Greenman static struct { 511a1f6d91cSDavid Greenman int address; 5122a4895f4SDavid Greenman vm_object_t object; 513a1f6d91cSDavid Greenman } reclaims[MAXRECLAIM]; 51426f9a767SRodney W. Grimes static int in_reclaim; 51526f9a767SRodney W. Grimes 51626f9a767SRodney W. Grimes /* 51726f9a767SRodney W. Grimes * allow only one process to be in the swap_pager_reclaim subroutine 51826f9a767SRodney W. Grimes */ 51926f9a767SRodney W. Grimes s = splbio(); 52026f9a767SRodney W. Grimes if (in_reclaim) { 52124a1cce3SDavid Greenman tsleep(&in_reclaim, PSWP, "swrclm", 0); 52226f9a767SRodney W. Grimes splx(s); 52326f9a767SRodney W. Grimes return; 52426f9a767SRodney W. Grimes } 52526f9a767SRodney W. Grimes in_reclaim = 1; 52626f9a767SRodney W. Grimes reclaimcount = 0; 52726f9a767SRodney W. Grimes 52826f9a767SRodney W. Grimes /* for each pager queue */ 52926f9a767SRodney W. Grimes for (k = 0; swp_qs[k]; k++) { 53026f9a767SRodney W. Grimes 53124a1cce3SDavid Greenman object = swp_qs[k]->tqh_first; 53224a1cce3SDavid Greenman while (object && (reclaimcount < MAXRECLAIM)) { 53326f9a767SRodney W. Grimes 53426f9a767SRodney W. Grimes /* 53526f9a767SRodney W. Grimes * see if any blocks associated with a pager has been 53626f9a767SRodney W. Grimes * allocated but not used (written) 53726f9a767SRodney W. Grimes */ 538a316d390SJohn Dyson if (object->paging_in_progress == 0) { 5392a4895f4SDavid Greenman for (i = 0; i < object->un_pager.swp.swp_nblocks; i++) { 5402a4895f4SDavid Greenman sw_blk_t swb = &object->un_pager.swp.swp_blocks[i]; 5410d94caffSDavid Greenman 54226f9a767SRodney W. Grimes if (swb->swb_locked) 54326f9a767SRodney W. Grimes continue; 54426f9a767SRodney W. Grimes for (j = 0; j < SWB_NPAGES; j++) { 54526f9a767SRodney W. Grimes if (swb->swb_block[j] != SWB_EMPTY && 54626f9a767SRodney W. Grimes (swb->swb_valid & (1 << j)) == 0) { 547a1f6d91cSDavid Greenman reclaims[reclaimcount].address = swb->swb_block[j]; 5482a4895f4SDavid Greenman reclaims[reclaimcount++].object = object; 54926f9a767SRodney W. Grimes swb->swb_block[j] = SWB_EMPTY; 55026f9a767SRodney W. Grimes if (reclaimcount >= MAXRECLAIM) 55126f9a767SRodney W. Grimes goto rfinished; 55226f9a767SRodney W. Grimes } 55326f9a767SRodney W. Grimes } 55426f9a767SRodney W. Grimes } 555a316d390SJohn Dyson } 55624a1cce3SDavid Greenman object = object->pager_object_list.tqe_next; 55726f9a767SRodney W. Grimes } 55826f9a767SRodney W. Grimes } 55926f9a767SRodney W. Grimes 56026f9a767SRodney W. Grimes rfinished: 56126f9a767SRodney W. Grimes 56226f9a767SRodney W. Grimes /* 56326f9a767SRodney W. Grimes * free the blocks that have been added to the reclaim list 56426f9a767SRodney W. Grimes */ 56526f9a767SRodney W. Grimes for (i = 0; i < reclaimcount; i++) { 5662a4895f4SDavid Greenman swap_pager_freeswapspace(reclaims[i].object, 5672a4895f4SDavid Greenman reclaims[i].address, reclaims[i].address + btodb(PAGE_SIZE) - 1); 56826f9a767SRodney W. Grimes } 56926f9a767SRodney W. Grimes splx(s); 57026f9a767SRodney W. Grimes in_reclaim = 0; 57124a1cce3SDavid Greenman wakeup(&in_reclaim); 57226f9a767SRodney W. Grimes } 57326f9a767SRodney W. Grimes 57426f9a767SRodney W. Grimes 57526f9a767SRodney W. Grimes /* 57626f9a767SRodney W. Grimes * swap_pager_copy copies blocks from one pager to another and 57726f9a767SRodney W. Grimes * destroys the source pager 57826f9a767SRodney W. Grimes */ 57926f9a767SRodney W. Grimes 58026f9a767SRodney W. Grimes void 58124a1cce3SDavid Greenman swap_pager_copy(srcobject, srcoffset, dstobject, dstoffset, offset) 58224a1cce3SDavid Greenman vm_object_t srcobject; 583a316d390SJohn Dyson vm_pindex_t srcoffset; 58424a1cce3SDavid Greenman vm_object_t dstobject; 585a316d390SJohn Dyson vm_pindex_t dstoffset; 586a316d390SJohn Dyson vm_pindex_t offset; 58726f9a767SRodney W. Grimes { 588a316d390SJohn Dyson vm_pindex_t i; 589a1f6d91cSDavid Greenman int origsize; 59026f9a767SRodney W. Grimes int s; 59126f9a767SRodney W. Grimes 59224ea4a96SDavid Greenman if (vm_swap_size) 59324ea4a96SDavid Greenman no_swap_space = 0; 59424ea4a96SDavid Greenman 5952a4895f4SDavid Greenman origsize = srcobject->un_pager.swp.swp_allocsize; 59626f9a767SRodney W. Grimes 59726f9a767SRodney W. Grimes /* 59824a1cce3SDavid Greenman * remove the source object from the swap_pager internal queue 59926f9a767SRodney W. Grimes */ 60024a1cce3SDavid Greenman if (srcobject->handle == NULL) { 60124a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_un_object_list, srcobject, pager_object_list); 60226f9a767SRodney W. Grimes } else { 60324a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_object_list, srcobject, pager_object_list); 60426f9a767SRodney W. Grimes } 60526f9a767SRodney W. Grimes 60624a1cce3SDavid Greenman s = splbio(); 6072a4895f4SDavid Greenman while (srcobject->un_pager.swp.swp_poip) { 6082a4895f4SDavid Greenman tsleep(srcobject, PVM, "spgout", 0); 60926f9a767SRodney W. Grimes } 61026f9a767SRodney W. Grimes splx(s); 61126f9a767SRodney W. Grimes 61226f9a767SRodney W. Grimes /* 61326f9a767SRodney W. Grimes * clean all of the pages that are currently active and finished 61426f9a767SRodney W. Grimes */ 61524a1cce3SDavid Greenman swap_pager_sync(); 61626f9a767SRodney W. Grimes 61726f9a767SRodney W. Grimes s = splbio(); 61826f9a767SRodney W. Grimes /* 61926f9a767SRodney W. Grimes * transfer source to destination 62026f9a767SRodney W. Grimes */ 621a316d390SJohn Dyson for (i = 0; i < dstobject->size; i += 1) { 62226f9a767SRodney W. Grimes int srcvalid, dstvalid; 623a316d390SJohn Dyson daddr_t *srcaddrp = swap_pager_diskaddr(srcobject, i + offset + srcoffset, 62426f9a767SRodney W. Grimes &srcvalid); 625a316d390SJohn Dyson daddr_t *dstaddrp; 6260d94caffSDavid Greenman 62726f9a767SRodney W. Grimes /* 62826f9a767SRodney W. Grimes * see if the source has space allocated 62926f9a767SRodney W. Grimes */ 63026f9a767SRodney W. Grimes if (srcaddrp && *srcaddrp != SWB_EMPTY) { 63126f9a767SRodney W. Grimes /* 6320d94caffSDavid Greenman * if the source is valid and the dest has no space, 6330d94caffSDavid Greenman * then copy the allocation from the srouce to the 6340d94caffSDavid Greenman * dest. 63526f9a767SRodney W. Grimes */ 63626f9a767SRodney W. Grimes if (srcvalid) { 63724a1cce3SDavid Greenman dstaddrp = swap_pager_diskaddr(dstobject, i + dstoffset, 638a1f6d91cSDavid Greenman &dstvalid); 63926f9a767SRodney W. Grimes /* 6400d94caffSDavid Greenman * if the dest already has a valid block, 6410d94caffSDavid Greenman * deallocate the source block without 6420d94caffSDavid Greenman * copying. 64326f9a767SRodney W. Grimes */ 64426f9a767SRodney W. Grimes if (!dstvalid && dstaddrp && *dstaddrp != SWB_EMPTY) { 6452a4895f4SDavid Greenman swap_pager_freeswapspace(dstobject, *dstaddrp, 646a1f6d91cSDavid Greenman *dstaddrp + btodb(PAGE_SIZE) - 1); 64726f9a767SRodney W. Grimes *dstaddrp = SWB_EMPTY; 64826f9a767SRodney W. Grimes } 64926f9a767SRodney W. Grimes if (dstaddrp && *dstaddrp == SWB_EMPTY) { 65026f9a767SRodney W. Grimes *dstaddrp = *srcaddrp; 65126f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 6522a4895f4SDavid Greenman dstobject->un_pager.swp.swp_allocsize += btodb(PAGE_SIZE); 6532a4895f4SDavid Greenman srcobject->un_pager.swp.swp_allocsize -= btodb(PAGE_SIZE); 6542a4895f4SDavid Greenman swap_pager_setvalid(dstobject, i + dstoffset, 1); 65526f9a767SRodney W. Grimes } 65626f9a767SRodney W. Grimes } 65726f9a767SRodney W. Grimes /* 6580d94caffSDavid Greenman * if the source is not empty at this point, then 6590d94caffSDavid Greenman * deallocate the space. 66026f9a767SRodney W. Grimes */ 66126f9a767SRodney W. Grimes if (*srcaddrp != SWB_EMPTY) { 6622a4895f4SDavid Greenman swap_pager_freeswapspace(srcobject, *srcaddrp, 663a1f6d91cSDavid Greenman *srcaddrp + btodb(PAGE_SIZE) - 1); 66426f9a767SRodney W. Grimes *srcaddrp = SWB_EMPTY; 66526f9a767SRodney W. Grimes } 66626f9a767SRodney W. Grimes } 66726f9a767SRodney W. Grimes } 66826f9a767SRodney W. Grimes splx(s); 66926f9a767SRodney W. Grimes 670a1f6d91cSDavid Greenman /* 671a1f6d91cSDavid Greenman * Free left over swap blocks 672a1f6d91cSDavid Greenman */ 6732a4895f4SDavid Greenman swap_pager_free_swap(srcobject); 674a1f6d91cSDavid Greenman 6752a4895f4SDavid Greenman if (srcobject->un_pager.swp.swp_allocsize) { 6762a4895f4SDavid Greenman printf("swap_pager_copy: *warning* pager with %d blocks (orig: %d)\n", 6772a4895f4SDavid Greenman srcobject->un_pager.swp.swp_allocsize, origsize); 6782a4895f4SDavid Greenman } 6792a4895f4SDavid Greenman 6802a4895f4SDavid Greenman free(srcobject->un_pager.swp.swp_blocks, M_VMPGDATA); 6812a4895f4SDavid Greenman srcobject->un_pager.swp.swp_blocks = NULL; 68226f9a767SRodney W. Grimes 68326f9a767SRodney W. Grimes return; 68426f9a767SRodney W. Grimes } 68526f9a767SRodney W. Grimes 686f5a12711SPoul-Henning Kamp static void 68724a1cce3SDavid Greenman swap_pager_dealloc(object) 68824a1cce3SDavid Greenman vm_object_t object; 689df8bae1dSRodney W. Grimes { 690df8bae1dSRodney W. Grimes int s; 691df8bae1dSRodney W. Grimes 692df8bae1dSRodney W. Grimes /* 6930d94caffSDavid Greenman * Remove from list right away so lookups will fail if we block for 6940d94caffSDavid Greenman * pageout completion. 695df8bae1dSRodney W. Grimes */ 69624a1cce3SDavid Greenman if (object->handle == NULL) { 69724a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_un_object_list, object, pager_object_list); 69826f9a767SRodney W. Grimes } else { 69924a1cce3SDavid Greenman TAILQ_REMOVE(&swap_pager_object_list, object, pager_object_list); 700df8bae1dSRodney W. Grimes } 70124a1cce3SDavid Greenman 702df8bae1dSRodney W. Grimes /* 7030d94caffSDavid Greenman * Wait for all pageouts to finish and remove all entries from 7040d94caffSDavid Greenman * cleaning list. 705df8bae1dSRodney W. Grimes */ 70626f9a767SRodney W. Grimes 70724a1cce3SDavid Greenman s = splbio(); 7082a4895f4SDavid Greenman while (object->un_pager.swp.swp_poip) { 7092a4895f4SDavid Greenman tsleep(object, PVM, "swpout", 0); 710df8bae1dSRodney W. Grimes } 711df8bae1dSRodney W. Grimes splx(s); 71226f9a767SRodney W. Grimes 71326f9a767SRodney W. Grimes 71424a1cce3SDavid Greenman swap_pager_sync(); 715df8bae1dSRodney W. Grimes 716df8bae1dSRodney W. Grimes /* 717df8bae1dSRodney W. Grimes * Free left over swap blocks 718df8bae1dSRodney W. Grimes */ 7192a4895f4SDavid Greenman swap_pager_free_swap(object); 72026f9a767SRodney W. Grimes 7212a4895f4SDavid Greenman if (object->un_pager.swp.swp_allocsize) { 7222a4895f4SDavid Greenman printf("swap_pager_dealloc: *warning* freeing pager with %d blocks\n", 7232a4895f4SDavid Greenman object->un_pager.swp.swp_allocsize); 7242a4895f4SDavid Greenman } 725df8bae1dSRodney W. Grimes /* 726df8bae1dSRodney W. Grimes * Free swap management resources 727df8bae1dSRodney W. Grimes */ 7282a4895f4SDavid Greenman free(object->un_pager.swp.swp_blocks, M_VMPGDATA); 7292a4895f4SDavid Greenman object->un_pager.swp.swp_blocks = NULL; 73026f9a767SRodney W. Grimes } 73126f9a767SRodney W. Grimes 732cac597e4SBruce Evans static inline __pure int 733a316d390SJohn Dyson swap_pager_block_index(pindex) 734a316d390SJohn Dyson vm_pindex_t pindex; 73526f9a767SRodney W. Grimes { 736a316d390SJohn Dyson return (pindex / SWB_NPAGES); 73726f9a767SRodney W. Grimes } 73826f9a767SRodney W. Grimes 739cac597e4SBruce Evans static inline __pure int 740a316d390SJohn Dyson swap_pager_block_offset(pindex) 741a316d390SJohn Dyson vm_pindex_t pindex; 74226f9a767SRodney W. Grimes { 743a316d390SJohn Dyson return (pindex % SWB_NPAGES); 74426f9a767SRodney W. Grimes } 74526f9a767SRodney W. Grimes 74626f9a767SRodney W. Grimes /* 74724a1cce3SDavid Greenman * swap_pager_haspage returns TRUE if the pager has data that has 74826f9a767SRodney W. Grimes * been written out. 74926f9a767SRodney W. Grimes */ 750f5a12711SPoul-Henning Kamp static boolean_t 751a316d390SJohn Dyson swap_pager_haspage(object, pindex, before, after) 75224a1cce3SDavid Greenman vm_object_t object; 753a316d390SJohn Dyson vm_pindex_t pindex; 75424a1cce3SDavid Greenman int *before; 75524a1cce3SDavid Greenman int *after; 75626f9a767SRodney W. Grimes { 75726f9a767SRodney W. Grimes register sw_blk_t swb; 75826f9a767SRodney W. Grimes int ix; 75926f9a767SRodney W. Grimes 76024a1cce3SDavid Greenman if (before != NULL) 76124a1cce3SDavid Greenman *before = 0; 76224a1cce3SDavid Greenman if (after != NULL) 76324a1cce3SDavid Greenman *after = 0; 764a316d390SJohn Dyson ix = pindex / SWB_NPAGES; 7652a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 76626f9a767SRodney W. Grimes return (FALSE); 76726f9a767SRodney W. Grimes } 7682a4895f4SDavid Greenman swb = &object->un_pager.swp.swp_blocks[ix]; 769a316d390SJohn Dyson ix = pindex % SWB_NPAGES; 770170db9c6SJohn Dyson 77126f9a767SRodney W. Grimes if (swb->swb_block[ix] != SWB_EMPTY) { 772170db9c6SJohn Dyson 773170db9c6SJohn Dyson if (swb->swb_valid & (1 << ix)) { 774170db9c6SJohn Dyson int tix; 775170db9c6SJohn Dyson if (before) { 776170db9c6SJohn Dyson for(tix = ix - 1; tix >= 0; --tix) { 7772f82e604SDavid Greenman if ((swb->swb_valid & (1 << tix)) == 0) 7782f82e604SDavid Greenman break; 779ca56715fSJohn Dyson if ((swb->swb_block[tix] + 780170db9c6SJohn Dyson (ix - tix) * (PAGE_SIZE/DEV_BSIZE)) != 781170db9c6SJohn Dyson swb->swb_block[ix]) 782170db9c6SJohn Dyson break; 783170db9c6SJohn Dyson (*before)++; 784170db9c6SJohn Dyson } 785170db9c6SJohn Dyson } 786170db9c6SJohn Dyson 787170db9c6SJohn Dyson if (after) { 788170db9c6SJohn Dyson for(tix = ix + 1; tix < SWB_NPAGES; tix++) { 7892f82e604SDavid Greenman if ((swb->swb_valid & (1 << tix)) == 0) 7902f82e604SDavid Greenman break; 791ca56715fSJohn Dyson if ((swb->swb_block[tix] - 792170db9c6SJohn Dyson (tix - ix) * (PAGE_SIZE/DEV_BSIZE)) != 793170db9c6SJohn Dyson swb->swb_block[ix]) 794170db9c6SJohn Dyson break; 795170db9c6SJohn Dyson (*after)++; 796170db9c6SJohn Dyson } 797170db9c6SJohn Dyson } 798170db9c6SJohn Dyson 79926f9a767SRodney W. Grimes return TRUE; 80026f9a767SRodney W. Grimes } 801170db9c6SJohn Dyson } 80226f9a767SRodney W. Grimes return (FALSE); 80326f9a767SRodney W. Grimes } 80426f9a767SRodney W. Grimes 80526f9a767SRodney W. Grimes /* 80626f9a767SRodney W. Grimes * swap_pager_freepage is a convienience routine that clears the busy 80726f9a767SRodney W. Grimes * bit and deallocates a page. 808df8bae1dSRodney W. Grimes */ 80926f9a767SRodney W. Grimes static void 81026f9a767SRodney W. Grimes swap_pager_freepage(m) 81126f9a767SRodney W. Grimes vm_page_t m; 81226f9a767SRodney W. Grimes { 81326f9a767SRodney W. Grimes PAGE_WAKEUP(m); 81426f9a767SRodney W. Grimes vm_page_free(m); 81526f9a767SRodney W. Grimes } 81626f9a767SRodney W. Grimes 81726f9a767SRodney W. Grimes /* 81826f9a767SRodney W. Grimes * swap_pager_ridpages is a convienience routine that deallocates all 81926f9a767SRodney W. Grimes * but the required page. this is usually used in error returns that 82026f9a767SRodney W. Grimes * need to invalidate the "extra" readahead pages. 82126f9a767SRodney W. Grimes */ 82226f9a767SRodney W. Grimes static void 82326f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage) 82426f9a767SRodney W. Grimes vm_page_t *m; 82526f9a767SRodney W. Grimes int count; 82626f9a767SRodney W. Grimes int reqpage; 82726f9a767SRodney W. Grimes { 82826f9a767SRodney W. Grimes int i; 8290d94caffSDavid Greenman 83026f9a767SRodney W. Grimes for (i = 0; i < count; i++) 83126f9a767SRodney W. Grimes if (i != reqpage) 83226f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 83326f9a767SRodney W. Grimes } 83426f9a767SRodney W. Grimes 83526f9a767SRodney W. Grimes /* 83626f9a767SRodney W. Grimes * swap_pager_iodone1 is the completion routine for both reads and async writes 83726f9a767SRodney W. Grimes */ 838f5a12711SPoul-Henning Kamp static void 83926f9a767SRodney W. Grimes swap_pager_iodone1(bp) 84026f9a767SRodney W. Grimes struct buf *bp; 84126f9a767SRodney W. Grimes { 84226f9a767SRodney W. Grimes bp->b_flags |= B_DONE; 84326f9a767SRodney W. Grimes bp->b_flags &= ~B_ASYNC; 84424a1cce3SDavid Greenman wakeup(bp); 84526f9a767SRodney W. Grimes } 84626f9a767SRodney W. Grimes 847f708ef1bSPoul-Henning Kamp static int 84824a1cce3SDavid Greenman swap_pager_getpages(object, m, count, reqpage) 84924a1cce3SDavid Greenman vm_object_t object; 85026f9a767SRodney W. Grimes vm_page_t *m; 85126f9a767SRodney W. Grimes int count, reqpage; 852df8bae1dSRodney W. Grimes { 853df8bae1dSRodney W. Grimes register struct buf *bp; 85426f9a767SRodney W. Grimes sw_blk_t swb[count]; 855df8bae1dSRodney W. Grimes register int s; 85626f9a767SRodney W. Grimes int i; 857df8bae1dSRodney W. Grimes boolean_t rv; 85826f9a767SRodney W. Grimes vm_offset_t kva, off[count]; 859df8bae1dSRodney W. Grimes swp_clean_t spc; 860a316d390SJohn Dyson vm_pindex_t paging_offset; 86126f9a767SRodney W. Grimes int reqaddr[count]; 8626d40c3d3SDavid Greenman int sequential; 863df8bae1dSRodney W. Grimes 86426f9a767SRodney W. Grimes int first, last; 86526f9a767SRodney W. Grimes int failed; 86626f9a767SRodney W. Grimes int reqdskregion; 867df8bae1dSRodney W. Grimes 86826f9a767SRodney W. Grimes object = m[reqpage]->object; 869a316d390SJohn Dyson paging_offset = OFF_TO_IDX(object->paging_offset); 870a316d390SJohn Dyson sequential = (m[reqpage]->pindex == (object->last_read + 1)); 8712a4895f4SDavid Greenman 87226f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 873a316d390SJohn Dyson vm_pindex_t fidx = m[i]->pindex + paging_offset; 874a316d390SJohn Dyson int ix = swap_pager_block_index(fidx); 8750d94caffSDavid Greenman 8762a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 87726f9a767SRodney W. Grimes int j; 8780d94caffSDavid Greenman 87926f9a767SRodney W. Grimes if (i <= reqpage) { 88026f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 881df8bae1dSRodney W. Grimes return (VM_PAGER_FAIL); 88226f9a767SRodney W. Grimes } 88326f9a767SRodney W. Grimes for (j = i; j < count; j++) { 88426f9a767SRodney W. Grimes swap_pager_freepage(m[j]); 88526f9a767SRodney W. Grimes } 88626f9a767SRodney W. Grimes count = i; 88726f9a767SRodney W. Grimes break; 88826f9a767SRodney W. Grimes } 8892a4895f4SDavid Greenman swb[i] = &object->un_pager.swp.swp_blocks[ix]; 890a316d390SJohn Dyson off[i] = swap_pager_block_offset(fidx); 89126f9a767SRodney W. Grimes reqaddr[i] = swb[i]->swb_block[off[i]]; 89226f9a767SRodney W. Grimes } 89326f9a767SRodney W. Grimes 89426f9a767SRodney W. Grimes /* make sure that our required input request is existant */ 89526f9a767SRodney W. Grimes 89626f9a767SRodney W. Grimes if (reqaddr[reqpage] == SWB_EMPTY || 89726f9a767SRodney W. Grimes (swb[reqpage]->swb_valid & (1 << off[reqpage])) == 0) { 89826f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 89926f9a767SRodney W. Grimes return (VM_PAGER_FAIL); 90026f9a767SRodney W. Grimes } 90126f9a767SRodney W. Grimes reqdskregion = reqaddr[reqpage] / dmmax; 902df8bae1dSRodney W. Grimes 903df8bae1dSRodney W. Grimes /* 90426f9a767SRodney W. Grimes * search backwards for the first contiguous page to transfer 905df8bae1dSRodney W. Grimes */ 90626f9a767SRodney W. Grimes failed = 0; 90726f9a767SRodney W. Grimes first = 0; 90826f9a767SRodney W. Grimes for (i = reqpage - 1; i >= 0; --i) { 9096d40c3d3SDavid Greenman if (sequential || failed || (reqaddr[i] == SWB_EMPTY) || 91026f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 91126f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 91226f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 91326f9a767SRodney W. Grimes failed = 1; 91426f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 91526f9a767SRodney W. Grimes if (first == 0) 91626f9a767SRodney W. Grimes first = i + 1; 91726f9a767SRodney W. Grimes } 918df8bae1dSRodney W. Grimes } 919df8bae1dSRodney W. Grimes /* 92026f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 921df8bae1dSRodney W. Grimes */ 92226f9a767SRodney W. Grimes failed = 0; 92326f9a767SRodney W. Grimes last = count; 92426f9a767SRodney W. Grimes for (i = reqpage + 1; i < count; i++) { 92526f9a767SRodney W. Grimes if (failed || (reqaddr[i] == SWB_EMPTY) || 92626f9a767SRodney W. Grimes (swb[i]->swb_valid & (1 << off[i])) == 0 || 92726f9a767SRodney W. Grimes (reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) || 92826f9a767SRodney W. Grimes ((reqaddr[i] / dmmax) != reqdskregion)) { 92926f9a767SRodney W. Grimes failed = 1; 93026f9a767SRodney W. Grimes swap_pager_freepage(m[i]); 93126f9a767SRodney W. Grimes if (last == count) 93226f9a767SRodney W. Grimes last = i; 93326f9a767SRodney W. Grimes } 93426f9a767SRodney W. Grimes } 93526f9a767SRodney W. Grimes 93626f9a767SRodney W. Grimes count = last; 93726f9a767SRodney W. Grimes if (first != 0) { 93826f9a767SRodney W. Grimes for (i = first; i < count; i++) { 93926f9a767SRodney W. Grimes m[i - first] = m[i]; 94026f9a767SRodney W. Grimes reqaddr[i - first] = reqaddr[i]; 94126f9a767SRodney W. Grimes off[i - first] = off[i]; 94226f9a767SRodney W. Grimes } 94326f9a767SRodney W. Grimes count -= first; 94426f9a767SRodney W. Grimes reqpage -= first; 94526f9a767SRodney W. Grimes } 94626f9a767SRodney W. Grimes ++swb[reqpage]->swb_locked; 94726f9a767SRodney W. Grimes 94826f9a767SRodney W. Grimes /* 9490d94caffSDavid Greenman * at this point: "m" is a pointer to the array of vm_page_t for 9500d94caffSDavid Greenman * paging I/O "count" is the number of vm_page_t entries represented 9510d94caffSDavid Greenman * by "m" "object" is the vm_object_t for I/O "reqpage" is the index 9520d94caffSDavid Greenman * into "m" for the page actually faulted 95326f9a767SRodney W. Grimes */ 95426f9a767SRodney W. Grimes 95526f9a767SRodney W. Grimes spc = NULL; /* we might not use an spc data structure */ 95626f9a767SRodney W. Grimes 957a1f6d91cSDavid Greenman if ((count == 1) && (swap_pager_free.tqh_first != NULL)) { 95826f9a767SRodney W. Grimes spc = swap_pager_free.tqh_first; 95926f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 96026f9a767SRodney W. Grimes kva = spc->spc_kva; 96126f9a767SRodney W. Grimes bp = spc->spc_bp; 96226f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 96326f9a767SRodney W. Grimes bp->b_spc = spc; 9647609ab12SDavid Greenman bp->b_vnbufs.le_next = NOLIST; 96526f9a767SRodney W. Grimes } else { 96616f62314SDavid Greenman /* 96716f62314SDavid Greenman * Get a swap buffer header to perform the IO 96816f62314SDavid Greenman */ 96926f9a767SRodney W. Grimes bp = getpbuf(); 97016f62314SDavid Greenman kva = (vm_offset_t) bp->b_data; 97126f9a767SRodney W. Grimes } 97226f9a767SRodney W. Grimes 97316f62314SDavid Greenman /* 97416f62314SDavid Greenman * map our page(s) into kva for input 97516f62314SDavid Greenman */ 97616f62314SDavid Greenman pmap_qenter(kva, m, count); 97716f62314SDavid Greenman 978aba8f38eSDavid Greenman bp->b_flags = B_BUSY | B_READ | B_CALL | B_PAGING; 97926f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 980df8bae1dSRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 98126f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 98226f9a767SRodney W. Grimes crhold(bp->b_rcred); 98326f9a767SRodney W. Grimes crhold(bp->b_wcred); 98426f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva; 98526f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 98626f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE * count; 98726f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE * count; 98826f9a767SRodney W. Grimes 9890d94caffSDavid Greenman pbgetvp(swapdev_vp, bp); 990df8bae1dSRodney W. Grimes 991976e77fcSDavid Greenman cnt.v_swapin++; 992976e77fcSDavid Greenman cnt.v_swappgsin += count; 993df8bae1dSRodney W. Grimes /* 99426f9a767SRodney W. Grimes * perform the I/O 995df8bae1dSRodney W. Grimes */ 996df8bae1dSRodney W. Grimes VOP_STRATEGY(bp); 99726f9a767SRodney W. Grimes 99826f9a767SRodney W. Grimes /* 99926f9a767SRodney W. Grimes * wait for the sync I/O to complete 100026f9a767SRodney W. Grimes */ 10017609ab12SDavid Greenman s = splbio(); 100226f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 100324a1cce3SDavid Greenman tsleep(bp, PVM, "swread", 0); 1004df8bae1dSRodney W. Grimes } 10051b119d9dSDavid Greenman 10061b119d9dSDavid Greenman if (bp->b_flags & B_ERROR) { 10071b119d9dSDavid Greenman printf("swap_pager: I/O error - pagein failed; blkno %d, size %d, error %d\n", 10081b119d9dSDavid Greenman bp->b_blkno, bp->b_bcount, bp->b_error); 1009a83c285cSDavid Greenman rv = VM_PAGER_ERROR; 10101b119d9dSDavid Greenman } else { 10111b119d9dSDavid Greenman rv = VM_PAGER_OK; 10121b119d9dSDavid Greenman } 101326f9a767SRodney W. Grimes 101426f9a767SRodney W. Grimes /* 10150d94caffSDavid Greenman * relpbuf does this, but we maintain our own buffer list also... 101626f9a767SRodney W. Grimes */ 1017df8bae1dSRodney W. Grimes if (bp->b_vp) 10180d94caffSDavid Greenman pbrelvp(bp); 101926f9a767SRodney W. Grimes 1020df8bae1dSRodney W. Grimes splx(s); 10212a4895f4SDavid Greenman swb[reqpage]->swb_locked--; 102226f9a767SRodney W. Grimes 102326f9a767SRodney W. Grimes /* 102426f9a767SRodney W. Grimes * remove the mapping for kernel virtual 102526f9a767SRodney W. Grimes */ 102616f62314SDavid Greenman pmap_qremove(kva, count); 102726f9a767SRodney W. Grimes 102826f9a767SRodney W. Grimes if (spc) { 1029a316d390SJohn Dyson m[reqpage]->object->last_read = m[reqpage]->pindex; 10300d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 103124a1cce3SDavid Greenman wakeup(bp); 103226f9a767SRodney W. Grimes /* 103326f9a767SRodney W. Grimes * if we have used an spc, we need to free it. 103426f9a767SRodney W. Grimes */ 103526f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 103626f9a767SRodney W. Grimes crfree(bp->b_rcred); 103726f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 103826f9a767SRodney W. Grimes crfree(bp->b_wcred); 103926f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 104026f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 104124a1cce3SDavid Greenman wakeup(&swap_pager_free); 104226f9a767SRodney W. Grimes } 1043a1f6d91cSDavid Greenman if (swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1044f919ebdeSDavid Greenman pagedaemon_wakeup(); 1045a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 104626f9a767SRodney W. Grimes } else { 104726f9a767SRodney W. Grimes /* 104826f9a767SRodney W. Grimes * release the physical I/O buffer 104926f9a767SRodney W. Grimes */ 105026f9a767SRodney W. Grimes relpbuf(bp); 105126f9a767SRodney W. Grimes /* 105226f9a767SRodney W. Grimes * finish up input if everything is ok 105326f9a767SRodney W. Grimes */ 105426f9a767SRodney W. Grimes if (rv == VM_PAGER_OK) { 105526f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 105626f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 10570d94caffSDavid Greenman m[i]->dirty = 0; 1058894048d7SJohn Dyson m[i]->flags &= ~PG_ZERO; 105926f9a767SRodney W. Grimes if (i != reqpage) { 106026f9a767SRodney W. Grimes /* 10610d94caffSDavid Greenman * whether or not to leave the page 10620d94caffSDavid Greenman * activated is up in the air, but we 10630d94caffSDavid Greenman * should put the page on a page queue 10640d94caffSDavid Greenman * somewhere. (it already is in the 10650d94caffSDavid Greenman * object). After some emperical 10660d94caffSDavid Greenman * results, it is best to deactivate 10670d94caffSDavid Greenman * the readahead pages. 106826f9a767SRodney W. Grimes */ 106926f9a767SRodney W. Grimes vm_page_deactivate(m[i]); 107026f9a767SRodney W. Grimes 107126f9a767SRodney W. Grimes /* 10720d94caffSDavid Greenman * just in case someone was asking for 10730d94caffSDavid Greenman * this page we now tell them that it 10740d94caffSDavid Greenman * is ok to use 107526f9a767SRodney W. Grimes */ 10760d94caffSDavid Greenman m[i]->valid = VM_PAGE_BITS_ALL; 107726f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 107826f9a767SRodney W. Grimes } 107926f9a767SRodney W. Grimes } 10806d40c3d3SDavid Greenman 1081a316d390SJohn Dyson m[reqpage]->object->last_read = m[count-1]->pindex; 10826d40c3d3SDavid Greenman 10832e1e24ddSDavid Greenman /* 10842e1e24ddSDavid Greenman * If we're out of swap space, then attempt to free 10852e1e24ddSDavid Greenman * some whenever pages are brought in. We must clear 10862e1e24ddSDavid Greenman * the clean flag so that the page contents will be 10872e1e24ddSDavid Greenman * preserved. 10882e1e24ddSDavid Greenman */ 108926f9a767SRodney W. Grimes if (swap_pager_full) { 10902e1e24ddSDavid Greenman for (i = 0; i < count; i++) { 10910d94caffSDavid Greenman m[i]->dirty = VM_PAGE_BITS_ALL; 10922e1e24ddSDavid Greenman } 1093a316d390SJohn Dyson swap_pager_freespace(object, m[0]->pindex + paging_offset, count); 109426f9a767SRodney W. Grimes } 109526f9a767SRodney W. Grimes } else { 109626f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage); 109726f9a767SRodney W. Grimes } 109826f9a767SRodney W. Grimes } 109923922ccaSDavid Greenman if (rv == VM_PAGER_OK) { 110023922ccaSDavid Greenman pmap_clear_modify(VM_PAGE_TO_PHYS(m[reqpage])); 110123922ccaSDavid Greenman m[reqpage]->valid = VM_PAGE_BITS_ALL; 110223922ccaSDavid Greenman m[reqpage]->dirty = 0; 110323922ccaSDavid Greenman } 1104df8bae1dSRodney W. Grimes return (rv); 1105df8bae1dSRodney W. Grimes } 1106df8bae1dSRodney W. Grimes 110726f9a767SRodney W. Grimes int 110824a1cce3SDavid Greenman swap_pager_putpages(object, m, count, sync, rtvals) 110924a1cce3SDavid Greenman vm_object_t object; 111026f9a767SRodney W. Grimes vm_page_t *m; 111126f9a767SRodney W. Grimes int count; 111224a1cce3SDavid Greenman boolean_t sync; 111326f9a767SRodney W. Grimes int *rtvals; 1114df8bae1dSRodney W. Grimes { 111526f9a767SRodney W. Grimes register struct buf *bp; 111626f9a767SRodney W. Grimes sw_blk_t swb[count]; 111726f9a767SRodney W. Grimes register int s; 111826f9a767SRodney W. Grimes int i, j, ix; 111926f9a767SRodney W. Grimes boolean_t rv; 1120a316d390SJohn Dyson vm_offset_t kva, off, fidx; 112126f9a767SRodney W. Grimes swp_clean_t spc; 1122a316d390SJohn Dyson vm_pindex_t paging_pindex; 112326f9a767SRodney W. Grimes int reqaddr[count]; 112426f9a767SRodney W. Grimes int failed; 1125df8bae1dSRodney W. Grimes 112624ea4a96SDavid Greenman if (vm_swap_size) 112724ea4a96SDavid Greenman no_swap_space = 0; 112824ea4a96SDavid Greenman if (no_swap_space) { 11295663e6deSDavid Greenman for (i = 0; i < count; i++) 11305663e6deSDavid Greenman rtvals[i] = VM_PAGER_FAIL; 11315663e6deSDavid Greenman return VM_PAGER_FAIL; 11325663e6deSDavid Greenman } 113326f9a767SRodney W. Grimes spc = NULL; 113426f9a767SRodney W. Grimes 113526f9a767SRodney W. Grimes object = m[0]->object; 1136a316d390SJohn Dyson paging_pindex = OFF_TO_IDX(object->paging_offset); 113726f9a767SRodney W. Grimes 113826f9a767SRodney W. Grimes failed = 0; 113926f9a767SRodney W. Grimes for (j = 0; j < count; j++) { 1140a316d390SJohn Dyson fidx = m[j]->pindex + paging_pindex; 1141a316d390SJohn Dyson ix = swap_pager_block_index(fidx); 114226f9a767SRodney W. Grimes swb[j] = 0; 11432a4895f4SDavid Greenman if (ix >= object->un_pager.swp.swp_nblocks) { 114426f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 114526f9a767SRodney W. Grimes failed = 1; 114626f9a767SRodney W. Grimes continue; 114726f9a767SRodney W. Grimes } else { 114826f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_OK; 114926f9a767SRodney W. Grimes } 11502a4895f4SDavid Greenman swb[j] = &object->un_pager.swp.swp_blocks[ix]; 11512a4895f4SDavid Greenman swb[j]->swb_locked++; 115226f9a767SRodney W. Grimes if (failed) { 115326f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_FAIL; 115426f9a767SRodney W. Grimes continue; 115526f9a767SRodney W. Grimes } 1156a316d390SJohn Dyson off = swap_pager_block_offset(fidx); 115726f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 115826f9a767SRodney W. Grimes if (reqaddr[j] == SWB_EMPTY) { 1159a316d390SJohn Dyson daddr_t blk; 116026f9a767SRodney W. Grimes int tries; 116126f9a767SRodney W. Grimes int ntoget; 11620d94caffSDavid Greenman 116326f9a767SRodney W. Grimes tries = 0; 1164df8bae1dSRodney W. Grimes s = splbio(); 116526f9a767SRodney W. Grimes 1166df8bae1dSRodney W. Grimes /* 11670d94caffSDavid Greenman * if any other pages have been allocated in this 11680d94caffSDavid Greenman * block, we only try to get one page. 1169df8bae1dSRodney W. Grimes */ 117026f9a767SRodney W. Grimes for (i = 0; i < SWB_NPAGES; i++) { 117126f9a767SRodney W. Grimes if (swb[j]->swb_block[i] != SWB_EMPTY) 1172df8bae1dSRodney W. Grimes break; 1173df8bae1dSRodney W. Grimes } 117426f9a767SRodney W. Grimes 117526f9a767SRodney W. Grimes ntoget = (i == SWB_NPAGES) ? SWB_NPAGES : 1; 117626f9a767SRodney W. Grimes /* 11770d94caffSDavid Greenman * this code is alittle conservative, but works (the 11780d94caffSDavid Greenman * intent of this code is to allocate small chunks for 11790d94caffSDavid Greenman * small objects) 118026f9a767SRodney W. Grimes */ 1181a316d390SJohn Dyson if ((off == 0) && ((fidx + ntoget) > object->size)) { 1182a316d390SJohn Dyson ntoget = object->size - fidx; 118326f9a767SRodney W. Grimes } 118426f9a767SRodney W. Grimes retrygetspace: 118526f9a767SRodney W. Grimes if (!swap_pager_full && ntoget > 1 && 1186a316d390SJohn Dyson swap_pager_getswapspace(object, ntoget * btodb(PAGE_SIZE), 1187a316d390SJohn Dyson &blk)) { 118826f9a767SRodney W. Grimes 118926f9a767SRodney W. Grimes for (i = 0; i < ntoget; i++) { 119026f9a767SRodney W. Grimes swb[j]->swb_block[i] = blk + btodb(PAGE_SIZE) * i; 119126f9a767SRodney W. Grimes swb[j]->swb_valid = 0; 119226f9a767SRodney W. Grimes } 119326f9a767SRodney W. Grimes 119426f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 11952a4895f4SDavid Greenman } else if (!swap_pager_getswapspace(object, btodb(PAGE_SIZE), 119626f9a767SRodney W. Grimes &swb[j]->swb_block[off])) { 119726f9a767SRodney W. Grimes /* 11980d94caffSDavid Greenman * if the allocation has failed, we try to 11990d94caffSDavid Greenman * reclaim space and retry. 120026f9a767SRodney W. Grimes */ 120126f9a767SRodney W. Grimes if (++tries == 1) { 120226f9a767SRodney W. Grimes swap_pager_reclaim(); 120326f9a767SRodney W. Grimes goto retrygetspace; 120426f9a767SRodney W. Grimes } 120526f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_AGAIN; 120626f9a767SRodney W. Grimes failed = 1; 120724ea4a96SDavid Greenman swap_pager_full = 1; 120826f9a767SRodney W. Grimes } else { 120926f9a767SRodney W. Grimes reqaddr[j] = swb[j]->swb_block[off]; 121026f9a767SRodney W. Grimes swb[j]->swb_valid &= ~(1 << off); 1211df8bae1dSRodney W. Grimes } 1212df8bae1dSRodney W. Grimes splx(s); 121326f9a767SRodney W. Grimes } 121426f9a767SRodney W. Grimes } 121526f9a767SRodney W. Grimes 121626f9a767SRodney W. Grimes /* 121726f9a767SRodney W. Grimes * search forwards for the last contiguous page to transfer 121826f9a767SRodney W. Grimes */ 121926f9a767SRodney W. Grimes failed = 0; 122026f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 1221a316d390SJohn Dyson if (failed || 1222a316d390SJohn Dyson (reqaddr[i] != reqaddr[0] + i * btodb(PAGE_SIZE)) || 1223a316d390SJohn Dyson ((reqaddr[i] / dmmax) != (reqaddr[0] / dmmax)) || 122426f9a767SRodney W. Grimes (rtvals[i] != VM_PAGER_OK)) { 122526f9a767SRodney W. Grimes failed = 1; 122626f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) 122726f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 122826f9a767SRodney W. Grimes } 122926f9a767SRodney W. Grimes } 123026f9a767SRodney W. Grimes 123126f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 123226f9a767SRodney W. Grimes if (rtvals[i] != VM_PAGER_OK) { 123326f9a767SRodney W. Grimes if (swb[i]) 123426f9a767SRodney W. Grimes --swb[i]->swb_locked; 123526f9a767SRodney W. Grimes } 123626f9a767SRodney W. Grimes } 123726f9a767SRodney W. Grimes 123826f9a767SRodney W. Grimes for (i = 0; i < count; i++) 123926f9a767SRodney W. Grimes if (rtvals[i] != VM_PAGER_OK) 124026f9a767SRodney W. Grimes break; 124126f9a767SRodney W. Grimes 124226f9a767SRodney W. Grimes if (i == 0) { 124326f9a767SRodney W. Grimes return VM_PAGER_AGAIN; 124426f9a767SRodney W. Grimes } 124526f9a767SRodney W. Grimes count = i; 124626f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 1247a316d390SJohn Dyson if (reqaddr[i] == SWB_EMPTY) { 1248a316d390SJohn Dyson printf("I/O to empty block???? -- pindex: %d, i: %d\n", 1249a316d390SJohn Dyson m[i]->pindex, i); 1250a316d390SJohn Dyson } 125126f9a767SRodney W. Grimes } 125226f9a767SRodney W. Grimes 125326f9a767SRodney W. Grimes /* 12540d94caffSDavid Greenman * For synchronous writes, we clean up all completed async pageouts. 125526f9a767SRodney W. Grimes */ 125624a1cce3SDavid Greenman if (sync == TRUE) { 125724a1cce3SDavid Greenman swap_pager_sync(); 125826f9a767SRodney W. Grimes } 125926f9a767SRodney W. Grimes kva = 0; 126026f9a767SRodney W. Grimes 126126f9a767SRodney W. Grimes /* 126226f9a767SRodney W. Grimes * get a swap pager clean data structure, block until we get it 126326f9a767SRodney W. Grimes */ 1264a1f6d91cSDavid Greenman if (swap_pager_free.tqh_first == NULL || 1265a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next == NULL || 1266a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { 126726f9a767SRodney W. Grimes s = splbio(); 12680d94caffSDavid Greenman if (curproc == pageproc) { 1269bd7e5f99SJohn Dyson retryfree: 1270cb6962cdSJohn Dyson /* 1271cb6962cdSJohn Dyson * pageout daemon needs a swap control block 1272cb6962cdSJohn Dyson */ 1273cb6962cdSJohn Dyson swap_pager_needflags |= SWAP_FREE_NEEDED_BY_PAGEOUT|SWAP_FREE_NEEDED; 1274cb6962cdSJohn Dyson /* 1275cb6962cdSJohn Dyson * if it does not get one within a short time, then 1276cb6962cdSJohn Dyson * there is a potential deadlock, so we go-on trying 1277bd7e5f99SJohn Dyson * to free pages. It is important to block here as opposed 1278bd7e5f99SJohn Dyson * to returning, thereby allowing the pageout daemon to continue. 1279bd7e5f99SJohn Dyson * It is likely that pageout daemon will start suboptimally 1280bd7e5f99SJohn Dyson * reclaiming vnode backed pages if we don't block. Since the 1281bd7e5f99SJohn Dyson * I/O subsystem is probably already fully utilized, might as 1282bd7e5f99SJohn Dyson * well wait. 1283cb6962cdSJohn Dyson */ 1284bd7e5f99SJohn Dyson if (tsleep(&swap_pager_free, PVM, "swpfre", hz/5)) { 128524a1cce3SDavid Greenman swap_pager_sync(); 1286cb6962cdSJohn Dyson if (swap_pager_free.tqh_first == NULL || 1287cb6962cdSJohn Dyson swap_pager_free.tqh_first->spc_list.tqe_next == NULL || 1288cb6962cdSJohn Dyson swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { 12890d94caffSDavid Greenman splx(s); 12900d94caffSDavid Greenman return VM_PAGER_AGAIN; 1291cb6962cdSJohn Dyson } 1292bd7e5f99SJohn Dyson } else { 1293bd7e5f99SJohn Dyson /* 1294bd7e5f99SJohn Dyson * we make sure that pageouts aren't taking up all of 1295bd7e5f99SJohn Dyson * the free swap control blocks. 1296bd7e5f99SJohn Dyson */ 1297bd7e5f99SJohn Dyson swap_pager_sync(); 1298bd7e5f99SJohn Dyson if (swap_pager_free.tqh_first == NULL || 1299bd7e5f99SJohn Dyson swap_pager_free.tqh_first->spc_list.tqe_next == NULL || 1300bd7e5f99SJohn Dyson swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { 1301bd7e5f99SJohn Dyson goto retryfree; 1302bd7e5f99SJohn Dyson } 1303bd7e5f99SJohn Dyson } 1304bd7e5f99SJohn Dyson } else { 1305f919ebdeSDavid Greenman pagedaemon_wakeup(); 1306a1f6d91cSDavid Greenman while (swap_pager_free.tqh_first == NULL || 1307a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next == NULL || 1308a1f6d91cSDavid Greenman swap_pager_free.tqh_first->spc_list.tqe_next->spc_list.tqe_next == NULL) { 130926f9a767SRodney W. Grimes swap_pager_needflags |= SWAP_FREE_NEEDED; 131024a1cce3SDavid Greenman tsleep(&swap_pager_free, PVM, "swpfre", 0); 1311f919ebdeSDavid Greenman pagedaemon_wakeup(); 131226f9a767SRodney W. Grimes } 1313bd7e5f99SJohn Dyson } 131426f9a767SRodney W. Grimes splx(s); 131526f9a767SRodney W. Grimes } 131626f9a767SRodney W. Grimes spc = swap_pager_free.tqh_first; 131726f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_free, spc, spc_list); 1318fff93ab6SDavid Greenman 131926f9a767SRodney W. Grimes kva = spc->spc_kva; 132026f9a767SRodney W. Grimes 132126f9a767SRodney W. Grimes /* 132226f9a767SRodney W. Grimes * map our page(s) into kva for I/O 132326f9a767SRodney W. Grimes */ 132416f62314SDavid Greenman pmap_qenter(kva, m, count); 132526f9a767SRodney W. Grimes 132626f9a767SRodney W. Grimes /* 132726f9a767SRodney W. Grimes * get the base I/O offset into the swap file 132826f9a767SRodney W. Grimes */ 132926f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 1330a316d390SJohn Dyson fidx = m[i]->pindex + paging_pindex; 1331a316d390SJohn Dyson off = swap_pager_block_offset(fidx); 133226f9a767SRodney W. Grimes /* 133326f9a767SRodney W. Grimes * set the valid bit 133426f9a767SRodney W. Grimes */ 133526f9a767SRodney W. Grimes swb[i]->swb_valid |= (1 << off); 133626f9a767SRodney W. Grimes /* 133726f9a767SRodney W. Grimes * and unlock the data structure 133826f9a767SRodney W. Grimes */ 13392a4895f4SDavid Greenman swb[i]->swb_locked--; 134026f9a767SRodney W. Grimes } 134126f9a767SRodney W. Grimes 134226f9a767SRodney W. Grimes /* 134326f9a767SRodney W. Grimes * Get a swap buffer header and perform the IO 134426f9a767SRodney W. Grimes */ 134526f9a767SRodney W. Grimes bp = spc->spc_bp; 134626f9a767SRodney W. Grimes bzero(bp, sizeof *bp); 134726f9a767SRodney W. Grimes bp->b_spc = spc; 13487609ab12SDavid Greenman bp->b_vnbufs.le_next = NOLIST; 134926f9a767SRodney W. Grimes 1350aba8f38eSDavid Greenman bp->b_flags = B_BUSY | B_PAGING; 135126f9a767SRodney W. Grimes bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ 135226f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 1353a481f200SDavid Greenman if (bp->b_rcred != NOCRED) 135426f9a767SRodney W. Grimes crhold(bp->b_rcred); 1355a481f200SDavid Greenman if (bp->b_wcred != NOCRED) 135626f9a767SRodney W. Grimes crhold(bp->b_wcred); 1357a481f200SDavid Greenman bp->b_data = (caddr_t) kva; 135826f9a767SRodney W. Grimes bp->b_blkno = reqaddr[0]; 13590d94caffSDavid Greenman pbgetvp(swapdev_vp, bp); 136016f62314SDavid Greenman 136126f9a767SRodney W. Grimes bp->b_bcount = PAGE_SIZE * count; 136226f9a767SRodney W. Grimes bp->b_bufsize = PAGE_SIZE * count; 136326f9a767SRodney W. Grimes swapdev_vp->v_numoutput++; 136426f9a767SRodney W. Grimes 136526f9a767SRodney W. Grimes /* 13660d94caffSDavid Greenman * If this is an async write we set up additional buffer fields and 13670d94caffSDavid Greenman * place a "cleaning" entry on the inuse queue. 136826f9a767SRodney W. Grimes */ 13697609ab12SDavid Greenman s = splbio(); 137024a1cce3SDavid Greenman if (sync == FALSE) { 137126f9a767SRodney W. Grimes spc->spc_flags = 0; 13722a4895f4SDavid Greenman spc->spc_object = object; 137326f9a767SRodney W. Grimes for (i = 0; i < count; i++) 137426f9a767SRodney W. Grimes spc->spc_m[i] = m[i]; 137526f9a767SRodney W. Grimes spc->spc_count = count; 137626f9a767SRodney W. Grimes /* 137726f9a767SRodney W. Grimes * the completion routine for async writes 137826f9a767SRodney W. Grimes */ 137926f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 138026f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone; 138126f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 138226f9a767SRodney W. Grimes bp->b_dirtyend = bp->b_bcount; 13832a4895f4SDavid Greenman object->un_pager.swp.swp_poip++; 138426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list); 138526f9a767SRodney W. Grimes } else { 13862a4895f4SDavid Greenman object->un_pager.swp.swp_poip++; 138726f9a767SRodney W. Grimes bp->b_flags |= B_CALL; 138826f9a767SRodney W. Grimes bp->b_iodone = swap_pager_iodone1; 138926f9a767SRodney W. Grimes } 1390976e77fcSDavid Greenman 1391976e77fcSDavid Greenman cnt.v_swapout++; 1392976e77fcSDavid Greenman cnt.v_swappgsout += count; 139326f9a767SRodney W. Grimes /* 139426f9a767SRodney W. Grimes * perform the I/O 139526f9a767SRodney W. Grimes */ 139626f9a767SRodney W. Grimes VOP_STRATEGY(bp); 139724a1cce3SDavid Greenman if (sync == FALSE) { 139826f9a767SRodney W. Grimes if ((bp->b_flags & B_DONE) == B_DONE) { 139924a1cce3SDavid Greenman swap_pager_sync(); 140026f9a767SRodney W. Grimes } 140126f9a767SRodney W. Grimes splx(s); 140226f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 140326f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_PEND; 140426f9a767SRodney W. Grimes } 140526f9a767SRodney W. Grimes return VM_PAGER_PEND; 140626f9a767SRodney W. Grimes } 140726f9a767SRodney W. Grimes /* 140826f9a767SRodney W. Grimes * wait for the sync I/O to complete 140926f9a767SRodney W. Grimes */ 141026f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 141124a1cce3SDavid Greenman tsleep(bp, PVM, "swwrt", 0); 141226f9a767SRodney W. Grimes } 14131b119d9dSDavid Greenman if (bp->b_flags & B_ERROR) { 14141b119d9dSDavid Greenman printf("swap_pager: I/O error - pageout failed; blkno %d, size %d, error %d\n", 14151b119d9dSDavid Greenman bp->b_blkno, bp->b_bcount, bp->b_error); 1416a83c285cSDavid Greenman rv = VM_PAGER_ERROR; 14171b119d9dSDavid Greenman } else { 14181b119d9dSDavid Greenman rv = VM_PAGER_OK; 14191b119d9dSDavid Greenman } 142026f9a767SRodney W. Grimes 14212a4895f4SDavid Greenman object->un_pager.swp.swp_poip--; 14222a4895f4SDavid Greenman if (object->un_pager.swp.swp_poip == 0) 14232a4895f4SDavid Greenman wakeup(object); 142426f9a767SRodney W. Grimes 142526f9a767SRodney W. Grimes if (bp->b_vp) 14260d94caffSDavid Greenman pbrelvp(bp); 14270d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 142824a1cce3SDavid Greenman wakeup(bp); 142926f9a767SRodney W. Grimes 143026f9a767SRodney W. Grimes splx(s); 143126f9a767SRodney W. Grimes 143226f9a767SRodney W. Grimes /* 143326f9a767SRodney W. Grimes * remove the mapping for kernel virtual 143426f9a767SRodney W. Grimes */ 143516f62314SDavid Greenman pmap_qremove(kva, count); 143626f9a767SRodney W. Grimes 143726f9a767SRodney W. Grimes /* 14380d94caffSDavid Greenman * if we have written the page, then indicate that the page is clean. 143926f9a767SRodney W. Grimes */ 144026f9a767SRodney W. Grimes if (rv == VM_PAGER_OK) { 144126f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 144226f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) { 144326f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 14440d94caffSDavid Greenman m[i]->dirty = 0; 144526f9a767SRodney W. Grimes /* 14460d94caffSDavid Greenman * optimization, if a page has been read 14470d94caffSDavid Greenman * during the pageout process, we activate it. 144826f9a767SRodney W. Grimes */ 1449bd7e5f99SJohn Dyson if ((m[i]->queue != PQ_ACTIVE) && 14507fb0c17eSDavid Greenman ((m[i]->flags & (PG_WANTED|PG_REFERENCED)) || 14517fb0c17eSDavid Greenman pmap_is_referenced(VM_PAGE_TO_PHYS(m[i])))) { 145226f9a767SRodney W. Grimes vm_page_activate(m[i]); 145326f9a767SRodney W. Grimes } 145426f9a767SRodney W. Grimes } 14557fb0c17eSDavid Greenman } 145626f9a767SRodney W. Grimes } else { 145726f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 145826f9a767SRodney W. Grimes rtvals[i] = rv; 145926f9a767SRodney W. Grimes } 146026f9a767SRodney W. Grimes } 146126f9a767SRodney W. Grimes 146226f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 146326f9a767SRodney W. Grimes crfree(bp->b_rcred); 146426f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 146526f9a767SRodney W. Grimes crfree(bp->b_wcred); 146626f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 146726f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 146824a1cce3SDavid Greenman wakeup(&swap_pager_free); 146926f9a767SRodney W. Grimes } 1470a1f6d91cSDavid Greenman if (swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1471f919ebdeSDavid Greenman pagedaemon_wakeup(); 1472a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 147326f9a767SRodney W. Grimes return (rv); 147426f9a767SRodney W. Grimes } 147526f9a767SRodney W. Grimes 1476f708ef1bSPoul-Henning Kamp static void 147724a1cce3SDavid Greenman swap_pager_sync() 147826f9a767SRodney W. Grimes { 147926f9a767SRodney W. Grimes register swp_clean_t spc, tspc; 148026f9a767SRodney W. Grimes register int s; 148126f9a767SRodney W. Grimes 148226f9a767SRodney W. Grimes tspc = NULL; 148326f9a767SRodney W. Grimes if (swap_pager_done.tqh_first == NULL) 148424a1cce3SDavid Greenman return; 148526f9a767SRodney W. Grimes for (;;) { 148626f9a767SRodney W. Grimes s = splbio(); 148726f9a767SRodney W. Grimes /* 14880d94caffSDavid Greenman * Look up and removal from done list must be done at splbio() 14890d94caffSDavid Greenman * to avoid conflicts with swap_pager_iodone. 149026f9a767SRodney W. Grimes */ 149105f0fdd2SPoul-Henning Kamp while ((spc = swap_pager_done.tqh_first) != 0) { 1492fff93ab6SDavid Greenman pmap_qremove(spc->spc_kva, spc->spc_count); 149326f9a767SRodney W. Grimes swap_pager_finish(spc); 149426f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_done, spc, spc_list); 149526f9a767SRodney W. Grimes goto doclean; 149626f9a767SRodney W. Grimes } 1497df8bae1dSRodney W. Grimes 1498df8bae1dSRodney W. Grimes /* 1499df8bae1dSRodney W. Grimes * No operations done, thats all we can do for now. 1500df8bae1dSRodney W. Grimes */ 150126f9a767SRodney W. Grimes 150226f9a767SRodney W. Grimes splx(s); 1503df8bae1dSRodney W. Grimes break; 1504df8bae1dSRodney W. Grimes 1505df8bae1dSRodney W. Grimes /* 15060d94caffSDavid Greenman * The desired page was found to be busy earlier in the scan 15070d94caffSDavid Greenman * but has since completed. 1508df8bae1dSRodney W. Grimes */ 150926f9a767SRodney W. Grimes doclean: 151026f9a767SRodney W. Grimes if (tspc && tspc == spc) { 151126f9a767SRodney W. Grimes tspc = NULL; 151226f9a767SRodney W. Grimes } 151326f9a767SRodney W. Grimes spc->spc_flags = 0; 151426f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list); 151526f9a767SRodney W. Grimes if (swap_pager_needflags & SWAP_FREE_NEEDED) { 151624a1cce3SDavid Greenman wakeup(&swap_pager_free); 151726f9a767SRodney W. Grimes } 1518a1f6d91cSDavid Greenman if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) 1519f919ebdeSDavid Greenman pagedaemon_wakeup(); 1520a1f6d91cSDavid Greenman swap_pager_needflags &= ~(SWAP_FREE_NEEDED|SWAP_FREE_NEEDED_BY_PAGEOUT); 152126f9a767SRodney W. Grimes splx(s); 152226f9a767SRodney W. Grimes } 152326f9a767SRodney W. Grimes 152424a1cce3SDavid Greenman return; 152526f9a767SRodney W. Grimes } 152626f9a767SRodney W. Grimes 152726f9a767SRodney W. Grimes void 152826f9a767SRodney W. Grimes swap_pager_finish(spc) 152926f9a767SRodney W. Grimes register swp_clean_t spc; 153026f9a767SRodney W. Grimes { 153126f9a767SRodney W. Grimes vm_object_t object = spc->spc_m[0]->object; 153226f9a767SRodney W. Grimes int i; 153326f9a767SRodney W. Grimes 1534c0503609SDavid Greenman object->paging_in_progress -= spc->spc_count; 1535c0503609SDavid Greenman if ((object->paging_in_progress == 0) && 1536c0503609SDavid Greenman (object->flags & OBJ_PIPWNT)) { 1537c0503609SDavid Greenman object->flags &= ~OBJ_PIPWNT; 153824a1cce3SDavid Greenman wakeup(object); 1539c0503609SDavid Greenman } 1540df8bae1dSRodney W. Grimes 1541df8bae1dSRodney W. Grimes /* 15425f55e841SDavid Greenman * If no error, mark as clean and inform the pmap system. If error, 15430d94caffSDavid Greenman * mark as dirty so we will try again. (XXX could get stuck doing 15440d94caffSDavid Greenman * this, should give up after awhile) 1545df8bae1dSRodney W. Grimes */ 1546df8bae1dSRodney W. Grimes if (spc->spc_flags & SPC_ERROR) { 154726f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 1548a83c285cSDavid Greenman printf("swap_pager_finish: I/O error, clean of page %lx failed\n", 154905f0fdd2SPoul-Henning Kamp (u_long) VM_PAGE_TO_PHYS(spc->spc_m[i])); 155026f9a767SRodney W. Grimes } 1551df8bae1dSRodney W. Grimes } else { 155226f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 155326f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m[i])); 15540d94caffSDavid Greenman spc->spc_m[i]->dirty = 0; 1555bd7e5f99SJohn Dyson if ((spc->spc_m[i]->queue != PQ_ACTIVE) && 15560d94caffSDavid Greenman ((spc->spc_m[i]->flags & PG_WANTED) || pmap_is_referenced(VM_PAGE_TO_PHYS(spc->spc_m[i])))) 15570d94caffSDavid Greenman vm_page_activate(spc->spc_m[i]); 1558df8bae1dSRodney W. Grimes } 1559df8bae1dSRodney W. Grimes } 1560df8bae1dSRodney W. Grimes 156126f9a767SRodney W. Grimes 156226f9a767SRodney W. Grimes for (i = 0; i < spc->spc_count; i++) { 1563df8bae1dSRodney W. Grimes /* 15640d94caffSDavid Greenman * we wakeup any processes that are waiting on these pages. 1565df8bae1dSRodney W. Grimes */ 156626f9a767SRodney W. Grimes PAGE_WAKEUP(spc->spc_m[i]); 1567df8bae1dSRodney W. Grimes } 156826f9a767SRodney W. Grimes nswiodone -= spc->spc_count; 1569df8bae1dSRodney W. Grimes 1570df8bae1dSRodney W. Grimes return; 157126f9a767SRodney W. Grimes } 1572df8bae1dSRodney W. Grimes 157326f9a767SRodney W. Grimes /* 157426f9a767SRodney W. Grimes * swap_pager_iodone 157526f9a767SRodney W. Grimes */ 1576f5a12711SPoul-Henning Kamp static void 1577df8bae1dSRodney W. Grimes swap_pager_iodone(bp) 1578df8bae1dSRodney W. Grimes register struct buf *bp; 1579df8bae1dSRodney W. Grimes { 1580df8bae1dSRodney W. Grimes register swp_clean_t spc; 1581df8bae1dSRodney W. Grimes int s; 1582df8bae1dSRodney W. Grimes 1583df8bae1dSRodney W. Grimes s = splbio(); 158426f9a767SRodney W. Grimes spc = (swp_clean_t) bp->b_spc; 158526f9a767SRodney W. Grimes TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list); 158626f9a767SRodney W. Grimes TAILQ_INSERT_TAIL(&swap_pager_done, spc, spc_list); 158726f9a767SRodney W. Grimes if (bp->b_flags & B_ERROR) { 1588df8bae1dSRodney W. Grimes spc->spc_flags |= SPC_ERROR; 1589c3a1e425SDavid Greenman printf("swap_pager: I/O error - async %s failed; blkno %lu, size %ld, error %d\n", 15901b119d9dSDavid Greenman (bp->b_flags & B_READ) ? "pagein" : "pageout", 1591c3a1e425SDavid Greenman (u_long) bp->b_blkno, bp->b_bcount, bp->b_error); 1592df8bae1dSRodney W. Grimes } 159326f9a767SRodney W. Grimes 15940d94caffSDavid Greenman if (bp->b_vp) 15950d94caffSDavid Greenman pbrelvp(bp); 15960d94caffSDavid Greenman 15970d94caffSDavid Greenman if (bp->b_flags & B_WANTED) 159824a1cce3SDavid Greenman wakeup(bp); 15990d94caffSDavid Greenman 160026f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 160126f9a767SRodney W. Grimes crfree(bp->b_rcred); 160226f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 160326f9a767SRodney W. Grimes crfree(bp->b_wcred); 160426f9a767SRodney W. Grimes 160526f9a767SRodney W. Grimes nswiodone += spc->spc_count; 16062a4895f4SDavid Greenman if (--spc->spc_object->un_pager.swp.swp_poip == 0) { 16072a4895f4SDavid Greenman wakeup(spc->spc_object); 160826f9a767SRodney W. Grimes } 160926f9a767SRodney W. Grimes if ((swap_pager_needflags & SWAP_FREE_NEEDED) || 161026f9a767SRodney W. Grimes swap_pager_inuse.tqh_first == 0) { 161126f9a767SRodney W. Grimes swap_pager_needflags &= ~SWAP_FREE_NEEDED; 161224a1cce3SDavid Greenman wakeup(&swap_pager_free); 1613a1f6d91cSDavid Greenman } 1614a1f6d91cSDavid Greenman 1615a1f6d91cSDavid Greenman if( swap_pager_needflags & SWAP_FREE_NEEDED_BY_PAGEOUT) { 1616a1f6d91cSDavid Greenman swap_pager_needflags &= ~SWAP_FREE_NEEDED_BY_PAGEOUT; 1617f919ebdeSDavid Greenman pagedaemon_wakeup(); 161826f9a767SRodney W. Grimes } 1619a1f6d91cSDavid Greenman 162026f9a767SRodney W. Grimes if (vm_pageout_pages_needed) { 162124a1cce3SDavid Greenman wakeup(&vm_pageout_pages_needed); 1622a1f6d91cSDavid Greenman vm_pageout_pages_needed = 0; 162326f9a767SRodney W. Grimes } 162426f9a767SRodney W. Grimes if ((swap_pager_inuse.tqh_first == NULL) || 16250d94caffSDavid Greenman ((cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min && 16260d94caffSDavid Greenman nswiodone + cnt.v_free_count + cnt.v_cache_count >= cnt.v_free_min)) { 1627f919ebdeSDavid Greenman pagedaemon_wakeup(); 162826f9a767SRodney W. Grimes } 162926f9a767SRodney W. Grimes splx(s); 163026f9a767SRodney W. Grimes } 1631