From 47f07b2669e74eb957db56befa2237df5afa8474 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Thu, 12 Jan 2017 20:13:20 +0100 Subject: [PATCH] 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 #include #include 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); } --- sys/src/9/port/cache.c | 45 +++++++++++++++++++++++++++++++--------- sys/src/9/port/devmnt.c | 12 +++++++++-- sys/src/9/port/portfns.h | 3 ++- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/sys/src/9/port/cache.c b/sys/src/9/port/cache.c index 306228731..37a4d6813 100644 --- a/sys/src/9/port/cache.c +++ b/sys/src/9/port/cache.c @@ -187,7 +187,7 @@ ccache(Chan *c) return nil; } -void +int copen(Chan *c) { Mntcache *m, *f, **l; @@ -195,19 +195,20 @@ copen(Chan *c) /* 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 @@ copen(Chan *c) unlock(&cache); cacheunlock(m); c->mcp = f; - return; + return 1; } } @@ -251,10 +252,9 @@ copen(Chan *c) m->rah.vers = m->qid.vers; mntrahinit(&m->rah); cnodata(m); - cacheunlock(m); - c->mcp = m; + return 0; } enum { @@ -482,6 +482,31 @@ cwrite(Chan* c, uchar *buf, int len, vlong off) 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 cclunk(Chan *c) { diff --git a/sys/src/9/port/devmnt.c b/sys/src/9/port/devmnt.c index 095381d57..fc5ccbf1e 100644 --- a/sys/src/9/port/devmnt.c +++ b/sys/src/9/port/devmnt.c @@ -521,8 +521,11 @@ mntopencreate(int type, Chan *c, char *name, int omode, ulong perm) 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 @@ mntwstat(Chan *c, uchar *dp, int n) mountrpc(m, r); poperror(); mntfree(r); + + if(c->flag & CCACHE) + if(GBIT64(&dp[STATFIXLEN-4*BIT16SZ-BIT64SZ]) != ~0ULL) + ctrunc(c); + return n; } diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index 7c7eec461..5564ce0c8 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -41,13 +41,14 @@ void confinit(void); 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); 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);