plan 9 kernel history: overview | file list | diff list

1993/1014/port/cache.c (diff list | history)

port/cache.c on 1993/1011
1993/1011    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
#include	"devtab.h" 
 
1993/1013    
Image	fscache; 
 
1993/1014    
enum 
{ 
	NHASH		= 128, 
	MAXCACHE	= 1024*1024, 
	NFILE		= 4096, 
}; 
 
typedef struct Extent Extent; 
1993/1013    
struct Extent 
1993/1011    
{ 
1993/1013    
	int	bid; 
	ulong	start; 
	int	len; 
1993/1014    
	Page	*cache; 
1993/1013    
	Extent	*next; 
}; 
 
typedef struct Mntcache Mntcache; 
struct Mntcache 
{ 
1993/1011    
	Qid; 
1993/1013    
	int	dev; 
	int	type; 
1993/1014    
	QLock; 
1993/1013    
	Extent	 *list; 
	Mntcache *hash; 
	Mntcache *prev; 
	Mntcache *next; 
1993/1011    
}; 
 
1993/1013    
typedef struct Cache Cache; 
struct Cache 
1993/1011    
{ 
1993/1013    
	Ref; 
	Mntcache	*head; 
	Mntcache	*tail; 
	Mntcache	*hash[NHASH]; 
1993/1011    
}; 
1993/1013    
Cache cache; 
1993/1011    
 
1993/1014    
void 
cinit(void) 
{ 
	int i; 
	Mntcache *m; 
 
	cache.ref = 1; 
	cache.head = xalloc(sizeof(Mntcache)*NFILE); 
	m = cache.head; 
	 
	for(i = NFILE; i > 0; i++) { 
		m->next = m+1; 
		m->prev = m-1; 
		m++; 
	} 
 
	cache.tail = m; 
	cache.tail->next = 0; 
	cache.head->prev = 0; 
} 
 
1993/1013    
Mntcache* 
clook(Chan *c) 
1993/1011    
{ 
1993/1013    
	int h; 
1993/1014    
	Mntcache *m; 
1993/1011    
 
1993/1013    
	h = c->qid.path%NHASH; 
 
	lock(&cache); 
	for(m = cache.hash[h]; m; m = m->hash) { 
1993/1014    
		if(m->path == c->qid.path) { 
1993/1013    
			qlock(m); 
			if(m->path == c->qid.path) 
			if(m->dev  == c->dev) 
			if(m->type == c->type) { 
				unlock(&cache); 
				return m; 
			} 
			qunlock(m); 
		} 
	} 
	unlock(&cache); 
	return 0; 
} 
 
void 
1993/1014    
cprint(Mntcache *m) 
{ 
	Extent *e; 
 
	print("%lux.%lux %d %d\n", m->path, m->vers, m->type, m->dev); 
 
	while(e) 
		print("\t%4d %5d %4d %lux\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); 
} 
 
void 
1993/1013    
cnodata(Mntcache *m) 
{ 
	Extent *e, *n; 
 
	/* 
	 * Invalidate all extent data 
	 * Image lru will waste the pages 
	 */ 
	for(e = m->list; e; e = n) { 
1993/1014    
		n = e->next; 
1993/1013    
		free(e); 
	} 
} 
 
void 
ctail(Mntcache *m) 
{ 
	lock(&cache); 
 
	/* 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 = cache.tail = m; 
		m->prev = m->next = 0; 
	} 
 
	unlock(&cache); 
} 
 
void 
copen(Chan *c) 
{ 
	Mntcache *m, *f, **l; 
 
	m = clook(c); 
	if(m != 0) { 
		/* File was updated */ 
1993/1014    
		if(m->vers != c->qid.vers) 
1993/1013    
			cnodata(m); 
 
		ctail(m); 
		qunlock(m); 
		return; 
	} 
 
	/* LRU the cache headers */ 
	m = cache.head; 
	qlock(m); 
1993/1014    
	lock(&cache); 
	l = &cache.hash[m->path%NHASH]; 
1993/1013    
	for(f = *l; f; f = f->next) { 
		if(f == m) { 
			*l = f->next; 
			break; 
		} 
		l = &f->next; 
	} 
	l = &cache.hash[c->qid.path%NHASH]; 
	m->hash = *l; 
	*l = m; 
1993/1014    
	unlock(&cache); 
	m->Qid = c->qid; 
1993/1013    
	m->dev = c->dev; 
	m->type = c->type; 
	cnodata(m); 
	ctail(m); 
	c->mcp = m; 
	qunlock(m); 
} 
 
static int 
cdev(Mntcache *m, Chan *c) 
{ 
1993/1014    
	if(m->path != c->qid.path) 
1993/1013    
		return 0; 
1993/1014    
	if(m->vers != c->qid.vers) 
1993/1013    
		return 0; 
	if(m->dev != c->dev) 
		return 0; 
	if(m->type != c->type) 
		return 0; 
	return 1; 
} 
 
int 
1993/1014    
cread(Chan *c, uchar *buf, int len, ulong offset) 
1993/1013    
{ 
	KMap *k; 
	Page *p; 
	Mntcache *m; 
1993/1014    
	Extent *e, **t; 
	int o, l, total, end; 
1993/1013    
 
	m = c->mcp; 
	if(m == 0) 
		return 0; 
	qlock(m); 
	if(cdev(m, c) == 0) { 
		qunlock(m); 
		return 0; 
	} 
 
	end = offset+len; 
1993/1014    
	t = &m->list; 
	for(e = *t; e; e = e->next) { 
1993/1013    
		if(e->start >= offset && e->start+e->len < end) 
			break; 
1993/1014    
		t = &e->next; 
1993/1013    
	} 
 
	if(e == 0) { 
		qunlock(m); 
		return 0; 
	} 
 
	total = 0; 
	while(len) { 
1993/1014    
		p = cpage(e); 
1993/1013    
		if(p == 0) { 
1993/1014    
			*t = e->next; 
1993/1013    
			free(e); 
			qunlock(m); 
			return total; 
		} 
 
		k = kmap(p); 
		if(waserror()) { 
			kunmap(k); 
			putpage(p); 
			qunlock(m); 
			nexterror(); 
		} 
 
		o = offset - e->start; 
		l = len; 
		if(l > e->len-o) 
			l = e->len-o; 
 
1993/1014    
		memmove(buf, (uchar*)VA(k) + o, l); 
1993/1013    
		kunmap(k); 
		putpage(p); 
 
		buf += l; 
		len -= l; 
		offset += l; 
		total += l; 
1993/1014    
		t = &e->next; 
1993/1013    
		e = e->next; 
		if(e == 0 || e->start != offset) 
			break; 
	} 
1993/1014    
	qunlock(m); 
1993/1013    
	return total; 
} 
 
1993/1014    
Extent* 
cchain(uchar *buf, ulong offset, int len, Extent **tail) 
{ 
	int l; 
	Page *p; 
	KMap *k; 
	Extent *e, *start, **t; 
 
	start = 0; 
	t = &start; 
	while(len) { 
		e = malloc(sizeof(Extent)); 
		if(e == 0) 
			break; 
 
		p = auxpage(); 
		if(p == 0) { 
			free(e); 
			break; 
		} 
		e->cache = p; 
		e->start = offset; 
		l = len; 
		if(l > BY2PG) 
			l = BY2PG; 
 
		e->bid = incref(&cache); 
		p->daddr = e->bid; 
		k = kmap(p); 
		memmove((void*)VA(k), buf, l); 
		kunmap(k); 
 
		cachepage(p, &fscache); 
		putpage(p); 
 
		buf += l; 
		offset += l; 
		len -= l; 
 
		*t = e; 
		*tail = e; 
		t = &e->next; 
	} 
	return start; 
} 
 
int 
cpgmove(Extent *e, uchar *buf, int boff, int len) 
{ 
	Page *p; 
	KMap *k; 
 
	p = cpage(e); 
	if(p == 0) 
		return 0; 
	k = kmap(p); 
	memmove((uchar*)VA(k)+boff, buf, len); 
	kunmap(k); 
	putpage(p); 
 
	return 1; 
} 
 
1993/1013    
void 
1993/1014    
cupdate(Chan *c, uchar *buf, int len, ulong offset) 
1993/1013    
{ 
	Mntcache *m; 
1993/1014    
	Extent *tail; 
	Extent *e, *f, *p; 
	int o, ee, eblock;  
1993/1013    
 
	if(offset > MAXCACHE) 
		return; 
 
	m = c->mcp; 
	if(m == 0) 
		return; 
	qlock(m); 
	if(cdev(m, c) == 0) { 
		qunlock(m); 
		return; 
	} 
 
1993/1014    
	/* 
	 * Find the insertion point 
	 */ 
	p = 0; 
	for(f = m->list; f; f = f->next) { 
		if(f->start >= offset) 
			break; 
		p = f; 
	} 
	if(p == 0) {		/* at the head */ 
		eblock = offset+len; 
		/* trim if there is a successor */ 
		if(f != 0 && eblock >= f->start) { 
			len -= (eblock - f->start); 
			if(len <= 0) { 
				qunlock(m); 
				return; 
			} 
		} 
		e = cchain(buf, offset, len, &tail); 
		m->list = e; 
		if(tail != 0) 
			tail->next = f; 
		qunlock(m); 
		return; 
	} 
 
	/* trim to the predecessor */ 
	ee = p->start+p->len; 
	if(offset < ee) { 
		o = ee - offset; 
		len -= o; 
		if(len <= 0) { 
			qunlock(m); 
1993/1013    
			return; 
1993/1014    
		} 
		buf += o; 
		offset += o; 
	} 
 
	/* try and pack data into the predecessor */ 
	if(offset == ee && p->len < BY2PG) { 
		o = len; 
		if(o > BY2PG - p->len) 
			o = BY2PG - p->len; 
		if(len <= 0) { 
			qunlock(m); 
1993/1013    
			return; 
1993/1014    
		} 
		if(cpgmove(e, buf, p->len, o)) { 
			e->len += o; 
			buf += o; 
			len -= o; 
			offset += o; 
			if(len <= 0) { 
				qunlock(m); 
				return; 
			} 
		} 
1993/1013    
	} 
1993/1014    
 
	/* append to extent list */ 
	if(f == 0) { 
		p->next = cchain(buf, offset, len, &tail); 
		qunlock(m); 
		return; 
	} 
 
	/* trim data against successor */ 
	eblock = offset+len; 
	if(eblock > f->start) { 
		o = eblock - f->start; 
		if(o < 0) { 
			qunlock(m); 
			return; 
		} 
		len -= o; 
	} 
 
	/* Insert a middle block */ 
	p->next = cchain(buf, offset, len, &tail); 
	if(p->next == 0) 
		p->next = f; 
	else 
		tail->next = f; 
 
	qunlock(m); 
1993/1011    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)