xref: /plan9-contrib/sys/src/9k/port/cache.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier 
79ef1f84bSDavid du Colombier enum
89ef1f84bSDavid du Colombier {
99ef1f84bSDavid du Colombier 	NHASH		= 128,
109ef1f84bSDavid du Colombier 	MAXCACHE	= 1024*1024,
119ef1f84bSDavid du Colombier 	NFILE		= 4096,
129ef1f84bSDavid du Colombier 	NEXTENT		= 200,		/* extent allocation size */
139ef1f84bSDavid du Colombier };
149ef1f84bSDavid du Colombier 
159ef1f84bSDavid du Colombier typedef struct Extent Extent;
169ef1f84bSDavid du Colombier struct Extent
179ef1f84bSDavid du Colombier {
189ef1f84bSDavid du Colombier 	int	bid;
199ef1f84bSDavid du Colombier 	ulong	start;
209ef1f84bSDavid du Colombier 	int	len;
219ef1f84bSDavid du Colombier 	Page	*cache;
229ef1f84bSDavid du Colombier 	Extent	*next;
239ef1f84bSDavid du Colombier };
249ef1f84bSDavid du Colombier 
259ef1f84bSDavid du Colombier typedef struct Mntcache Mntcache;
269ef1f84bSDavid du Colombier struct Mntcache
279ef1f84bSDavid du Colombier {
289ef1f84bSDavid du Colombier 	Qid	qid;
299ef1f84bSDavid du Colombier 	uint	devno;
309ef1f84bSDavid du Colombier 	Dev*	dev;
319ef1f84bSDavid du Colombier 	QLock;
329ef1f84bSDavid du Colombier 	Extent	 *list;
339ef1f84bSDavid du Colombier 	Mntcache *hash;
349ef1f84bSDavid du Colombier 	Mntcache *prev;
359ef1f84bSDavid du Colombier 	Mntcache *next;
369ef1f84bSDavid du Colombier };
379ef1f84bSDavid du Colombier 
389ef1f84bSDavid du Colombier typedef struct Cache Cache;
399ef1f84bSDavid du Colombier struct Cache
409ef1f84bSDavid du Colombier {
419ef1f84bSDavid du Colombier 	QLock;
429ef1f84bSDavid du Colombier 	int		pgno;
439ef1f84bSDavid du Colombier 	Mntcache	*head;
449ef1f84bSDavid du Colombier 	Mntcache	*tail;
459ef1f84bSDavid du Colombier 	Mntcache	*hash[NHASH];
469ef1f84bSDavid du Colombier };
479ef1f84bSDavid du Colombier 
489ef1f84bSDavid du Colombier typedef struct Ecache Ecache;
499ef1f84bSDavid du Colombier struct Ecache
509ef1f84bSDavid du Colombier {
519ef1f84bSDavid du Colombier 	Lock;
529ef1f84bSDavid du Colombier 	int	total;
539ef1f84bSDavid du Colombier 	int	free;
549ef1f84bSDavid du Colombier 	Extent*	head;
559ef1f84bSDavid du Colombier };
569ef1f84bSDavid du Colombier 
579ef1f84bSDavid du Colombier static Image fscache;
589ef1f84bSDavid du Colombier static Cache cache;
599ef1f84bSDavid du Colombier static Ecache ecache;
609ef1f84bSDavid du Colombier static int maxcache = MAXCACHE;
619ef1f84bSDavid du Colombier 
629ef1f84bSDavid du Colombier static void
extentfree(Extent * e)639ef1f84bSDavid du Colombier extentfree(Extent* e)
649ef1f84bSDavid du Colombier {
659ef1f84bSDavid du Colombier 	lock(&ecache);
669ef1f84bSDavid du Colombier 	e->next = ecache.head;
679ef1f84bSDavid du Colombier 	ecache.head = e;
689ef1f84bSDavid du Colombier 	ecache.free++;
699ef1f84bSDavid du Colombier 	unlock(&ecache);
709ef1f84bSDavid du Colombier }
719ef1f84bSDavid du Colombier 
729ef1f84bSDavid du Colombier static Extent*
extentalloc(void)739ef1f84bSDavid du Colombier extentalloc(void)
749ef1f84bSDavid du Colombier {
759ef1f84bSDavid du Colombier 	Extent *e;
769ef1f84bSDavid du Colombier 	int i;
779ef1f84bSDavid du Colombier 
789ef1f84bSDavid du Colombier 	lock(&ecache);
799ef1f84bSDavid du Colombier 	if(ecache.head == nil){
809ef1f84bSDavid du Colombier 		e = malloc(NEXTENT*sizeof(Extent));
819ef1f84bSDavid du Colombier 		if(e == nil){
829ef1f84bSDavid du Colombier 			unlock(&ecache);
839ef1f84bSDavid du Colombier 			return nil;
849ef1f84bSDavid du Colombier 		}
859ef1f84bSDavid du Colombier 		for(i = 0; i < NEXTENT; i++){
869ef1f84bSDavid du Colombier 			e->next = ecache.head;
879ef1f84bSDavid du Colombier 			ecache.head = e;
889ef1f84bSDavid du Colombier 			e++;
899ef1f84bSDavid du Colombier 		}
909ef1f84bSDavid du Colombier 		ecache.free += NEXTENT;
919ef1f84bSDavid du Colombier 		ecache.total += NEXTENT;
929ef1f84bSDavid du Colombier 	}
939ef1f84bSDavid du Colombier 
949ef1f84bSDavid du Colombier 	e = ecache.head;
959ef1f84bSDavid du Colombier 	ecache.head = e->next;
969ef1f84bSDavid du Colombier 	memset(e, 0, sizeof(Extent));
979ef1f84bSDavid du Colombier 	ecache.free--;
989ef1f84bSDavid du Colombier 	unlock(&ecache);
999ef1f84bSDavid du Colombier 
1009ef1f84bSDavid du Colombier 	return e;
1019ef1f84bSDavid du Colombier }
1029ef1f84bSDavid du Colombier 
1039ef1f84bSDavid du Colombier void
cinit(void)1049ef1f84bSDavid du Colombier cinit(void)
1059ef1f84bSDavid du Colombier {
1069ef1f84bSDavid du Colombier 	int i;
1079ef1f84bSDavid du Colombier 	Mntcache *mc;
1089ef1f84bSDavid du Colombier 
1099ef1f84bSDavid du Colombier 	if((cache.head = malloc(sizeof(Mntcache)*NFILE)) == nil)
1109ef1f84bSDavid du Colombier 		panic("cinit: no memory");
1119ef1f84bSDavid du Colombier 	mc = cache.head;
1129ef1f84bSDavid du Colombier 
1139ef1f84bSDavid du Colombier 	/* a good algorithm to set maxcache would be nice */
1149ef1f84bSDavid du Colombier 
1159ef1f84bSDavid du Colombier 	for(i = 0; i < NFILE-1; i++) {
1169ef1f84bSDavid du Colombier 		mc->next = mc+1;
1179ef1f84bSDavid du Colombier 		mc->prev = mc-1;
1189ef1f84bSDavid du Colombier 		mc++;
1199ef1f84bSDavid du Colombier 	}
1209ef1f84bSDavid du Colombier 
1219ef1f84bSDavid du Colombier 	cache.tail = mc;
1229ef1f84bSDavid du Colombier 	cache.tail->next = 0;
1239ef1f84bSDavid du Colombier 	cache.head->prev = 0;
1249ef1f84bSDavid du Colombier 
1259ef1f84bSDavid du Colombier 	fscache.notext = 1;
1269ef1f84bSDavid du Colombier }
1279ef1f84bSDavid du Colombier 
1289ef1f84bSDavid du Colombier Page*
cpage(Extent * e)1299ef1f84bSDavid du Colombier cpage(Extent *e)
1309ef1f84bSDavid du Colombier {
1319ef1f84bSDavid du Colombier 	/* Easy consistency check */
1329ef1f84bSDavid du Colombier 	if(e->cache->daddr != e->bid)
1339ef1f84bSDavid du Colombier 		return 0;
1349ef1f84bSDavid du Colombier 
1359ef1f84bSDavid du Colombier 	return lookpage(&fscache, e->bid);
1369ef1f84bSDavid du Colombier }
1379ef1f84bSDavid du Colombier 
1389ef1f84bSDavid du Colombier void
cnodata(Mntcache * mc)1399ef1f84bSDavid du Colombier cnodata(Mntcache *mc)
1409ef1f84bSDavid du Colombier {
1419ef1f84bSDavid du Colombier 	Extent *e, *n;
1429ef1f84bSDavid du Colombier 
1439ef1f84bSDavid du Colombier 	/*
1449ef1f84bSDavid du Colombier 	 * Invalidate all extent data
1459ef1f84bSDavid du Colombier 	 * Image lru will waste the pages
1469ef1f84bSDavid du Colombier 	 */
1479ef1f84bSDavid du Colombier 	for(e = mc->list; e; e = n) {
1489ef1f84bSDavid du Colombier 		n = e->next;
1499ef1f84bSDavid du Colombier 		extentfree(e);
1509ef1f84bSDavid du Colombier 	}
1519ef1f84bSDavid du Colombier 	mc->list = 0;
1529ef1f84bSDavid du Colombier }
1539ef1f84bSDavid du Colombier 
1549ef1f84bSDavid du Colombier void
ctail(Mntcache * mc)1559ef1f84bSDavid du Colombier ctail(Mntcache *mc)
1569ef1f84bSDavid du Colombier {
1579ef1f84bSDavid du Colombier 	/* Unlink and send to the tail */
1589ef1f84bSDavid du Colombier 	if(mc->prev)
1599ef1f84bSDavid du Colombier 		mc->prev->next = mc->next;
1609ef1f84bSDavid du Colombier 	else
1619ef1f84bSDavid du Colombier 		cache.head = mc->next;
1629ef1f84bSDavid du Colombier 	if(mc->next)
1639ef1f84bSDavid du Colombier 		mc->next->prev = mc->prev;
1649ef1f84bSDavid du Colombier 	else
1659ef1f84bSDavid du Colombier 		cache.tail = mc->prev;
1669ef1f84bSDavid du Colombier 
1679ef1f84bSDavid du Colombier 	if(cache.tail) {
1689ef1f84bSDavid du Colombier 		mc->prev = cache.tail;
1699ef1f84bSDavid du Colombier 		cache.tail->next = mc;
1709ef1f84bSDavid du Colombier 		mc->next = 0;
1719ef1f84bSDavid du Colombier 		cache.tail = mc;
1729ef1f84bSDavid du Colombier 	}
1739ef1f84bSDavid du Colombier 	else {
1749ef1f84bSDavid du Colombier 		cache.head = mc;
1759ef1f84bSDavid du Colombier 		cache.tail = mc;
1769ef1f84bSDavid du Colombier 		mc->prev = 0;
1779ef1f84bSDavid du Colombier 		mc->next = 0;
1789ef1f84bSDavid du Colombier 	}
1799ef1f84bSDavid du Colombier }
1809ef1f84bSDavid du Colombier 
1819ef1f84bSDavid du Colombier void
copen(Chan * c)1829ef1f84bSDavid du Colombier copen(Chan *c)
1839ef1f84bSDavid du Colombier {
1849ef1f84bSDavid du Colombier 	int h;
1859ef1f84bSDavid du Colombier 	Extent *e, *next;
1869ef1f84bSDavid du Colombier 	Mntcache *mc, *f, **l;
1879ef1f84bSDavid du Colombier 
1889ef1f84bSDavid du Colombier 	/* directories aren't cacheable and append-only files confuse us */
1899ef1f84bSDavid du Colombier 	if(c->qid.type&(QTDIR|QTAPPEND))
1909ef1f84bSDavid du Colombier 		return;
1919ef1f84bSDavid du Colombier 
1929ef1f84bSDavid du Colombier 	h = c->qid.path%NHASH;
1939ef1f84bSDavid du Colombier 	qlock(&cache);
1949ef1f84bSDavid du Colombier 	for(mc = cache.hash[h]; mc != nil; mc = mc->hash) {
1959ef1f84bSDavid du Colombier 		if(mc->qid.path == c->qid.path)
1969ef1f84bSDavid du Colombier 		if(mc->qid.type == c->qid.type)
1979ef1f84bSDavid du Colombier 		if(mc->devno == c->devno && mc->dev == c->dev) {
1989ef1f84bSDavid du Colombier 			c->mc = mc;
1999ef1f84bSDavid du Colombier 			ctail(mc);
2009ef1f84bSDavid du Colombier 			qunlock(&cache);
2019ef1f84bSDavid du Colombier 
2029ef1f84bSDavid du Colombier 			/* File was updated, invalidate cache */
2039ef1f84bSDavid du Colombier 			if(mc->qid.vers != c->qid.vers) {
2049ef1f84bSDavid du Colombier 				mc->qid.vers = c->qid.vers;
2059ef1f84bSDavid du Colombier 				qlock(mc);
2069ef1f84bSDavid du Colombier 				cnodata(mc);
2079ef1f84bSDavid du Colombier 				qunlock(mc);
2089ef1f84bSDavid du Colombier 			}
2099ef1f84bSDavid du Colombier 			return;
2109ef1f84bSDavid du Colombier 		}
2119ef1f84bSDavid du Colombier 	}
2129ef1f84bSDavid du Colombier 
2139ef1f84bSDavid du Colombier 	/* LRU the cache headers */
2149ef1f84bSDavid du Colombier 	mc = cache.head;
2159ef1f84bSDavid du Colombier 	l = &cache.hash[mc->qid.path%NHASH];
2169ef1f84bSDavid du Colombier 	for(f = *l; f; f = f->hash) {
2179ef1f84bSDavid du Colombier 		if(f == mc) {
2189ef1f84bSDavid du Colombier 			*l = mc->hash;
2199ef1f84bSDavid du Colombier 			break;
2209ef1f84bSDavid du Colombier 		}
2219ef1f84bSDavid du Colombier 		l = &f->hash;
2229ef1f84bSDavid du Colombier 	}
2239ef1f84bSDavid du Colombier 
2249ef1f84bSDavid du Colombier 	mc->qid = c->qid;
2259ef1f84bSDavid du Colombier 	mc->devno = c->devno;
2269ef1f84bSDavid du Colombier 	mc->dev = c->dev;
2279ef1f84bSDavid du Colombier 
2289ef1f84bSDavid du Colombier 	l = &cache.hash[h];
2299ef1f84bSDavid du Colombier 	mc->hash = *l;
2309ef1f84bSDavid du Colombier 	*l = mc;
2319ef1f84bSDavid du Colombier 	ctail(mc);
2329ef1f84bSDavid du Colombier 
2339ef1f84bSDavid du Colombier 	qlock(mc);
2349ef1f84bSDavid du Colombier 	c->mc = mc;
2359ef1f84bSDavid du Colombier 	e = mc->list;
2369ef1f84bSDavid du Colombier 	mc->list = 0;
2379ef1f84bSDavid du Colombier 	qunlock(&cache);
2389ef1f84bSDavid du Colombier 
2399ef1f84bSDavid du Colombier 	while(e) {
2409ef1f84bSDavid du Colombier 		next = e->next;
2419ef1f84bSDavid du Colombier 		extentfree(e);
2429ef1f84bSDavid du Colombier 		e = next;
2439ef1f84bSDavid du Colombier 	}
2449ef1f84bSDavid du Colombier 	qunlock(mc);
2459ef1f84bSDavid du Colombier }
2469ef1f84bSDavid du Colombier 
2479ef1f84bSDavid du Colombier static int
cdev(Mntcache * mc,Chan * c)2489ef1f84bSDavid du Colombier cdev(Mntcache *mc, Chan *c)
2499ef1f84bSDavid du Colombier {
2509ef1f84bSDavid du Colombier 	if(mc->qid.path != c->qid.path)
2519ef1f84bSDavid du Colombier 		return 0;
2529ef1f84bSDavid du Colombier 	if(mc->qid.type != c->qid.type)
2539ef1f84bSDavid du Colombier 		return 0;
2549ef1f84bSDavid du Colombier 	if(mc->devno != c->devno)
2559ef1f84bSDavid du Colombier 		return 0;
2569ef1f84bSDavid du Colombier 	if(mc->dev != c->dev)
2579ef1f84bSDavid du Colombier 		return 0;
2589ef1f84bSDavid du Colombier 	if(mc->qid.vers != c->qid.vers)
2599ef1f84bSDavid du Colombier 		return 0;
2609ef1f84bSDavid du Colombier 	return 1;
2619ef1f84bSDavid du Colombier }
2629ef1f84bSDavid du Colombier 
2639ef1f84bSDavid du Colombier int
cread(Chan * c,uchar * buf,int len,vlong off)2649ef1f84bSDavid du Colombier cread(Chan *c, uchar *buf, int len, vlong off)
2659ef1f84bSDavid du Colombier {
2669ef1f84bSDavid du Colombier 	KMap *k;
2679ef1f84bSDavid du Colombier 	Page *p;
2689ef1f84bSDavid du Colombier 	Mntcache *mc;
2699ef1f84bSDavid du Colombier 	Extent *e, **t;
2709ef1f84bSDavid du Colombier 	int o, l, total;
2719ef1f84bSDavid du Colombier 	ulong offset;
2729ef1f84bSDavid du Colombier 
2739ef1f84bSDavid du Colombier 	if(off+len > maxcache)
2749ef1f84bSDavid du Colombier 		return 0;
2759ef1f84bSDavid du Colombier 
2769ef1f84bSDavid du Colombier 	mc = c->mc;
2779ef1f84bSDavid du Colombier 	if(mc == nil)
2789ef1f84bSDavid du Colombier 		return 0;
2799ef1f84bSDavid du Colombier 
2809ef1f84bSDavid du Colombier 	qlock(mc);
2819ef1f84bSDavid du Colombier 	if(cdev(mc, c) == 0) {
2829ef1f84bSDavid du Colombier 		qunlock(mc);
2839ef1f84bSDavid du Colombier 		return 0;
2849ef1f84bSDavid du Colombier 	}
2859ef1f84bSDavid du Colombier 
2869ef1f84bSDavid du Colombier 	offset = off;
2879ef1f84bSDavid du Colombier 	t = &mc->list;
2889ef1f84bSDavid du Colombier 	for(e = *t; e; e = e->next) {
2899ef1f84bSDavid du Colombier 		if(offset >= e->start && offset < e->start+e->len)
2909ef1f84bSDavid du Colombier 			break;
2919ef1f84bSDavid du Colombier 		t = &e->next;
2929ef1f84bSDavid du Colombier 	}
2939ef1f84bSDavid du Colombier 
2949ef1f84bSDavid du Colombier 	if(e == 0) {
2959ef1f84bSDavid du Colombier 		qunlock(mc);
2969ef1f84bSDavid du Colombier 		return 0;
2979ef1f84bSDavid du Colombier 	}
2989ef1f84bSDavid du Colombier 
2999ef1f84bSDavid du Colombier 	total = 0;
3009ef1f84bSDavid du Colombier 	while(len) {
3019ef1f84bSDavid du Colombier 		p = cpage(e);
3029ef1f84bSDavid du Colombier 		if(p == 0) {
3039ef1f84bSDavid du Colombier 			*t = e->next;
3049ef1f84bSDavid du Colombier 			extentfree(e);
3059ef1f84bSDavid du Colombier 			qunlock(mc);
3069ef1f84bSDavid du Colombier 			return total;
3079ef1f84bSDavid du Colombier 		}
3089ef1f84bSDavid du Colombier 
3099ef1f84bSDavid du Colombier 		o = offset - e->start;
3109ef1f84bSDavid du Colombier 		l = len;
3119ef1f84bSDavid du Colombier 		if(l > e->len-o)
3129ef1f84bSDavid du Colombier 			l = e->len-o;
3139ef1f84bSDavid du Colombier 
3149ef1f84bSDavid du Colombier 		k = kmap(p);
3159ef1f84bSDavid du Colombier 		if(waserror()) {
3169ef1f84bSDavid du Colombier 			kunmap(k);
3179ef1f84bSDavid du Colombier 			putpage(p);
3189ef1f84bSDavid du Colombier 			qunlock(mc);
3199ef1f84bSDavid du Colombier 			nexterror();
3209ef1f84bSDavid du Colombier 		}
3219ef1f84bSDavid du Colombier 
3229ef1f84bSDavid du Colombier 		memmove(buf, (uchar*)VA(k) + o, l);
3239ef1f84bSDavid du Colombier 
3249ef1f84bSDavid du Colombier 		poperror();
3259ef1f84bSDavid du Colombier 		kunmap(k);
3269ef1f84bSDavid du Colombier 
3279ef1f84bSDavid du Colombier 		putpage(p);
3289ef1f84bSDavid du Colombier 
3299ef1f84bSDavid du Colombier 		buf += l;
3309ef1f84bSDavid du Colombier 		len -= l;
3319ef1f84bSDavid du Colombier 		offset += l;
3329ef1f84bSDavid du Colombier 		total += l;
3339ef1f84bSDavid du Colombier 		t = &e->next;
3349ef1f84bSDavid du Colombier 		e = e->next;
3359ef1f84bSDavid du Colombier 		if(e == 0 || e->start != offset)
3369ef1f84bSDavid du Colombier 			break;
3379ef1f84bSDavid du Colombier 	}
3389ef1f84bSDavid du Colombier 
3399ef1f84bSDavid du Colombier 	qunlock(mc);
3409ef1f84bSDavid du Colombier 	return total;
3419ef1f84bSDavid du Colombier }
3429ef1f84bSDavid du Colombier 
3439ef1f84bSDavid du Colombier Extent*
cchain(uchar * buf,ulong offset,int len,Extent ** tail)3449ef1f84bSDavid du Colombier cchain(uchar *buf, ulong offset, int len, Extent **tail)
3459ef1f84bSDavid du Colombier {
3469ef1f84bSDavid du Colombier 	int l;
3479ef1f84bSDavid du Colombier 	Page *p;
3489ef1f84bSDavid du Colombier 	KMap *k;
3499ef1f84bSDavid du Colombier 	Extent *e, *start, **t;
3509ef1f84bSDavid du Colombier 
3519ef1f84bSDavid du Colombier 	start = 0;
3529ef1f84bSDavid du Colombier 	*tail = 0;
3539ef1f84bSDavid du Colombier 	t = &start;
3549ef1f84bSDavid du Colombier 	while(len) {
3559ef1f84bSDavid du Colombier 		e = extentalloc();
3569ef1f84bSDavid du Colombier 		if(e == 0)
3579ef1f84bSDavid du Colombier 			break;
3589ef1f84bSDavid du Colombier 
359*094d6818SDavid du Colombier 		p = auxpage(PGSHFT);
3609ef1f84bSDavid du Colombier 		if(p == 0) {
3619ef1f84bSDavid du Colombier 			extentfree(e);
3629ef1f84bSDavid du Colombier 			break;
3639ef1f84bSDavid du Colombier 		}
3649ef1f84bSDavid du Colombier 		l = len;
3659ef1f84bSDavid du Colombier 		if(l > PGSZ)
3669ef1f84bSDavid du Colombier 			l = PGSZ;
3679ef1f84bSDavid du Colombier 
3689ef1f84bSDavid du Colombier 		e->cache = p;
3699ef1f84bSDavid du Colombier 		e->start = offset;
3709ef1f84bSDavid du Colombier 		e->len = l;
3719ef1f84bSDavid du Colombier 
3729ef1f84bSDavid du Colombier 		qlock(&cache);
3739ef1f84bSDavid du Colombier 		e->bid = cache.pgno;
3749ef1f84bSDavid du Colombier 		cache.pgno += PGSZ;
3759ef1f84bSDavid du Colombier 		/* wrap the counter; low bits are unused by pghash but checked by lookpage */
3769ef1f84bSDavid du Colombier 		if((cache.pgno & ~(PGSZ-1)) == 0){
3779ef1f84bSDavid du Colombier 			if(cache.pgno == PGSZ-1){
3789ef1f84bSDavid du Colombier 				print("cache wrapped\n");
3799ef1f84bSDavid du Colombier 				cache.pgno = 0;
3809ef1f84bSDavid du Colombier 			}else
3819ef1f84bSDavid du Colombier 				cache.pgno++;
3829ef1f84bSDavid du Colombier 		}
3839ef1f84bSDavid du Colombier 		qunlock(&cache);
3849ef1f84bSDavid du Colombier 
3859ef1f84bSDavid du Colombier 		p->daddr = e->bid;
3869ef1f84bSDavid du Colombier 		k = kmap(p);
3879ef1f84bSDavid du Colombier 		if(waserror()) {		/* buf may be virtual */
3889ef1f84bSDavid du Colombier 			kunmap(k);
3899ef1f84bSDavid du Colombier 			nexterror();
3909ef1f84bSDavid du Colombier 		}
3919ef1f84bSDavid du Colombier 		memmove((void*)VA(k), buf, l);
3929ef1f84bSDavid du Colombier 		poperror();
3939ef1f84bSDavid du Colombier 		kunmap(k);
3949ef1f84bSDavid du Colombier 
3959ef1f84bSDavid du Colombier 		cachepage(p, &fscache);
3969ef1f84bSDavid du Colombier 		putpage(p);
3979ef1f84bSDavid du Colombier 
3989ef1f84bSDavid du Colombier 		buf += l;
3999ef1f84bSDavid du Colombier 		offset += l;
4009ef1f84bSDavid du Colombier 		len -= l;
4019ef1f84bSDavid du Colombier 
4029ef1f84bSDavid du Colombier 		*t = e;
4039ef1f84bSDavid du Colombier 		*tail = e;
4049ef1f84bSDavid du Colombier 		t = &e->next;
4059ef1f84bSDavid du Colombier 	}
4069ef1f84bSDavid du Colombier 
4079ef1f84bSDavid du Colombier 	return start;
4089ef1f84bSDavid du Colombier }
4099ef1f84bSDavid du Colombier 
4109ef1f84bSDavid du Colombier int
cpgmove(Extent * e,uchar * buf,int boff,int len)4119ef1f84bSDavid du Colombier cpgmove(Extent *e, uchar *buf, int boff, int len)
4129ef1f84bSDavid du Colombier {
4139ef1f84bSDavid du Colombier 	Page *p;
4149ef1f84bSDavid du Colombier 	KMap *k;
4159ef1f84bSDavid du Colombier 
4169ef1f84bSDavid du Colombier 	p = cpage(e);
4179ef1f84bSDavid du Colombier 	if(p == 0)
4189ef1f84bSDavid du Colombier 		return 0;
4199ef1f84bSDavid du Colombier 
4209ef1f84bSDavid du Colombier 	k = kmap(p);
4219ef1f84bSDavid du Colombier 	if(waserror()) {		/* Since buf may be virtual */
4229ef1f84bSDavid du Colombier 		kunmap(k);
4239ef1f84bSDavid du Colombier 		nexterror();
4249ef1f84bSDavid du Colombier 	}
4259ef1f84bSDavid du Colombier 
4269ef1f84bSDavid du Colombier 	memmove((uchar*)VA(k)+boff, buf, len);
4279ef1f84bSDavid du Colombier 
4289ef1f84bSDavid du Colombier 	poperror();
4299ef1f84bSDavid du Colombier 	kunmap(k);
4309ef1f84bSDavid du Colombier 	putpage(p);
4319ef1f84bSDavid du Colombier 
4329ef1f84bSDavid du Colombier 	return 1;
4339ef1f84bSDavid du Colombier }
4349ef1f84bSDavid du Colombier 
4359ef1f84bSDavid du Colombier void
cupdate(Chan * c,uchar * buf,int len,vlong off)4369ef1f84bSDavid du Colombier cupdate(Chan *c, uchar *buf, int len, vlong off)
4379ef1f84bSDavid du Colombier {
4389ef1f84bSDavid du Colombier 	Mntcache *mc;
4399ef1f84bSDavid du Colombier 	Extent *tail;
4409ef1f84bSDavid du Colombier 	Extent *e, *f, *p;
4419ef1f84bSDavid du Colombier 	int o, ee, eblock;
4429ef1f84bSDavid du Colombier 	ulong offset;
4439ef1f84bSDavid du Colombier 
4449ef1f84bSDavid du Colombier 	if(off > maxcache || len == 0)
4459ef1f84bSDavid du Colombier 		return;
4469ef1f84bSDavid du Colombier 
4479ef1f84bSDavid du Colombier 	mc = c->mc;
4489ef1f84bSDavid du Colombier 	if(mc == nil)
4499ef1f84bSDavid du Colombier 		return;
4509ef1f84bSDavid du Colombier 	qlock(mc);
4519ef1f84bSDavid du Colombier 	if(cdev(mc, c) == 0) {
4529ef1f84bSDavid du Colombier 		qunlock(mc);
4539ef1f84bSDavid du Colombier 		return;
4549ef1f84bSDavid du Colombier 	}
4559ef1f84bSDavid du Colombier 
4569ef1f84bSDavid du Colombier 	/*
4579ef1f84bSDavid du Colombier 	 * Find the insertion point
4589ef1f84bSDavid du Colombier 	 */
4599ef1f84bSDavid du Colombier 	offset = off;
4609ef1f84bSDavid du Colombier 	p = 0;
4619ef1f84bSDavid du Colombier 	for(f = mc->list; f; f = f->next) {
4629ef1f84bSDavid du Colombier 		if(f->start > offset)
4639ef1f84bSDavid du Colombier 			break;
4649ef1f84bSDavid du Colombier 		p = f;
4659ef1f84bSDavid du Colombier 	}
4669ef1f84bSDavid du Colombier 
4679ef1f84bSDavid du Colombier 	/* trim if there is a successor */
4689ef1f84bSDavid du Colombier 	eblock = offset+len;
4699ef1f84bSDavid du Colombier 	if(f != 0 && eblock > f->start) {
4709ef1f84bSDavid du Colombier 		len -= (eblock - f->start);
4719ef1f84bSDavid du Colombier 		if(len <= 0) {
4729ef1f84bSDavid du Colombier 			qunlock(mc);
4739ef1f84bSDavid du Colombier 			return;
4749ef1f84bSDavid du Colombier 		}
4759ef1f84bSDavid du Colombier 	}
4769ef1f84bSDavid du Colombier 
4779ef1f84bSDavid du Colombier 	if(p == 0) {		/* at the head */
4789ef1f84bSDavid du Colombier 		e = cchain(buf, offset, len, &tail);
4799ef1f84bSDavid du Colombier 		if(e != 0) {
4809ef1f84bSDavid du Colombier 			mc->list = e;
4819ef1f84bSDavid du Colombier 			tail->next = f;
4829ef1f84bSDavid du Colombier 		}
4839ef1f84bSDavid du Colombier 		qunlock(mc);
4849ef1f84bSDavid du Colombier 		return;
4859ef1f84bSDavid du Colombier 	}
4869ef1f84bSDavid du Colombier 
4879ef1f84bSDavid du Colombier 	/* trim to the predecessor */
4889ef1f84bSDavid du Colombier 	ee = p->start+p->len;
4899ef1f84bSDavid du Colombier 	if(offset < ee) {
4909ef1f84bSDavid du Colombier 		o = ee - offset;
4919ef1f84bSDavid du Colombier 		len -= o;
4929ef1f84bSDavid du Colombier 		if(len <= 0) {
4939ef1f84bSDavid du Colombier 			qunlock(mc);
4949ef1f84bSDavid du Colombier 			return;
4959ef1f84bSDavid du Colombier 		}
4969ef1f84bSDavid du Colombier 		buf += o;
4979ef1f84bSDavid du Colombier 		offset += o;
4989ef1f84bSDavid du Colombier 	}
4999ef1f84bSDavid du Colombier 
5009ef1f84bSDavid du Colombier 	/* try and pack data into the predecessor */
5019ef1f84bSDavid du Colombier 	if(offset == ee && p->len < PGSZ) {
5029ef1f84bSDavid du Colombier 		o = len;
5039ef1f84bSDavid du Colombier 		if(o > PGSZ - p->len)
5049ef1f84bSDavid du Colombier 			o = PGSZ - p->len;
5059ef1f84bSDavid du Colombier 		if(cpgmove(p, buf, p->len, o)) {
5069ef1f84bSDavid du Colombier 			p->len += o;
5079ef1f84bSDavid du Colombier 			buf += o;
5089ef1f84bSDavid du Colombier 			len -= o;
5099ef1f84bSDavid du Colombier 			offset += o;
5109ef1f84bSDavid du Colombier 			if(len <= 0) {
5119ef1f84bSDavid 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);
5129ef1f84bSDavid du Colombier 				qunlock(mc);
5139ef1f84bSDavid du Colombier 				return;
5149ef1f84bSDavid du Colombier 			}
5159ef1f84bSDavid du Colombier 		}
5169ef1f84bSDavid du Colombier 	}
5179ef1f84bSDavid du Colombier 
5189ef1f84bSDavid du Colombier 	e = cchain(buf, offset, len, &tail);
5199ef1f84bSDavid du Colombier 	if(e != 0) {
5209ef1f84bSDavid du Colombier 		p->next = e;
5219ef1f84bSDavid du Colombier 		tail->next = f;
5229ef1f84bSDavid du Colombier 	}
5239ef1f84bSDavid du Colombier 	qunlock(mc);
5249ef1f84bSDavid du Colombier }
5259ef1f84bSDavid du Colombier 
5269ef1f84bSDavid du Colombier void
cwrite(Chan * c,uchar * buf,int len,vlong off)5279ef1f84bSDavid du Colombier cwrite(Chan* c, uchar *buf, int len, vlong off)
5289ef1f84bSDavid du Colombier {
5299ef1f84bSDavid du Colombier 	int o, eo;
5309ef1f84bSDavid du Colombier 	Mntcache *mc;
5319ef1f84bSDavid du Colombier 	ulong eblock, ee;
5329ef1f84bSDavid du Colombier 	Extent *p, *f, *e, *tail;
5339ef1f84bSDavid du Colombier 	ulong offset;
5349ef1f84bSDavid du Colombier 
5359ef1f84bSDavid du Colombier 	if(off > maxcache || len == 0)
5369ef1f84bSDavid du Colombier 		return;
5379ef1f84bSDavid du Colombier 
5389ef1f84bSDavid du Colombier 	mc = c->mc;
5399ef1f84bSDavid du Colombier 	if(mc == nil)
5409ef1f84bSDavid du Colombier 		return;
5419ef1f84bSDavid du Colombier 
5429ef1f84bSDavid du Colombier 	qlock(mc);
5439ef1f84bSDavid du Colombier 	if(cdev(mc, c) == 0) {
5449ef1f84bSDavid du Colombier 		qunlock(mc);
5459ef1f84bSDavid du Colombier 		return;
5469ef1f84bSDavid du Colombier 	}
5479ef1f84bSDavid du Colombier 
5489ef1f84bSDavid du Colombier 	offset = off;
5499ef1f84bSDavid du Colombier 	mc->qid.vers++;
5509ef1f84bSDavid du Colombier 	c->qid.vers++;
5519ef1f84bSDavid du Colombier 
5529ef1f84bSDavid du Colombier 	p = 0;
5539ef1f84bSDavid du Colombier 	for(f = mc->list; f; f = f->next) {
5549ef1f84bSDavid du Colombier 		if(f->start >= offset)
5559ef1f84bSDavid du Colombier 			break;
5569ef1f84bSDavid du Colombier 		p = f;
5579ef1f84bSDavid du Colombier 	}
5589ef1f84bSDavid du Colombier 
5599ef1f84bSDavid du Colombier 	if(p != 0) {
5609ef1f84bSDavid du Colombier 		ee = p->start+p->len;
5619ef1f84bSDavid du Colombier 		eo = offset - p->start;
5629ef1f84bSDavid du Colombier 		/* pack in predecessor if there is space */
5639ef1f84bSDavid du Colombier 		if(offset <= ee && eo < PGSZ) {
5649ef1f84bSDavid du Colombier 			o = len;
5659ef1f84bSDavid du Colombier 			if(o > PGSZ - eo)
5669ef1f84bSDavid du Colombier 				o = PGSZ - eo;
5679ef1f84bSDavid du Colombier 			if(cpgmove(p, buf, eo, o)) {
5689ef1f84bSDavid du Colombier 				if(eo+o > p->len)
5699ef1f84bSDavid du Colombier 					p->len = eo+o;
5709ef1f84bSDavid du Colombier 				buf += o;
5719ef1f84bSDavid du Colombier 				len -= o;
5729ef1f84bSDavid du Colombier 				offset += o;
5739ef1f84bSDavid du Colombier 			}
5749ef1f84bSDavid du Colombier 		}
5759ef1f84bSDavid du Colombier 	}
5769ef1f84bSDavid du Colombier 
5779ef1f84bSDavid du Colombier 	/* free the overlap -- it's a rare case */
5789ef1f84bSDavid du Colombier 	eblock = offset+len;
5799ef1f84bSDavid du Colombier 	while(f && f->start < eblock) {
5809ef1f84bSDavid du Colombier 		e = f->next;
5819ef1f84bSDavid du Colombier 		extentfree(f);
5829ef1f84bSDavid du Colombier 		f = e;
5839ef1f84bSDavid du Colombier 	}
5849ef1f84bSDavid du Colombier 
5859ef1f84bSDavid du Colombier 	/* link the block (if any) into the middle */
5869ef1f84bSDavid du Colombier 	e = cchain(buf, offset, len, &tail);
5879ef1f84bSDavid du Colombier 	if(e != 0) {
5889ef1f84bSDavid du Colombier 		tail->next = f;
5899ef1f84bSDavid du Colombier 		f = e;
5909ef1f84bSDavid du Colombier 	}
5919ef1f84bSDavid du Colombier 
5929ef1f84bSDavid du Colombier 	if(p == 0)
5939ef1f84bSDavid du Colombier 		mc->list = f;
5949ef1f84bSDavid du Colombier 	else
5959ef1f84bSDavid du Colombier 		p->next = f;
5969ef1f84bSDavid du Colombier 	qunlock(mc);
5979ef1f84bSDavid du Colombier }
598