/* * 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. Load more
/* * 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 void extentfree(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; } void cinit(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; } void cprint(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); } void cnodata(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; } void ctail(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; } } void copen(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 int cdev(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; } int cread(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; } 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); if(waserror()) { /* Since buf may be virtual */ kunmap(k); nexterror(); } memmove((uchar*)VA(k)+boff, buf, len); poperror(); kunmap(k); putpage(p); return 1; } void cupdate(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 */