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;
211 /* called with cache locked */
213 clookup(Chan *c, int skipvers)
217 for(m = cache.hash[c->qid.path%NHASH]; m; m = m->hash)
218 if(eqchantdqid(c, m->type, m->dev, m->qid, skipvers) && c->qid.type == m->qid.type)
227 Mntcache *m, *f, **l;
229 /* directories aren't cacheable and append-only files confuse us */
230 if(c->qid.type&(QTDIR|QTAPPEND)){
239 else if(m->qid.vers == c->qid.vers) {
247 l = &cache.hash[m->qid.path%NHASH];
248 for(f = *l; f; f = f->hash) {
263 * someone got there first while cache lock
264 * was released and added a updated Mntcache
265 * for us. update LRU and use it.
279 l = &cache.hash[c->qid.path%NHASH];
288 /* return locked Mntcache if still valid else reset mcp */
297 if(eqchantdqid(c, m->type, m->dev, m->qid, 0) && c->qid.type == m->qid.type)
306 cread(Chan *c, uchar *buf, int len, vlong off)
315 if(off+len > maxcache)
324 for(e = *t; e; e = e->next) {
325 if(offset >= e->start && offset < e->start+e->len)
345 o = offset - e->start;
358 memmove(buf, (uchar*)VA(k) + o, l);
371 if(e == 0 || e->start != offset)
380 cchain(uchar *buf, ulong offset, int len, Extent **tail)
385 Extent *e, *start, **t;
411 /* wrap the counter; low bits are unused by pghash but checked by lookpage */
412 if((cache.pgno & ~(BY2PG-1)) == 0){
413 if(cache.pgno == BY2PG-1){
414 print("cache wrapped\n");
423 if(waserror()) { /* buf may be virtual */
427 memmove((void*)VA(k), buf, l);
431 cachepage(p, &fscache);
447 cpgmove(Extent *e, uchar *buf, int boff, int len)
457 if(waserror()) { /* Since buf may be virtual */
462 memmove((uchar*)VA(k)+boff, buf, len);
472 cupdate(Chan *c, uchar *buf, int len, vlong off)
480 if(off > maxcache || len == 0)
488 * Find the insertion point
492 for(f = m->list; f; f = f->next) {
493 if(f->start > offset)
498 /* trim if there is a successor */
500 if(f != 0 && eblock > f->start) {
501 len -= (eblock - f->start);
508 if(p == 0) { /* at the head */
509 e = cchain(buf, offset, len, &tail);
518 /* trim to the predecessor */
519 ee = p->start+p->len;
531 /* try and pack data into the predecessor */
532 if(offset == ee && p->len < BY2PG) {
534 if(o > BY2PG - p->len)
536 if(cpgmove(p, buf, p->len, o)) {
542 if(f && p->start + p->len > f->start)
543 print("CACHE: p->start=%uld p->len=%d f->start=%uld\n",
544 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)
580 for(f = m->list; f; f = f->next) {
581 if(f->start >= offset)
587 ee = p->start+p->len;
588 eo = offset - p->start;
589 /* pack in predecessor if there is space */
590 if(offset <= ee && eo < BY2PG) {
594 if(cpgmove(p, buf, eo, o)) {
604 /* free the overlap -- it's a rare case */
606 while(f && f->start < eblock) {
612 /* link the block (if any) into the middle */
613 e = cchain(buf, offset, len, &tail);