git: 9front

Download patch

ref: b575d3a7ca745f1ded3c06b6c74c1dfe3e20d368
parent: 9ea7dd53088a6bc09a225616fbece2e429565aa8
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);
--