639 lines · 9.5 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h" enum{	NHASH		= 128,	MAXCACHE	= 1024*1024,	NFILE		= 4096,	NEXTENT		= 200,		/* extent allocation size */}; typedef struct Extent Extent;struct Extent{	int	bid;	ulong	start;	int	len;	Page	*cache;	Extent	*next;}; typedef struct Mntcache Mntcache;struct Mntcache{	Qid	qid;	int	dev;	int	type;	QLock;	Extent	 *list;	Mntcache *hash;	Mntcache *prev;	Mntcache *next;}; typedef struct Cache Cache;struct Cache{	QLock;	int		pgno;	Mntcache	*head;	Mntcache	*tail;	Mntcache	*hash[NHASH];}; typedef struct Ecache Ecache;struct Ecache{	Lock;	int	total;	int	free;	Extent*	head;}; static Image fscache;static Cache cache;static Ecache ecache;static int maxcache = MAXCACHE; static voidextentfree(Extent* e){	lock(&ecache);	e->next = ecache.head;	ecache.head = e;	ecache.free++;	unlock(&ecache);} static Extent*extentalloc(void){	Extent *e;	int i; 	lock(&ecache);	if(ecache.head == nil){		e = xalloc(NEXTENT*sizeof(Extent));		if(e == nil){			unlock(&ecache);			return nil;		}		for(i = 0; i < NEXTENT; i++){			e->next = ecache.head;			ecache.head = e;			e++;		}		ecache.free += NEXTENT;		ecache.total += NEXTENT;	} 	e = ecache.head;	ecache.head = e->next;	memset(e, 0, sizeof(Extent));	ecache.free--;	unlock(&ecache); 	return e;} voidcinit(void){	int i;	Mntcache *m; 	cache.head = xalloc(sizeof(Mntcache)*NFILE);	m = cache.head;	if (m == nil)		panic("cinit: no memory"); 	/* a better algorithm would be nice */	if(conf.npage*BY2PG > 400*MB)		maxcache = 20*MAXCACHE;	else if(conf.npage*BY2PG > 200*MB)		maxcache = 10*MAXCACHE; 	for(i = 0; i < NFILE-1; i++) {		m->next = m+1;		m->prev = m-1;		m++;	} 	cache.tail = m;	cache.tail->next = 0;	cache.head->prev = 0; 	fscache.notext = 1;} voidcprint(Chan *c, Mntcache *m, char *s){	ulong o;	int nb, ct;	Extent *e; 	nb = 0;	ct = 1;	o = 0;	if(m->list)		o = m->list->start;	for(e = m->list; e; e = e->next) {		nb += e->len;		if(o != e->start)			ct = 0;		o = e->start+e->len;	}	pprint("%s: %#llux.%#lux %d %d %s (%d %c)\n",	s, m->qid.path, m->qid.vers, m->type, m->dev, c->path->s, nb, ct ? 'C' : 'N'); 	for(e = m->list; e; e = e->next) {		pprint("\t%4d %5lud %4d %#p\n",			e->bid, e->start, e->len, e->cache);	}} Page*cpage(Extent *e){	/* Easy consistency check */	if(e->cache->daddr != e->bid)		return 0; 	return lookpage(&fscache, e->bid);} voidcnodata(Mntcache *m){	Extent *e, *n; 	/*	 * Invalidate all extent data	 * Image lru will waste the pages	 */	for(e = m->list; e; e = n) {		n = e->next;		extentfree(e);	}	m->list = 0;} voidctail(Mntcache *m){	/* Unlink and send to the tail */	if(m->prev)		m->prev->next = m->next;	else		cache.head = m->next;	if(m->next)		m->next->prev = m->prev;	else		cache.tail = m->prev; 	if(cache.tail) {		m->prev = cache.tail;		cache.tail->next = m;		m->next = 0;		cache.tail = m;	}	else {		cache.head = m;		cache.tail = m;		m->prev = 0;		m->next = 0;	}} voidcopen(Chan *c){	int h;	Extent *e, *next;	Mntcache *m, *f, **l; 	/* directories aren't cacheable and append-only files confuse us */	if(c->qid.type&(QTDIR|QTAPPEND))		return; 	h = c->qid.path%NHASH;	qlock(&cache);	for(m = cache.hash[h]; m; m = m->hash) {		if(m->qid.path == c->qid.path)		if(m->qid.type == c->qid.type)		if(m->dev == c->dev && m->type == c->type) {			c->mcp = m;			ctail(m);			qunlock(&cache); 			/* File was updated, invalidate cache */			if(m->qid.vers != c->qid.vers) {				m->qid.vers = c->qid.vers;				qlock(m);				cnodata(m);				qunlock(m);			}			return;		}	} 	/* LRU the cache headers */	m = cache.head;	l = &cache.hash[m->qid.path%NHASH];	for(f = *l; f; f = f->hash) {		if(f == m) {			*l = m->hash;			break;		}		l = &f->hash;	} 	m->qid = c->qid;	m->dev = c->dev;	m->type = c->type; 	l = &cache.hash[h];	m->hash = *l;	*l = m;	ctail(m); 	qlock(m);	c->mcp = m;	e = m->list;	m->list = 0;	qunlock(&cache); 	while(e) {		next = e->next;		extentfree(e);		e = next;	}	qunlock(m);} static intcdev(Mntcache *m, Chan *c){	if(m->qid.path != c->qid.path)		return 0;	if(m->qid.type != c->qid.type)		return 0;	if(m->dev != c->dev)		return 0;	if(m->type != c->type)		return 0;	if(m->qid.vers != c->qid.vers)		return 0;	return 1;} intcread(Chan *c, uchar *buf, int len, vlong off){	KMap *k;	Page *p;	Mntcache *m;	Extent *e, **t;	int o, l, total;	ulong offset; 	if(off+len > maxcache)		return 0; 	m = c->mcp;	if(m == 0)		return 0; 	qlock(m);	if(cdev(m, c) == 0) {		qunlock(m);		return 0;	} 	offset = off;	t = &m->list;	for(e = *t; e; e = e->next) {		if(offset >= e->start && offset < e->start+e->len)			break;		t = &e->next;	} 	if(e == 0) {		qunlock(m);		return 0;	} 	total = 0;	while(len) {		p = cpage(e);		if(p == 0) {			*t = e->next;			extentfree(e);			qunlock(m);			return total;		} 		o = offset - e->start;		l = len;		if(l > e->len-o)			l = e->len-o; 		k = kmap(p);		if(waserror()) {			kunmap(k);			putpage(p);			qunlock(m);			nexterror();		} 		memmove(buf, (uchar*)VA(k) + o, l); 		poperror();		kunmap(k); 		putpage(p); 		buf += l;		len -= l;		offset += l;		total += l;		t = &e->next;		e = e->next;		if(e == 0 || e->start != offset)			break;	} 	qunlock(m);	return total;} Extent*cchain(uchar *buf, ulong offset, int len, Extent **tail){	int l;	Page *p;	KMap *k;	Extent *e, *start, **t; 	start = 0;	*tail = 0;	t = &start;	while(len) {		e = extentalloc();		if(e == 0)			break; 		p = auxpage();		if(p == 0) {			extentfree(e);			break;		}		l = len;		if(l > BY2PG)			l = BY2PG; 		e->cache = p;		e->start = offset;		e->len = l; 		qlock(&cache);		e->bid = cache.pgno;		cache.pgno += BY2PG;		/* wrap the counter; low bits are unused by pghash but checked by lookpage */		if((cache.pgno & ~(BY2PG-1)) == 0){			if(cache.pgno == BY2PG-1){				print("cache wrapped\n");				cache.pgno = 0;			}else				cache.pgno++;		}		qunlock(&cache); 		p->daddr = e->bid;		k = kmap(p);		if(waserror()) {		/* buf may be virtual */			kunmap(k);			nexterror();		}		memmove((void*)VA(k), buf, l);		poperror();		kunmap(k); 		cachepage(p, &fscache);		putpage(p); 		buf += l;		offset += l;		len -= l; 		*t = e;		*tail = e;		t = &e->next;	} 	return start;} intcpgmove(Extent *e, uchar *buf, int boff, int len){	Page *p;	KMap *k; 	p = cpage(e);	if(p == 0)		return 0; 	k = kmap(p);	if(waserror()) {		/* Since buf may be virtual */		kunmap(k);		nexterror();	} 	memmove((uchar*)VA(k)+boff, buf, len); 	poperror();	kunmap(k);	putpage(p); 	return 1;} voidcupdate(Chan *c, uchar *buf, int len, vlong off){	Mntcache *m;	Extent *tail;	Extent *e, *f, *p;	int o, ee, eblock;	ulong offset; 	if(off > maxcache || len == 0)		return; 	m = c->mcp;	if(m == 0)		return;	qlock(m);	if(cdev(m, c) == 0) {		qunlock(m);		return;	} 	/*	 * Find the insertion point	 */

Lines 1–500 of 639.