vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

swap.c (7036B)


      1 #include	"u.h"
      2 #include	"lib.h"
      3 #include	"mem.h"
      4 #include	"dat.h"
      5 #include	"fns.h"
      6 #include	"error.h"
      7 
      8 static int	canflush(Proc*, Segment*);
      9 static void	executeio(void);
     10 static int	needpages(void *v);
     11 static void	pageout(Proc*, Segment*);
     12 static void	pagepte(int, Page**);
     13 static void	pager(void *v);
     14 
     15 	Image 	swapimage;
     16 static	Page	**iolist;
     17 static	int	ioptr;
     18 
     19 void
     20 swapinit(void)
     21 {
     22 	swapalloc.swmap = xalloc(conf.nswap);
     23 	swapalloc.top = &swapalloc.swmap[conf.nswap];
     24 	swapalloc.alloc = swapalloc.swmap;
     25 	swapalloc.last = swapalloc.swmap;
     26 	swapalloc.free = conf.nswap;
     27 	iolist = xalloc(conf.nswppo*sizeof(Page*));
     28 	if(swapalloc.swmap == 0 || iolist == 0)
     29 		panic("swapinit: not enough memory");
     30 
     31 	swapimage.notext = 1;
     32 }
     33 
     34 ulong
     35 newswap(void)
     36 {
     37 	uchar *look;
     38 
     39 	lock(&swapalloc.lk);
     40 
     41 	if(swapalloc.free == 0){
     42 		unlock(&swapalloc.lk);
     43 		return ~0;
     44 	}
     45 
     46 	look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);
     47 	if(look == 0)
     48 		panic("inconsistent swap");
     49 
     50 	*look = 1;
     51 	swapalloc.last = look;
     52 	swapalloc.free--;
     53 	unlock(&swapalloc.lk);
     54 	return (look-swapalloc.swmap) * BY2PG;
     55 }
     56 
     57 void
     58 putswap(Page *p)
     59 {
     60 	uchar *idx;
     61 
     62 	lock(&swapalloc.lk);
     63 	idx = &swapalloc.swmap[((ulong)p)/BY2PG];
     64 	if(--(*idx) == 0) {
     65 		swapalloc.free++;
     66 		if(idx < swapalloc.last)
     67 			swapalloc.last = idx;
     68 	}
     69 	if(*idx >= 254)
     70 		panic("putswap %#p == %ud", p, *idx);
     71 	unlock(&swapalloc.lk);
     72 }
     73 
     74 void
     75 dupswap(Page *p)
     76 {
     77 	lock(&swapalloc.lk);
     78 	if(++swapalloc.swmap[((ulong)p)/BY2PG] == 0)
     79 		panic("dupswap");
     80 	unlock(&swapalloc.lk);
     81 }
     82 
     83 int
     84 swapcount(ulong daddr)
     85 {
     86 	return swapalloc.swmap[daddr/BY2PG];
     87 }
     88 
     89 void
     90 kickpager(void)
     91 {
     92 	static int started;
     93 
     94 	if(started)
     95 		wakeup(&swapalloc.r);
     96 	else {
     97 		kproc("pager", pager, 0);
     98 		started = 1;
     99 	}
    100 }
    101 
    102 static void
    103 pager(void *junk)
    104 {
    105 	int i;
    106 	Segment *s;
    107 	Proc *p, *ep;
    108 
    109 	if(waserror())
    110 		panic("pager: os error");
    111 
    112 	p = proctab(0);
    113 	ep = &p[conf.nproc];
    114 
    115 loop:
    116 	up->psstate = "Idle";
    117 	sleep(&swapalloc.r, needpages, 0);
    118 
    119 	while(needpages(junk)) {
    120 
    121 		if(swapimage.c) {
    122 			p++;
    123 			if(p >= ep)
    124 				p = proctab(0);
    125 	
    126 			if(p->state == Dead || p->noswap)
    127 				continue;
    128 
    129 			if(!canqlock(&p->seglock))
    130 				continue;		/* process changing its segments */
    131 
    132 			for(i = 0; i < NSEG; i++) {
    133 				if(!needpages(junk)){
    134 					qunlock(&p->seglock);
    135 					goto loop;
    136 				}
    137 
    138 				if((s = p->seg[i])) {
    139 					switch(s->type&SG_TYPE) {
    140 					default:
    141 						break;
    142 					case SG_TEXT:
    143 						pageout(p, s);
    144 						break;
    145 					case SG_DATA:
    146 					case SG_BSS:
    147 					case SG_STACK:
    148 					case SG_SHARED:
    149 						up->psstate = "Pageout";
    150 						pageout(p, s);
    151 						if(ioptr != 0) {
    152 							up->psstate = "I/O";
    153 							executeio();
    154 						}
    155 						break;
    156 					}
    157 				}
    158 			}
    159 			qunlock(&p->seglock);
    160 		}
    161 		else {
    162 			print("out of physical memory; no swap configured\n");
    163 			if(!cpuserver || freebroken() == 0)
    164 				killbig("out of memory");
    165 
    166 			/* Emulate the old system if no swap channel */
    167 			tsleep(&up->sleep, return0, 0, 5000);
    168 			wakeup(&palloc.r);
    169 		}
    170 	}
    171 	goto loop;
    172 }
    173 
    174 static void
    175 pageout(Proc *p, Segment *s)
    176 {
    177 	int type, i, size;
    178 	Pte *l;
    179 	Page **pg, *entry;
    180 
    181 	if(!canqlock(&s->lk))	/* We cannot afford to wait, we will surely deadlock */
    182 		return;
    183 
    184 	if(s->steal) {		/* Protected by /dev/proc */
    185 		qunlock(&s->lk);
    186 		return;
    187 	}
    188 
    189 	if(!canflush(p, s)) {	/* Able to invalidate all tlbs with references */
    190 		qunlock(&s->lk);
    191 		putseg(s);
    192 		return;
    193 	}
    194 
    195 	if(waserror()) {
    196 		qunlock(&s->lk);
    197 		putseg(s);
    198 		return;
    199 	}
    200 
    201 	/* Pass through the pte tables looking for memory pages to swap out */
    202 	type = s->type&SG_TYPE;
    203 	size = s->mapsize;
    204 	for(i = 0; i < size; i++) {
    205 		l = s->map[i];
    206 		if(l == 0)
    207 			continue;
    208 		for(pg = l->first; pg < l->last; pg++) {
    209 			entry = *pg;
    210 			if(pagedout(entry))
    211 				continue;
    212 
    213 			if(entry->modref & PG_REF) {
    214 				entry->modref &= ~PG_REF;
    215 				continue;
    216 			}
    217 
    218 			pagepte(type, pg);
    219 
    220 			if(ioptr >= conf.nswppo)
    221 				goto out;
    222 		}
    223 	}
    224 out:
    225 	poperror();
    226 	qunlock(&s->lk);
    227 	putseg(s);
    228 }
    229 
    230 static int
    231 canflush(Proc *p, Segment *s)
    232 {
    233 	int i;
    234 	Proc *ep;
    235 
    236 	lock(&s->ref.lk);
    237 	if(s->ref.ref == 1) {		/* Easy if we are the only user */
    238 		s->ref.ref++;
    239 		unlock(&s->ref.lk);
    240 		return canpage(p);
    241 	}
    242 	s->ref.ref++;
    243 	unlock(&s->ref.lk);
    244 
    245 	/* Now we must do hardwork to ensure all processes which have tlb
    246 	 * entries for this segment will be flushed if we succeed in paging it out
    247 	 */
    248 	p = proctab(0);
    249 	ep = &p[conf.nproc];
    250 	while(p < ep) {
    251 		if(p->state != Dead) {
    252 			for(i = 0; i < NSEG; i++)
    253 				if(p->seg[i] == s)
    254 					if(!canpage(p))
    255 						return 0;
    256 		}
    257 		p++;
    258 	}
    259 	return 1;
    260 }
    261 
    262 static void
    263 pagepte(int type, Page **pg)
    264 {
    265 	ulong daddr;
    266 	Page *outp;
    267 
    268 	outp = *pg;
    269 	switch(type) {
    270 	case SG_TEXT:				/* Revert to demand load */
    271 		putpage(outp);
    272 		*pg = 0;
    273 		break;
    274 
    275 	case SG_DATA:
    276 	case SG_BSS:
    277 	case SG_STACK:
    278 	case SG_SHARED:
    279 		/*
    280 		 *  get a new swap address and clear any pages
    281 		 *  referring to it from the cache
    282 		 */
    283 		daddr = newswap();
    284 		if(daddr == ~0)
    285 			break;
    286 		cachedel(&swapimage, daddr);
    287 
    288 		lock(&outp->lk);
    289 
    290 		/* forget anything that it used to cache */
    291 		uncachepage(outp);
    292 
    293 		/*
    294 		 *  incr the reference count to make sure it sticks around while
    295 		 *  being written
    296 		 */
    297 		outp->ref++;
    298 
    299 		/*
    300 		 *  enter it into the cache so that a fault happening
    301 		 *  during the write will grab the page from the cache
    302 		 *  rather than one partially written to the disk
    303 		 */
    304 		outp->daddr = daddr;
    305 		cachepage(outp, &swapimage);
    306 		*pg = (Page*)(daddr|PG_ONSWAP);
    307 		unlock(&outp->lk);
    308 
    309 		/* Add page to IO transaction list */
    310 		iolist[ioptr++] = outp;
    311 		break;
    312 	}
    313 }
    314 
    315 void
    316 pagersummary(void)
    317 {
    318 	print("%lud/%lud memory %lud/%lud swap %d iolist\n",
    319 		palloc.user-palloc.freecount,
    320 		palloc.user, conf.nswap-swapalloc.free, conf.nswap,
    321 		ioptr);
    322 }
    323 
    324 static void
    325 executeio(void)
    326 {
    327 	Page *out;
    328 	int i, n;
    329 	Chan *c;
    330 	char *kaddr;
    331 	KMap *k;
    332 
    333 	c = swapimage.c;
    334 
    335 	for(i = 0; i < ioptr; i++) {
    336 		if(ioptr > conf.nswppo)
    337 			panic("executeio: ioptr %d > %d", ioptr, conf.nswppo);
    338 		out = iolist[i];
    339 		k = kmap(out);
    340 		kaddr = (char*)VA(k);
    341 
    342 		if(waserror())
    343 			panic("executeio: page out I/O error");
    344 
    345 		n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
    346 		if(n != BY2PG)
    347 			nexterror();
    348 
    349 		kunmap(k);
    350 		poperror();
    351 
    352 		/* Free up the page after I/O */
    353 		lock(&out->lk);
    354 		out->ref--;
    355 		unlock(&out->lk);
    356 		putpage(out);
    357 	}
    358 	ioptr = 0;
    359 }
    360 
    361 static int
    362 needpages(void *v)
    363 {
    364 	return palloc.freecount < swapalloc.headroom;
    365 }
    366 
    367 void
    368 setswapchan(Chan *c)
    369 {
    370 	uchar dirbuf[sizeof(Dir)+100];
    371 	Dir d;
    372 	int n;
    373 
    374 	if(swapimage.c) {
    375 		if(swapalloc.free != conf.nswap){
    376 			cclose(c);
    377 			error(Einuse);
    378 		}
    379 		cclose(swapimage.c);
    380 	}
    381 
    382 	/*
    383 	 *  if this isn't a file, set the swap space
    384 	 *  to be at most the size of the partition
    385 	 */
    386 	if(devtab[c->type]->dc != L'M'){
    387 		n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
    388 		if(n <= 0){
    389 			cclose(c);
    390 			error("stat failed in setswapchan");
    391 		}
    392 		convM2D(dirbuf, n, &d, nil);
    393 		if(d.length < conf.nswap*BY2PG){
    394 			conf.nswap = d.length/BY2PG;
    395 			swapalloc.top = &swapalloc.swmap[conf.nswap];
    396 			swapalloc.free = conf.nswap;
    397 		}
    398 	}
    399 
    400 	swapimage.c = c;
    401 }
    402 
    403 int
    404 swapfull(void)
    405 {
    406 	return swapalloc.free < conf.nswap/10;
    407 }