ref: 47f07b2669e74eb957db56befa2237df5afa8474
parent: 4aeefba6811e57afe04a909fe147a29bb419d06b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Jan 12 15:13:20 EST 2017
kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat introducing new ctrunc() function that invalidates any caches for the passed in chan, invoked when handling wstat with a specified file length or on file creation/truncation. test program to reproduce the problem: #include <u.h> #include <libc.h> #include <libsec.h> void main(int argc, char *argv[]) { int fd; Dir *d, nd; fd = create("xxx", ORDWR, 0666); write(fd, "1234", 4); d = dirstat("xxx"); assert(d->length == 4); nulldir(&nd); nd.length = 0; dirwstat("xxx", &nd); d = dirstat("xxx"); assert(d->length == 0); fd = open("xxx", OREAD); assert(read(fd, (void*)&d, 4) == 0); }
--- a/sys/src/9/port/cache.c
+++ b/sys/src/9/port/cache.c
@@ -187,7 +187,7 @@
return nil;
}
-void
+int
copen(Chan *c)
{
Mntcache *m, *f, **l;
@@ -195,19 +195,20 @@
/* directories aren't cacheable */
if(c->qid.type&QTDIR){
c->mcp = nil;
- return;
+ return 0;
}
lock(&cache);
- m = clookup(c, 1);
- if(m == nil)
- m = cache.head;
- else if(m->qid.vers == c->qid.vers) {
+ m = clookup(c, 0);
+ if(m != nil){
ctail(m);
unlock(&cache);
c->mcp = m;
- return;
+ return 1;
}
+ m = clookup(c, 1);
+ if(m == nil)
+ m = cache.head;
ctail(m);
l = &cache.hash[m->qid.path%NHASH];
@@ -234,7 +235,7 @@
unlock(&cache);
cacheunlock(m);
c->mcp = f;
- return;
+ return 1;
}
}
@@ -251,10 +252,9 @@
m->rah.vers = m->qid.vers;
mntrahinit(&m->rah);
cnodata(m);
-
cacheunlock(m);
-
c->mcp = m;
+ return 0;
}
enum {
@@ -480,6 +480,31 @@
return;
}
cachedata(m, buf, len, off);
+}
+
+void
+ctrunc(Chan *c)
+{
+ Mntcache *m;
+
+ if(c->qid.type&QTDIR)
+ return;
+
+ if((c->flag&COPEN) == 0){
+ lock(&cache);
+ c->mcp = clookup(c, 0);
+ unlock(&cache);
+ }
+
+ m = ccache(c);
+ if(m == nil)
+ return;
+ mntrahinit(&m->rah);
+ cnodata(m);
+ cacheunlock(m);
+
+ if((c->flag&COPEN) == 0)
+ c->mcp = nil;
}
void
--- a/sys/src/9/port/devmnt.c
+++ b/sys/src/9/port/devmnt.c
@@ -521,8 +521,11 @@
poperror();
mntfree(r);
- if(c->flag & CCACHE)
- copen(c);
+ if(c->flag & CCACHE){
+ if(copen(c))
+ if(type == Tcreate || (omode&OTRUNC) != 0)
+ ctrunc(c);
+ }
return c;
}
@@ -620,6 +623,11 @@
mountrpc(m, r);
poperror();
mntfree(r);
+
+ if(c->flag & CCACHE)
+ if(GBIT64(&dp[STATFIXLEN-4*BIT16SZ-BIT64SZ]) != ~0ULL)
+ ctrunc(c);
+
return n;
}
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -41,7 +41,7 @@
int consactive(void);
void (*consdebug)(void);
void cpushutdown(void);
-void copen(Chan*);
+int copen(Chan*);
void cclunk(Chan*);
Block* concatblock(Block*);
Block* copyblock(Block*, int);
@@ -48,6 +48,7 @@
void copypage(Page*, Page*);
void countpagerefs(ulong*, int);
int cread(Chan*, uchar*, int, vlong);
+void ctrunc(Chan*);
void cunmount(Chan*, Chan*);
void cupdate(Chan*, uchar*, int, vlong);
void cwrite(Chan*, uchar*, int, vlong);