2 #include "../port/lib.h"
6 #include "../port/error.h"
11 NFILE = 4093, /* should be prime */
12 MAXCACHE = 8*1024*1024,
14 MAPBITS = 8*sizeof(ulong),
15 NBITMAP = (PGROUND(MAXCACHE)/BY2PG + MAPBITS-1) / MAPBITS,
18 /* devmnt.c: parallel read ahread implementation */
19 extern void mntrahinit(Mntrah *rah);
20 extern long mntrahread(Mntrah *rah, Chan *c, uchar *buf, long len, vlong off);
22 typedef struct Mntcache Mntcache;
37 /* page bitmap of valid pages */
38 ulong bitmap[NBITMAP];
40 /* read ahead state */
44 typedef struct Cache Cache;
51 Mntcache *hash[NHASH];
64 m = xalloc(sizeof(Mntcache)*NFILE);
66 panic("cinit: no memory");
71 for(i = 0; i < NFILE-1; i++) {
78 cache.tail->next = nil;
79 cache.head->prev = nil;
85 cacheaddr(Mntcache *m, ulong pn)
87 uintptr da = pn * NFILE + (m - cache.alloc);
88 return (da << PGSHIFT) | (da >> (sizeof(da)*8 - PGSHIFT));
94 memset(m->bitmap, 0, sizeof(m->bitmap));
100 /* Unlink and send to the tail */
102 m->prev->next = m->next;
104 cache.head = m->next;
106 m->next->prev = m->prev;
108 cache.tail = m->prev;
110 if(cache.tail != nil) {
111 m->prev = cache.tail;
112 cache.tail->next = m;
124 /* called with cache locked */
126 clookup(Chan *c, int skipvers)
130 for(m = cache.hash[c->qid.path%NHASH]; m != nil; m = m->hash)
131 if(eqchantdqid(c, m->type, m->dev, m->qid, skipvers) && c->qid.type == m->qid.type)
138 * resursive Mntcache locking. Mntcache.rah is protected by the
139 * same lock and we want to call cupdate() from mntrahread()
140 * while holding the lock.
143 cancachelock(Mntcache *m)
145 if(m->locked == up || canqlock(m)){
153 cachelock(Mntcache *m)
157 assert(m->nlocked == 0);
164 cacheunlock(Mntcache *m)
166 assert(m->locked == up);
167 if(--m->nlocked == 0){
173 /* return locked Mntcache if still valid else reset mcp */
182 if(eqchantdqid(c, m->type, m->dev, m->qid, 0) && c->qid.type == m->qid.type)
193 Mntcache *m, *f, **l;
195 /* directories aren't cacheable */
196 if(c->qid.type&QTDIR){
214 l = &cache.hash[m->qid.path%NHASH];
215 for(f = *l; f != nil; f = f->hash) {
223 if(!cancachelock(m)){
230 * someone got there first while cache lock
231 * was released and added a updated Mntcache
232 * for us. update LRU and use it.
246 l = &cache.hash[c->qid.path%NHASH];
252 m->rah.vers = m->qid.vers;
261 VABITS = 8*sizeof(uintptr) - 2*PGSHIFT,
262 VAMASK = (((uintptr)1 << VABITS)-1) << PGSHIFT,
266 cpage(Mntcache *m, ulong pn, ulong *po, ulong *pe)
271 b = 1 << (pn%MAPBITS);
272 if((m->bitmap[pn/MAPBITS] & b) == 0)
274 p = lookpage(&fscache, cacheaddr(m, pn));
276 m->bitmap[pn/MAPBITS] &= ~b;
279 *po = p->va & (BY2PG-1);
280 *pe = 1 + (p->va >> (PGSHIFT+VABITS));
286 cpageset(Page *p, ulong po, ulong pe)
289 p->va = po | (p->va & VAMASK) | ((uintptr)pe - 1) << (PGSHIFT+VABITS);
293 cread(Chan *c, uchar *buf, int len, vlong off)
299 ulong offset, pn, po, pe;
318 if(offset+len > MAXCACHE)
319 len = MAXCACHE - offset;
324 p = cpage(m, pn, &po, &pe);
327 if(offset < po || offset >= pe){
341 memmove(buf, (uchar*)VA(k) + offset, l);
360 if(m->rah.vers != m->qid.vers){
362 m->rah.vers = m->qid.vers;
365 tot += mntrahread(&m->rah, c, buf, len, off);
373 /* invalidate pages in page bitmap */
375 invalidate(Mntcache *m, ulong offset, int len)
379 for(pn = offset/BY2PG; len > 0; pn++, len -= BY2PG)
380 m->bitmap[pn/MAPBITS] &= ~(1 << (pn%MAPBITS));
383 /* replace buf data from [off, off+len) in the cache or invalidate */
385 cachedata(Mntcache *m, uchar *buf, int len, vlong off)
390 ulong offset, pn, po, pe;
392 if(off >= MAXCACHE || len <= 0){
398 if(offset+len > MAXCACHE)
399 len = MAXCACHE - offset;
407 p = cpage(m, pn, &po, &pe);
409 if(offset > pe || (offset+l) < po){
410 /* cached range not extendable, set new cached range */
414 /* extend cached range */
422 invalidate(m, offset + pn*BY2PG, len);
425 p = newpage(0, nil, pn*BY2PG);
426 p->daddr = cacheaddr(m, pn);
427 cachedel(&fscache, p->daddr);
428 cachepage(p, &fscache);
429 m->bitmap[pn/MAPBITS] |= 1 << (pn%MAPBITS);
440 invalidate(m, offset + pn*BY2PG, len);
444 memmove((uchar*)VA(k) + offset, buf, l);
458 cupdate(Chan *c, uchar *buf, int len, vlong off)
465 cachedata(m, buf, len, off);
469 cwrite(Chan* c, uchar *buf, int len, vlong off)
478 if(c->qid.type&QTAPPEND){
482 cachedata(m, buf, len, off);
490 if(c->qid.type&QTDIR)
493 if((c->flag&COPEN) == 0){
495 c->mcp = clookup(c, 0);
506 if((c->flag&COPEN) == 0)