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;
118 // if(conf.npage*BY2PG > 400*MB)
119 // maxcache = 50*MAXCACHE;
121 for(i = 0; i < NFILE-1; i++) {
128 cache.tail->next = 0;
129 cache.head->prev = 0;
135 cprint(Chan *c, Mntcache *m, char *s)
146 for(e = m->list; e; e = e->next) {
152 pprint("%s: %#llux.%#lux %d %d %s (%d %c)\n",
153 s, m->qid.path, m->qid.vers, m->type, m->dev, c->path->s, nb, ct ? 'C' : 'N');
155 for(e = m->list; e; e = e->next) {
156 pprint("\t%4d %5lud %4d %#p\n",
157 e->bid, e->start, e->len, e->cache);
164 /* Easy consistency check */
165 if(e->cache->daddr != e->bid)
168 return lookpage(&fscache, e->bid);
177 * Invalidate all extent data
178 * Image lru will waste the pages
180 for(e = m->list; e; e = n) {
190 /* Unlink and send to the tail */
192 m->prev->next = m->next;
194 cache.head = m->next;
196 m->next->prev = m->prev;
198 cache.tail = m->prev;
201 m->prev = cache.tail;
202 cache.tail->next = m;
219 Mntcache *m, *f, **l;
221 /* directories aren't cacheable and append-only files confuse us */
222 if(c->qid.type&(QTDIR|QTAPPEND))
225 h = c->qid.path%NHASH;
227 for(m = cache.hash[h]; m; m = m->hash) {
228 if(m->qid.path == c->qid.path)
229 if(m->qid.type == c->qid.type)
230 if(m->dev == c->dev && m->type == c->type) {
235 /* File was updated, invalidate cache */
236 if(m->qid.vers != c->qid.vers) {
237 m->qid.vers = c->qid.vers;
246 /* LRU the cache headers */
248 l = &cache.hash[m->qid.path%NHASH];
249 for(f = *l; f; f = f->hash) {
281 cdev(Mntcache *m, Chan *c)
283 if(m->qid.path != c->qid.path)
285 if(m->qid.type != c->qid.type)
289 if(m->type != c->type)
291 if(m->qid.vers != c->qid.vers)
297 cread(Chan *c, uchar *buf, int len, vlong off)
306 if(off+len > maxcache)
314 if(cdev(m, c) == 0) {
321 for(e = *t; e; e = e->next) {
322 if(offset >= e->start && offset < e->start+e->len)
342 o = offset - e->start;
355 memmove(buf, (uchar*)VA(k) + o, l);
368 if(e == 0 || e->start != offset)
377 cchain(uchar *buf, ulong offset, int len, Extent **tail)
382 Extent *e, *start, **t;
408 /* wrap the counter; low bits are unused by pghash but checked by lookpage */
409 if((cache.pgno & ~(BY2PG-1)) == 0){
410 if(cache.pgno == BY2PG-1){
411 print("cache wrapped\n");
420 if(waserror()) { /* buf may be virtual */
424 memmove((void*)VA(k), buf, l);
428 cachepage(p, &fscache);
444 cpgmove(Extent *e, uchar *buf, int boff, int len)
454 if(waserror()) { /* Since buf may be virtual */
459 memmove((uchar*)VA(k)+boff, buf, len);
469 cupdate(Chan *c, uchar *buf, int len, vlong off)
477 if(off > maxcache || len == 0)
484 if(cdev(m, c) == 0) {
490 * Find the insertion point
494 for(f = m->list; f; f = f->next) {
495 if(f->start > offset)
500 /* trim if there is a successor */
502 if(f != 0 && eblock > f->start) {
503 len -= (eblock - f->start);
510 if(p == 0) { /* at the head */
511 e = cchain(buf, offset, len, &tail);
520 /* trim to the predecessor */
521 ee = p->start+p->len;
533 /* try and pack data into the predecessor */
534 if(offset == ee && p->len < BY2PG) {
536 if(o > BY2PG - p->len)
538 if(cpgmove(p, buf, p->len, o)) {
544 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);
551 e = cchain(buf, offset, len, &tail);
560 cwrite(Chan* c, uchar *buf, int len, vlong off)
565 Extent *p, *f, *e, *tail;
568 if(off > maxcache || len == 0)
576 if(cdev(m, c) == 0) {
586 for(f = m->list; f; f = f->next) {
587 if(f->start >= offset)
593 ee = p->start+p->len;
594 eo = offset - p->start;
595 /* pack in predecessor if there is space */
596 if(offset <= ee && eo < BY2PG) {
600 if(cpgmove(p, buf, eo, o)) {
610 /* free the overlap -- it's a rare case */
612 while(f && f->start < eblock) {
618 /* link the block (if any) into the middle */
619 e = cchain(buf, offset, len, &tail);