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); }
This commit is contained in:
parent
4aeefba681
commit
47f07b2669
3 changed files with 47 additions and 13 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue