2 #include "../port/lib.h"
6 #include "../port/error.h"
13 NEXTENT = 200, /* extent allocation size */
16 typedef struct Extent Extent;
26 typedef struct Mntcache Mntcache;
39 typedef struct Cache Cache;
46 Mntcache *hash[NHASH];
49 typedef struct Ecache Ecache;
61 static int maxcache = MAXCACHE;
67 e->next = ecache.head;
80 if(ecache.head == nil){
81 e = xalloc(NEXTENT*sizeof(Extent));
86 for(i = 0; i < NEXTENT; i++){
87 e->next = ecache.head;
91 ecache.free += NEXTENT;
92 ecache.total += NEXTENT;
96 ecache.head = e->next;
97 memset(e, 0, sizeof(Extent));
110 cache.head = xalloc(sizeof(Mntcache)*NFILE);
113 panic("cinit: no memory");
115 /* a better algorithm would be nice */
116 if(conf.npage*BY2PG > 200*MB)
117 maxcache = 10*MAXCACHE;
119 for(i = 0; i < NFILE-1; i++) {
126 cache.tail->next = 0;
127 cache.head->prev = 0;
133 cprint(Chan *c, Mntcache *m, char *s)
144 for(e = m->list; e; e = e->next) {
150 pprint("%s: %#llux.%#lux %d %d %s (%d %c)\n",
151 s, m->qid.path, m->qid.vers, m->type, m->dev, c->path->s, nb, ct ? 'C' : 'N');
153 for(e = m->list; e; e = e->next) {
154 pprint("\t%4d %5lud %4d %#p\n",
155 e->bid, e->start, e->len, e->cache);
162 /* Easy consistency check */
163 if(e->cache->daddr != e->bid)
166 return lookpage(&fscache, e->bid);
175 * Invalidate all extent data
176 * Image lru will waste the pages
187 /* Unlink and send to the tail */
189 m->prev->next = m->next;
191 cache.head = m->next;
193 m->next->prev = m->prev;
195 cache.tail = m->prev;
198 m->prev = cache.tail;
199 cache.tail->next = m;
215 Mntcache *m, *f, **l;
217 /* directories aren't cacheable and append-only files confuse us */
218 if(c->qid.type&(QTDIR|QTAPPEND))
220 h = c->qid.path%NHASH;
222 for(m = cache.hash[h]; m; m = m->hash) {
223 if(m->qid.path == c->qid.path)
224 if(m->qid.type == c->qid.type)
225 if(m->dev == c->dev && m->type == c->type) {
226 /* File was updated, invalidate cache */
227 if(m->qid.vers != c->qid.vers){
230 m->qid.vers = c->qid.vers;
240 /* LRU the cache headers */
244 l = &cache.hash[m->qid.path%NHASH];
245 for(f = *l; f; f = f->hash) {
273 cdev(Mntcache *m, Chan *c)
275 if(m->qid.path != c->qid.path)
277 if(m->qid.type != c->qid.type)
281 if(m->type != c->type)
283 if(m->qid.vers != c->qid.vers)
289 cread(Chan *c, uchar *buf, int len, vlong off)
298 if(off+len > maxcache)
306 if(cdev(m, c) == 0) {
314 for(e = *t; e; e = e->next) {
315 if(offset >= e->start && offset < e->start+e->len)
335 o = offset - e->start;
348 memmove(buf, (uchar*)VA(k) + o, l);
361 if(e == 0 || e->start != offset)
370 cchain(uchar *buf, ulong offset, int len, Extent **tail)
375 Extent *e, *start, **t;
401 /* wrap the counter; low bits are unused by pghash but checked by lookpage */
402 if((cache.pgno & ~(BY2PG-1)) == 0){
403 if(cache.pgno == BY2PG-1){
404 print("cache wrapped\n");
413 if(waserror()) { /* buf may be virtual */
417 memmove((void*)VA(k), buf, l);
421 cachepage(p, &fscache);
437 cpgmove(Extent *e, uchar *buf, int boff, int len)
447 if(waserror()) { /* Since buf may be virtual */
452 memmove((uchar*)VA(k)+boff, buf, len);
462 cupdate(Chan *c, uchar *buf, int len, vlong off)
470 if(off > maxcache || len == 0)
477 if(cdev(m, c) == 0) {
484 * Find the insertion point
488 for(f = m->list; f; f = f->next) {
489 if(f->start > offset)
494 /* trim if there is a successor */
496 if(f != 0 && eblock > f->start) {
497 len -= (eblock - f->start);
504 if(p == 0) { /* at the head */
505 e = cchain(buf, offset, len, &tail);
514 /* trim to the predecessor */
515 ee = p->start+p->len;
527 /* try and pack data into the predecessor */
528 if(offset == ee && p->len < BY2PG) {
530 if(o > BY2PG - p->len)
532 if(cpgmove(p, buf, p->len, o)) {
538 if(f && p->start + p->len > f->start)
539 print("CACHE: p->start=%uld p->len=%d f->start=%uld\n",
540 p->start, p->len, f->start);
547 e = cchain(buf, offset, len, &tail);
556 cwrite(Chan* c, uchar *buf, int len, vlong off)
561 Extent *p, *f, *e, *tail;
564 if(off > maxcache || len == 0)
572 if(cdev(m, c) == 0) {
583 for(f = m->list; f; f = f->next) {
584 if(f->start >= offset)
590 ee = p->start+p->len;
591 eo = offset - p->start;
592 /* pack in predecessor if there is space */
593 if(offset <= ee && eo < BY2PG) {
597 if(cpgmove(p, buf, eo, o)) {
607 /* free the overlap -- it's a rare case */
609 while(f && f->start < eblock) {
615 /* link the block (if any) into the middle */
616 e = cchain(buf, offset, len, &tail);