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:
cinap_lenrek 2017-01-12 20:13:20 +01:00
parent 4aeefba681
commit 47f07b2669
3 changed files with 47 additions and 13 deletions

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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);