code: mafs

Download patch

ref: ca4b900c544ce32fdb60b58cdbe0f64453ada12f
parent: e6ed176a5366eb410de4c9a126a2cc540de0f0db
author: 9ferno <gophone2015@gmail.com>
date: Sun Nov 27 19:07:46 EST 2022

working flush and sync

--- a/9p.c
+++ b/9p.c
@@ -3,11 +3,13 @@
 Tlock	*tlockhead = nil, *tlocktail = nil;
 QLock	tlock;
 extern u32 mpsrvpid;
-extern u8 synchronouswrites;
+static u64 lastflushtime = 0;
+static RWLock flushlck;
 
 s32 readfile(u64 dblkno, u64 qpath, char *rbuf, s32 rbufsize, u64 offset);
 s32 writefile(u64 dblkno, u64 qpath, s16 uid, char *wbuf, s32 wbufsize, u64 offset);
 s32 writeallappend(Iobuf *dbuf, Dentry *d, u64 dblkno);
+static void fsflush(void);
 
 Aux*
 newaux(u64 addr, u16 uid)
@@ -92,7 +94,7 @@
 		qunlock(&tlock);
 	}
 
-	/* allocate on remove */
+	/* allocate on close */
 	dbuf = getmeta(((Aux*)fid->aux)->dblkno, Bwritable, Bused);
 	if(dbuf != nil){
 		if(dbuf->xiobuf != nil &&
@@ -312,7 +314,6 @@
 	respond(req, nil);
 }
 
-
 static void
 fswrite(Req *req)
 {
@@ -337,7 +338,6 @@
 		respond(req, errstring[Einval]);
 		return;
 	}
-
 	rv = writefile(((Aux*)req->fid->aux)->dblkno, req->fid->qid.path,
 					((Aux*)req->fid->aux)->uid,
 					req->ifcall.data, req->ifcall.count,
@@ -351,6 +351,12 @@
 		req->ofcall.offset = req->ifcall.offset+rv;
 		respond(req, nil);
 	}
+	if(shuttingdown == 0 &&
+		mpsrvpid == 0 &&
+		lastflushtime < nsec()-Nrefresh){
+		fsflush();
+		lastflushtime = nsec();
+	}
 }
 
 static void
@@ -1054,8 +1060,17 @@
 	worker[id].pid = 0;
 }
 
+static void
+fsflush(void)
+{
+	if(canwlock(&flushlck)){
+		flushold();
+		wunlock(&flushlck);
+	}
+}
+
 void
-startproc(Buffer *b, int id)
+startproc(Buffer *b, int id, u8 syncer)
 {
 	char name[128];
 
@@ -1069,9 +1084,16 @@
 	default:
 		return;
 	}
-	snprint(name, 128, "%s worker %d", service, id);
+	if(syncer)
+		snprint(name, 128, "%s worker %d", service, id);
+	else
+		snprint(name, 128, "%s flusher %d", service, id);
 	procsetname(name);
-	work(b, id);
+	if(syncer){
+		while(shuttingdown == 0 && sleep(Nrefresh))
+			fsflush();
+	}else
+		work(b, id);
 	if(chatty9p)
 		dprint("%s process exited\n", name);
 	exits(nil);
@@ -1087,7 +1109,8 @@
 	if(chatty9p > 1)
 		dprint("srv() parent process pid: %d\n", mpsrvpid);
 	for(i = 0; i < Nworkers; i++)
-		startproc(&buf, i);
+		startproc(&buf, i, 0);
+	startproc(&buf, i, 1);
 }
 
 /* read the comment above shutdown() to understand */
--- a/all.h
+++ b/all.h
@@ -92,6 +92,7 @@
 	u64 appendsize;
 	u8 freshalloc;	/* uninitialized blocks on the disk */
 	u64 atime;		/* to find old buffers to flush to the disk */
+	u8 tag;
 };
 
 extern	u64	nbuckets;		/* n hash buckets for i/o */
@@ -101,7 +102,7 @@
 
 /* Iobuf routines - contents of the blocks in memory */
 void	initmemunitpool(u64 nunits);
-u8 *allocmemunits(u16 len);
+u8*		allocmemunits(u16 len);
 void	freememunits(u8 *m, u16 len);
 int		checktag(Iobuf *p, u16 len, u8 tag, u64 qpath);
 Iobuf*	getbuf(u64 blkno, u16 len, u8 readonly, u8 freshalloc);
@@ -113,6 +114,7 @@
 void	putbuffree(Iobuf *p);
 void	settag(Iobuf *p, u8 tag, u64 qpath);
 void	showbuf(Iobuf *p);
+s32		showhashbuckets(s8 *buf, s32 nbuf);
 
 /* writer functions */
 void	initwriter(void);
@@ -156,6 +158,7 @@
 s32		writefile(u64 dblkno, u64 qpath, s16 uid, char *wbuf, s32 wbufsize, u64 offset);
 s8		flush(Iobuf *b);
 u64		sync(void);
+void	flushold(void);
 
 /* user access routines */
 int	byname(void*, void*);
--- a/block.c
+++ b/block.c
@@ -18,7 +18,7 @@
 void
 main(int argc, char *argv[])
 {
-	u64 size, blkno, nunits;
+	u64 size, blkno;
 	u8 buf[Blocksize];
 
 	ARGBEGIN{
--- a/ctl.c
+++ b/ctl.c
@@ -12,7 +12,6 @@
 	Csync,
 	Chalt,
 	Cusers,
-	Cecho,
 	Cmax
 };
 
@@ -26,7 +25,7 @@
 		dprint("sync(): finds %llud locked blocks\n", n);
 		sleep(1000);
 	}
-	return 0;
+	return 1;
 }
 
 int
@@ -33,7 +32,7 @@
 cmdhalt(Cmdbuf *)
 {
 	shutdown();
-	return Chalt;
+	return 1;
 }
 
 int
@@ -42,36 +41,21 @@
 	extern int chatty9p;
 
 	chatty9p = !chatty9p;
-	return 0;
-}
-
-int
-cmdnoauth(Cmdbuf *)
-{
-	noauth = 1;
 	return 1;
 }
 
 int
-cmdecho(Cmdbuf *cb)
-{
-	echo = strcmp(cb->f[1], "on") == 0;
-	return 1;
-}
-
-int
 cmdusers(Cmdbuf *)
 {
 	syncusers();
-	return 0;
+	return 1;
 }
 
 Cmdtab cmds[] = {
 	{Cchatty, "chatty", 1},
 	{Csync, "sync", 1},
-	{Chalt, "halt", 0},
+	{Chalt, "halt", 1},
 	{Cusers, "users", 1},
-	{Cecho, "echo", 2},
 };
 
 int
@@ -82,11 +66,10 @@
 		case Csync:	return cmdsync(cb); break;
 		case Chalt:	return cmdhalt(cb); break;
 		case Cusers:	return cmdusers(cb); break;
-		case Cecho:	return cmdecho(cb); break;
 		default:
 			dprint("unknown idx %d\n", idx);
 	}
-	return idx;
+	return 0;
 };
 
 void
@@ -100,7 +83,9 @@
 	used = config.nblocks - free;
 
 /*	n = snprint(buf, 1024, "pending writes %llud blocks\n", pendingwrites());*/
-	n = snprint(buf, 1024, "memunits extents:\n");
+	n = snprint(buf, 1024, "hash buckets:\n");
+	n += showhashbuckets(buf+n, 1024-n);
+	n += snprint(buf+n, 1024-n, "memunits extents:\n");
 	n += saveextents(&memunits, buf+n, 1024-n);
 	n += snprint(buf+n, 1024-n, "frees extents:\n");
 	n += saveextents(&frees, buf+n, 1024-n);
@@ -167,15 +152,21 @@
 	int n;
 
 	if(chatty9p)
-		dprint("consproc: >%s\n", req->ifcall.data);
-	while((cb = parsecmd(req->ifcall.data, req->ifcall.count)) != nil){
+		dprint("ctlwrite %d -%s-\n", req->ifcall.count, req->ifcall.data);
+	while((cb = parsecmd(req->ifcall.data, req->ifcall.count)) != nil &&
+			cb->nf > 0){
 		ct = lookupcmd(cb, cmds, nelem(cmds));
 		if(ct != nil){
 			req->ofcall.count = req->ifcall.count;
 			req->ofcall.offset = req->ifcall.offset+req->ifcall.count;
 			n = runcmd(ct->index, cb);
-			respond(req, nil);
-			if(ct->index == Chalt || n == Chalt){
+			/* should respond based on n */
+			// dprint("ct->index %d n %d\n", ct->index, n);
+			if(n == 1)
+				respond(req, nil);
+			else
+				respondcmderror(req, cb, "%r");
+			if(ct->index == Chalt){
 				/* /srv/mafs_service file will not exist when mounted with -s */
 				if(mpsrvpid &&
 					snprint(srvfilename, Namelen, "/srv/%s", service) > 5){
@@ -202,167 +193,3 @@
 		free(cb);
 	}
 }
-
-/* get rid of this after understanding what it does
-static int
-walkpath(Chan *ch, char *path, char **cr)
-{
-	char buf[Namelen], *p, *fp;
-
-	fp = path;
-	if(*path != '/'){
-	noent:
-		werrstr("%s: %s", fp, Enoent);
-		return -1;
-	}
-	path++;
-	for(;;){
-		p = strchr(path, '/');
-		if(p == nil){
-			if(cr != nil){
-				if(*path == 0){
-					werrstr("%s: trailing slash", fp);
-					return -1;
-				}
-				*cr = path;
-				break;
-			}
-			p = path + strlen(path);
-		}
-		if(*path == '/'){
-			path++;
-			continue;
-		}
-		if(*path == 0)
-			break;
-		if(p - path >= Namelen)
-			goto noent;
-		memset(buf, 0, sizeof buf);
-		memcpy(buf, path, p - path);
-		if(chanwalk(ch, buf) <= 0){
-			werrstr("%s: %r", fp);
-			return -1;
-		}
-		if(*p == 0)
-			break;
-		path = p + 1;
-	}
-	return 1;
-}
-
-int
-cmddebugdeind(int, char **argv)
-{
-	Chan *ch;
-	Buf *b;
-	Dentry *d;
-
-	ch = chanattach(fsmain, 0);
-	if(ch == nil)
-		return -1;
-	ch->uid = -1;
-	if(walkpath(ch, argv[1], nil) < 0)
-		goto error;
-	rlock(fsmain);
-	dprint("loc %ulld / %uld, offset %ulld\n", ch->loc->blk, ch->loc->deind, BLOCK * ch->loc->blk + (RBLOCK - BLOCK) + DENTRYSIZ * ch->loc->deind);
-	b = getbuf(fsmain->d, ch->loc->blk, TDENTRY, 0);
-	if(b == nil){
-		runlock(fsmain);
-		goto error;
-	}
-	d = &b->de[ch->loc->deind];
-	dprint("name %s\n", d->name);
-	dprint("uid %d, muid %d, gid %d\n", d->uid, d->muid, d->gid);
-	dprint("mode %#o, qid %ulld, type %#x, version %d\n", d->mode, d->path, d->type, d->vers);
-	dprint("size %d\n", d->size);
-	dprint("atime %ulld, mtime %ulld\n", d->atime, d->mtime);
-	putbuf(b);
-	runlock(fsmain);
-	chanclunk(ch);
-	return 0;
-error:
-	chanclunk(ch);
-	return -1;
-}
-
-int
-cmddebugchdeind(int, char **argv)
-{
-	Chan *ch;
-	uchar *c;
-	Buf *b;
-	int loc, new;
-
-	loc = strtol(argv[2], nil, 0);
-	new = strtol(argv[3], nil, 0);
-	if(loc >= DENTRYSIZ)
-		return -9001;
-	ch = chanattach(fsmain, 0);
-	if(ch == nil)
-		return -1;
-	ch->uid = -1;
-	if(walkpath(ch, argv[1], nil) < 0)
-		goto error;
-	rlock(fsmain);
-	b = getbuf(fsmain->d, ch->loc->blk, TDENTRY, 0);
-	if(b == nil){
-		runlock(fsmain);
-		goto error;
-	}
-	c = (uchar *) &b->de[ch->loc->deind];
-	dprint("loc %d, old value %#.2x, new value %#.2x\n", loc, c[loc], new);
-	c[loc] = new;
-	b->op |= BDELWRI;
-	putbuf(b);
-	runlock(fsmain);
-	chanclunk(ch);
-	return 0;
-error:
-	chanclunk(ch);
-	return -1;
-}
-
-int
-cmddebuggetblk(int argc, char **argv)
-{
-	Chan *ch;
-	Buf *b;
-	int rc;
-	uvlong r, start, end, i;
-
-	if(argc != 3 && argc != 4)
-		return -9001;
-	start = atoll(argv[2]);
-	if(argc == 4)
-		end = atoll(argv[3]);
-	else
-		end = start;
-	ch = chanattach(fsmain, 0);
-	if(ch == nil)
-		return -1;
-	ch->uid = -1;
-	if(walkpath(ch, argv[1], nil) < 0)
-		goto error;
-	rlock(fsmain);
-	b = getbuf(fsmain->d, ch->loc->blk, TDENTRY, 0);
-	if(b == nil){
-		runlock(fsmain);
-		goto error;
-	}
-	for(i = start; i <= end; i++){
-		rc = getblk(fsmain, ch->loc, b, i, &r, GBREAD);
-		if(rc > 0)
-			dprint("getblk %ulld = %ulld\n", i, r);
-		if(rc == 0)
-			dprint("getblk %ulld not found\n", i);
-		if(rc < 0)
-			dprint("getblk %ulld: %r\n", i);
-	}
-	putbuf(b);
-	runlock(fsmain);
-	chanclunk(ch);
-	return 0;
-error:
-	chanclunk(ch);
-	return -1;
-} */
--- a/dat.h
+++ b/dat.h
@@ -37,7 +37,7 @@
 	Usec	= 1000ULL*1000,
 	Msec	= 1000ULL,
 	Nbkp	= 1,
-	Nrefresh = 3*Nsec,
+	Nrefresh = 10*Nsec,
 };
 
 /*
@@ -181,7 +181,7 @@
 };
 struct Indirect
 {
-	u8 tag;
+	u8 tagi;
 	u8 veri;
 	u8 pad[6];	/* unused, to align to a multiple of 8 */
 	u64 dblkno;	/* block number of the directory entry */
--- a/dentry.c
+++ b/dentry.c
@@ -4,19 +4,21 @@
 s8
 flush(Iobuf *b)
 {
-	if(b->xiobuf[0] != Tdentry)
+	if(b->tag != Tdentry)
 		return 0;
-	if(b->append != nil && b->appendsize == 0){
+	if(b->append != nil){
+		if(b->appendsize > 0){
+			recentmetadata(b->m, &b->cur, &b->new);
+			/* writable */
+			memcpy(b->new, b->cur, Blocksize);
+			b->new->verd++;
+			writeallappend(b, b->new, b->blkno);
+			putbuf(b, 1);
+		}
 		freememunits(b->append, Maxdatablockunits);
 		b->append = nil;
 		return 0;
 	}
-	recentmetadata(b->m, &b->cur, &b->new);
-	/* writable */
-	memcpy(b->new, b->cur, Blocksize);
-	b->new->verd++;
-	writeallappend(b, b->new, b->blkno);
-	putbuf(b, 1);
 	return 1;
 }
 
--- a/find.c
+++ b/find.c
@@ -109,8 +109,8 @@
 
 	devread(blkno, buf, Metadataunits);
 	t = (Indirect*)buf;
-	if(checkvalid(blkno, t->tag, t->path, tag, qpath, Metadataunits)){
-		if(t->tag == Tind0){
+	if(checkvalid(blkno, t->tagi, t->path, tag, qpath, Metadataunits)){
+		if(t->tagi == Tind0){
 			bufa = (u64*)buf;
 			for(i = 0; i<Nindperblock; i++){
 				cblkno = bufa[i];
@@ -204,7 +204,7 @@
 			return;
 		devread(cblkno, cbuf, Metadataunits);
 		ct = (Indirect*)cbuf;
-		if(ct->tag == Tind0+i){
+		if(ct->tagi == Tind0+i){
 			walkindir(cblkno, Tind0+i, Tdentry, d->qpath, depth);
 		}else{
 			fprint(2, "invalid indir tag %llud\n", cblkno);
@@ -259,7 +259,7 @@
 			return;
 		devread(cblkno, cbuf, Metadataunits);
 		it = (Indirect*)cbuf;
-		if(it->tag == Tind0+i){
+		if(it->tagi == Tind0+i){
 			walkindir(cblkno, Tind0+i, Tdata, d->qpath, depth);
 		}else{
 			fprint(2, "invalid indir tag %llud\n", cblkno);
--- a/free.c
+++ b/free.c
@@ -105,8 +105,8 @@
 
 	devread(blkno, buf, Metadataunits);
 	t = (Indirect*)buf;
-	if(checkvalid(blkno, t->tag, t->path, tag, qpath, Metadataunits)){
-		if(t->tag == Tind0){
+	if(checkvalid(blkno, t->tagi, t->path, tag, qpath, Metadataunits)){
+		if(t->tagi == Tind0){
 			for(i = 0; i<Nindperblock; i++){
 				cblkno = t->bufa[i];
 				if(cblkno == 0)
--- a/iobuf.c
+++ b/iobuf.c
@@ -3,7 +3,6 @@
 u64  nbuckets = 0;	/* number of hash buckets, -m changes it */
 Hiob *hiob = nil;	/* array of nbuckets */
 Extents frees = {0};/* extents of free blocks on the disk */
-extern u8 synchronouswrites;
 
 /*
 	extents of Blocksize units of memory used to store
@@ -13,8 +12,6 @@
 Extents memunits = {0};
 u8 *memunitpool = nil;
 u8 *memunitstart = nil;
-static u64 lastflushtime = 0;
-static RWLock flushlck;
 
 /* using nunits + 1 for alignment */
 void
@@ -58,28 +55,135 @@
 	bfree(&memunits, (m-memunitpool)/Blocksize, len);
 }
 
-u64
+s32
+showhashbucket(Iobuf *p, s8 *buf, s32 nbuf)
+{
+	s32 n;
+	char locked[32];
+	u8 tag;
+	char *name;
+
+	if(p == nil)
+		return 0;
+
+	if(canwlock(p)){
+		strcpy(locked, "unlocked");
+		wunlock(p);
+	}else
+		strcpy(locked, "locked");
+	if(p->io->tag == Tdata)
+		n = snprint(buf, nbuf, "%s %llud %s\n",
+					tagnames[p->io->tag], p->blkno, locked);
+	else{
+		if(p->m->d[0].tag > Tdata && p->m->d[0].tag < MAXTAG){
+			tag = p->m->d[0].tag;
+			name = p->m->d[0].name;
+		}else{
+			tag = p->m->d[1].tag;
+			name = p->m->d[1].name;
+		}
+		if(tag == Tdentry)
+			n = snprint(buf, nbuf, "%s %llud %s %lluds %s %s %llud\n",
+					tagnames[tag], p->blkno, name, (nsec()-p->atime)/Nsec,
+					locked, p->append!=nil?"data":"nil", p->appendsize);
+		else
+			n = snprint(buf, nbuf, "%s %llud %lluds %s\n",
+					tagnames[tag], p->blkno, (nsec()-p->atime)/Nsec, locked);
+	}
+	return n;
+}
+
+s32
+showhashbuckets(s8 *buf, s32 nbuf)
+{
+	Iobuf *p;
+	Hiob *hp;
+	s32 n;
+	u64 i;
+
+	for(i = n = 0; i < nbuckets; i++){
+		hp=&hiob[i];
+		qlock(hp);
+			if(hp->link != nil){
+				n += snprint(buf+n, nbuf-n, "i %llud ", i);
+				n += showhashbucket(hp->link, buf+n, nbuf-n);
+				for(p = hp->link->fore;
+					p!=hp->link;
+					p=p->fore){
+					n+=showhashbucket(p, buf+n, nbuf-n);
+				}
+				// n+=snprint(buf+n,nbuf-n,"\n");
+			}
+		qunlock(hp);
+	}
+	return n;
+}
+
+/*
+	flushold:
+		flush old unflushed data appended to the Tdentry to the disk
+		remove old Iobuf's until hp->n <= Ncollisions
+	sync: send all Tdata to the disk
+ */
+void
 flushold(void)
 {
 	Iobuf *p;
 	Hiob *hp;
-	u64 nchecked, i;
+	u64 i;
+//	char buf[1024]={'\0'};
 
-	nchecked = 0;
+	/* flush old unflushed data appended to the Tdentry */
+/*	dprint("flushold start\n");
+	showhashbuckets(buf, 1024);
+	dprint(buf);*/
 Again:
 	for(i = 0; i < nbuckets; i++){
 		hp=&hiob[i];
 		qlock(hp);
-		if((p = hp->link) != nil){
-			for(p = p->back; p != hp->link; p = p->back){
+		if(hp->link != nil){
+			for(p = hp->link->back; p!=hp->link; p=p->back){
+				/* all new data from here */
+				if(p->atime > nsec()-Nrefresh)
+					break;
 				if(p->ref == 0 &&
-					p->atime < nsec()-Nrefresh){
-					if(canwlock(p)){
-						/* p->ref cannot change without a lock on the hash bucket */
-						if(p->atime > nsec()-Nrefresh){
-							wunlock(p);
-							continue;
-						}
+					p->tag == Tdentry &&
+					p->append != nil &&
+					canwlock(p)){
+					qunlock(hp);
+					flush(p);
+					goto Again;
+				}
+			}
+			if(p == hp->link &&
+				p->ref == 0 &&
+				p->atime < nsec()-Nrefresh &&
+				p->tag == Tdentry &&
+				p->append != nil &&
+				canwlock(p)){
+				qunlock(hp);
+				flush(p);
+				goto Oldbufs;
+			}
+		}
+		qunlock(hp);
+	}
+
+Oldbufs:
+	/* remove old Iobuf's until hp->n <= Ncollisions */
+	for(i = 0; i < nbuckets; i++){
+		hp=&hiob[i];
+		qlock(hp);
+		if(hp->n > Ncollisions){
+			if(hp->link != nil){
+				for(p = hp->link->back;
+					hp->n > Ncollisions && p!=hp->link;
+					p=p->back){
+					/* all new data from here */
+					if(p->atime > nsec()-Nrefresh)
+						break;
+					if(p->ref == 0 &&
+						canwlock(p)){
 						incref(p); /* not needed */
 						/* remove p from its current position in the lru circular buffer */
 						p->back->fore = p->fore;
@@ -89,47 +193,50 @@
 						flush(p);
 						freememunits(p->xiobuf, p->len);
 						free(p);
-						goto Again;
+						goto Oldbufs;
 					}
 				}
 			}
 		}
-		nchecked++;
 		qunlock(hp);
 	}
-	return i==nbuckets;
 }
 
 u64
 sync(void)
 {
-	Iobuf *p, *s;
+	Iobuf *p;
 	Hiob *hp;
 	u64 nlocked, i;
+	char buf[1024]={'\0'};
 
+	/* flush any unflushed data appended to the Tdentry */
+Resync:
 	nlocked = 0;
-Again:
 	for(i = 0; i < nbuckets; i++){
 		hp=&hiob[i];
 		qlock(hp);
-		if((s = hp->link) != nil){
-			p=s;
-			do{
-				if(p->xiobuf[0] == Tdentry &&
+		if(hp->link != nil){
+			for(p = hp->link->back; p!=hp->link; p=p->back){
+				if(p->tag == Tdentry &&
 					p->append != nil){
-						if(canwlock(p)){
+						if(p->ref == 0 && canwlock(p)){
 							qunlock(hp);
-							if(flush(p) == 0)
-								wunlock(p);
-							goto Again;
-						}else{
-							// cannot be sure about this without a lock
-							// if(p->xiobuf[0] == Tdentry)
+							flush(p);
+							goto Resync;
+						}else
 							nlocked++;
-						}
 				}
-				p = p->back;
-			}while(p != s);
+			}
+			if(p == hp->link &&	p->tag == Tdentry){
+				if(p->ref == 0 &&
+					p->append != nil &&
+					canwlock(p)){
+					qunlock(hp);
+					flush(p);
+					goto Resync;
+				}
+			}
 		}
 		qunlock(hp);
 	}
@@ -159,7 +266,6 @@
 	Iobuf *s, *p;
 
 	hp = &hiob[blkno%nbuckets];
-
 	if(chatty9p > 4)
 		dprint("getbuf blkno %llud blkno%%nbuckets %llud pc 0x%p"
 				" hiob 0x%p hp 0x%p readonly %d\n",
@@ -296,8 +402,8 @@
 	if(readonly){
 		wunlock(p);
 		rlock(p);
-		decref(p);
 	}
+	decref(p);
 	return p;
 }
 
@@ -415,7 +521,7 @@
 	}else{
 		srcbno = p->blkno;
 		if(dowrite){
-			if(p->xiobuf[0] == Tdata){
+			if(p->tag == Tdata){
 				devwrite(p->blkno, p->xiobuf, p->len);
 			}else{
 				if(p->blkno == config.config.srcbno ||
@@ -427,7 +533,7 @@
 				else
 					devwrite(p->blkno+(p->new>p->cur?1:0), p->new, 1);
 			}
-		}else if(p->xiobuf[0] > Tdata && p->xiobuf[0] < MAXTAG){
+		}else if(p->tag > Tdata && p->tag < MAXTAG){
 			/*
 				make the new->ver below the cur->ver so the new gets
 				overwritten on the next access instead of a memcpy() to
@@ -449,13 +555,6 @@
 			}
 		}
 	}
-	if(canwlock(&flushlck)){
-		if(lastflushtime < nsec()-Nrefresh){
-			flushold();
-			lastflushtime = nsec();
-		}else
-			wunlock(&flushlck);
-	}
 }
 
 int
@@ -518,6 +617,7 @@
 		((Dentry*)p->new)->tag = tag;
 		((Dentry*)p->new)->path = qpath;
 	}
+	p->tag = tag;
 }
 
 void *amalloc(u64 n){
@@ -566,12 +666,12 @@
 				p, getcallerpc(&p));
 		return;
 	}
-	dprint("showbuf p 0x%p ref %d readers %d writer %d"
+	dprint("showbuf p 0x%p %s ref %d readers %d writer %d"
 			" blkno %llud len %d"
 			" fore 0x%p back 0x%p"
 			" xiobuf 0x%p"
 			" caller %#p\n",
-			p, p->ref, p->readers, p->writer,
+			p, tagnames[p->tag], p->ref, p->readers, p->writer,
 			p->blkno, p->len,
 			p->fore, p->back,
 			p->xiobuf,
--- a/mafs.c
+++ b/mafs.c
@@ -18,7 +18,7 @@
 static void
 usage(void)
 {
-	fprint(2, "usage: mafs [-Ds] [-r service] [-n service] [-m nmemunits] [-h nbuckets] [-w npendingwrites] file\n");
+	fprint(2, "usage: mafs [-Ds] [-r service] [-n service] [-m nmemunits] [-h nbuckets] file\n");
 	exits("usage");
 }
 
@@ -76,22 +76,22 @@
 	if(size == 0)
 		panic("null size %s", devfile);
 
-	/* 2/3rds of the memory for the pending writes
-		and 1/3rd for the buffer cache
-	 */
 	if(nmemunits == 0)
-		nmemunits = size/Blocksize > 500*KiB ? 500*KiB : size/Blocksize;
+		if(size/Blocksize > 8*MiB)
+			nmemunits = 8*MiB;
+		else if(size/Blocksize < 8*KiB)
+			nmemunits = 8*KiB;
 	if(nbuckets == 0)
 		nbuckets = nmemunits/(4*Ncollisions*Maxdatablockunits);
 	if(nbuckets == 0)
 		nbuckets = 7;
 
-	if(chatty9p){
+//	if(chatty9p){
 		dprint("\nPlan 9 %d-bit file server with %d-deep indirect blocks\n",
 			sizeof(u64)*8, Niblock);
 		dprint("nmemunits %llud nbuckets %llud\n",
 				nmemunits, nbuckets);
-	}
+//	}
 
 	formatinit();
 
--- a/sub.c
+++ b/sub.c
@@ -115,6 +115,7 @@
 	if(buf->readers)
 		panic("freeblockbuf without Bwritable");
 
+	buf->tag = Tblank;
 	/* clear the buf to avoid leaks on reuse */
 	memset(buf->xiobuf, 0, buf->len*Blocksize);
 	bfree(&frees, buf->blkno, buf->len);
--- a/used.c
+++ b/used.c
@@ -99,7 +99,7 @@
 
 	devread(blkno, buf, Metadataunits);
 	recentmetadata(buf, &t, nil);
-	if(checkvalid(blkno, t->tag, t->path, tag, qpath, Metadataunits)){
+	if(checkvalid(blkno, t->tagi, t->path, tag, qpath, Metadataunits)){
 		if(tag == Tind0){
 			for(i = 0; i<Nindperblock; i++){
 				cblkno = t->bufa[i];
@@ -181,7 +181,7 @@
 			return;
 		devread(cblkno, cbuf, Metadataunits);
 		recentmetadata(cbuf, &it, nil);
-		if(it->tag == Tind0+i){
+		if(it->tagi == Tind0+i){
 			walkindir(cblkno, Tind0+i, Tdentry, d->qpath);
 		}else{
 			fprint(2, "invalid indir tag %llud\n", cblkno);
@@ -242,7 +242,7 @@
 		}
 		devread(cblkno, cbuf, Metadataunits);
 		recentmetadata(buf, &it, nil);
-		if(it->tag == Tind0+i){
+		if(it->tagi == Tind0+i){
 			walkindir(cblkno, Tind0+i, Tdata, d->qpath);
 		}else{
 			fprint(2, "invalid indir tag %llud\n", cblkno);