code: mafs

Download patch

ref: 334cd4d87fc9fd8e48183128e9d60de669ab29fe
parent: 16f09290e03ec4fba68b6587dc01c13299c2a6f6
author: 9ferno <gophone2015@gmail.com>
date: Sat Nov 19 09:18:43 EST 2022

copy on write for data blocks

--- a/9p.c
+++ b/9p.c
@@ -1267,13 +1267,13 @@
 		tosend = filesize - offset;
 
 	for(sent = 0; sent < tosend && offset+sent < d->size; ){
-		buf = getdatablkat(d, (offset+sent)/Blocksize, Breadonly);
+		buf = getdatablkat(d, (offset+sent)/Datablocksize, Breadonly);
 		if(buf == nil){
 			putbuf(dbuf);
 			return -1;
 		}
-		n = min(Blocksize-((offset+sent)%Blocksize), tosend-sent);
-		memcpy(rbuf+sent, buf->io->buf+((offset+sent)%Blocksize), n);
+		n = min(Datablocksize-((offset+sent)%Datablocksize), tosend-sent);
+		memcpy(rbuf+sent, buf->io->buf+((offset+sent)%Datablocksize), n);
 		sent += n;
 		putbuf(buf);
 	}
@@ -1305,18 +1305,18 @@
 		overlay data
 	 */
 
-	blkno = rel2abs(d, offset/Blocksize);
+	blkno = rel2abs(d, offset/Datablocksize);
 	if(chatty9p > 1)
 	dprint("update d->name %s d->size %llud offset %llud"
-				" rel2abs(offset/Blocksize %llud) = blkno %llud\n",
-				d->name, d->size, offset, offset/Blocksize, blkno);
+				" rel2abs(offset/Datablocksize %llud) = blkno %llud\n",
+				d->name, d->size, offset, offset/Datablocksize, blkno);
 	buf = getbufchk(blkno, Bwritable, Tdata, d->qid.path);
 	if(buf == nil)
 		return -1;
 
 	/* overlay the new contents */
-	to = offset%Blocksize;
-	howmuch = min(Blocksize-to, wbufsize);
+	to = offset%Datablocksize;
+	howmuch = min(Datablocksize-to, wbufsize);
 	if(chatty9p > 1){
 		dprint("updating buf->blkno %llud offset %llud size %llud\n",
 				buf->blkno, to, howmuch);
@@ -1343,15 +1343,15 @@
 	if(chatty9p > 1)
 		dprint("append wbufsize %d\n", wbufsize);
 
-	if((lastblksize=d->size%Blocksize) == 0){
+	if((lastblksize=d->size%Datablocksize) == 0){
 		/* last block is full, use a new block */
 		if(chatty9p > 1)
 		dprint("append new data block rel2abs d->name %s reli d->size %llud"
-				" d->size/Blocksize %llud\n",
-				d->name, d->size, d->size/Blocksize);
+				" d->size/Datablocksize %llud\n",
+				d->name, d->size, d->size/Datablocksize);
 
 		/* write single block */
-		howmuch = min(Blocksize, wbufsize);
+		howmuch = min(Datablocksize, wbufsize);
 		buf = allocblock(Tdata, d->qid.path);
 		if(buf == nil)
 			return -1;
@@ -1359,7 +1359,7 @@
 		memcpy(buf->io->buf, wbuf, howmuch);
 		putbuf(buf);
 
-		if(addrelative(d, dblkno, d->size/Blocksize, blkno) == 0){
+		if(addrelative(d, dblkno, d->size/Datablocksize, blkno) == 0){
 			panic("could not write Tdata block\n");
 			freeblock(blkno, Tdata, d->qid.path);
 			return -2;
@@ -1368,21 +1368,21 @@
 	}else{
 		/* last block is partially full, fill it up */
 
-		blkno = rel2abs(d, d->size/Blocksize);
+		blkno = rel2abs(d, d->size/Datablocksize);
 		if(blkno == 0)
 			panic("append update rel2abs blkno == 0"
 					" d->name %s reli d->size %llud"
-					" d->size/Blocksize %llud s.blkno %llud\n",
-					d->name, d->size, d->size/Blocksize, blkno);
+					" d->size/Datablocksize %llud s.blkno %llud\n",
+					d->name, d->size, d->size/Datablocksize, blkno);
 		if(chatty9p > 1)
 		dprint("append update rel2abs d->name %s reli d->size %llud"
-				" d->size/Blocksize %llud blkno %llud\n",
-				d->name, d->size, d->size/Blocksize, blkno);
+				" d->size/Datablocksize %llud blkno %llud\n",
+				d->name, d->size, d->size/Datablocksize, blkno);
 		buf = getbufchk(blkno, Bwritable, Tdata, d->qid.path);
 		if(buf == nil)
 			return -1;
 
-		howmuch = min(Blocksize-lastblksize, wbufsize);
+		howmuch = min(Datablocksize-lastblksize, wbufsize);
 		if(chatty9p > 1)
 		dprint("fill lastblksize %llud howmuch %llud\n",
 				lastblksize, howmuch);
@@ -1401,7 +1401,7 @@
 
 	if(d == nil || size <= 0)
 		return 0;
-	n = min(size, Blocksize - d->size%Blocksize);
+	n = min(size, Datablocksize - d->size%Datablocksize);
 	buf = emalloc9p(n);
 	n = append(d, dblkno, buf, n);
 	free(buf);
--- a/TODO
+++ b/TODO
@@ -1,5 +1,6 @@
 test exclusive use file access
 test syncusers()
+not updating Qid.version on writes or changes
 fswstat TODO
 streamline the error codes
 mafswrite():
--- a/all.h
+++ b/all.h
@@ -23,6 +23,10 @@
 	through a linked list.
 	 */
 	Ncollisions = 3,	/* soft limit after which we start reusing older Iobuf's */
+
+	/* for dirty */
+	Add = 1,
+	Remove
 };
 
 typedef	struct	Hiob	Hiob;
@@ -71,15 +75,25 @@
 	RWLock;			/* controls access to this Iobuf */
 	u64	blkno;		/* block number on the disk, primary key */
 	u16	len;		/* number of Units */
-	Iobuf	*fore;	/* for lru */
-	Iobuf	*back;	/* for lru */
+	Iobuf *fore;	/* for lru */
+	Iobuf *back;	/* for lru */
 	union{
 		u8	*xiobuf;	/* "real" buffer pointer */
-		Content *io;	/* cast'able to contents */
-		Dentry *d;
+		Data *io;
+		Metadata *m;
 	};
+	Metadata *use;	/* use this unit for changes */
 
-	/*
+	/* head of a linked list of children with changes yet to be written */
+	Iobuf *changes;
+
+	/* linked list of sibling changes not yet written */
+	u8 change;	/* Add or Remove. Am I being added or removed? */
+	Iobuf *prev, *next;
+
+	u8 *append;		/* appended data added not yet written to disk */
+
+	/* obsolete
 		This field is used by mafs to ensure that Iobufs are not reused
 		while there are pending writes.
 
@@ -105,8 +119,8 @@
 u8 *allocmemunits(u16 len);
 void	freememunits(u8 *m, u16 len);
 int		checktag(Iobuf *p, u8 tag, u64 qpath);
-Iobuf*	getbuf(u64 blkno, u16 len, u8 readonly, u8 freshalloc);
-Iobuf*	getbufchk(u64 blkno, u8 readonly, int tag, u64 qpath);
+Iobuf*	getbuf(u64 blkno, u64 len, u8 readonly, u8 freshalloc);
+Iobuf*	getbufchk(u64 blkno, u64 len, u8 readonly, int tag, u64 qpath);
 void	iobufinit(void);
 void	putbuf(Iobuf *p);
 void	putbuffree(Iobuf *p);
@@ -120,9 +134,9 @@
 u64		pendingwrites(void);
 
 /* routines to manipulate the contents */
-Iobuf*	allocblock(int tag, u64 qpath);
+Iobuf*	allocblocks(u64 len, int tag, u64 qpath);
 void	freeblockbuf(Iobuf *buf);
-void	freeblock(u64 blkno, u16 tag, u64 qpath);
+void	freeblocks(u64 blkno, u64 len, u16 tag, u64 qpath);
 void	fsok(int ok);
 void	init(int doream, u64 size);
 u64		newqpath();
@@ -173,10 +187,6 @@
 int	leadgroup(s16 uid, s16 gid);
 s16	lookupid(char *name);
 u64	min(u64 a, u64 b);
-int	mkqidcmp(Qid*, Dentry*);
-void	mkqid9p1(Qid9p1*, Qid*);
-void	mkqid9p2(Qid*, Qid9p1*, int);
-int	netserve(char*);
 Aux	*newaux(u64 addr, u16 uid);
 u64	newqpath(void);
 void	newstart(void);
--- a/blk.c
+++ b/blk.c
@@ -17,8 +17,8 @@
 	fprint(fd, "pdblkno %llud\n", d->pdblkno);
 	fprint(fd, "pqpath %llud\n", d->pqpath);
 	fprint(fd, "mtime %llud\n", d->mtime);
-	fprint(fd, "qid.path %llud\n", d->qid.path);
-	fprint(fd, "qid.version %ud\n", d->qid.version);
+	fprint(fd, "path %llud\n", d->path);
+	fprint(fd, "version %ud\n", d->version);
 	fprint(fd, "mode %uo\n", d->mode);
 }
 void
@@ -34,9 +34,9 @@
 void
 showsuper(int fd, u8 *d)
 {
-	Super *s;
+	Dentry *s;
 
-	s = (Super*)d;
+	s = (Dentry*)d;
 	fprint(fd, "qidgen %llud\n", s->qidgen);
 	fprint(fd, "fsok %llud\n", s->fsok);
 }
@@ -48,14 +48,14 @@
 
 	showdentryhdr(fd, buf);
 	d = (Dentry*)buf;
-	if(d->path == Qpconfig || d->path == Qpconfig0 || d->path == Qpconfig1)
+	if(d->path == Qpconfig || d->path == Qpconfig0)
 		showconfig(fd, buf);
-	else if(d->path == Qpsuper || d->path == Qpsuper0 || d->path == Qpsuper1)
+	else if(d->path == Qpsuper || d->path == Qpsuper0)
 		showsuper(fd, buf);
 	else if(d->path == Qpmagic)
 		showmagic(fd, buf);
 	else if(d->size <= Ddatasize && (d->mode&DMDIR) == 0 &&
-			d->qid.path != Qproot0 && d->qid.path != Qproot1){
+			d->path != Qproot0){
 		fprint(fd, "%s", d->buf);
 	}else{
 		fprint(fd, "direct blocks\n");
@@ -70,9 +70,9 @@
 showind(int fd, u8 *buf)
 {
 	int j;
-	Content *t;
+	Indirect *t;
 
-	t = (Content*)buf;
+	t = (Indirect*)buf;
 	for(j = 0; j<Nindperblock; j++)
 		fprint(fd, "	%d %llud\n", j, t->bufa[j]);
 }
@@ -79,9 +79,9 @@
 void
 showdata(int fd, u8 *buf)
 {
-	Content *c;
+	Data *c;
 
-	c = (Content*)buf;
+	c = (Data*)buf;
 	fprint(fd, "%s", (s8*)c->buf);
 }
 
@@ -88,31 +88,31 @@
 void
 showblock(int fd, u8 *buf)
 {
-	Content *t;
+	Data *t;
 	Dentry *d;
+	u8 tag;
+	Indirect *r;
 
+	tag = buf[0];
 	d = (Dentry*)buf;
-	if(d->tag == Tblank){
-		fprint(fd, "%s\n", tagnames[d->tag]);
+	t = (Data*)buf;
+	r = (Indirect*)buf;
+	if(tag == Tblank){
+		fprint(fd, "%s\n", tagnames[tag]);
 		return;
-	}else if(d->tag == Tdentry){
-		fprint(fd, "%s %llud\n", tagnames[d->tag], d->path);
+	}else if(tag == Tdentry){
+		fprint(fd, "%s %llud %d\n", tagnames[tag], d->path, d->ver);
 		showdentry(fd, buf);
 		return;
-	}
-	t = (Content*)buf;
-	if(t->tag < Maxtind)
-		fprint(fd, "%s %llud\n", tagnames[t->tag], t->path);
-	if(t->tag == Tdata)
+	}else if(tag == Tdata){
+		fprint(fd, "%s %d %llud %llud\n", tagnames[tag], t->len, t->dblkno, t->path);
 		showdata(fd, buf);
-	else if(t->tag >= Tind0 && t->tag < Maxtind)
+		return;
+	}else if(tag < Maxtind)
+		fprint(fd, "%s %d %llud %llud\n", tagnames[tag], r->ver, r->dblkno, r->path);
+
+	if(t->tag >= Tind0 && t->tag < Maxtind)
 		showind(fd, buf);
 	else if(t->tag != 0 || t->path != 0)
 		fprint(fd, "unknown tag type %d path %llud\n", t->tag, t->path);
-}
-
-u16
-blklen(u16 tag)
-{
-	return (tag == Tdentry || tag == Tblank) ? Dentryunits : Rawblockunits;
 }
--- a/config.c
+++ b/config.c
@@ -5,7 +5,7 @@
 initconfig(u64 dblkno)
 {
 	Iobuf *buf;
-	char *tokens[128], cfg[Blocksize], *nl;
+	char *tokens[128], cfg[Datablocksize], *nl;
 	s32 n, i;
 
 	buf = getbufchk(dblkno, Breadonly, Tdentry, Qpconfig);
--- a/ctl.c
+++ b/ctl.c
@@ -100,14 +100,14 @@
 						"(GiB) free %ulld, used %ulld, total %ulld\n"
 						"(TiB) free %ulld, used %ulld, total %ulld\n",
 						free, used, config.nblocks,
-						free * Unit / MiB,
-						used * Unit / MiB,
+						free * Blocksize / MiB,
+						used * Blocksize / MiB,
 						config.size / MiB,
-						free * Unit / GiB,
-						used * Unit / GiB,
+						free * Blocksize / GiB,
+						used * Blocksize / GiB,
 						config.size / GiB,
-						free * Unit / TiB,
-						used * Unit / TiB,
+						free * Blocksize / TiB,
+						used * Blocksize / TiB,
 						config.size / TiB
 						);
 	else if(config.size > GiB)
@@ -115,11 +115,11 @@
 						"(MiB) free %ulld, used %ulld, total %ulld\n"
 						"(GiB) free %ulld, used %ulld, total %ulld\n",
 						free, used, config.nblocks,
-						free * Unit / MiB,
-						used * Unit / MiB,
+						free * Blocksize / MiB,
+						used * Blocksize / MiB,
 						config.size / MiB,
-						free * Unit / GiB,
-						used * Unit / GiB,
+						free * Blocksize / GiB,
+						used * Blocksize / GiB,
 						config.size / GiB
 						);
 	else if(config.size > MiB)
@@ -126,8 +126,8 @@
 	n += snprint(buf+n, 1024-n, "(blocks) free %ulld, used %ulld, total %ulld\n"
 						"(MiB) free %ulld, used %ulld, total %ulld\n",
 						free, used, config.nblocks,
-						free * Unit / MiB,
-						used * Unit / MiB,
+						free * Blocksize / MiB,
+						used * Blocksize / MiB,
 						config.size / MiB
 						);
 	else
@@ -134,8 +134,8 @@
 	n += snprint(buf+n, 1024-n, "(blocks) free %ulld, used %ulld, total %ulld\n"
 						"(KiB) free %ulld, used %ulld, total %ulld\n",
 						free, used, config.nblocks,
-						free * Unit / KiB,
-						used * Unit / KiB,
+						free * Blocksize / KiB,
+						used * Blocksize / KiB,
 						config.size / KiB
 						);
 	if(req->ifcall.offset < n){
--- a/dat.c
+++ b/dat.c
@@ -10,6 +10,8 @@
 	[Tind0]		"Tind0",
 	[Tind1]		"Tind1",
 	[Tind2]		"Tind2",
+	[Tind3]		"Tind3",
+	[Tind4]		"Tind4",
 
 	/* add more Tind tags here ... */
 };
--- a/dat.h
+++ b/dat.h
@@ -9,10 +9,12 @@
 typedef unsigned long long u64;
 
 typedef	struct	Config	Config;
-typedef	struct	Content	Content;
+typedef	struct	Data	Data;
+typedef struct	Metadata Metadata;
 typedef	struct	Dentryhdr	Dentryhdr;
 typedef	struct	Dentry	Dentry;
-typedef struct	Qid9p1	Qid9p1;
+typedef	struct	Datahdr	Datahdr;
+typedef	struct	Indirect	Indirect;
 typedef	struct	Super	Super;
 typedef	struct	Tlock	Tlock;
 typedef	struct	User	User;
@@ -33,7 +35,7 @@
 	Nsec	= 1000ULL*1000*1000,
 	Usec	= 1000ULL*1000,
 	Msec	= 1000ULL,
-	Nbkp	= 2,
+	Nbkp	= 1,
 };
 
 /*
@@ -48,38 +50,34 @@
  * Nindperblock number of block pointers in a block
  */
 enum {
-	Unit	= 512ULL,		/* minimum data unit size */
-	Dentryunits	= 1,		/* number of units per Tdentry */
-	Rawblockunits= 16,		/* number of units for others */
+	Blocksize	= 512ULL,	/* minimum data unit size */
 
-	Dentrysize	= Dentryunits*Unit,		/* real block size of a Tdentry */
-	/* real block size of others. a multiple of Unit to keep the extents code uniform */
-	Rawblocksize= Rawblockunits*Unit,
-	Blocksize	= Rawblocksize - sizeof(u8 /* tag */) -sizeof(u64 /* path */),
-	Nindperblock= (Blocksize-7)/sizeof(u64),/* number of pointers per block. -7 for pad */
+	Metadataunits	= 2,
+	Metadatablocksize = Metadataunits*Blocksize, /* Keep the original and a copy together */
 
-	Namelen = 129,	/* maximum length of a file name, calculated manually */
+	Maxdatablockunits = 2048,
+	Nindperblock= (Blocksize-3*sizeof(u64))/sizeof(u64),/* number of pointers per block */
+
+	Namelen = 127,	/* maximum length of a file name, calculated manually */
 	Ndblock	= 32,	/* number of direct blocks in a Dentry */
-	Niblock	= 3,	/* maximum depth of indirect blocks, can increase it to 6 without issues */
-	MAXRPC	= Blocksize,/* Tdata block size in bytes */
-	Iounit	= MAXRPC,	/* in bytes, TODO adjust for the 9p header size? */
+	Niblock	= 5,	/* maximum depth of indirect blocks, can increase it to 8 without issues */
 
 	/* global block numbers. The bkp contents locations are calculated by ream() */
 	Bdmagic	= 0,	/* block number of first block. Bmagic conflicts with bio.h */
-	Bdconfig= 1,	/* block number of /adm/config dentry and contents */
-	Bdsuper	= 2,	/* block number of /adm/super dentry and contents */
-	Bdadm	= 3,	/* block number of /adm directory */
-	Bdusers	= 4,	/* block number of /adm/users/ dentry */
+	Bdconfig= 2,	/* block number of /adm/config dentry and contents */
+	Bdsuper	= 4,	/* block number of /adm/super dentry and contents */
+	Bdadm	= 6,	/* block number of /adm directory */
+	Bdusers	= 8,	/* block number of /adm/users/ dentry */
 
 					/* contents of blocks below change on use */ 
-	Bdbkp	= 5,	/* block number of /adm/bkp directory */
-	Bdusersinuse = 6,	/* block number of /adm/users/inuse dentry and contents */
-	Bdfrees = 7,	/* block number of /adm/frees dentry, text file of free extents */
+	Bdbkp	= 10,	/* block number of /adm/bkp directory */
+	Bdusersinuse = 12,	/* block number of /adm/users/inuse dentry and contents */
+	Bdfrees = 14,	/* block number of /adm/frees dentry, text file of free extents */
 
 					/* no user writes allowed on blocks below Bdctl */
-	Bdctl	= 8,	/* block number of /adm/ctl dentry, empty contents, virtual file */
-	Bdusersstaging = 9,/* block number of /adm/users/staging dentry */
-	Bdroot	= 10,	/* block number of root directory */
+	Bdctl	= 16,	/* block number of /adm/ctl dentry, empty contents, virtual file */
+	Bdusersstaging = 18,/* block number of /adm/users/staging dentry */
+	Bdroot	= 20,	/* block number of root directory */
 	Nbused,			/* blocks used up by default */
 	Nminblocks = Nbused+(Nbkp*3), /* number of blocks used by the above and the backup blocks */
 
@@ -100,13 +98,10 @@
 	Qproot		= Bdroot,	/* /, so fscreate() can disallow any create's below */
 
 				/* system qpaths */
-	Qpmagic,	/* magic block Tag.qpath */
-	Qpconfig0,	/* /adm/bkp/config.0 block Tag.qpath */
-	Qpsuper0,	/* /adm/bkp/super.0 block Tag.qpath */
-	Qproot0	,	/* /adm/bkp/root.0 block Tag.qpath */
-	Qpconfig1,	/* /adm/bkp/config.1 block Tag.qpath */
-	Qpsuper1,	/* /adm/bkp/super.1 block Tag.qpath */
-	Qproot1	,	/* /adm/bkp/root.1 block Tag.qpath */
+	Qpmagic = 1,	/* magic block Tag.qpath */
+	Qpconfig0 = 3,	/* /adm/bkp/config.0 block Tag.qpath */
+	Qpsuper0  = 5,	/* /adm/bkp/super.0 block Tag.qpath */
+	Qproot0	  = 21,	/* /adm/bkp/root.0 block Tag.qpath */
 
 	Nqidgen	= 64,
 
@@ -118,38 +113,49 @@
 
 #pragma pack on
 /* DONT TOUCH, this is the disk structure */
-struct Qid9p1
+/* no access time */
+struct Dentryhdr
 {
-	u64 path;	/* unique identifier */
-	u32 version;
+	u8 tag;
+	u8 ver;			/* a counter to do copy on write */
+	s16 uid;
+	s16 gid;
+	s16 muid;		/* 8 */
+	u64 size;		/* 0 for directories. For files, size in bytes of the content - 16 */
+	u64 pdblkno; 	/* block number of the parent directory entry. Will be 0 for root. - 24 */
+	u64 pqpath; 	/* parent qid.path - 32 */
+	u64 mtime;		/* modified time in nano seconds from epoch - 40 */
+	u64 path;		/* unique identifier Qid.path 48 */
+	u32 version;	/* Qid.version 52 */
+	u32 mode;		/* same bits as defined in /sys/include/libc.h:/Dir\.mode/ - 56 */
+	u8 namelen;		/* store name as a counted string 57 */
+	s8 name[Namelen]; /* Namelen = 127 - 184*/
 };
-
-/* DONT TOUCH, this is the disk structure */
-/*
- * no access time
- */
-struct Dentryhdr
+struct Datahdr
 {
 	u8 tag;
-	s8  name[Namelen]; /* 130, Namelen = 129 to align to a u64 after the ids*/
-	s16 uid;		/* 132 */
-	s16 gid;		/* 134 */
-	s16 muid;		/* 136 */
-	u64 size;		/* 0 for directories. For files, size in bytes of the content - 8 */
-	u64 pdblkno; 	/* block number of the parent directory entry. Will be 0 for root. - 16 */
-	u64 pqpath; 	/* parent qid.path - 24 */
-	u64 mtime;		/* modified time in nano seconds from epoch - 32 */
-	Qid9p1	qid;	/* 44 bytes */
-	u32 mode;		/* same bits as defined in /sys/include/libc.h:/Dir\.mode/ - 48 */
+	u8 unused;	/* for alignment and future use */
+	u16 len;
+	u64 dblkno;	/* block number of the directory entry */
+	u64 path;	/* same as qid.path */
 };
 #pragma pack off
 
 enum {
 	/* max possible size of data that can be stuffed into a Dentry */
-	Ddatasize = Dentrysize -sizeof(u64 /* path */) -sizeof(Dentryhdr),
+	Ddatasize = Blocksize -sizeof(u64 /* path */) -sizeof(Dentryhdr),
+	Maxdatablocksize = Maxdatablockunits*Blocksize -sizeof(Datahdr) -sizeof(u64 /* trailing path */),
+	Iounit	= Maxdatablocksize,	/* in bytes, TODO adjust for the 9p header size? */
 };
 
 #pragma pack on
+/* DONT TOUCH, these are all disk structures */
+struct Super
+{
+	u64 qidgen;	/* generator for unique ids. starts from 1024. */
+				/* TODO make fsok a time stamp in nano seconds */
+	u64 fsok;	/* fsck status, using 64 bits to keep it all aligned */
+};
 struct Dentry
 {
 	Dentryhdr;
@@ -162,35 +168,40 @@
 										Tdentry block numbers for directories */
 			u64 iblocks[Niblock];	/* indirect blocks */
 		};
+		Super;
+
 		/* when size <= Dentrysize-184-sizeof(Tag), store the data here itself */
 		s8 buf[Ddatasize];
 	};
 	u64 path;
 };
-/* DONT TOUCH, this is the disk structure */
-struct Super
+struct Indirect
 {
-	Dentryhdr;
-	u64 qidgen;	/* generator for unique ids. starts from 1024. */
-			/* make fsok a time stamp with the highest bit being the fsok flag */
-	u64 fsok;	/* fsck status, using 64 bits to keep it all aligned */
-	u64 path;
+	u8 tag;
+	u8 ver;
+	u8 pad[6];	/* unused, to align to a multiple of 8 */
+	u64 dblkno;	/* block number of the directory entry */
+	u64 bufa[Nindperblock];
+	u64 path;	/* same as qid.path */
 };
-/* DONT TOUCH, this is the disk structure */
-struct Content	/* used to unmarshall the disk contents */
+struct Metadataunit
 {
-	u8 tag;
 	union
 	{
-		u8 buf[Blocksize];
-		struct
-		{
-			u8 pad[7];	/* unused, to align to a multiple of 8 */
-			u64 bufa[Nindperblock];
-		};
+		Indirect;
+		Dentry;
 	};
-	u64 path;	/* same as qid.path */
 };
+struct Metadata
+{
+	struct Metadataunit m[2];
+};
+struct Data		/* used to unmarshall the disk contents */
+{
+	Datahdr;
+	u8 buf[1];	/* upto Maxdatablocksize, followed by u64 qid.path */
+	/* u64 path; same as qid.path at the end of the data content */
+};
 #pragma pack off
 
 /*
@@ -227,12 +238,12 @@
 	User *prev, *next;	/* linked list sorted by id */
 };
 
+/* storing this in ascii to the Bdconfig block */
 struct Bkp
 {
 	u64 srcbno;		/* source of the backup */
 	u64 dest[Nbkp];	/* destinations written to */
 };
-
 struct Config
 {
 	u64 size;	/* size from dirfstat */
@@ -327,8 +338,10 @@
 					and Tdentry block numbers for directories.*/
 	Tind1,		/* contains a list of Tind0 block numbers */
 	Tind2,		/* contains a list of Tind1 block numbers */
+	Tind3,		/* contains a list of Tind1 block numbers */
+	Tind4,		/* contains a list of Tind1 block numbers */
 				/* gap for more indirect block depth in future.
-					It can be put upto Tind5 without needing any code changes */
+					It can be put upto Tind7 without needing any code changes */
 	Maxtind,	/* should be Tind0+Niblock */
 	MAXTAG,
 
--- a/dev.c
+++ b/dev.c
@@ -23,9 +23,8 @@
 {
 	s32 n;
 
-	if((n= pread(devfd, b, len*Unit, blkno*Unit)) != len*Unit)
+	if((n= pread(devfd, b, len*Blocksize, blkno*Blocksize)) != len*Blocksize)
 		panic("devread failed: %r\n");
-	/* print("devread i %d n %d\n", i, n); */
 	return n;
 }
 
@@ -34,7 +33,7 @@
 {
 	s32 wn;
 
-	if((wn = pwrite(devfd, b, len*Unit, blkno*Unit)) != len*Unit)
+	if((wn = pwrite(devfd, b, len*Blocksize, blkno*Blocksize)) != len*Blocksize)
 		panic("devwrite failed: %r\n");
 	return wn;
 }
--- a/free.c
+++ b/free.c
@@ -91,7 +91,7 @@
 
 	buf = emalloc(Rawblocksize);
 	devread(blkno, buf, Rawblockunits);
-	loadextents(&frees, buf, Blocksize);
+	loadextents(&frees, buf, Datablocksize);
 	free(buf);
 }
 
--- a/iobuf.c
+++ b/iobuf.c
@@ -339,7 +339,8 @@
 			memcpy(buf, p->d->buf, Ddatasize);
 		}
 		if(synchronouswrites){
-			devwrite(p->blkno, p->xiobuf, p->len);
+			if(p->blkno < 10)
+				devwrite(p->blkno, p->xiobuf, p->len);
 			if(chkwunlock(p) == 0){
 				showbuf(p);
 				panic("putbuf: chkwunlock(p) == 0 called by %#p\n", getcallerpc(&p));
--- a/mafs.c
+++ b/mafs.c
@@ -84,13 +84,13 @@
 		and 1/3rd for the buffer cache
 	 */
 	if(nmemunits == 0)
-		nmemunits = size/Unit > 8*MiB ? 8*MiB : size/Unit;
-	if(nmemunits < KiB)
-		nmemunits = KiB;
-	if(npendingwrites == 0)
-		npendingwrites = nmemunits/(2*Rawblockunits);
+		nmemunits = size/Blocksize > 8*MiB ? 8*MiB : size/Blocksize;
+	if(nmemunits < 16*MiB)
+		nmemunits = 16*MiB;
 	if(nbuckets == 0)
-		nbuckets = nmemunits/(4*Ncollisions*Rawblockunits);
+		nbuckets = nmemunits/(4*Ncollisions*Maxdatablockunits);
+	if(nbuckets == 0)
+		nbuckets = 7;
 
 	if(chatty9p){
 		dprint("\nPlan 9 %d-bit file server with %d-deep indirect blocks\n",
--- a/mkfile
+++ b/mkfile
@@ -1,6 +1,6 @@
 </$objtype/mkfile
 
-TARG=mfs mafs used reconcile block find free unused updatefrees
+TARG=mafs used reconcile block find free unused updatefrees # mfs
 
 OFILES=\
 	9p.$O\
--- a/sub.c
+++ b/sub.c
@@ -7,15 +7,15 @@
 {
 	u64 qpath;
 	Iobuf *sb;
-	Super *s;
+	Dentry *s;
 	s32 on, nn;
 	s8 buf[Ddatasize-16];
 
-	sb = getbufchk(Bdsuper, Bwritable, Tdentry, Qpsuper);
+	sb = getbufchk(Bdsuper, Metadataunits, Bwritable, Tdentry, Qpsuper);
 	if(sb == nil){
 		panic("newqpath: sb == nil\n");
 	}
-	s = (Super*)sb->d;
+	s = (Dentry*)sb->use;
 	on = snprint(buf, Ddatasize-16, "%llud", s->qidgen);
 	qpath = s->qidgen++;
 	nn = snprint(buf, Ddatasize-16, "%llud", s->qidgen);
@@ -64,9 +64,9 @@
 int
 isbkp(u64 bno)
 {
-	if(bno == config.config.dest[0] || bno == config.config.dest[1] ||
-		bno == config.super.dest[0] || bno == config.super.dest[1] ||
-		bno == config.root.dest[0] || bno == config.root.dest[1])
+	if(bno == config.config.dest[0] ||
+		bno == config.super.dest[0] ||
+		bno == config.root.dest[0])
 		return 1;
 	else
 		return 0;
@@ -74,13 +74,11 @@
 
 /* making the assumption that all allocations are not readonly */
 Iobuf *
-allocblock(int tag, u64 qpath)
+allocblocks(u64 len, int tag, u64 qpath)
 {
 	u64 blkno;
 	Iobuf *buf;
-	u16 len;
 
-	len = blklen(tag);
 	blkno = balloc(&frees, len);
 	if(blkno == 0)
 		return nil;	/* the caller should trigger an Efull message */
@@ -87,10 +85,12 @@
 
 	if(chatty9p > 1)
 		dprint("alloc %llud\n", blkno);
+
 	/* cannot do getbufchk() unless we ream the whole disk at start */
 	buf = getbuf(blkno, len, Bwritable, Bfreshalloc);
+
 	/* clear the buf to avoid leaks on reuse */
-	memset(buf->xiobuf, 0, len*Unit);
+	memset(buf->xiobuf, 0, len*Blocksize);
 	settag(buf, tag, qpath);
 	return buf;
 }
@@ -103,7 +103,7 @@
 		panic("freeblockbuf without Bwritable");
 
 	/* clear the buf to avoid leaks on reuse */
-	memset(buf->xiobuf, 0, buf->len*Unit);
+	memset(buf->xiobuf, 0, buf->len*Blocksize);
 	bfree(&frees, buf->blkno, buf->len);
 	putbuffree(buf);
 }
@@ -110,7 +110,7 @@
 
 /* add the block to the extents used to manage free blocks */
 void
-freeblock(u64 blkno, u16 tag, u64 qpath)
+freeblocks(u64 blkno, u64 len, u16 tag, u64 qpath)
 {
 	Iobuf *buf;
 
@@ -120,7 +120,7 @@
 		return;
 	}
 
-	buf = getbufchk(blkno, Bwritable, tag, qpath);
+	buf = getbufchk(blkno, len, Bwritable, tag, qpath);
 	if(buf == nil)
 		dprint("%s",errstring[Ephase]);
 	freeblockbuf(buf);
@@ -149,13 +149,13 @@
 fsok(int ok)
 {
 	Iobuf *sb;
-	Super *s;
+	Dentry *s;
 
-	sb = getbufchk(Bdsuper, Bwritable, Tdentry, Qpsuper);
+	sb = getbufchk(Bdsuper, Metadataunits, Bwritable, Tdentry, Qpsuper);
 	if(sb == nil){
 		panic("fsok: sb == nil\n");
 	}
-	s = (Super*)sb->d;
+	s = (Dentry*)sb->use;
 	s->fsok = ok;
 	if(chatty9p > 1){
 		dprint("fsok ok %d\n", ok);
@@ -177,10 +177,12 @@
 	Iobuf *b;
 	Dentry *d;
 
-	b = getbuf(dblkno, Dentryunits, Bwritable, Bfreshalloc);
-	memset(b->io, 0, Dentrysize);
+	b = getbuf(dblkno, Metadataunits, Bwritable, Bfreshalloc);
+	memset(b->m, 0, Metadatablocksize);
 	settag(b, Tdentry, qpath);
-	d = b->d;
+	d = (Dentry*)b->use;
+	d->ver++;
+	d->namelen = strlen(name);
 	strcpy(d->name, name);
 	d->uid = d->muid = d->gid = -1;
 	d->mode =
@@ -187,8 +189,8 @@
 		((DMREAD) << 6) |
 		((DMREAD) << 3) |
 		((DMREAD) << 0);
-	d->qid.path = qpath;
-	d->qid.version = 0;
+	d->path = qpath;
+	d->version = 0;
 	d->mtime = nsec();
 	d->size = size;
 	d->pdblkno = pdblkno;
@@ -204,7 +206,7 @@
  */
 char magic[] = "m[a]fs device\n";
 void
-reamdefaults(u64 bdconfig0, u64 bdsuper0, u64 bdroot0, u64 bdconfig1, u64 bdsuper1, u64 bdroot1)
+reamdefaults(u64 bdconfig0, u64 bdsuper0, u64 bdroot0)
 {
 	Iobuf *b;
 	Dentry *d;
@@ -221,10 +223,12 @@
 					"10006:%s:%s:\n", user, user, user);
 
 	/* cannot show this in /adm though as the block number is 0 */
-	b = getbuf(Bdmagic, Dentryunits, Bwritable, Bfreshalloc);
-	memset(b->d, 0, Dentrysize);
+	b = getbuf(Bdmagic, Metadataunits, Bwritable, Bfreshalloc);
+	memset(b->m, 0, Metadatablocksize);
 	settag(b, Tdentry, Qpmagic);
-	d = b->d;
+	d = (Dentry*)b->use;
+	d->ver++;
+	d->namelen = 5;
 	strncpy(d->name, "magic", 6);
 	d->uid = d->muid = d->gid = -1;
 	d->mode = DMDIR |
@@ -231,20 +235,22 @@
 		((DMREAD|DMWRITE|DMEXEC) << 6) |
 		((DMREAD|DMWRITE|DMEXEC) << 3) |
 		((DMREAD|DMWRITE|DMEXEC) << 0);
-	d->qid.path = Qpmagic;
-	d->qid.version = 0;
+	d->path = Qpmagic;
+	d->version = 0;
 	d->mtime = nsec();
 	d->pdblkno = Bdadm;
 	d->pqpath = Qpadm;
 	n = snprint((s8*)d->buf, Ddatasize, "%s%llud\n",
-			magic, Unit);
+			magic, Blocksize);
 	d->size = n;
 	putbuf(b);
 
-	b = getbuf(Bdadm, Dentryunits, Bwritable, Bfreshalloc);
-	memset(b->d, 0, Dentrysize);
+	b = getbuf(Bdadm, Metadataunits, Bwritable, Bfreshalloc);
+	memset(b->m, 0, Metadatablocksize);
 	settag(b, Tdentry, Qpadm);
-	d = b->d;
+	d = (Dentry*)b->use;
+	d->ver++;
+	d->namelen = 3;
 	strncpy(d->name, "adm", 4);
 	d->uid = d->muid = d->gid = -1;
 	d->mode = DMDIR |
@@ -251,8 +257,8 @@
 		((DMREAD|DMWRITE|DMEXEC) << 6) |
 		((DMREAD|DMWRITE|DMEXEC) << 3) |
 		((DMREAD|DMWRITE|DMEXEC) << 0);
-	d->qid.path = Qpadm;
-	d->qid.version = 0;
+	d->path = Qpadm;
+	d->version = 0;
 	d->mtime = nsec();
 	d->pdblkno = Bdroot;
 	d->pqpath = Qproot;
@@ -264,10 +270,12 @@
 	d->dblocks[5] = Bdctl;
 	putbuf(b);
 
-	b = getbuf(Bdbkp, Dentryunits, Bwritable, Bfreshalloc);
-	memset(b->d, 0, Dentrysize);
+	b = getbuf(Bdbkp, Metadataunits, Bwritable, Bfreshalloc);
+	memset(b->m, 0, Metadatablocksize);
 	settag(b, Tdentry, Qpbkp);
-	d = b->d;
+	d = (Dentry*)b->use;
+	d->ver++;
+	d->namelen = 3;
 	strncpy(d->name, "bkp", 4);
 	d->uid = d->muid = d->gid = -1;
 	d->mode = DMDIR |
@@ -274,8 +282,8 @@
 		((DMREAD|DMWRITE|DMEXEC) << 6) |
 		((DMREAD|DMWRITE|DMEXEC) << 3) |
 		((DMREAD|DMWRITE|DMEXEC) << 0);
-	d->qid.path = Qpbkp;
-	d->qid.version = 0;
+	d->path = Qpbkp;
+	d->version = 0;
 	d->mtime = nsec();
 	d->size = strlen(users)+1;
 	d->pdblkno = Bdadm;
@@ -283,15 +291,14 @@
 	d->dblocks[0] = bdconfig0;
 	d->dblocks[1] = bdsuper0;
 	d->dblocks[2] = bdroot0;
-	d->dblocks[3] = bdconfig1;
-	d->dblocks[4] = bdsuper1;
-	d->dblocks[5] = bdroot1;
 	putbuf(b);
 
-	b = getbuf(Bdusers, Dentryunits, Bwritable, Bfreshalloc);
-	memset(b->d, 0, Dentrysize);
+	b = getbuf(Bdusers, Metadataunits, Bwritable, Bfreshalloc);
+	memset(b->m, 0, Metadatablocksize);
 	settag(b, Tdentry, Qpusers);
-	d = b->d;
+	d = (Dentry*)b->use;
+	d->ver++;
+	d->namelen = 5;
 	strncpy(d->name, "users", 6);
 	d->uid = d->muid = d->gid = -1;
 	d->mode = DMDIR |
@@ -298,8 +305,8 @@
 		((DMREAD|DMWRITE|DMEXEC) << 6) |
 		((DMREAD|DMWRITE|DMEXEC) << 3) |
 		((DMREAD|DMWRITE|DMEXEC) << 0);
-	d->qid.path = Qpusers;
-	d->qid.version = 0;
+	d->path = Qpusers;
+	d->version = 0;
 	d->mtime = nsec();
 	d->size = strlen(users)+1;
 	d->pdblkno = Bdadm;
@@ -308,10 +315,12 @@
 	d->dblocks[1] = Bdusersstaging;
 	putbuf(b);
 
-	b = getbuf(Bdusersinuse, Dentryunits, Bwritable, Bfreshalloc);
-	memset(b->d, 0, Dentrysize);
+	b = getbuf(Bdusersinuse, Metadataunits, Bwritable, Bfreshalloc);
+	memset(b->m, 0, Metadatablocksize);
 	settag(b, Tdentry, Qpusersinuse);
-	d = b->d;
+	d = (Dentry*)b->use;
+	d->ver++;
+	d->namelen = 5;
 	strncpy(d->name, "inuse", 6);
 	d->uid = d->muid = d->gid = -1;
 	d->mode =
@@ -318,8 +327,8 @@
 		((DMREAD) << 6) |
 		((DMREAD) << 3) |
 		((DMREAD) << 0);
-	d->qid.path = Qpusersinuse;
-	d->qid.version = 0;
+	d->path = Qpusersinuse;
+	d->version = 0;
 	d->mtime = nsec();
 	d->size = userslen;
 	d->pdblkno = Bdusers;
@@ -327,10 +336,12 @@
 	strcpy((s8*)d->buf, users);
 	putbuf(b);
 
-	b = getbuf(Bdroot, Dentryunits, Bwritable, Bfreshalloc);
-	memset(b->d, 0, Dentrysize);
+	b = getbuf(Bdroot, Metadataunits, Bwritable, Bfreshalloc);
+	memset(b->m, 0, Metadatablocksize);
 	settag(b, Tdentry, Qproot);
-	d = b->d;
+	d = (Dentry*)b->use;
+	d->ver++;
+	d->namelen = 1;
 	strncpy(d->name, "/", 5);
 	d->uid = d->muid = -1;
 	d->gid = -1;
@@ -338,8 +349,8 @@
 		((DMREAD|DMWRITE|DMEXEC) << 6) |
 		((DMREAD|DMWRITE|DMEXEC) << 3) |
 		((DMREAD|DMWRITE|DMEXEC) << 0);
-	d->qid.path = Qproot;
-	d->qid.version = 0;
+	d->path = Qproot;
+	d->version = 0;
 	d->mtime = nsec();
 	d->dblocks[0] = Bdadm;
 	putbuf(b);
@@ -356,16 +367,18 @@
 superream(u64 size, u64 nblocks)
 {
 	Iobuf *sbuf;
-	Super *s;
+	Dentry *s;
 	u64 nbused;
 
 	nbused = Nbused;
-	sbuf = getbuf(Bdsuper, Dentryunits, Bwritable, Bfreshalloc);
+	sbuf = getbuf(Bdsuper, Metadataunits, Bwritable, Bfreshalloc);
 	if(sbuf == nil)
 		panic("superream: sbuf == nil");
-	memset(sbuf->d, 0, Dentrysize);
+	memset(sbuf->m, 0, Metadatablocksize);
 	settag(sbuf, Tdentry, Qpsuper);
-	s = (Super*)sbuf->d;
+	s = (Dentry*)sbuf->use;
+	s->ver++;
+	s->namelen = 5;
 	strncpy(s->name, "super", 6);
 	s->uid = s->muid = s->gid = -1;
 	s->mode =
@@ -372,8 +385,8 @@
 		((DMREAD) << 6) |
 		((DMREAD) << 3) |
 		((DMREAD) << 0);
-	s->qid.path = Qpsuper;
-	s->qid.version = 0;
+	s->path = Qpsuper;
+	s->version = 0;
 	s->mtime = nsec();
 	s->size = 18;
 	s->pdblkno = Bdadm;
@@ -386,11 +399,8 @@
 	config.size = size;
 	config.nblocks = nblocks;
 	config.config.dest[0] = nblocks-Bdconfig;
-	config.config.dest[1] = nbused+((nblocks-nbused)/2)-Bdconfig;
 	config.super.dest[0] = nblocks-Bdsuper;
-	config.super.dest[1] = nbused+((nblocks-nbused)/2)-Bdsuper;
 	config.root.dest[0] = nblocks-3;
-	config.root.dest[1] = nbused+((nblocks-nbused)/2)-3;
 
 	reamfile(config.config.dest[0], Qpconfig0, "config.0",
 			 0, Bdbkp, Qpbkp, config.config.dest[0]);
@@ -398,28 +408,19 @@
 			 0, Bdbkp, Qpbkp, config.super.dest[0]);
 	reamfile(config.root.dest[0], Qproot0, "root.0",
 			 0, Bdbkp, Qpbkp, config.root.dest[0]);
-
-	reamfile(config.config.dest[1], Qpconfig1, "config.1",
-			 0, Bdbkp, Qpbkp, config.config.dest[1]);
-	reamfile(config.super.dest[1], Qpsuper1, "super.1",
-			 0, Bdbkp, Qpbkp, config.super.dest[1]);
-	reamfile(config.root.dest[1], Qproot1, "root.1",
-			 0, Bdbkp, Qpbkp, config.root.dest[1]);
 	putbuf(sbuf);
 
 	if(chatty9p > 1)
-	dprint("backup config %llud %llud"
-		   " super %llud %llud"
-		   " root %llud %llud\n",
-				config.config.dest[0], config.config.dest[1],
-				config.super.dest[0], config.super.dest[1],
-				config.root.dest[0], config.root.dest[1]);
+	dprint("backup config %llud"
+		   " super %llud"
+		   " root %llud\n",
+				config.config.dest[0],
+				config.super.dest[0],
+				config.root.dest[0]);
 
-	reamdefaults(config.config.dest[0], config.super.dest[0], config.root.dest[0],
-				 config.config.dest[1], config.super.dest[1], config.root.dest[1]);
+	reamdefaults(config.config.dest[0], config.super.dest[0], config.root.dest[0]);
 
-	bfree(&frees, config.config.dest[1]+1, config.root.dest[0]-config.config.dest[1]-1);
-	bfree(&frees, nbused, config.root.dest[1]-nbused);
+	bfree(&frees, nbused, config.root.dest[0]-nbused);
 	if(chatty9p > 1)
 		showextents(2, "free extents: ", &frees);
 	if(chatty9p > 1)
@@ -442,24 +443,24 @@
 void
 ream(u64 size)
 {
-	char buf[Unit];
+	char buf[Blocksize];
 	int i;
 	u64 nblocks;
 
-	nblocks = size/Unit;
+	nblocks = size/Blocksize;
 	if(nblocks <= Nminblocks)
 		panic("not enough space");
 
 	if(chatty9p > 1){
-		dprint("%s %s ream %llud bytes into %llud units of %d bytes\n",
-				service, devfile, size, nblocks, Unit);
-		dprint("	(dentry size: raw %d bytes)\n", Dentrysize);
-		dprint("	(data block size: raw %d bytes, usable %d bytes)\n",
-				Rawblocksize, Blocksize);
+		dprint("%s %s ream %llud bytes into %llud blocks of %d bytes\n",
+				service, devfile, size, nblocks, Blocksize);
+		dprint("	(dentry size: raw %d bytes)\n", Metadatablocksize);
+		dprint("	(data block size: usable %d bytes)\n",
+				Maxdatablocksize);
 		dprint("	(name length: %d bytes)\n", Namelen);
 	}
 
-	memset(buf, 0, Unit);
+	memset(buf, 0, Blocksize);
 	for(i = 0; i < Nbused; i++)
 		devwrite(i, buf, 1);
 
@@ -478,7 +479,7 @@
 {
 	u32 unitsize;
 	Iobuf *sb, *b;
-	Super *s;
+	Dentry *s;
 	s8 *rptr;
 
 	if(doream)
@@ -489,30 +490,30 @@
 	}
 
 	/* check magic */
-	b = getbufchk(Bdmagic, Breadonly, Tdentry, Qpmagic);
+	b = getbufchk(Bdmagic, Metadataunits, Breadonly, Tdentry, Qpmagic);
 	if(b == nil){
 		panic("Invalid magic: %s",errstring[Ephase]);
 		return;
 	}
-	if(strncmp((s8*)b->d->buf,magic,strlen(magic)) != 0){
+	if(strncmp((s8*)((Dentry*)b->use)->buf,magic,strlen(magic)) != 0){
 		print("init: bad magic -%s-", (s8*)b->io+256);
 		panic("bad magic");
 	}
-	unitsize = strtoul((s8*)b->d->buf+strlen(magic), &rptr, 10);
-	if(unitsize != Unit){
-		print("init incorrect block size Unit %llud unitsize %d\n",
-				Unit, unitsize);
-		panic("bad Unit != unitsize");
+	unitsize = strtoul((s8*)((Dentry*)b->use)->buf+strlen(magic), &rptr, 10);
+	if(unitsize != Blocksize){
+		print("init incorrect block size Blocksize %llud unitsize %d\n",
+				Blocksize, unitsize);
+		panic("bad Blocksize != unitsize");
 	}
 	putbuf(b);
 
 	/* check super */
-	sb = getbufchk(Bdsuper, Breadonly, Tdentry, Qpsuper);
+	sb = getbufchk(Bdsuper, Metadataunits, Breadonly, Tdentry, Qpsuper);
 	if(sb == nil){
 		panic("Invalid super: %s",errstring[Ephase]);
 		return;
 	}
-	s = (Super*)sb->io;
+	s = (Dentry*)sb->use;
 	if(s->fsok != 1 || config.size != size)
 		panic(errstring[Edirty]);
 
--- a/tag.c
+++ b/tag.c
@@ -88,9 +88,8 @@
 
 /* blocks above this index have this tag
 	For example,
-		Tind0 starts from a reli >= 24
-		Tind1 starts from a reli >= 74
-		Tind2 starts from a reli >= 3100
+		Tind0 starts from a reli >= Ndblock
+		Tind1 starts from a reli >= Ndblock+Nindperblock
  */
 u64
 tagstartreli(u8 tag)
--- a/tests/sizes.c
+++ b/tests/sizes.c
@@ -9,32 +9,32 @@
 	int t;
 	u64 n;
 
-	print("Unit %llud Dentrysize %llud Rawblocksize %llud\n",
-			Unit, Dentrysize, Rawblocksize);
+	print("Blocksize %llud Metadataunits %d Maxdatablockunits %d\n",
+			Blocksize, Metadataunits, Maxdatablockunits);
 	print("Dentryhdr size %d Ddatasize %llud\n",
 			sizeof(Dentryhdr), Ddatasize);
 	print("Dentry size %d Namelen %d\n",
 			sizeof(Dentry), Namelen);
 	print("Namelen %d Ndblock %d Niblock %d\n", Namelen, Ndblock, Niblock);
-	print("Blocksize %llud Nindperblock %llud\n",
-			Blocksize, Nindperblock);
+	print("Nindperblock %llud Maxdatablocksize %llud\n",
+			Nindperblock, Maxdatablocksize);
 
 	for (t = Tind0; t < Maxtind; t++) {
 		n = nperindunit(t);
 		print("A %s unit points to %lld data blocks (%llud bytes)\n",
-			 tagnames[t], n, n*Blocksize);
+			 tagnames[t], n, n*Maxdatablocksize);
 		print("		block points to %llud data blocks\n", nperiblock(t));
 		print("		reli start %llud	max %llud\n",
 			tagstartreli(t), maxreli(t));
-		print("		max size %llud*Blocksize = %llud bytes",
+		print("		max size %llud*Maxdatablocksize = %llud bytes",
 				maxblocks(t),
-				maxblocks(t)*Blocksize);
-		if(maxblocks(t)*Blocksize/(TiB) > 0)
-			print("	= %llud TiB\n",maxblocks(t)*Blocksize/(TiB));
-		else if(maxblocks(t)*Blocksize/(GiB) > 0)
-			print("	= %llud GiB\n",maxblocks(t)*Blocksize/(GiB));
-		else if(maxblocks(t)*Blocksize/(MiB) > 0)
-			print("	= %llud MiB\n",maxblocks(t)*Blocksize/(MiB));
+				maxblocks(t)*Maxdatablocksize);
+		if(maxblocks(t)*Maxdatablocksize/(TiB) > 0)
+			print("	= %llud TiB\n",maxblocks(t)*Maxdatablocksize/(TiB));
+		else if(maxblocks(t)*Maxdatablocksize/(GiB) > 0)
+			print("	= %llud GiB\n",maxblocks(t)*Maxdatablocksize/(GiB));
+		else if(maxblocks(t)*Maxdatablocksize/(MiB) > 0)
+			print("	= %llud MiB\n",maxblocks(t)*Maxdatablocksize/(MiB));
 		else
 			print("\n");
 	}
--- a/updatefrees.c
+++ b/updatefrees.c
@@ -57,9 +57,9 @@
 	nfreesize = read(fd, frees, Rawblocksize);
 	if(nfreesize <= 0)
 		sysfatal("updatefrees: nfreesize %d <= 0\n", nfreesize);
-	if(nfreesize > Blocksize)
-		sysfatal("updatefrees: unsupported nfreesize %d > Blocksize %llud\n",
-					nfreesize, Blocksize);
+	if(nfreesize > Datablocksize)
+		sysfatal("updatefrees: unsupported nfreesize %d > Datablocksize %llud\n",
+					nfreesize, Datablocksize);
 	close(fd);
 
 	freeblkno = atoll((s8*)frees);