xref: /plan9/sys/src/9/port/cache.c (revision 401db9f5a25f1bed3a9d249925fdf1a097832bd3)
17dd7cddfSDavid du Colombier #include	"u.h"
27dd7cddfSDavid du Colombier #include	"../port/lib.h"
37dd7cddfSDavid du Colombier #include	"mem.h"
47dd7cddfSDavid du Colombier #include	"dat.h"
57dd7cddfSDavid du Colombier #include	"fns.h"
67dd7cddfSDavid du Colombier #include	"../port/error.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier enum
97dd7cddfSDavid du Colombier {
107dd7cddfSDavid du Colombier 	NHASH		= 128,
117dd7cddfSDavid du Colombier 	MAXCACHE	= 1024*1024,
127dd7cddfSDavid du Colombier 	NFILE		= 4096,
137dd7cddfSDavid du Colombier 	NEXTENT		= 200,		/* extent allocation size */
147dd7cddfSDavid du Colombier };
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier typedef struct Extent Extent;
177dd7cddfSDavid du Colombier struct Extent
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier 	int	bid;
207dd7cddfSDavid du Colombier 	ulong	start;
217dd7cddfSDavid du Colombier 	int	len;
227dd7cddfSDavid du Colombier 	Page	*cache;
237dd7cddfSDavid du Colombier 	Extent	*next;
247dd7cddfSDavid du Colombier };
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier typedef struct Mntcache Mntcache;
277dd7cddfSDavid du Colombier struct Mntcache
287dd7cddfSDavid du Colombier {
299a747e4fSDavid du Colombier 	Qid	qid;
307dd7cddfSDavid du Colombier 	int	dev;
317dd7cddfSDavid du Colombier 	int	type;
327dd7cddfSDavid du Colombier 	QLock;
337dd7cddfSDavid du Colombier 	Extent	 *list;
347dd7cddfSDavid du Colombier 	Mntcache *hash;
357dd7cddfSDavid du Colombier 	Mntcache *prev;
367dd7cddfSDavid du Colombier 	Mntcache *next;
377dd7cddfSDavid du Colombier };
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier typedef struct Cache Cache;
407dd7cddfSDavid du Colombier struct Cache
417dd7cddfSDavid du Colombier {
426bbfed0dSDavid du Colombier 	QLock;
437dd7cddfSDavid du Colombier 	int		pgno;
447dd7cddfSDavid du Colombier 	Mntcache	*head;
457dd7cddfSDavid du Colombier 	Mntcache	*tail;
467dd7cddfSDavid du Colombier 	Mntcache	*hash[NHASH];
477dd7cddfSDavid du Colombier };
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier typedef struct Ecache Ecache;
507dd7cddfSDavid du Colombier struct Ecache
517dd7cddfSDavid du Colombier {
527dd7cddfSDavid du Colombier 	Lock;
537dd7cddfSDavid du Colombier 	int	total;
547dd7cddfSDavid du Colombier 	int	free;
557dd7cddfSDavid du Colombier 	Extent*	head;
567dd7cddfSDavid du Colombier };
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier static Image fscache;
597dd7cddfSDavid du Colombier static Cache cache;
607dd7cddfSDavid du Colombier static Ecache ecache;
617dd7cddfSDavid du Colombier static int maxcache = MAXCACHE;
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier static void
extentfree(Extent * e)647dd7cddfSDavid du Colombier extentfree(Extent* e)
657dd7cddfSDavid du Colombier {
667dd7cddfSDavid du Colombier 	lock(&ecache);
677dd7cddfSDavid du Colombier 	e->next = ecache.head;
687dd7cddfSDavid du Colombier 	ecache.head = e;
697dd7cddfSDavid du Colombier 	ecache.free++;
707dd7cddfSDavid du Colombier 	unlock(&ecache);
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier 
737dd7cddfSDavid du Colombier static Extent*
extentalloc(void)747dd7cddfSDavid du Colombier extentalloc(void)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier 	Extent *e;
777dd7cddfSDavid du Colombier 	int i;
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier 	lock(&ecache);
807dd7cddfSDavid du Colombier 	if(ecache.head == nil){
817dd7cddfSDavid du Colombier 		e = xalloc(NEXTENT*sizeof(Extent));
827dd7cddfSDavid du Colombier 		if(e == nil){
837dd7cddfSDavid du Colombier 			unlock(&ecache);
847dd7cddfSDavid du Colombier 			return nil;
857dd7cddfSDavid du Colombier 		}
867dd7cddfSDavid du Colombier 		for(i = 0; i < NEXTENT; i++){
877dd7cddfSDavid du Colombier 			e->next = ecache.head;
887dd7cddfSDavid du Colombier 			ecache.head = e;
897dd7cddfSDavid du Colombier 			e++;
907dd7cddfSDavid du Colombier 		}
917dd7cddfSDavid du Colombier 		ecache.free += NEXTENT;
927dd7cddfSDavid du Colombier 		ecache.total += NEXTENT;
937dd7cddfSDavid du Colombier 	}
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier 	e = ecache.head;
967dd7cddfSDavid du Colombier 	ecache.head = e->next;
977dd7cddfSDavid du Colombier 	memset(e, 0, sizeof(Extent));
987dd7cddfSDavid du Colombier 	ecache.free--;
997dd7cddfSDavid du Colombier 	unlock(&ecache);
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier 	return e;
1027dd7cddfSDavid du Colombier }
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier void
cinit(void)1057dd7cddfSDavid du Colombier cinit(void)
1067dd7cddfSDavid du Colombier {
1077dd7cddfSDavid du Colombier 	int i;
1087dd7cddfSDavid du Colombier 	Mntcache *m;
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier 	cache.head = xalloc(sizeof(Mntcache)*NFILE);
1117dd7cddfSDavid du Colombier 	m = cache.head;
1129c63691cSDavid du Colombier 	if (m == nil)
1139c63691cSDavid du Colombier 		panic("cinit: no memory");
1147dd7cddfSDavid du Colombier 
11514414594SDavid du Colombier 	/* a better algorithm would be nice */
1166bbfed0dSDavid du Colombier 	if(conf.npage*BY2PG > 400*MB)
117*401db9f5SDavid du Colombier 		maxcache = 20*MAXCACHE;
1186bbfed0dSDavid du Colombier 	else if(conf.npage*BY2PG > 200*MB)
1196bbfed0dSDavid du Colombier 		maxcache = 10*MAXCACHE;
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	for(i = 0; i < NFILE-1; i++) {
1227dd7cddfSDavid du Colombier 		m->next = m+1;
1237dd7cddfSDavid du Colombier 		m->prev = m-1;
1247dd7cddfSDavid du Colombier 		m++;
1257dd7cddfSDavid du Colombier 	}
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier 	cache.tail = m;
1287dd7cddfSDavid du Colombier 	cache.tail->next = 0;
1297dd7cddfSDavid du Colombier 	cache.head->prev = 0;
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier 	fscache.notext = 1;
1327dd7cddfSDavid du Colombier }
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier void
cprint(Chan * c,Mntcache * m,char * s)1357dd7cddfSDavid du Colombier cprint(Chan *c, Mntcache *m, char *s)
1367dd7cddfSDavid du Colombier {
1377dd7cddfSDavid du Colombier 	ulong o;
1387dd7cddfSDavid du Colombier 	int nb, ct;
1397dd7cddfSDavid du Colombier 	Extent *e;
1407dd7cddfSDavid du Colombier 
1417dd7cddfSDavid du Colombier 	nb = 0;
1427dd7cddfSDavid du Colombier 	ct = 1;
1437dd7cddfSDavid du Colombier 	o = 0;
1447dd7cddfSDavid du Colombier 	if(m->list)
1457dd7cddfSDavid du Colombier 		o = m->list->start;
1467dd7cddfSDavid du Colombier 	for(e = m->list; e; e = e->next) {
1477dd7cddfSDavid du Colombier 		nb += e->len;
1487dd7cddfSDavid du Colombier 		if(o != e->start)
1497dd7cddfSDavid du Colombier 			ct = 0;
1507dd7cddfSDavid du Colombier 		o = e->start+e->len;
1517dd7cddfSDavid du Colombier 	}
152e464ed1aSDavid du Colombier 	pprint("%s: %#llux.%#lux %d %d %s (%d %c)\n",
153e464ed1aSDavid du Colombier 	s, m->qid.path, m->qid.vers, m->type, m->dev, c->path->s, nb, ct ? 'C' : 'N');
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier 	for(e = m->list; e; e = e->next) {
156e464ed1aSDavid du Colombier 		pprint("\t%4d %5lud %4d %#p\n",
1577dd7cddfSDavid du Colombier 			e->bid, e->start, e->len, e->cache);
1587dd7cddfSDavid du Colombier 	}
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier Page*
cpage(Extent * e)1627dd7cddfSDavid du Colombier cpage(Extent *e)
1637dd7cddfSDavid du Colombier {
1647dd7cddfSDavid du Colombier 	/* Easy consistency check */
1657dd7cddfSDavid du Colombier 	if(e->cache->daddr != e->bid)
1667dd7cddfSDavid du Colombier 		return 0;
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier 	return lookpage(&fscache, e->bid);
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier void
cnodata(Mntcache * m)1727dd7cddfSDavid du Colombier cnodata(Mntcache *m)
1737dd7cddfSDavid du Colombier {
1747dd7cddfSDavid du Colombier 	Extent *e, *n;
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier 	/*
1777dd7cddfSDavid du Colombier 	 * Invalidate all extent data
1787dd7cddfSDavid du Colombier 	 * Image lru will waste the pages
1797dd7cddfSDavid du Colombier 	 */
1807dd7cddfSDavid du Colombier 	for(e = m->list; e; e = n) {
1817dd7cddfSDavid du Colombier 		n = e->next;
1827dd7cddfSDavid du Colombier 		extentfree(e);
1837dd7cddfSDavid du Colombier 	}
1847dd7cddfSDavid du Colombier 	m->list = 0;
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier void
ctail(Mntcache * m)1887dd7cddfSDavid du Colombier ctail(Mntcache *m)
1897dd7cddfSDavid du Colombier {
1907dd7cddfSDavid du Colombier 	/* Unlink and send to the tail */
1917dd7cddfSDavid du Colombier 	if(m->prev)
1927dd7cddfSDavid du Colombier 		m->prev->next = m->next;
1937dd7cddfSDavid du Colombier 	else
1947dd7cddfSDavid du Colombier 		cache.head = m->next;
1957dd7cddfSDavid du Colombier 	if(m->next)
1967dd7cddfSDavid du Colombier 		m->next->prev = m->prev;
1977dd7cddfSDavid du Colombier 	else
1987dd7cddfSDavid du Colombier 		cache.tail = m->prev;
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier 	if(cache.tail) {
2017dd7cddfSDavid du Colombier 		m->prev = cache.tail;
2027dd7cddfSDavid du Colombier 		cache.tail->next = m;
2037dd7cddfSDavid du Colombier 		m->next = 0;
2047dd7cddfSDavid du Colombier 		cache.tail = m;
2057dd7cddfSDavid du Colombier 	}
2067dd7cddfSDavid du Colombier 	else {
2077dd7cddfSDavid du Colombier 		cache.head = m;
2087dd7cddfSDavid du Colombier 		cache.tail = m;
2097dd7cddfSDavid du Colombier 		m->prev = 0;
2107dd7cddfSDavid du Colombier 		m->next = 0;
2117dd7cddfSDavid du Colombier 	}
2127dd7cddfSDavid du Colombier }
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier void
copen(Chan * c)2157dd7cddfSDavid du Colombier copen(Chan *c)
2167dd7cddfSDavid du Colombier {
2177dd7cddfSDavid du Colombier 	int h;
2187dd7cddfSDavid du Colombier 	Extent *e, *next;
2197dd7cddfSDavid du Colombier 	Mntcache *m, *f, **l;
2207dd7cddfSDavid du Colombier 
2219a747e4fSDavid du Colombier 	/* directories aren't cacheable and append-only files confuse us */
2229a747e4fSDavid du Colombier 	if(c->qid.type&(QTDIR|QTAPPEND))
2237dd7cddfSDavid du Colombier 		return;
2247dd7cddfSDavid du Colombier 
2257dd7cddfSDavid du Colombier 	h = c->qid.path%NHASH;
2266bbfed0dSDavid du Colombier 	qlock(&cache);
2277dd7cddfSDavid du Colombier 	for(m = cache.hash[h]; m; m = m->hash) {
2289a747e4fSDavid du Colombier 		if(m->qid.path == c->qid.path)
2299a747e4fSDavid du Colombier 		if(m->qid.type == c->qid.type)
2307dd7cddfSDavid du Colombier 		if(m->dev == c->dev && m->type == c->type) {
2317dd7cddfSDavid du Colombier 			c->mcp = m;
2327dd7cddfSDavid du Colombier 			ctail(m);
2336bbfed0dSDavid du Colombier 			qunlock(&cache);
2347dd7cddfSDavid du Colombier 
2357dd7cddfSDavid du Colombier 			/* File was updated, invalidate cache */
2369a747e4fSDavid du Colombier 			if(m->qid.vers != c->qid.vers) {
2379a747e4fSDavid du Colombier 				m->qid.vers = c->qid.vers;
2387dd7cddfSDavid du Colombier 				qlock(m);
2397dd7cddfSDavid du Colombier 				cnodata(m);
2407dd7cddfSDavid du Colombier 				qunlock(m);
2417dd7cddfSDavid du Colombier 			}
2427dd7cddfSDavid du Colombier 			return;
2437dd7cddfSDavid du Colombier 		}
2447dd7cddfSDavid du Colombier 	}
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier 	/* LRU the cache headers */
2477dd7cddfSDavid du Colombier 	m = cache.head;
2489a747e4fSDavid du Colombier 	l = &cache.hash[m->qid.path%NHASH];
2497dd7cddfSDavid du Colombier 	for(f = *l; f; f = f->hash) {
2507dd7cddfSDavid du Colombier 		if(f == m) {
2517dd7cddfSDavid du Colombier 			*l = m->hash;
2527dd7cddfSDavid du Colombier 			break;
2537dd7cddfSDavid du Colombier 		}
2547dd7cddfSDavid du Colombier 		l = &f->hash;
2557dd7cddfSDavid du Colombier 	}
2567dd7cddfSDavid du Colombier 
2579a747e4fSDavid du Colombier 	m->qid = c->qid;
2587dd7cddfSDavid du Colombier 	m->dev = c->dev;
2597dd7cddfSDavid du Colombier 	m->type = c->type;
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 	l = &cache.hash[h];
2627dd7cddfSDavid du Colombier 	m->hash = *l;
2637dd7cddfSDavid du Colombier 	*l = m;
2647dd7cddfSDavid du Colombier 	ctail(m);
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier 	qlock(m);
2677dd7cddfSDavid du Colombier 	c->mcp = m;
2687dd7cddfSDavid du Colombier 	e = m->list;
2697dd7cddfSDavid du Colombier 	m->list = 0;
2706bbfed0dSDavid du Colombier 	qunlock(&cache);
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier 	while(e) {
2737dd7cddfSDavid du Colombier 		next = e->next;
2747dd7cddfSDavid du Colombier 		extentfree(e);
2757dd7cddfSDavid du Colombier 		e = next;
2767dd7cddfSDavid du Colombier 	}
2777dd7cddfSDavid du Colombier 	qunlock(m);
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier static int
cdev(Mntcache * m,Chan * c)2817dd7cddfSDavid du Colombier cdev(Mntcache *m, Chan *c)
2827dd7cddfSDavid du Colombier {
2839a747e4fSDavid du Colombier 	if(m->qid.path != c->qid.path)
2849a747e4fSDavid du Colombier 		return 0;
2859a747e4fSDavid du Colombier 	if(m->qid.type != c->qid.type)
2867dd7cddfSDavid du Colombier 		return 0;
2877dd7cddfSDavid du Colombier 	if(m->dev != c->dev)
2887dd7cddfSDavid du Colombier 		return 0;
2897dd7cddfSDavid du Colombier 	if(m->type != c->type)
2907dd7cddfSDavid du Colombier 		return 0;
2919a747e4fSDavid du Colombier 	if(m->qid.vers != c->qid.vers)
2927dd7cddfSDavid du Colombier 		return 0;
2937dd7cddfSDavid du Colombier 	return 1;
2947dd7cddfSDavid du Colombier }
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier int
cread(Chan * c,uchar * buf,int len,vlong off)2977dd7cddfSDavid du Colombier cread(Chan *c, uchar *buf, int len, vlong off)
2987dd7cddfSDavid du Colombier {
2997dd7cddfSDavid du Colombier 	KMap *k;
3007dd7cddfSDavid du Colombier 	Page *p;
3017dd7cddfSDavid du Colombier 	Mntcache *m;
3027dd7cddfSDavid du Colombier 	Extent *e, **t;
3037dd7cddfSDavid du Colombier 	int o, l, total;
3047dd7cddfSDavid du Colombier 	ulong offset;
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier 	if(off+len > maxcache)
3077dd7cddfSDavid du Colombier 		return 0;
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier 	m = c->mcp;
3107dd7cddfSDavid du Colombier 	if(m == 0)
3117dd7cddfSDavid du Colombier 		return 0;
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier 	qlock(m);
3147dd7cddfSDavid du Colombier 	if(cdev(m, c) == 0) {
3157dd7cddfSDavid du Colombier 		qunlock(m);
3167dd7cddfSDavid du Colombier 		return 0;
3177dd7cddfSDavid du Colombier 	}
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 	offset = off;
3207dd7cddfSDavid du Colombier 	t = &m->list;
3217dd7cddfSDavid du Colombier 	for(e = *t; e; e = e->next) {
3227dd7cddfSDavid du Colombier 		if(offset >= e->start && offset < e->start+e->len)
3237dd7cddfSDavid du Colombier 			break;
3247dd7cddfSDavid du Colombier 		t = &e->next;
3257dd7cddfSDavid du Colombier 	}
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier 	if(e == 0) {
3287dd7cddfSDavid du Colombier 		qunlock(m);
3297dd7cddfSDavid du Colombier 		return 0;
3307dd7cddfSDavid du Colombier 	}
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	total = 0;
3337dd7cddfSDavid du Colombier 	while(len) {
3347dd7cddfSDavid du Colombier 		p = cpage(e);
3357dd7cddfSDavid du Colombier 		if(p == 0) {
3367dd7cddfSDavid du Colombier 			*t = e->next;
3377dd7cddfSDavid du Colombier 			extentfree(e);
3387dd7cddfSDavid du Colombier 			qunlock(m);
3397dd7cddfSDavid du Colombier 			return total;
3407dd7cddfSDavid du Colombier 		}
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier 		o = offset - e->start;
3437dd7cddfSDavid du Colombier 		l = len;
3447dd7cddfSDavid du Colombier 		if(l > e->len-o)
3457dd7cddfSDavid du Colombier 			l = e->len-o;
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier 		k = kmap(p);
3487dd7cddfSDavid du Colombier 		if(waserror()) {
3497dd7cddfSDavid du Colombier 			kunmap(k);
3507dd7cddfSDavid du Colombier 			putpage(p);
3517dd7cddfSDavid du Colombier 			qunlock(m);
3527dd7cddfSDavid du Colombier 			nexterror();
3537dd7cddfSDavid du Colombier 		}
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier 		memmove(buf, (uchar*)VA(k) + o, l);
3567dd7cddfSDavid du Colombier 
3577dd7cddfSDavid du Colombier 		poperror();
3587dd7cddfSDavid du Colombier 		kunmap(k);
3597dd7cddfSDavid du Colombier 
3607dd7cddfSDavid du Colombier 		putpage(p);
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier 		buf += l;
3637dd7cddfSDavid du Colombier 		len -= l;
3647dd7cddfSDavid du Colombier 		offset += l;
3657dd7cddfSDavid du Colombier 		total += l;
3667dd7cddfSDavid du Colombier 		t = &e->next;
3677dd7cddfSDavid du Colombier 		e = e->next;
3687dd7cddfSDavid du Colombier 		if(e == 0 || e->start != offset)
3697dd7cddfSDavid du Colombier 			break;
3707dd7cddfSDavid du Colombier 	}
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier 	qunlock(m);
3737dd7cddfSDavid du Colombier 	return total;
3747dd7cddfSDavid du Colombier }
3757dd7cddfSDavid du Colombier 
3767dd7cddfSDavid du Colombier Extent*
cchain(uchar * buf,ulong offset,int len,Extent ** tail)3777dd7cddfSDavid du Colombier cchain(uchar *buf, ulong offset, int len, Extent **tail)
3787dd7cddfSDavid du Colombier {
3797dd7cddfSDavid du Colombier 	int l;
3807dd7cddfSDavid du Colombier 	Page *p;
3817dd7cddfSDavid du Colombier 	KMap *k;
3827dd7cddfSDavid du Colombier 	Extent *e, *start, **t;
3837dd7cddfSDavid du Colombier 
3847dd7cddfSDavid du Colombier 	start = 0;
3857dd7cddfSDavid du Colombier 	*tail = 0;
3867dd7cddfSDavid du Colombier 	t = &start;
3877dd7cddfSDavid du Colombier 	while(len) {
3887dd7cddfSDavid du Colombier 		e = extentalloc();
3897dd7cddfSDavid du Colombier 		if(e == 0)
3907dd7cddfSDavid du Colombier 			break;
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 		p = auxpage();
3937dd7cddfSDavid du Colombier 		if(p == 0) {
3947dd7cddfSDavid du Colombier 			extentfree(e);
3957dd7cddfSDavid du Colombier 			break;
3967dd7cddfSDavid du Colombier 		}
3977dd7cddfSDavid du Colombier 		l = len;
3987dd7cddfSDavid du Colombier 		if(l > BY2PG)
3997dd7cddfSDavid du Colombier 			l = BY2PG;
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 		e->cache = p;
4027dd7cddfSDavid du Colombier 		e->start = offset;
4037dd7cddfSDavid du Colombier 		e->len = l;
4047dd7cddfSDavid du Colombier 
4056bbfed0dSDavid du Colombier 		qlock(&cache);
4067dd7cddfSDavid du Colombier 		e->bid = cache.pgno;
4077dd7cddfSDavid du Colombier 		cache.pgno += BY2PG;
4087dd7cddfSDavid du Colombier 		/* wrap the counter; low bits are unused by pghash but checked by lookpage */
4097dd7cddfSDavid du Colombier 		if((cache.pgno & ~(BY2PG-1)) == 0){
4107dd7cddfSDavid du Colombier 			if(cache.pgno == BY2PG-1){
4117dd7cddfSDavid du Colombier 				print("cache wrapped\n");
4127dd7cddfSDavid du Colombier 				cache.pgno = 0;
4137dd7cddfSDavid du Colombier 			}else
4147dd7cddfSDavid du Colombier 				cache.pgno++;
4157dd7cddfSDavid du Colombier 		}
4166bbfed0dSDavid du Colombier 		qunlock(&cache);
4177dd7cddfSDavid du Colombier 
4187dd7cddfSDavid du Colombier 		p->daddr = e->bid;
4197dd7cddfSDavid du Colombier 		k = kmap(p);
4207dd7cddfSDavid du Colombier 		if(waserror()) {		/* buf may be virtual */
4217dd7cddfSDavid du Colombier 			kunmap(k);
4227dd7cddfSDavid du Colombier 			nexterror();
4237dd7cddfSDavid du Colombier 		}
4247dd7cddfSDavid du Colombier 		memmove((void*)VA(k), buf, l);
4257dd7cddfSDavid du Colombier 		poperror();
4267dd7cddfSDavid du Colombier 		kunmap(k);
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier 		cachepage(p, &fscache);
4297dd7cddfSDavid du Colombier 		putpage(p);
4307dd7cddfSDavid du Colombier 
4317dd7cddfSDavid du Colombier 		buf += l;
4327dd7cddfSDavid du Colombier 		offset += l;
4337dd7cddfSDavid du Colombier 		len -= l;
4347dd7cddfSDavid du Colombier 
4357dd7cddfSDavid du Colombier 		*t = e;
4367dd7cddfSDavid du Colombier 		*tail = e;
4377dd7cddfSDavid du Colombier 		t = &e->next;
4387dd7cddfSDavid du Colombier 	}
4397dd7cddfSDavid du Colombier 
4407dd7cddfSDavid du Colombier 	return start;
4417dd7cddfSDavid du Colombier }
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier int
cpgmove(Extent * e,uchar * buf,int boff,int len)4447dd7cddfSDavid du Colombier cpgmove(Extent *e, uchar *buf, int boff, int len)
4457dd7cddfSDavid du Colombier {
4467dd7cddfSDavid du Colombier 	Page *p;
4477dd7cddfSDavid du Colombier 	KMap *k;
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier 	p = cpage(e);
4507dd7cddfSDavid du Colombier 	if(p == 0)
4517dd7cddfSDavid du Colombier 		return 0;
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier 	k = kmap(p);
4547dd7cddfSDavid du Colombier 	if(waserror()) {		/* Since buf may be virtual */
4557dd7cddfSDavid du Colombier 		kunmap(k);
4567dd7cddfSDavid du Colombier 		nexterror();
4577dd7cddfSDavid du Colombier 	}
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier 	memmove((uchar*)VA(k)+boff, buf, len);
4607dd7cddfSDavid du Colombier 
4617dd7cddfSDavid du Colombier 	poperror();
4627dd7cddfSDavid du Colombier 	kunmap(k);
4637dd7cddfSDavid du Colombier 	putpage(p);
4647dd7cddfSDavid du Colombier 
4657dd7cddfSDavid du Colombier 	return 1;
4667dd7cddfSDavid du Colombier }
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier void
cupdate(Chan * c,uchar * buf,int len,vlong off)4697dd7cddfSDavid du Colombier cupdate(Chan *c, uchar *buf, int len, vlong off)
4707dd7cddfSDavid du Colombier {
4717dd7cddfSDavid du Colombier 	Mntcache *m;
4727dd7cddfSDavid du Colombier 	Extent *tail;
4737dd7cddfSDavid du Colombier 	Extent *e, *f, *p;
4747dd7cddfSDavid du Colombier 	int o, ee, eblock;
4757dd7cddfSDavid du Colombier 	ulong offset;
4767dd7cddfSDavid du Colombier 
4777dd7cddfSDavid du Colombier 	if(off > maxcache || len == 0)
4787dd7cddfSDavid du Colombier 		return;
4797dd7cddfSDavid du Colombier 
4807dd7cddfSDavid du Colombier 	m = c->mcp;
4817dd7cddfSDavid du Colombier 	if(m == 0)
4827dd7cddfSDavid du Colombier 		return;
4837dd7cddfSDavid du Colombier 	qlock(m);
4847dd7cddfSDavid du Colombier 	if(cdev(m, c) == 0) {
4857dd7cddfSDavid du Colombier 		qunlock(m);
4867dd7cddfSDavid du Colombier 		return;
4877dd7cddfSDavid du Colombier 	}
4887dd7cddfSDavid du Colombier 
4897dd7cddfSDavid du Colombier 	/*
4907dd7cddfSDavid du Colombier 	 * Find the insertion point
4917dd7cddfSDavid du Colombier 	 */
4927dd7cddfSDavid du Colombier 	offset = off;
4937dd7cddfSDavid du Colombier 	p = 0;
4947dd7cddfSDavid du Colombier 	for(f = m->list; f; f = f->next) {
4957dd7cddfSDavid du Colombier 		if(f->start > offset)
4967dd7cddfSDavid du Colombier 			break;
4977dd7cddfSDavid du Colombier 		p = f;
4987dd7cddfSDavid du Colombier 	}
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier 	/* trim if there is a successor */
5017dd7cddfSDavid du Colombier 	eblock = offset+len;
5027dd7cddfSDavid du Colombier 	if(f != 0 && eblock > f->start) {
5037dd7cddfSDavid du Colombier 		len -= (eblock - f->start);
5047dd7cddfSDavid du Colombier 		if(len <= 0) {
5057dd7cddfSDavid du Colombier 			qunlock(m);
5067dd7cddfSDavid du Colombier 			return;
5077dd7cddfSDavid du Colombier 		}
5087dd7cddfSDavid du Colombier 	}
5097dd7cddfSDavid du Colombier 
5107dd7cddfSDavid du Colombier 	if(p == 0) {		/* at the head */
5117dd7cddfSDavid du Colombier 		e = cchain(buf, offset, len, &tail);
5127dd7cddfSDavid du Colombier 		if(e != 0) {
5137dd7cddfSDavid du Colombier 			m->list = e;
5147dd7cddfSDavid du Colombier 			tail->next = f;
5157dd7cddfSDavid du Colombier 		}
5167dd7cddfSDavid du Colombier 		qunlock(m);
5177dd7cddfSDavid du Colombier 		return;
5187dd7cddfSDavid du Colombier 	}
5197dd7cddfSDavid du Colombier 
5207dd7cddfSDavid du Colombier 	/* trim to the predecessor */
5217dd7cddfSDavid du Colombier 	ee = p->start+p->len;
5227dd7cddfSDavid du Colombier 	if(offset < ee) {
5237dd7cddfSDavid du Colombier 		o = ee - offset;
5247dd7cddfSDavid du Colombier 		len -= o;
5257dd7cddfSDavid du Colombier 		if(len <= 0) {
5267dd7cddfSDavid du Colombier 			qunlock(m);
5277dd7cddfSDavid du Colombier 			return;
5287dd7cddfSDavid du Colombier 		}
5297dd7cddfSDavid du Colombier 		buf += o;
5307dd7cddfSDavid du Colombier 		offset += o;
5317dd7cddfSDavid du Colombier 	}
5327dd7cddfSDavid du Colombier 
5337dd7cddfSDavid du Colombier 	/* try and pack data into the predecessor */
5347dd7cddfSDavid du Colombier 	if(offset == ee && p->len < BY2PG) {
5357dd7cddfSDavid du Colombier 		o = len;
5367dd7cddfSDavid du Colombier 		if(o > BY2PG - p->len)
5377dd7cddfSDavid du Colombier 			o = BY2PG - p->len;
5387dd7cddfSDavid du Colombier 		if(cpgmove(p, buf, p->len, o)) {
5397dd7cddfSDavid du Colombier 			p->len += o;
5407dd7cddfSDavid du Colombier 			buf += o;
5417dd7cddfSDavid du Colombier 			len -= o;
5427dd7cddfSDavid du Colombier 			offset += o;
5437dd7cddfSDavid du Colombier 			if(len <= 0) {
5447dd7cddfSDavid du Colombier if(f && p->start + p->len > f->start) print("CACHE: p->start=%uld p->len=%d f->start=%uld\n", p->start, p->len, f->start);
5457dd7cddfSDavid du Colombier 				qunlock(m);
5467dd7cddfSDavid du Colombier 				return;
5477dd7cddfSDavid du Colombier 			}
5487dd7cddfSDavid du Colombier 		}
5497dd7cddfSDavid du Colombier 	}
5507dd7cddfSDavid du Colombier 
5517dd7cddfSDavid du Colombier 	e = cchain(buf, offset, len, &tail);
5527dd7cddfSDavid du Colombier 	if(e != 0) {
5537dd7cddfSDavid du Colombier 		p->next = e;
5547dd7cddfSDavid du Colombier 		tail->next = f;
5557dd7cddfSDavid du Colombier 	}
5567dd7cddfSDavid du Colombier 	qunlock(m);
5577dd7cddfSDavid du Colombier }
5587dd7cddfSDavid du Colombier 
5597dd7cddfSDavid du Colombier void
cwrite(Chan * c,uchar * buf,int len,vlong off)5607dd7cddfSDavid du Colombier cwrite(Chan* c, uchar *buf, int len, vlong off)
5617dd7cddfSDavid du Colombier {
5627dd7cddfSDavid du Colombier 	int o, eo;
5637dd7cddfSDavid du Colombier 	Mntcache *m;
5647dd7cddfSDavid du Colombier 	ulong eblock, ee;
5657dd7cddfSDavid du Colombier 	Extent *p, *f, *e, *tail;
5667dd7cddfSDavid du Colombier 	ulong offset;
5677dd7cddfSDavid du Colombier 
5687dd7cddfSDavid du Colombier 	if(off > maxcache || len == 0)
5697dd7cddfSDavid du Colombier 		return;
5707dd7cddfSDavid du Colombier 
5717dd7cddfSDavid du Colombier 	m = c->mcp;
5727dd7cddfSDavid du Colombier 	if(m == 0)
5737dd7cddfSDavid du Colombier 		return;
5747dd7cddfSDavid du Colombier 
5757dd7cddfSDavid du Colombier 	qlock(m);
5767dd7cddfSDavid du Colombier 	if(cdev(m, c) == 0) {
5777dd7cddfSDavid du Colombier 		qunlock(m);
5787dd7cddfSDavid du Colombier 		return;
5797dd7cddfSDavid du Colombier 	}
5807dd7cddfSDavid du Colombier 
5817dd7cddfSDavid du Colombier 	offset = off;
5829a747e4fSDavid du Colombier 	m->qid.vers++;
5837dd7cddfSDavid du Colombier 	c->qid.vers++;
5847dd7cddfSDavid du Colombier 
5857dd7cddfSDavid du Colombier 	p = 0;
5867dd7cddfSDavid du Colombier 	for(f = m->list; f; f = f->next) {
5877dd7cddfSDavid du Colombier 		if(f->start >= offset)
5887dd7cddfSDavid du Colombier 			break;
5897dd7cddfSDavid du Colombier 		p = f;
5907dd7cddfSDavid du Colombier 	}
5917dd7cddfSDavid du Colombier 
5927dd7cddfSDavid du Colombier 	if(p != 0) {
5937dd7cddfSDavid du Colombier 		ee = p->start+p->len;
5947dd7cddfSDavid du Colombier 		eo = offset - p->start;
5957dd7cddfSDavid du Colombier 		/* pack in predecessor if there is space */
5967dd7cddfSDavid du Colombier 		if(offset <= ee && eo < BY2PG) {
5977dd7cddfSDavid du Colombier 			o = len;
5987dd7cddfSDavid du Colombier 			if(o > BY2PG - eo)
5997dd7cddfSDavid du Colombier 				o = BY2PG - eo;
6007dd7cddfSDavid du Colombier 			if(cpgmove(p, buf, eo, o)) {
6017dd7cddfSDavid du Colombier 				if(eo+o > p->len)
6027dd7cddfSDavid du Colombier 					p->len = eo+o;
6037dd7cddfSDavid du Colombier 				buf += o;
6047dd7cddfSDavid du Colombier 				len -= o;
6057dd7cddfSDavid du Colombier 				offset += o;
6067dd7cddfSDavid du Colombier 			}
6077dd7cddfSDavid du Colombier 		}
6087dd7cddfSDavid du Colombier 	}
6097dd7cddfSDavid du Colombier 
6107dd7cddfSDavid du Colombier 	/* free the overlap -- it's a rare case */
6117dd7cddfSDavid du Colombier 	eblock = offset+len;
6127dd7cddfSDavid du Colombier 	while(f && f->start < eblock) {
6137dd7cddfSDavid du Colombier 		e = f->next;
6147dd7cddfSDavid du Colombier 		extentfree(f);
6157dd7cddfSDavid du Colombier 		f = e;
6167dd7cddfSDavid du Colombier 	}
6177dd7cddfSDavid du Colombier 
6187dd7cddfSDavid du Colombier 	/* link the block (if any) into the middle */
6197dd7cddfSDavid du Colombier 	e = cchain(buf, offset, len, &tail);
6207dd7cddfSDavid du Colombier 	if(e != 0) {
6217dd7cddfSDavid du Colombier 		tail->next = f;
6227dd7cddfSDavid du Colombier 		f = e;
6237dd7cddfSDavid du Colombier 	}
6247dd7cddfSDavid du Colombier 
6257dd7cddfSDavid du Colombier 	if(p == 0)
6267dd7cddfSDavid du Colombier 		m->list = f;
6277dd7cddfSDavid du Colombier 	else
6287dd7cddfSDavid du Colombier 		p->next = f;
6297dd7cddfSDavid du Colombier 	qunlock(m);
6307dd7cddfSDavid du Colombier }
631