xref: /plan9-contrib/sys/src/9/port/swap.c (revision d1be6b086622eecc0da76db1fbd64349a5e85293)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
73e12c5d1SDavid du Colombier 
87dd7cddfSDavid du Colombier static int	canflush(Proc*, Segment*);
97dd7cddfSDavid du Colombier static void	executeio(void);
107dd7cddfSDavid du Colombier static int	needpages(void*);
117dd7cddfSDavid du Colombier static void	pageout(Proc*, Segment*);
127dd7cddfSDavid du Colombier static void	pagepte(int, Page**);
137dd7cddfSDavid du Colombier static void	pager(void*);
143e12c5d1SDavid du Colombier 
153e12c5d1SDavid du Colombier Image 	swapimage;
16*d1be6b08SDavid du Colombier 
173e12c5d1SDavid du Colombier static 	int	swopen;
18bd389b36SDavid du Colombier static	Page	**iolist;
193e12c5d1SDavid du Colombier static	int	ioptr;
203e12c5d1SDavid du Colombier 
21*d1be6b08SDavid du Colombier static	ulong	genage, genclock, gencount;
22*d1be6b08SDavid du Colombier static	uvlong	gensum;
23*d1be6b08SDavid du Colombier 
24*d1be6b08SDavid du Colombier static void
gentick(void)25*d1be6b08SDavid du Colombier gentick(void)
26*d1be6b08SDavid du Colombier {
27*d1be6b08SDavid du Colombier 	genclock++;
28*d1be6b08SDavid du Colombier 	if(gencount)
29*d1be6b08SDavid du Colombier 		genage = gensum / gencount;
30*d1be6b08SDavid du Colombier 	else
31*d1be6b08SDavid du Colombier 		genage = 0;
32*d1be6b08SDavid du Colombier 	gensum = gencount = 0;
33*d1be6b08SDavid du Colombier }
34*d1be6b08SDavid du Colombier 
353e12c5d1SDavid du Colombier void
swapinit(void)363e12c5d1SDavid du Colombier swapinit(void)
373e12c5d1SDavid du Colombier {
383e12c5d1SDavid du Colombier 	swapalloc.swmap = xalloc(conf.nswap);
393e12c5d1SDavid du Colombier 	swapalloc.top = &swapalloc.swmap[conf.nswap];
403e12c5d1SDavid du Colombier 	swapalloc.alloc = swapalloc.swmap;
413e12c5d1SDavid du Colombier 	swapalloc.last = swapalloc.swmap;
423e12c5d1SDavid du Colombier 	swapalloc.free = conf.nswap;
437dd7cddfSDavid du Colombier 	iolist = xalloc(conf.nswppo*sizeof(Page*));
44bd389b36SDavid du Colombier 	if(swapalloc.swmap == 0 || iolist == 0)
45bd389b36SDavid du Colombier 		panic("swapinit: not enough memory");
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier 	swapimage.notext = 1;
483e12c5d1SDavid du Colombier }
493e12c5d1SDavid du Colombier 
503e12c5d1SDavid du Colombier ulong
newswap(void)513e12c5d1SDavid du Colombier newswap(void)
523e12c5d1SDavid du Colombier {
533e12c5d1SDavid du Colombier 	uchar *look;
543e12c5d1SDavid du Colombier 
553e12c5d1SDavid du Colombier 	lock(&swapalloc);
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier 	if(swapalloc.free == 0){
587dd7cddfSDavid du Colombier 		unlock(&swapalloc);
597dd7cddfSDavid du Colombier 		return ~0;
607dd7cddfSDavid du Colombier 	}
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier 	look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);
633e12c5d1SDavid du Colombier 	if(look == 0)
643e12c5d1SDavid du Colombier 		panic("inconsistent swap");
653e12c5d1SDavid du Colombier 
663e12c5d1SDavid du Colombier 	*look = 1;
673e12c5d1SDavid du Colombier 	swapalloc.last = look;
683e12c5d1SDavid du Colombier 	swapalloc.free--;
693e12c5d1SDavid du Colombier 	unlock(&swapalloc);
703e12c5d1SDavid du Colombier 	return (look-swapalloc.swmap) * BY2PG;
713e12c5d1SDavid du Colombier }
723e12c5d1SDavid du Colombier 
733e12c5d1SDavid du Colombier void
putswap(Page * p)743e12c5d1SDavid du Colombier putswap(Page *p)
753e12c5d1SDavid du Colombier {
763e12c5d1SDavid du Colombier 	uchar *idx;
773e12c5d1SDavid du Colombier 
783e12c5d1SDavid du Colombier 	lock(&swapalloc);
793e12c5d1SDavid du Colombier 	idx = &swapalloc.swmap[((ulong)p)/BY2PG];
803e12c5d1SDavid du Colombier 	if(--(*idx) == 0) {
813e12c5d1SDavid du Colombier 		swapalloc.free++;
823e12c5d1SDavid du Colombier 		if(idx < swapalloc.last)
833e12c5d1SDavid du Colombier 			swapalloc.last = idx;
843e12c5d1SDavid du Colombier 	}
857dd7cddfSDavid du Colombier 	if(*idx >= 254)
86c9b6d007SDavid du Colombier 		panic("putswap %#p == %ud", p, *idx);
873e12c5d1SDavid du Colombier 	unlock(&swapalloc);
883e12c5d1SDavid du Colombier }
893e12c5d1SDavid du Colombier 
903e12c5d1SDavid du Colombier void
dupswap(Page * p)913e12c5d1SDavid du Colombier dupswap(Page *p)
923e12c5d1SDavid du Colombier {
933e12c5d1SDavid du Colombier 	lock(&swapalloc);
947dd7cddfSDavid du Colombier 	if(++swapalloc.swmap[((ulong)p)/BY2PG] == 0)
957dd7cddfSDavid du Colombier 		panic("dupswap");
963e12c5d1SDavid du Colombier 	unlock(&swapalloc);
973e12c5d1SDavid du Colombier }
983e12c5d1SDavid du Colombier 
997dd7cddfSDavid du Colombier int
swapcount(ulong daddr)1007dd7cddfSDavid du Colombier swapcount(ulong daddr)
1017dd7cddfSDavid du Colombier {
1027dd7cddfSDavid du Colombier 	return swapalloc.swmap[daddr/BY2PG];
1037dd7cddfSDavid du Colombier }
1047dd7cddfSDavid du Colombier 
1053e12c5d1SDavid du Colombier void
kickpager(void)1063e12c5d1SDavid du Colombier kickpager(void)
1073e12c5d1SDavid du Colombier {
1083e12c5d1SDavid du Colombier 	static int started;
1093e12c5d1SDavid du Colombier 
1103e12c5d1SDavid du Colombier 	if(started)
1113e12c5d1SDavid du Colombier 		wakeup(&swapalloc.r);
1123e12c5d1SDavid du Colombier 	else {
1133e12c5d1SDavid du Colombier 		kproc("pager", pager, 0);
1143e12c5d1SDavid du Colombier 		started = 1;
1153e12c5d1SDavid du Colombier 	}
1163e12c5d1SDavid du Colombier }
1173e12c5d1SDavid du Colombier 
1187dd7cddfSDavid du Colombier static void
pager(void * junk)1193e12c5d1SDavid du Colombier pager(void *junk)
1203e12c5d1SDavid du Colombier {
1213e12c5d1SDavid du Colombier 	int i;
1227dd7cddfSDavid du Colombier 	Segment *s;
123219b2ee8SDavid du Colombier 	Proc *p, *ep;
1243e12c5d1SDavid du Colombier 
1253e12c5d1SDavid du Colombier 	if(waserror())
126c9b6d007SDavid du Colombier 		panic("pager: os error");
1273e12c5d1SDavid du Colombier 
1283e12c5d1SDavid du Colombier 	p = proctab(0);
1293e12c5d1SDavid du Colombier 	ep = &p[conf.nproc];
1303e12c5d1SDavid du Colombier 
1313e12c5d1SDavid du Colombier loop:
1327dd7cddfSDavid du Colombier 	up->psstate = "Idle";
133*d1be6b08SDavid du Colombier 	wakeup(&palloc.r);
1343e12c5d1SDavid du Colombier 	sleep(&swapalloc.r, needpages, 0);
1353e12c5d1SDavid du Colombier 
136219b2ee8SDavid du Colombier 	while(needpages(junk)) {
1377dd7cddfSDavid du Colombier 		if(swapimage.c) {
1383e12c5d1SDavid du Colombier 			p++;
139*d1be6b08SDavid du Colombier 			if(p >= ep){
1403e12c5d1SDavid du Colombier 				p = proctab(0);
141*d1be6b08SDavid du Colombier 				gentick();
142*d1be6b08SDavid du Colombier 			}
1433e12c5d1SDavid du Colombier 
144b7b24591SDavid du Colombier 			if(p->state == Dead || p->noswap)
1453e12c5d1SDavid du Colombier 				continue;
1463e12c5d1SDavid du Colombier 
1477dd7cddfSDavid du Colombier 			if(!canqlock(&p->seglock))
1487dd7cddfSDavid du Colombier 				continue;		/* process changing its segments */
149219b2ee8SDavid du Colombier 
1503e12c5d1SDavid du Colombier 			for(i = 0; i < NSEG; i++) {
1517dd7cddfSDavid du Colombier 				if(!needpages(junk)){
1527dd7cddfSDavid du Colombier 					qunlock(&p->seglock);
1533e12c5d1SDavid du Colombier 					goto loop;
1547dd7cddfSDavid du Colombier 				}
1553e12c5d1SDavid du Colombier 
1563e12c5d1SDavid du Colombier 				if(s = p->seg[i]) {
1573e12c5d1SDavid du Colombier 					switch(s->type&SG_TYPE) {
1583e12c5d1SDavid du Colombier 					default:
1593e12c5d1SDavid du Colombier 						break;
1603e12c5d1SDavid du Colombier 					case SG_TEXT:
1613e12c5d1SDavid du Colombier 						pageout(p, s);
1623e12c5d1SDavid du Colombier 						break;
1633e12c5d1SDavid du Colombier 					case SG_DATA:
1643e12c5d1SDavid du Colombier 					case SG_BSS:
1653e12c5d1SDavid du Colombier 					case SG_STACK:
1663e12c5d1SDavid du Colombier 					case SG_SHARED:
1677dd7cddfSDavid du Colombier 						up->psstate = "Pageout";
1683e12c5d1SDavid du Colombier 						pageout(p, s);
1693e12c5d1SDavid du Colombier 						if(ioptr != 0) {
1707dd7cddfSDavid du Colombier 							up->psstate = "I/O";
1713e12c5d1SDavid du Colombier 							executeio();
1723e12c5d1SDavid du Colombier 						}
1737dd7cddfSDavid du Colombier 						break;
1743e12c5d1SDavid du Colombier 					}
1753e12c5d1SDavid du Colombier 				}
1763e12c5d1SDavid du Colombier 			}
1777dd7cddfSDavid du Colombier 			qunlock(&p->seglock);
178*d1be6b08SDavid du Colombier 		} else {
179*d1be6b08SDavid du Colombier 			print("out of memory\n");
180cd42b314SDavid du Colombier 			killbig("out of memory");
181*d1be6b08SDavid du Colombier 			freebroken();		/* can use the memory */
1823e12c5d1SDavid du Colombier 
1833e12c5d1SDavid du Colombier 			/* Emulate the old system if no swap channel */
184*d1be6b08SDavid du Colombier 			if(!swapimage.c)
185dc5a79c1SDavid du Colombier 				tsleep(&up->sleep, return0, 0, 5000);
1863e12c5d1SDavid du Colombier 		}
1873e12c5d1SDavid du Colombier 	}
1883e12c5d1SDavid du Colombier 	goto loop;
1893e12c5d1SDavid du Colombier }
1903e12c5d1SDavid du Colombier 
1917dd7cddfSDavid du Colombier static void
pageout(Proc * p,Segment * s)1923e12c5d1SDavid du Colombier pageout(Proc *p, Segment *s)
1933e12c5d1SDavid du Colombier {
1947dd7cddfSDavid du Colombier 	int type, i, size;
195*d1be6b08SDavid du Colombier 	ulong age;
1963e12c5d1SDavid du Colombier 	Pte *l;
1973e12c5d1SDavid du Colombier 	Page **pg, *entry;
1983e12c5d1SDavid du Colombier 
1993e12c5d1SDavid du Colombier 	if(!canqlock(&s->lk))	/* We cannot afford to wait, we will surely deadlock */
2003e12c5d1SDavid du Colombier 		return;
2013e12c5d1SDavid du Colombier 
2023e12c5d1SDavid du Colombier 	if(s->steal) {		/* Protected by /dev/proc */
2033e12c5d1SDavid du Colombier 		qunlock(&s->lk);
2043e12c5d1SDavid du Colombier 		return;
2053e12c5d1SDavid du Colombier 	}
2063e12c5d1SDavid du Colombier 
2073e12c5d1SDavid du Colombier 	if(!canflush(p, s)) {	/* Able to invalidate all tlbs with references */
2083e12c5d1SDavid du Colombier 		qunlock(&s->lk);
2093e12c5d1SDavid du Colombier 		putseg(s);
2103e12c5d1SDavid du Colombier 		return;
2113e12c5d1SDavid du Colombier 	}
2123e12c5d1SDavid du Colombier 
2133e12c5d1SDavid du Colombier 	if(waserror()) {
2143e12c5d1SDavid du Colombier 		qunlock(&s->lk);
2153e12c5d1SDavid du Colombier 		putseg(s);
2163e12c5d1SDavid du Colombier 		return;
2173e12c5d1SDavid du Colombier 	}
2183e12c5d1SDavid du Colombier 
2193e12c5d1SDavid du Colombier 	/* Pass through the pte tables looking for memory pages to swap out */
2203e12c5d1SDavid du Colombier 	type = s->type&SG_TYPE;
2217dd7cddfSDavid du Colombier 	size = s->mapsize;
2227dd7cddfSDavid du Colombier 	for(i = 0; i < size; i++) {
2233e12c5d1SDavid du Colombier 		l = s->map[i];
2243e12c5d1SDavid du Colombier 		if(l == 0)
2253e12c5d1SDavid du Colombier 			continue;
2263e12c5d1SDavid du Colombier 		for(pg = l->first; pg < l->last; pg++) {
2273e12c5d1SDavid du Colombier 			entry = *pg;
2283e12c5d1SDavid du Colombier 			if(pagedout(entry))
2293e12c5d1SDavid du Colombier 				continue;
2303e12c5d1SDavid du Colombier 
2313e12c5d1SDavid du Colombier 			if(entry->modref & PG_REF) {
2323e12c5d1SDavid du Colombier 				entry->modref &= ~PG_REF;
233*d1be6b08SDavid du Colombier 				entry->gen = genclock;
2343e12c5d1SDavid du Colombier 			}
2353e12c5d1SDavid du Colombier 
236*d1be6b08SDavid du Colombier 			if(genclock < entry->gen)
237*d1be6b08SDavid du Colombier 				age = ~(entry->gen - genclock);
238*d1be6b08SDavid du Colombier 			else
239*d1be6b08SDavid du Colombier 				age = genclock - entry->gen;
240*d1be6b08SDavid du Colombier 			gensum += age;
241*d1be6b08SDavid du Colombier 			gencount++;
242*d1be6b08SDavid du Colombier 			if(age <= genage)
243*d1be6b08SDavid du Colombier 				continue;
244*d1be6b08SDavid du Colombier 
2453e12c5d1SDavid du Colombier 			pagepte(type, pg);
2463e12c5d1SDavid du Colombier 
2477dd7cddfSDavid du Colombier 			if(ioptr >= conf.nswppo)
2483e12c5d1SDavid du Colombier 				goto out;
2493e12c5d1SDavid du Colombier 		}
2503e12c5d1SDavid du Colombier 	}
2513e12c5d1SDavid du Colombier out:
2523e12c5d1SDavid du Colombier 	poperror();
2533e12c5d1SDavid du Colombier 	qunlock(&s->lk);
2543e12c5d1SDavid du Colombier 	putseg(s);
2553e12c5d1SDavid du Colombier }
2563e12c5d1SDavid du Colombier 
2577dd7cddfSDavid du Colombier static int
canflush(Proc * p,Segment * s)2583e12c5d1SDavid du Colombier canflush(Proc *p, Segment *s)
2593e12c5d1SDavid du Colombier {
2603e12c5d1SDavid du Colombier 	int i;
2613e12c5d1SDavid du Colombier 	Proc *ep;
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier 	lock(s);
2643e12c5d1SDavid du Colombier 	if(s->ref == 1) {		/* Easy if we are the only user */
2653e12c5d1SDavid du Colombier 		s->ref++;
2663e12c5d1SDavid du Colombier 		unlock(s);
2673e12c5d1SDavid du Colombier 		return canpage(p);
2683e12c5d1SDavid du Colombier 	}
2693e12c5d1SDavid du Colombier 	s->ref++;
2703e12c5d1SDavid du Colombier 	unlock(s);
2713e12c5d1SDavid du Colombier 
2723e12c5d1SDavid du Colombier 	/* Now we must do hardwork to ensure all processes which have tlb
2737dd7cddfSDavid du Colombier 	 * entries for this segment will be flushed if we succeed in paging it out
2743e12c5d1SDavid du Colombier 	 */
2753e12c5d1SDavid du Colombier 	p = proctab(0);
2763e12c5d1SDavid du Colombier 	ep = &p[conf.nproc];
2773e12c5d1SDavid du Colombier 	while(p < ep) {
2783e12c5d1SDavid du Colombier 		if(p->state != Dead) {
2793e12c5d1SDavid du Colombier 			for(i = 0; i < NSEG; i++)
2803e12c5d1SDavid du Colombier 				if(p->seg[i] == s)
2813e12c5d1SDavid du Colombier 					if(!canpage(p))
2823e12c5d1SDavid du Colombier 						return 0;
2833e12c5d1SDavid du Colombier 		}
2843e12c5d1SDavid du Colombier 		p++;
2853e12c5d1SDavid du Colombier 	}
2863e12c5d1SDavid du Colombier 	return 1;
2873e12c5d1SDavid du Colombier }
2883e12c5d1SDavid du Colombier 
2897dd7cddfSDavid du Colombier static void
pagepte(int type,Page ** pg)2903e12c5d1SDavid du Colombier pagepte(int type, Page **pg)
2913e12c5d1SDavid du Colombier {
2923e12c5d1SDavid du Colombier 	ulong daddr;
2933e12c5d1SDavid du Colombier 	Page *outp;
2943e12c5d1SDavid du Colombier 
2953e12c5d1SDavid du Colombier 	outp = *pg;
2963e12c5d1SDavid du Colombier 	switch(type) {
2973e12c5d1SDavid du Colombier 	case SG_TEXT:				/* Revert to demand load */
2983e12c5d1SDavid du Colombier 		putpage(outp);
2993e12c5d1SDavid du Colombier 		*pg = 0;
3003e12c5d1SDavid du Colombier 		break;
3013e12c5d1SDavid du Colombier 
3023e12c5d1SDavid du Colombier 	case SG_DATA:
3033e12c5d1SDavid du Colombier 	case SG_BSS:
3043e12c5d1SDavid du Colombier 	case SG_STACK:
3053e12c5d1SDavid du Colombier 	case SG_SHARED:
3067dd7cddfSDavid du Colombier 		/*
3077dd7cddfSDavid du Colombier 		 *  get a new swap address and clear any pages
3087dd7cddfSDavid du Colombier 		 *  referring to it from the cache
3097dd7cddfSDavid du Colombier 		 */
3103e12c5d1SDavid du Colombier 		daddr = newswap();
3117dd7cddfSDavid du Colombier 		if(daddr == ~0)
3127dd7cddfSDavid du Colombier 			break;
3133e12c5d1SDavid du Colombier 		cachedel(&swapimage, daddr);
3143e12c5d1SDavid du Colombier 
3157dd7cddfSDavid du Colombier 		lock(outp);
3167dd7cddfSDavid du Colombier 
3177dd7cddfSDavid du Colombier 		/* forget anything that it used to cache */
3187dd7cddfSDavid du Colombier 		uncachepage(outp);
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier 		/*
3217dd7cddfSDavid du Colombier 		 *  incr the reference count to make sure it sticks around while
3227dd7cddfSDavid du Colombier 		 *  being written
3237dd7cddfSDavid du Colombier 		 */
3247dd7cddfSDavid du Colombier 		outp->ref++;
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 		/*
3277dd7cddfSDavid du Colombier 		 *  enter it into the cache so that a fault happening
3287dd7cddfSDavid du Colombier 		 *  during the write will grab the page from the cache
3297dd7cddfSDavid du Colombier 		 *  rather than one partially written to the disk
3303e12c5d1SDavid du Colombier 		 */
3313e12c5d1SDavid du Colombier 		outp->daddr = daddr;
3323e12c5d1SDavid du Colombier 		cachepage(outp, &swapimage);
3333e12c5d1SDavid du Colombier 		*pg = (Page*)(daddr|PG_ONSWAP);
3347dd7cddfSDavid du Colombier 		unlock(outp);
3353e12c5d1SDavid du Colombier 
3367dd7cddfSDavid du Colombier 		/* Add page to IO transaction list */
3373e12c5d1SDavid du Colombier 		iolist[ioptr++] = outp;
3387dd7cddfSDavid du Colombier 		break;
3393e12c5d1SDavid du Colombier 	}
3403e12c5d1SDavid du Colombier }
3413e12c5d1SDavid du Colombier 
3423e12c5d1SDavid du Colombier void
pagersummary(void)3437dd7cddfSDavid du Colombier pagersummary(void)
3447dd7cddfSDavid du Colombier {
3457dd7cddfSDavid du Colombier 	print("%lud/%lud memory %lud/%lud swap %d iolist\n",
3467dd7cddfSDavid du Colombier 		palloc.user-palloc.freecount,
3477dd7cddfSDavid du Colombier 		palloc.user, conf.nswap-swapalloc.free, conf.nswap,
3487dd7cddfSDavid du Colombier 		ioptr);
3497dd7cddfSDavid du Colombier }
3507dd7cddfSDavid du Colombier 
351*d1be6b08SDavid du Colombier static int
pageiocomp(void * a,void * b)352*d1be6b08SDavid du Colombier pageiocomp(void *a, void *b)
353*d1be6b08SDavid du Colombier {
354*d1be6b08SDavid du Colombier 	Page *p1, *p2;
355*d1be6b08SDavid du Colombier 
356*d1be6b08SDavid du Colombier 	p1 = *(Page **)a;
357*d1be6b08SDavid du Colombier 	p2 = *(Page **)b;
358*d1be6b08SDavid du Colombier 	if(p1->daddr > p2->daddr)
359*d1be6b08SDavid du Colombier 		return 1;
360*d1be6b08SDavid du Colombier 	else
361*d1be6b08SDavid du Colombier 		return -1;
362*d1be6b08SDavid du Colombier }
363*d1be6b08SDavid du Colombier 
3647dd7cddfSDavid du Colombier static void
executeio(void)3653e12c5d1SDavid du Colombier executeio(void)
3663e12c5d1SDavid du Colombier {
3673e12c5d1SDavid du Colombier 	Page *out;
3683e12c5d1SDavid du Colombier 	int i, n;
3693e12c5d1SDavid du Colombier 	Chan *c;
3703e12c5d1SDavid du Colombier 	char *kaddr;
3713e12c5d1SDavid du Colombier 	KMap *k;
3723e12c5d1SDavid du Colombier 
3733e12c5d1SDavid du Colombier 	c = swapimage.c;
374*d1be6b08SDavid du Colombier 	qsort(iolist, ioptr, sizeof iolist[0], pageiocomp);
3753e12c5d1SDavid du Colombier 	for(i = 0; i < ioptr; i++) {
3767dd7cddfSDavid du Colombier 		if(ioptr > conf.nswppo)
377c9b6d007SDavid du Colombier 			panic("executeio: ioptr %d > %d", ioptr, conf.nswppo);
3783e12c5d1SDavid du Colombier 		out = iolist[i];
3793e12c5d1SDavid du Colombier 		k = kmap(out);
3803e12c5d1SDavid du Colombier 		kaddr = (char*)VA(k);
3813e12c5d1SDavid du Colombier 
3823e12c5d1SDavid du Colombier 		if(waserror())
3833e12c5d1SDavid du Colombier 			panic("executeio: page out I/O error");
3843e12c5d1SDavid du Colombier 
3857dd7cddfSDavid du Colombier 		n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
3863e12c5d1SDavid du Colombier 		if(n != BY2PG)
3873e12c5d1SDavid du Colombier 			nexterror();
3883e12c5d1SDavid du Colombier 
3893e12c5d1SDavid du Colombier 		kunmap(k);
3903e12c5d1SDavid du Colombier 		poperror();
3913e12c5d1SDavid du Colombier 
3923e12c5d1SDavid du Colombier 		/* Free up the page after I/O */
3933e12c5d1SDavid du Colombier 		lock(out);
3943e12c5d1SDavid du Colombier 		out->ref--;
3953e12c5d1SDavid du Colombier 		unlock(out);
3963e12c5d1SDavid du Colombier 		putpage(out);
3973e12c5d1SDavid du Colombier 	}
3983e12c5d1SDavid du Colombier 	ioptr = 0;
3993e12c5d1SDavid du Colombier }
4003e12c5d1SDavid du Colombier 
4017dd7cddfSDavid du Colombier static int
needpages(void *)4027dd7cddfSDavid du Colombier needpages(void*)
4033e12c5d1SDavid du Colombier {
4043e12c5d1SDavid du Colombier 	return palloc.freecount < swapalloc.headroom;
4053e12c5d1SDavid du Colombier }
4063e12c5d1SDavid du Colombier 
4073e12c5d1SDavid du Colombier void
setswapchan(Chan * c)4083e12c5d1SDavid du Colombier setswapchan(Chan *c)
4093e12c5d1SDavid du Colombier {
4109a747e4fSDavid du Colombier 	uchar dirbuf[sizeof(Dir)+100];
4117dd7cddfSDavid du Colombier 	Dir d;
4129a747e4fSDavid du Colombier 	int n;
4137dd7cddfSDavid du Colombier 
4143e12c5d1SDavid du Colombier 	if(swapimage.c) {
4157dd7cddfSDavid du Colombier 		if(swapalloc.free != conf.nswap){
4167dd7cddfSDavid du Colombier 			cclose(c);
4173e12c5d1SDavid du Colombier 			error(Einuse);
4183e12c5d1SDavid du Colombier 		}
4197dd7cddfSDavid du Colombier 		cclose(swapimage.c);
4207dd7cddfSDavid du Colombier 	}
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	/*
4237dd7cddfSDavid du Colombier 	 *  if this isn't a file, set the swap space
4247dd7cddfSDavid du Colombier 	 *  to be at most the size of the partition
4257dd7cddfSDavid du Colombier 	 */
4267dd7cddfSDavid du Colombier 	if(devtab[c->type]->dc != L'M'){
4279a747e4fSDavid du Colombier 		n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
4289a747e4fSDavid du Colombier 		if(n <= 0){
4299a747e4fSDavid du Colombier 			cclose(c);
4309a747e4fSDavid du Colombier 			error("stat failed in setswapchan");
4319a747e4fSDavid du Colombier 		}
4329a747e4fSDavid du Colombier 		convM2D(dirbuf, n, &d, nil);
4337dd7cddfSDavid du Colombier 		if(d.length < conf.nswap*BY2PG){
4347dd7cddfSDavid du Colombier 			conf.nswap = d.length/BY2PG;
4357dd7cddfSDavid du Colombier 			swapalloc.top = &swapalloc.swmap[conf.nswap];
4367dd7cddfSDavid du Colombier 			swapalloc.free = conf.nswap;
4377dd7cddfSDavid du Colombier 		}
4387dd7cddfSDavid du Colombier 	}
4397dd7cddfSDavid du Colombier 
4403e12c5d1SDavid du Colombier 	swapimage.c = c;
4413e12c5d1SDavid du Colombier }
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier int
swapfull(void)4447dd7cddfSDavid du Colombier swapfull(void)
4457dd7cddfSDavid du Colombier {
4467dd7cddfSDavid du Colombier 	return swapalloc.free < conf.nswap/10;
4477dd7cddfSDavid du Colombier }
448