M port/cache.c => port/cache.c +225 -40
@@ 8,12 8,20 @@
Image fscache;
-typedef Extent Extent;
+enum
+{
+ NHASH = 128,
+ MAXCACHE = 1024*1024,
+ NFILE = 4096,
+};
+
+typedef struct Extent Extent;
struct Extent
{
int bid;
ulong start;
int len;
+ Page *cache;
Extent *next;
};
@@ 23,7 31,7 @@ struct Mntcache
Qid;
int dev;
int type;
- Qlock;
+ QLock;
Extent *list;
Mntcache *hash;
Mntcache *prev;
@@ 40,16 48,38 @@ struct Cache
};
Cache cache;
+void
+cinit(void)
+{
+ int i;
+ Mntcache *m;
+
+ cache.ref = 1;
+ cache.head = xalloc(sizeof(Mntcache)*NFILE);
+ m = cache.head;
+
+ for(i = NFILE; i > 0; i++) {
+ m->next = m+1;
+ m->prev = m-1;
+ m++;
+ }
+
+ cache.tail = m;
+ cache.tail->next = 0;
+ cache.head->prev = 0;
+}
+
Mntcache*
clook(Chan *c)
{
int h;
+ Mntcache *m;
h = c->qid.path%NHASH;
lock(&cache);
for(m = cache.hash[h]; m; m = m->hash) {
- if(m->path == c->path) {
+ if(m->path == c->qid.path) {
qlock(m);
if(m->path == c->qid.path)
if(m->dev == c->dev)
@@ 65,6 95,28 @@ clook(Chan *c)
}
void
+cprint(Mntcache *m)
+{
+ Extent *e;
+
+ print("%lux.%lux %d %d\n", m->path, m->vers, m->type, m->dev);
+
+ while(e)
+ print("\t%4d %5d %4d %lux\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;
@@ 74,7 126,7 @@ cnodata(Mntcache *m)
* Image lru will waste the pages
*/
for(e = m->list; e; e = n) {
- n = e->list;
+ n = e->next;
free(e);
}
}
@@ 116,7 168,7 @@ copen(Chan *c)
m = clook(c);
if(m != 0) {
/* File was updated */
- if(m->vers != c->vers)
+ if(m->vers != c->qid.vers)
cnodata(m);
ctail(m);
@@ 127,8 179,8 @@ copen(Chan *c)
/* LRU the cache headers */
m = cache.head;
qlock(m);
- lock(cache);
- l = &cache.hash[m->qid.path%NHASH];
+ lock(&cache);
+ l = &cache.hash[m->path%NHASH];
for(f = *l; f; f = f->next) {
if(f == m) {
*l = f->next;
@@ 139,8 191,8 @@ copen(Chan *c)
l = &cache.hash[c->qid.path%NHASH];
m->hash = *l;
*l = m;
- unlock(cache);
- m->qid = c->qid;
+ unlock(&cache);
+ m->Qid = c->qid;
m->dev = c->dev;
m->type = c->type;
cnodata(m);
@@ 152,9 204,9 @@ copen(Chan *c)
static int
cdev(Mntcache *m, Chan *c)
{
- if(m->path != c->path)
+ if(m->path != c->qid.path)
return 0;
- if(m->vers != c->vers)
+ if(m->vers != c->qid.vers)
return 0;
if(m->dev != c->dev)
return 0;
@@ 164,13 216,13 @@ cdev(Mntcache *m, Chan *c)
}
int
-cread(Chan *c, uchar *buf, int len, long offset)
+cread(Chan *c, uchar *buf, int len, ulong offset)
{
KMap *k;
Page *p;
Mntcache *m;
- Extent *e, **l;
- int o, l, total;
+ Extent *e, **t;
+ int o, l, total, end;
m = c->mcp;
if(m == 0)
@@ 182,11 234,11 @@ cread(Chan *c, uchar *buf, int len, long offset)
}
end = offset+len;
- l = &m->list;
- for(e = *l; e; e = e->next) {
+ t = &m->list;
+ for(e = *t; e; e = e->next) {
if(e->start >= offset && e->start+e->len < end)
break;
- l = &e->next;
+ t = &e->next;
}
if(e == 0) {
@@ 196,9 248,9 @@ cread(Chan *c, uchar *buf, int len, long offset)
total = 0;
while(len) {
- p = lookpage(&fscache, e->bid);
+ p = cpage(e);
if(p == 0) {
- *l = e->next;
+ *t = e->next;
free(e);
qunlock(m);
return total;
@@ 217,8 269,7 @@ cread(Chan *c, uchar *buf, int len, long offset)
if(l > e->len-o)
l = e->len-o;
- p = (uchar*)VA(k) + o;
- memset(buf, p, l);
+ memmove(buf, (uchar*)VA(k) + o, l);
kunmap(k);
putpage(p);
@@ 226,20 277,85 @@ cread(Chan *c, uchar *buf, int len, long offset)
len -= l;
offset += l;
total += l;
- l = &e->next;
+ t = &e->next;
e = e->next;
if(e == 0 || e->start != offset)
break;
}
- qunlock(m)
+ 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;
+ t = &start;
+ while(len) {
+ e = malloc(sizeof(Extent));
+ if(e == 0)
+ break;
+
+ p = auxpage();
+ if(p == 0) {
+ free(e);
+ break;
+ }
+ e->cache = p;
+ e->start = offset;
+ l = len;
+ if(l > BY2PG)
+ l = BY2PG;
+
+ e->bid = incref(&cache);
+ p->daddr = e->bid;
+ k = kmap(p);
+ memmove((void*)VA(k), buf, l);
+ 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);
+ memmove((uchar*)VA(k)+boff, buf, len);
+ kunmap(k);
+ putpage(p);
+
+ return 1;
+}
+
void
-cwrite(Chan *c, uchar *buf, int len, long offset)
+cupdate(Chan *c, uchar *buf, int len, ulong offset)
{
- Extent *e;
Mntcache *m;
+ Extent *tail;
+ Extent *e, *f, *p;
+ int o, ee, eblock;
if(offset > MAXCACHE)
return;
@@ 253,22 369,91 @@ cwrite(Chan *c, uchar *buf, int len, long offset)
return;
}
- if(m->list == 0) {
- e = malloc(sizeof(Extent));
- if(e == 0)
+ /*
+ * Find the insertion point
+ */
+ p = 0;
+ for(f = m->list; f; f = f->next) {
+ if(f->start >= offset)
+ break;
+ p = f;
+ }
+ if(p == 0) { /* at the head */
+ eblock = offset+len;
+ /* trim if there is a successor */
+ if(f != 0 && eblock >= f->start) {
+ len -= (eblock - f->start);
+ if(len <= 0) {
+ qunlock(m);
+ return;
+ }
+ }
+ e = cchain(buf, offset, len, &tail);
+ m->list = e;
+ if(tail != 0)
+ tail->next = f;
+ qunlock(m);
+ return;
+ }
+
+ /* trim to the predecessor */
+ ee = p->start+p->len;
+ if(offset < ee) {
+ o = ee - offset;
+ len -= o;
+ if(len <= 0) {
+ qunlock(m);
return;
- e->start = offset;
- l = len;
- if(l > BY2PG)
- l = BY2PG;
- p = auxpage();
- if(p == 0)
+ }
+ buf += o;
+ offset += o;
+ }
+
+ /* try and pack data into the predecessor */
+ if(offset == ee && p->len < BY2PG) {
+ o = len;
+ if(o > BY2PG - p->len)
+ o = BY2PG - p->len;
+ if(len <= 0) {
+ qunlock(m);
return;
- e->bid = incref(&cache);
- p->daddr = e->bid;
- cachepage(p, fscache);
- k = kmap(p);
-
- kunmap(p);
+ }
+ if(cpgmove(e, buf, p->len, o)) {
+ e->len += o;
+ buf += o;
+ len -= o;
+ offset += o;
+ if(len <= 0) {
+ qunlock(m);
+ return;
+ }
+ }
+ }
+
+ /* append to extent list */
+ if(f == 0) {
+ p->next = cchain(buf, offset, len, &tail);
+ qunlock(m);
+ return;
+ }
+
+ /* trim data against successor */
+ eblock = offset+len;
+ if(eblock > f->start) {
+ o = eblock - f->start;
+ if(o < 0) {
+ qunlock(m);
+ return;
+ }
+ len -= o;
}
+
+ /* Insert a middle block */
+ p->next = cchain(buf, offset, len, &tail);
+ if(p->next == 0)
+ p->next = f;
+ else
+ tail->next = f;
+
+ qunlock(m);
}
M port/devmnt.c => port/devmnt.c +24 -16
@@ 44,7 44,7 @@ void mntgate(Mnt*);
void mntpntfree(Mnt*);
void mntqrm(Mnt*, Mntrpc*);
Mntrpc* mntralloc(Chan*);
-long mntrdwr(int , Chan*, void*,long , ulong);
+long mntrdwr(int , Mnt*, Chan*, void*,long , ulong);
void mntrpcread(Mnt*, Mntrpc*);
void mountio(Mnt*, Mntrpc*);
void mountmux(Mnt*, Mntrpc*);
@@ 83,7 83,7 @@ mntattach(char *muxattach)
struct bogus{
Chan *chan;
char *spec;
- char recov;
+ int flag;
}bogus;
bogus = *((struct bogus *)muxattach);
@@ 133,7 133,7 @@ mntattach(char *muxattach)
m->c = c;
m->c->flag |= CMSG;
m->blocksize = MAXFDATA; /**/
- m->recov = bogus.recov;
+ m->flags = bogus.flags;
switch(devchar[m->c->type]) {
default:
@@ 302,13 302,6 @@ mntwalk(Chan *c, char *name)
op = c->path;
c->path = ptenter(&m->tree, op, name);
-/* ASSERT do not remove */
-if(op->ref == 0) {
- char buf[128];
- ptpath(op, buf, sizeof(buf));
- print("PATH: '%s' walking %s\n", op, name);
-}
-
decref(op);
poperror();
@@ 488,31 481,46 @@ mntwstat(Chan *c, char *dp)
long
mntread(Chan *c, void *buf, long n, ulong offset)
{
+ int nc;
uchar *p, *e;
- n = mntrdwr(Tread, c, buf, n, offset);
+ m = mntchk(c);
+ nc = 0;
+ if((m->flags&MCACHE) && !isdir(c)) {
+ nc = cread(c, buf, n, offset);
+ if(nc == n)
+ return n;
+
+ buf = (uchar*)buf+nc;
+ offset += nc;
+ n -= nc;
+ }
+
+ n = mntrdwr(Tread, m, c, buf, n, offset);
if(c->qid.path & CHDIR)
for(p = (uchar*)buf, e = &p[n]; p < e; p += DIRLEN)
mntdirfix(p, c);
+ if(nc != 0)
+ cupdate(c, buf, n, offset);
+
return n;
}
long
mntwrite(Chan *c, void *buf, long n, ulong offset)
{
- return mntrdwr(Twrite, c, buf, n, offset);
+ m = mntchk(c);
+ return mntrdwr(Twrite, m, c, buf, n, offset);
}
long
-mntrdwr(int type, Chan *c, void *buf, long n, ulong offset)
+mntrdwr(int type, Mnt *m, Chan *c, void *buf, long n, ulong offset)
{
- Mnt *m;
Mntrpc *r;
char *uba;
ulong cnt, nr;
- m = mntchk(c);
uba = buf;
cnt = 0;
for(;;) {
@@ 553,7 561,7 @@ mountrpc(Mnt *m, Mntrpc *r)
r->reply.type = 4;
while(waserror()) {
- if(m->recov == 0)
+ if((m->flags & MRECOV) == 0)
nexterror();
mntrecover(m, r);
}
M port/lib.h => port/lib.h +2 -1
@@ 80,7 80,8 @@ extern char end[];
#define MAFTER 0x0002 /* mount goes after others in union directory */
#define MCREATE 0x0004 /* permit creation in mounted directory */
#define MRECOV 0x0008 /* perform recovery if mount channel is lost */
-#define MMASK 0x000F /* all bits on */
+#define MCACHE 0x0010 /* cache some data */
+#define MMASK 0x001F /* all bits on */
#define OREAD 0 /* open for read */
#define OWRITE 1 /* write */
M port/portdat.h => port/portdat.h +1 -1
@@ 269,7 269,7 @@ struct Mnt
ulong id; /* Multiplexor id for channel check */
Mnt *list; /* Free list */
char mux; /* Set if the device does the multiplexing */
- char recov; /* Run recovery if channel is lost */
+ int flags; /* recover/cache */
char recprog; /* Recovery in progress */
int blocksize; /* read/write block size */
ushort flushtag; /* Tag to send flush on */
M port/portfns.h => port/portfns.h +5 -0
@@ 10,6 10,7 @@ long authread(Chan*, char*, int);
void authreply(Session*, ulong, Fcall*);
ulong authrequest(Session*, Fcall*);
long authwrite(Chan*, char*, int);
+Page* auxpage(void);
void bitdebug(void);
void bitdepth(void);
void bitreverse(uchar*, int);
@@ 272,3 273,7 @@ Segment* newseg(int, ulong, ulong);
Scsibuf* scsialloc(ulong);
Scsibuf* scsibuf(void);
Segment* seg(Proc*, ulong, int);
+
+
+int cread(Chan*, uchar*, int, ulong);
+void cupdate(Chan*, uchar*, int, ulong);
M port/sysfile.c => port/sysfile.c +2 -2
@@ 450,7 450,7 @@ bindmount(ulong *arg, int ismount)
struct{
Chan *chan;
char *spec;
- char recov;
+ int flags;
}bogus;
flag = arg[2];
@@ 458,7 458,7 @@ bindmount(ulong *arg, int ismount)
if(flag>MMASK || (flag&MORDER)==(MBEFORE|MAFTER))
error(Ebadarg);
- bogus.recov = flag&MRECOV;
+ bogus.flags = flag & (MRECOV|MCACHE);
if(ismount){
bc = fdtochan(fd, ORDWR, 0, 1);