code: mafs

Download patch

ref: a28ab4b24201666d434ef01e34758d5f034659c0
parent: 2a4b2263ba485afc5bed8a485c8220ca485eadd4
author: 9ferno <gophone2015@gmail.com>
date: Thu Nov 24 21:07:35 EST 2022

updated documentation for copy on write and allocate on flush

--- a/docs/mafs.ms
+++ b/docs/mafs.ms
@@ -8,21 +8,17 @@
 .RT
 .ft B
 .ce
-M[a]fs - Plan 9 userspace file systems
+Mafs - Plan 9 userspace file systems
 .ft R
 .sp
-Mfs and Mafs wants you to be able to understand it, so you can be self-sufficient and fix a crash at two in the morning or satisfy your need for speed or a feature. This empowerment is priceless for those with skin in the game.
+Mafs wants you to be able to understand it, so you can be self-sufficient and fix a crash at two in the morning or satisfy your need for speed or a feature. This empowerment is priceless for those with skin in the game.
 .sp
-Mfs and Mafs are user space file systems to provide system stability and security. They are based on kfs.
+Mafs is a user space file systems to provide system stability and security. It is based on kfs.
 .sp
 As this document aims to also provide working knowledge, it gratuitously uses the actual commands and the relevant C data structure definitions to convey information.
 .sp
-Mfs writes synchronously to the disk. It ensures that what has been said to be written has been passed along to the disk driver. Mafs writes asynchronously to the disk. It stores the writes in memory for a writer process to write to the disk at leisure.
-.sp
-This document uses the word M[a]fs to refer to both mfs and mafs.
-.sp
 .ft B
-Mfs Workflow
+Mafs Workflow
 .ft R
 .sp
 .PS
@@ -64,65 +60,17 @@
 	line <-> from Buffercache.ne - 0,0.1i to Inmemory.sw + 0,0.1i
 .PE
 .sp
-.ne 14
-.ft B
-Mafs Workflow
-.ft R
 .sp
-.PS
-right;
-{
-	Client: box invis height 4*boxht wid 2*boxwid "" "" "" "Chan.aux has" "file offset, etc.";
-	"Client" at Client.n
-	line from Client.ne to Client.se
-}
-move 2*boxwid
-{
-	Multiple: box invis
-	{
-		" multiple" at Multiple.nw - 0,0.1 ljust
-		" workers" at Multiple.sw + 0,0.1 ljust
-		line <-> from Client to Multiple.w "9p" above
-	}
-	move 0.5*boxwid
-	Abstractions: box invis "Abstractions"
-	{ "Directory" "File" at Abstractions.s }
-	move 0.75*boxwid
-	Datastructures: box invis "Data Structures"
-	{ "Dentry" at Datastructures.s }
-	Buffercache: box invis "Buffer cache" "used blocks" with .sw at Datastructures.ne + 0.5i,0
-	Extents: box invis "Extents" "free blocks" with .nw at Datastructures.se + 0.5i,0
-	move 0.5*boxwid
-	Writer: box invis "writer" with .nw at Buffercache.ne + 0.4i,0
-	Inmemory: box invis "In-memory" "block contents" with .sw at Buffercache.n + 0.5i,0
-	down
-	move 0.5*boxwid
-	Disk: box "Disk" "blocks" height 1.5*boxht with .sw at Extents.se + 0.4i,0
-}
-	line <-> from Multiple.e to Abstractions.w - 0.1i,0
-	line <-> from Abstractions.e + 0.1i,0 to Datastructures.w - 0.2i,0
-	line <-> from Datastructures.e + 0,0.1i to Buffercache.w - 0.1i,0
-	line <-> from Datastructures.e - 0,0.1i to Extents.w
-	line <- from Buffercache.se + 0.1i,0 to Disk.w
-	line -> from Buffercache.e + 0.1i,0 to Writer.w
-	line -> from Writer.s + 0,0.1i to Disk.n
-	line <-> from Extents.e to Disk.w
-	line <-> from Buffercache.s to Extents.n
-	line <-> from Buffercache.ne - 0,0.1i to Inmemory.sw + 0,0.1i
-	line <-> from Writer.n - 0,0.1i to Inmemory.s + 0.2i,0.1i
-.PE
-.sp
-.sp
 .ft B
 Disk Contents
 .ft R
 .sp
-M[a]fs organizes and saves content on a disk as directories and files, just like any other filesystem.
+Mafs organizes and saves content on a disk as directories and files, just like any other filesystem.
 .sp
-The unit of storage is a logical block (not physical sector) of data. Disk space is split into 512 byte units. A directory entry block uses 1 unit (512 bytes) and a data block uses 16 units (8192 bytes).
+The unit of storage is a logical block (not physical sector) of data. Disk space is split into blocks of 512 bytes. A directory entry uses 2 blocks (1KiB) and a data block could use upto 2048 blocks (1MiB).
 .sp
 .ne 14
-A sample disk of 2048 bytes with 4 units.
+A sample disk of 2048 bytes with 4 blocks.
 .PS
 right
 {
@@ -145,7 +93,7 @@
 	box height 4*boxht;
 	move 0.2i
 	"disk of" " 2048 bytes"
-	"Unit  " at Block0.nw rjust
+	"Block  " at Block0.nw rjust
 	"0  " at Block0.w rjust
 	"1  " at Block1.w rjust
 	"2  " at Block2.w rjust
@@ -161,17 +109,19 @@
 	Tblank = 0,
 	Tfree  = 0,	/* free block */
 	Tnone  = 0,
-	Tdentry,		/* directory entry, size = Dentrysize */
-				/* Tdata & indirect blocks are last, to allow for greater depth */
 	Tdata,		/* actual file contents */
+	Tdentry,	/* directory entry, size = Dentrysize */
+				/* Tdata & indirect blocks are last, to allow for greater depth */
 	Tind0,		/* contains a list of Tdata block numbers for files
 					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 */
-	Maxtind,		/* should be Tind0+Niblock */
-	MAXTAG,
+					It can be put upto Tind7 without needing any code changes */
+	Maxtind,	/* should be Tind0+Niblock */
+	MAXTAG = Maxtind,
 
 	Tmaxind = Maxtind - 1,
 };
@@ -187,49 +137,54 @@
 .sp
 A block number of zero represents the end of the file's contents. If a file is truncated, the data and indirect blocks are given up and the dentry.dblocks[0] = 0.
 .sp
-M[a]fs does not store the last access time of a file or directory.
+Mafs does not store the last access time of a file or directory.
 .ne 20
 .sp
 A directory entry is defined as:
 .nf
 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 */
+	Niblock	= 5,	/* maximum depth of indirect blocks, can increase it to 8 without issues */
 };
-struct Qid9p1
+struct Dentryhdr
 {
-	u64 path;	/* unique identifier */
-	u32 version;
+	u8 tag;
+	u8 verd;
+	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 path - 32 */
+	u64 mtime;		/* modified time in nano seconds from epoch - 40 */
+	u64 qpath;		/* 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*/
 };
-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 path */
 };
 
 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 */),
 };
 
 struct Dentry
@@ -244,44 +199,88 @@
 										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;
+	u64 path;	/* same as path */
 };
+struct Indirect
+{
+	u8 tag;
+	u8 veri;
+	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 path */
+};
+struct Metadataunit
+{
+	union
+	{
+		Indirect;
+		Dentry;
+	};
+};
+struct Metadata
+{
+	union
+	{
+		Indirect i[2];
+		Dentry d[2];
+	};
+};
+struct Data		/* used to unmarshall the disk contents */
+{
+	Datahdr;
+	u8 buf[1];	/* upto Maxdatablocksize, followed by u64 path */
+	/* u64 path; same as path at the end of the data content */
+};
 .fi
 .sp
 A directory entry once assigned is not given up until the parent directory is removed. It is zero'ed if the directory entry is removed. It is reused by the next directory entry created under that parent directory. This removes the need for garbage collection of directory entries on removals and also avoids zero block numbers in the middle of a directory entry's list of blocks. A zero block number while traversing a directory entry's dblocks or iblocks represents the end of directory or file contents. When a directory is removed, the parent will have a directory entry with a tag of Tdentry and Qpnone and the rest of the contents set to zero.
 .sp
+A directory entry is stored in two blocks to have a copy on write. These entries are in consecutive blocks.
+.sp
 A directory's size is always zero.
 .sp
 .nf
 	; tests/6.sizes
-	Unit 512 Dentrysize 512 Rawblocksize 8192
-	Dentryhdr size 184 Ddatasize 320
-	Dentry size 512 Namelen 129
-	Namelen 129 Ndblock 32 Niblock 3
-	Blocksize 8183 Nindperblock 1022
-	A Tind0 unit points to 1 data blocks (8183 bytes)
-			block points to 1022 data blocks
-			reli start 32	max 1053
-			max size 1054*Blocksize = 8624882 bytes	= 8 MiB
-	A Tind1 unit points to 1022 data blocks (8363026 bytes)
-			block points to 1044484 data blocks
-			reli start 1054	max 1045537
-			max size 1045538*Blocksize = 8555637454 bytes	= 7 GiB
-	A Tind2 unit points to 1044484 data blocks (8547012572 bytes)
-			block points to 1067462648 data blocks
-			reli start 1045538	max 1068508185
-			max size 1068508186*Blocksize = 8743602486038 bytes	= 7 TiB
+		Blocksize 512 Metadataunits 2 Maxdatablockunits 2048
+		Dentryhdr size 184 Ddatasize 320
+		Dentry size 512 Namelen 127
+		Namelen 127 Ndblock 32 Niblock 5
+		Nindperblock 61 Maxdatablocksize 1048548
+		A Tind0 unit points to 1 data blocks (1048548 bytes)
+				block points to 61 data blocks
+				reli start 32	max 92
+				max size 93*Maxdatablocksize = 97514964 bytes	= 92 MiB
+		A Tind1 unit points to 61 data blocks (63961428 bytes)
+				block points to 3721 data blocks
+				reli start 93	max 3813
+				max size 3814*Maxdatablocksize = 3999162072 bytes	= 3 GiB
+		A Tind2 unit points to 3721 data blocks (3901647108 bytes)
+				block points to 226981 data blocks
+				reli start 3814	max 230794
+				max size 230795*Maxdatablocksize = 241999635660 bytes	= 225 GiB
+		A Tind3 unit points to 226981 data blocks (238000473588 bytes)
+				block points to 13845841 data blocks
+				reli start 230795	max 14076635
+				max size 14076636*Maxdatablocksize = 14760028524528 bytes	= 13 TiB
+		A Tind4 unit points to 13845841 data blocks (14518028888868 bytes)
+				block points to 844596301 data blocks
+				reli start 14076636	max 858672936
+				max size 858672937*Maxdatablocksize = 900359790745476 bytes	= 818 TiB
 .fi
 .ne 30
 .sp
-On an empty m[a]fs filesystem mounted at /n/mafs, the disk contents added by the below commands are:
+On an empty mafs filesystem mounted at /n/mafs, the disk contents added by the below commands are:
 .nf
 mkdir /n/mafs/dir1
 echo test > /n/mafs/dir1/file1
 .fi
+\" from test.9
 .PS
 right
 bigboxht = boxht
@@ -288,15 +287,15 @@
 fieldht = 0.35*boxht
 {
 	down
-	{ Bound: box height 10*bigboxht width 3.3*boxwid }
+	{ Bound: box height 9*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdentry 64"
+	box height fieldht invis "Tdentry 64 2"
 	box height fieldht invis "name dir1"
-	box height fieldht invis "qid.version 0"
-	box height fieldht invis "qid.path 64"
+	box height fieldht invis "version 0"
+	box height fieldht invis "path 64"
 	box height fieldht invis "size 0"
-	box height fieldht invis "pdblkno 10"
-	box height fieldht invis "pqpath 10"
+	box height fieldht invis "pdblkno 20"
+	box height fieldht invis "pqpath 20"
 	box height fieldht invis "mtime 1653302180819962729"
 	box height fieldht invis "mode 20000000777"
 	box height fieldht invis "uid 10006"
@@ -303,7 +302,7 @@
 	box height fieldht invis "gid -1"
 	box height fieldht invis "muid 10006"
 	box height fieldht invis "direct blocks"
-	box height fieldht invis "        0 12"
+	box height fieldht invis "        0 24"
 	box height fieldht invis "        1 0"
 	box height fieldht invis "        2 0"
 	box height fieldht invis "."
@@ -315,18 +314,18 @@
 	box height fieldht invis "        0 0"
 	box height fieldht invis "        1 0"
 	box height fieldht invis "        2 0"
-	"Block 11 contents: /dir1 Dentry" at Bound.nw + 0,0.1i ljust
+	"Block 22 contents: /dir1 Dentry" at Bound.nw + 0,0.1i ljust
 	"Representation of a file in a directory: /dir1/file1" ljust at Bound.n + 0,0.3i
 }
 move 4*boxwid
 {
 	down
-	{ Bound: box height 10*bigboxht width 3.3*boxwid }
+	{ Bound: box height 5*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdentry 65"
+	box height fieldht invis "Tdentry 65 2"
 	box height fieldht invis "name file1"
-	box height fieldht invis "qid.version 0"
-	box height fieldht invis "qid.path 65"
+	box height fieldht invis ",version 0"
+	box height fieldht invis "path 65"
 	box height fieldht invis "size 5"
 	box height fieldht invis "pdblkno "
 	box height fieldht invis "pqpath 64"
@@ -335,8 +334,28 @@
 	box height fieldht invis "uid 10006"
 	box height fieldht invis "gid -1"
 	box height fieldht invis "muid 10006"
+	"Block 24 contents: file1 Dentry" at Bound.nw + 0,0.1i ljust
+}
+down
+move 9*bigboxht
+{
+	down
+	{ Bound: box height 5*bigboxht width 3.3*boxwid }
+	move 0.1i
+	box height fieldht invis "Tdentry 65 3"
+	box height fieldht invis "name file1"
+	box height fieldht invis "version 0"
+	box height fieldht invis "path 65"
+	box height fieldht invis "size 5"
+	box height fieldht invis "pdblkno "
+	box height fieldht invis "pqpath 64"
+	box height fieldht invis "mtime 1653302180823455071"
+	box height fieldht invis "mode 666"
+	box height fieldht invis "uid 10006"
+	box height fieldht invis "gid -1"
+	box height fieldht invis "muid 10006"
 	box height fieldht invis "test"
-	"Block 12 contents: file1 Dentry" at Bound.nw + 0,0.1i ljust
+	"Block 25 contents: file1 Dentry" at Bound.nw + 0,0.1i ljust
 }
 .PE
 .sp
@@ -346,10 +365,10 @@
 	down
 	{ Bound: box height 8.5*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdentry 66"
+	box height fieldht invis "Tdentry 66 3"
 	box height fieldht invis "name dir2"
-	box height fieldht invis "qid.version 0"
-	box height fieldht invis "qid.path 66"
+	box height fieldht invis "version 0"
+	box height fieldht invis "path 66"
 	box height fieldht invis "size 0"
 	box height fieldht invis "pdblkno 10"
 	box height fieldht invis "pqpath 10"
@@ -359,8 +378,8 @@
 	box height fieldht invis "gid -1"
 	box height fieldht invis "muid 10006"
 	box height fieldht invis "direct blocks"
-	box height fieldht invis "        0 14"
-	box height fieldht invis "        1 15"
+	box height fieldht invis "        0 28"
+	box height fieldht invis "        1 30"
 	box height fieldht invis "."
 	box height fieldht invis "."
 	box height fieldht invis "."
@@ -369,7 +388,7 @@
 	box height fieldht invis "        0 0"
 	box height fieldht invis "        1 0"
 	box height fieldht invis "        2 0"
-	"Block 13 contents: /dir2 directory entry" at Bound.nw + 0,0.1i ljust
+	"Block 27 contents: /dir2 directory entry" at Bound.nw + 0,0.1i ljust
 	"Representation of two files in a directory (/dir2/file1 and /dir2/file2)" ljust at Bound.nw + 0.2,0.3i
 }
 move 4*boxwid
@@ -377,10 +396,10 @@
 	down
 	{ Bound: box height 8.5*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdentry 67"
+	box height fieldht invis "Tdentry 67 3"
 	box height fieldht invis "name file1"
-	box height fieldht invis "qid.version 0"
-	box height fieldht invis "qid.path 67"
+	box height fieldht invis "version 0"
+	box height fieldht invis "path 67"
 	box height fieldht invis "size 5"
 	box height fieldht invis "pdblkno 13"
 	box height fieldht invis "pqpath 66"
@@ -390,7 +409,7 @@
 	box height fieldht invis "gid -1"
 	box height fieldht invis "muid 10006"
 	box height fieldht invis "test"
-	"Block 14 contents: file1 directory entry" at Bound.nw + 0,0.1i ljust
+	"Block 29 contents: file1 directory entry" at Bound.nw + 0,0.1i ljust
 }
 down
 move 9*bigboxht
@@ -398,10 +417,10 @@
 	down
 	{ Bound: box height 8.5*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdentry 68"
+	box height fieldht invis "Tdentry 68 3"
 	box height fieldht invis "name file2"
-	box height fieldht invis "qid.version 0"
-	box height fieldht invis "qid.path 68"
+	box height fieldht invis "version 0"
+	box height fieldht invis "path 68"
 	box height fieldht invis "size 5"
 	box height fieldht invis "pdblkno 13"
 	box height fieldht invis "pqpath 66"
@@ -411,7 +430,7 @@
 	box height fieldht invis "gid -1"
 	box height fieldht invis "muid 10006"
 	box height fieldht invis "test"
-	"Block 15 contents: file2 directory entry" at Bound.nw + 0,0.1i ljust
+	"Block 31 contents: file2 directory entry" at Bound.nw + 0,0.1i ljust
 }
 .PE
 .sp
@@ -450,8 +469,8 @@
 
 	tests/6.reli 32
 	reli 32
-	iblock[0]
-	Tind0 reli 0 is at [0]
+	iblock[0] tagstartreli 32
+	Tind0 reli 0 is at [0] nperindunit 1
 .fi
 .sp
 .PS
@@ -460,10 +479,10 @@
 	down
 	{ Bound: box height 8.5*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdentry 70"
+	box height fieldht invis "Tdentry 70 5"
 	box height fieldht invis "name 2MB.file"
-	box height fieldht invis "qid.version 0"
-	box height fieldht invis "qid.path 70"
+	box height fieldht invis "version 0"
+	box height fieldht invis "path 70"
 	box height fieldht invis "size 2056192"
 	box height fieldht invis "pdblkno 16"
 	box height fieldht invis "pqpath 69"
@@ -473,17 +492,17 @@
 	box height fieldht invis "gid -1"
 	box height fieldht invis "muid 10006"
 	box height fieldht invis "direct blocks"
-	box height fieldht invis "        0 18"
-	box height fieldht invis "        1 34"
-	box height fieldht invis "        2 50"
+	box height fieldht invis "        0 36"
+	box height fieldht invis "        1 41000"
+	box height fieldht invis "        2 0"
 	box height fieldht invis "."
 	box height fieldht invis "."
 	box height fieldht invis "indirect blocks"
-	box height fieldht invis "       0 546"
+	box height fieldht invis "       0 0"
 	box height fieldht invis "       1 0"
 	box height fieldht invis "       2 0"
-	"Block 17 contents" at Bound.nw + 0,0.1i ljust
-	"Representation of a 2 MB file (/dir3/2MB.file)" ljust at Bound.n + 0,0.3i
+	"Block 35 contents" at Bound.nw + 0,0.1i ljust
+	"Representation of a 2 MiB file (/dir3/2MB.file)" ljust at Bound.n + 0,0.3i
 }
 move 4*boxwid
 {
@@ -490,11 +509,12 @@
 	down
 	{ Bound: box height 6*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdata 70"
+	box height fieldht invis "Tdata 70 34 2048"
 	box height fieldht invis "0 0123456789"; {"contents of 2MB.file" at last box.e + 1i,0 ljust}
-	"Block 18 contents" at Bound.nw + 0,0.1i ljust
+	"Block 36 contents" at Bound.nw + 0,0.1i ljust
 }
 .PE
+\" from test.a
 .PS
 right
 Start: {
@@ -501,13 +521,13 @@
 	down
 	{ Bound: box height 9*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdentry 72"
-	box height fieldht invis "name 25MB.file"
-	box height fieldht invis "qid.version 0"
-	box height fieldht invis "qid.path 72"
+	box height fieldht invis "Tdentry 64 104"
+	box height fieldht invis "name big.file"
+	box height fieldht invis "version 0"
+	box height fieldht invis "path 64"
 	box height fieldht invis "size 26214400"
-	box height fieldht invis "pdblkno 4066"
-	box height fieldht invis "pqpath 71"
+	box height fieldht invis "pdblkno 20"
+	box height fieldht invis "pqpath 20"
 	box height fieldht invis "mtime 1653302180819962729"
 	box height fieldht invis "mode 664"
 	box height fieldht invis "uid 10006"
@@ -514,18 +534,18 @@
 	box height fieldht invis "gid -1"
 	box height fieldht invis "muid 10006"
 	box height fieldht invis "direct blocks"
-	box height fieldht invis "       0 4068"
-	box height fieldht invis "       1 4084"
-	box height fieldht invis "       2 4100"
+	box height fieldht invis "       0 24"
+	box height fieldht invis "       1 2072"
+	box height fieldht invis "       2 4120"
 	box height fieldht invis "."
 	box height fieldht invis "."
-	box height fieldht invis "       31 4564"
+	box height fieldht invis "       31 63512"
 	box height fieldht invis "indirect blocks"
-	box height fieldht invis "       0 4596"
-	box height fieldht invis "       1 20964"
+	box height fieldht invis "       0 67608"
+	box height fieldht invis "       1 192538"
 	box height fieldht invis "       2 0"
-	"Block 4067 contents" at Bound.nw + 0,0.1i ljust
-	"Representation of a 25MB file (/dir4/25MB.file)" ljust at Bound.n + 0,0.3i
+	"Block 22 contents" at Bound.nw + 0,0.1i ljust
+	"Representation of a 100 MiB file (/big.file)" ljust at Bound.n + 0,0.3i
 }
 move 4*boxwid
 {
@@ -532,12 +552,12 @@
 	down
 	{ Bound: box height 4*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdata 72"
+	box height fieldht invis "Tdata 64 22 2048"
 	box height fieldht invis "0 0123456789"; {"starting contents" at last box.e + 1i,0 ljust;}
-	box height fieldht invis "."; {"of 25MB.file" at last box.e + 1i,0 ljust}	
+	box height fieldht invis "."; {"of big.file" at last box.e + 1i,0 ljust}	
 	box height fieldht invis "."
 	box height fieldht invis "."
-	"Block 4068 contents" at Bound.nw + 0,0.1i ljust
+	"Block 24 contents" at Bound.nw + 0,0.1i ljust
 }
 move to Start - 0,9.5*bigboxht
 {
@@ -544,13 +564,13 @@
 	down
 	{ Bound: box height 3*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tind0 72"
-	box height fieldht invis "	0 4580"
-	box height fieldht invis "	1 4612"
-	box height fieldht invis "	2 4628"
+	box height fieldht invis "Tind0 64 60 22"
+	box height fieldht invis "	0 65560"
+	box height fieldht invis "	1 67610"
+	box height fieldht invis "	2 69658"
 	box height fieldht invis "."
 	box height fieldht invis "."
-	"Block 4596 contents" at Bound.nw + 0,0.1i ljust
+	"Block 67608 contents" at Bound.nw + 0,0.1i ljust
 }
 right
 move 4*boxwid
@@ -558,11 +578,11 @@
 	down
 	{ Bound: box height 3*bigboxht width 3.3*boxwid }
 	move 0.1i
-	box height fieldht invis "Tdata 72"
-	box height fieldht invis "89"; {"more content" at last box.e + 1i,0 ljust}
-	box height fieldht invis "."; {"of 25MB.file" at last box.e + 1i,0 ljust}
+	box height fieldht invis "Tdata 64 22 2048"
+	box height fieldht invis "+06 0123456789"; {"more content" at last box.e + 1i,0 ljust}
+	box height fieldht invis "."; {"of big.file" at last box.e + 1i,0 ljust}
 	box height fieldht invis "."
-	"Block 4580 contents" at Bound.nw + 0,0.1i ljust
+	"Block 65560 contents" at Bound.nw + 0,0.1i ljust
 }
 .PE
 .sp
@@ -574,20 +594,21 @@
 System Files
 =
 Block	Description
-0	magic
-1	/adm/config
-2	/adm/super
+0	magic dir entry and data
+2	/adm/config dir entry
+4	/adm/super dir entry
 _
-3	/adm
-4	/adm/users
-5	/adm/bkp/
+6	/adm/ dir entry
+8	/adm/users/ dir entry
+10	/adm/bkp/ dir entry
 _
-6	/adm/users/inuse
-7	/adm/frees
-8	/adm/ctl (virtual file, empty contents)
-9	/adm/users/staging
-10	/
+12	/adm/users/inuse dir entry
+14	/adm/frees dir entry
+16	/adm/ctl dir entry -- virtual file, empty contents
 _
+18	/adm/users/staging dir entry
+20	/ direntry
+_
 .TE
 .ta 5n 10n 15n 20n 25n 30n 35n 40n 45n 50n 55n 60n 65n 70n 75n 80n
 .sp
@@ -599,28 +620,26 @@
 .ne 4
 Backup blocks
 .sp
-Three copies of Config, Super and Root blocks are maintained. This ensures two backups of config, Super and root blocks.
+A copy of Config, Super and Root blocks is maintained. This ensures a backup of config, Super and root blocks.
 .sp
 The backup block numbers on the disk are calculated during ream based on the disk size.
 .sp
 .TS
 box;
-c l c s
-c l c c
-l a a a .
-		Backup Blocks
-Block	Description	1	2
+c l c
+l a a .
+Block	Description	Backup Block
 _
-1	/adm/config	last block number -1	middle block number -1
-2	/adm/super	last block number -2	middle block number -2
-10	/	last block number -3	middle block number -3
+1	/adm/config	last block number -2
+2	/adm/super	last block number -4
+10	/	last block number -6
 .TE
 .ta 5n 10n 15n 20n 25n 30n 35n 40n 45n 50n 55n 60n 65n 70n 75n 80n
 .sp
-M[a]fs needs atleast Nminblocks=16 blocks (8 KiB). The middle block number is Nminblocks + ((nblocks - Nminblocks)/2), where nblocks = total number of blocks.
+Mafs needs atleast Nminblocks=28 blocks (14 KiB).
 .fi
 .sp
-kfs and cwfs use 8192 byte blocks. Hence, they store multiple directory entries (Dentry) per block. They use slot numbers to identify a particular directory entry in a block of directory entries. M[a]fs avoids that be using 512 byte blocks thus having only one directory entry per block. This avoids locking up other sibling directory entries on access.
+kfs and cwfs use 8192 byte blocks. Hence, they store multiple directory entries (Dentry) per block. They use slot numbers to identify a particular directory entry in a block of directory entries. Mafs avoids that be using 512 byte blocks thus having only one directory entry per block. This avoids locking up other sibling directory entries on access.
 .sp
 .sp
 .ne 4
@@ -656,46 +675,25 @@
 	Iobuf* link;	/* least recently used Iobuf in the circular linked list */
 	QLock;		/* controls access to this hash bucket */
 };
-struct Content	/* used to unmarshall the disk contents */
-{
-	u8 tag;
-	union
-	{
-		u8 buf[Blocksize];
-		struct
-		{
-			u8 pad[7];	/* unused, to align to a multiple of 8 */
-			u64 bufa[Nindperblock];
-		};
-	};
-	u64 path;	/* same as qid.path */
-};
 struct Iobuf
 {
 	Ref;
 	RWLock;			/* controls access to this Iobuf */
 	u64	blkno;		/* block number on the disk, primary key */
-	Iobuf	*fore;	/* for lru */
-	Iobuf	*back;	/* for lru */
+	u16	len;		/* number of Units */
+	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;
 	};
-	/*
-		This field is used by mafs to ensure that Iobufs are not reused
-		while there are pending writes.
+	Metadataunit *cur;	/* this has the current Indirect or Dentry values */
+	Metadataunit *new;	/* use this unit for Indirect or Dentry changes */
 
-		dowrite() uses a Ref instead of a wlock() to mark Iobuf's
-		with pending writes.
-		Using a wlock() in dowrite() causes a deadlock with putwrite()
-		especially when the writer queue is full.
-		getbuf() guarantees that even a free'ed block cannot be
-		stolen until the dirties == 0. This avoids dirty blocks
-		being stolen for other block numbers.
-		incref(dirties) only happens while holding a wlock() in putwrite().
-	 */
-	Ref	dirties;	/* number of versions of this block yet to be written by the writer */
+	u8 *append;		/* appended data added not yet written to disk */
+	u64 appendsize;
+	u8 freshalloc;	/* uninitialized blocks on the disk */
 };
 .fi
 .sp
@@ -757,48 +755,6 @@
 .fi
 .sp
 .sp
-.ne 10
-.ft B
-Asynchronous writes of Mafs
-.ft R
-.sp
-The blocks to be written to a disk are stored in a linked list represented by:
-.br
-.nf
-struct Dirties
-{
-	QLock lck;		/* controls access to this writer queue */
-	Wbuf *head, *tail;	/* linked list of dirty blocks yet to be written to the disk */
-	s32 n;			/* number of dirty blocks in this linked list */
-	Rendez isfull;		/* write throttling */
-	Rendez isempty; 	/* writer does not have to keep polling to find work */
-} drts = {0};
-
-struct Wbuf
-{
-	u64	blkno;	/* block number on the disk, primary key */
-	Wbuf *prev, *next;	/* writer queue */
-	Iobuf *iobuf;		/* pointer to the used Iobuf in the buffer cache */
-	union{
-		u8	payload;	/* "real" contents */
-		Content io;	/* cast'able to contents */
-	};
-};
-.fi
-.sp
-A single writer process takes the blocks from the Dirties linked list on a FIFO (first-in-first-out) basis and writes them to the disk. putbuf() and putbufs() add blocks to the end of this linked list, the writer queue.
-.sp
-The dirty blocks not yet written to the disk remain in the buffer cache and cannot be stolen when a need for a new Iobuf arises.
-.sp
-Free'd blocks are not written to the disk to avoid writing blanks to a disk.
-.sp
-The writer throttles input when there are more than Npendingwrites waiting to be written. This can be adjusted with the -w parameter.
-.sp
-The alternative to having a single writer process is to have each worker process write to the disk, as mfs does. Synchronous writes throttle writes to disk write speed. With asynchronous writes, memory is used to hold the data until written to the disk. This shows increased write throughput until we fill up memory. After filling up memory, writes happen at disk speed. Asynchronous writes have the side effect of a single disk write queue.
-.sp
-The ideal npendingwrites = ((ups time in seconds)/2) * (diskspeed in bytes/second) / Rawblocksize.
-.sp
-.sp
 .ne 4
 .ft B
 Free blocks
@@ -806,7 +762,7 @@
 .sp
 Free blocks are managed using Extents. The list of free blocks is stored to the disk when shutting down. If this state is not written, then the file system needs to be checked and the list of free blocks should be updated.
 .sp
-When shutting down, the Extents are written to free blocks. This information can be accessed from /adm/frees. Also, fsok in the super block is set to 1. M[a]fs does not start until fsok is 1. When fsok = 0, run the sanity check that the unused blocks and the free blocks in /adm/frees match up. disk/reconcile identifies any missing blocks or blocks that are marked as both used and free.
+When shutting down, the Extents are written to free blocks. This information can be accessed from /adm/frees. Also, fsok in the super block is set to 1. Mafs does not start until fsok is 1. When fsok = 0, run the sanity check that the unused blocks and the free blocks in /adm/frees match up. disk/reconcile identifies any missing blocks or blocks that are marked as both used and free.
 .sp
 This process of fixing issues and setting fsok to 1 is manual. There is no automatic file system checker as in other file systems. This document aims to empower you with the knowledge to fix your file system issues instead of entrusting your precious data to an arbitrary decision maker such as the file system checker.
 .sp
@@ -1111,7 +1067,6 @@
 l a .
 Program	Description
 _
-disk/mfs	Start mfs on a disk.
 disk/mafs	Start mafs on a disk.
 disk/free	List the free blocks. It reads the contents of /adm/frees.
 disk/used	List the used blocks by traversing all directory entries.
@@ -1136,7 +1091,6 @@
 sub.c	initialization and super block related routines.	2
 tag.c	routines to manage a relative index (reli) in a directory entry.
 user.c	user management routines.
-writer.c	disk writer routines.
 .TE
 .ta 5n 10n 15n 20n 25n 30n 35n 40n 45n 50n 55n 60n 65n 70n 75n 80n
 .in 0
@@ -1151,10 +1105,8 @@
 Useful commands:
 .ft R
 .sp
-disk/mfs and disk/mafs have the same arguments. The following commands use disk/mafs to avoid duplicating them for disk/mfs.
+Ream and start single process Mafs on a disk and also mount it for use.
 .sp
-Ream and start single process M[a]fs on a disk and also mount it for use.
-.sp
 .nf
 	mount -c <{disk/mafs -s -r mafs_myservice mydisk <[0=1]} /n/mafs_myservice
 .in 3n
@@ -1218,27 +1170,27 @@
 	mount -c /srv/mafs_ramfs_file /n/mafs_ramfs_file
 .fi
 .sp
-Sync M[a]fs. This command does not return until all the writes are written to the disk. So, could take a long time if you have a long writer queue.
+Sync Mafs. This command does not return until all the writes are written to the disk. So, could take a long time if you have a long writer queue.
 .sp
 	echo sync >> /n/mafs_myservice/adm/ctl
 .sp
 .sp
 .ne 4
-Stop M[a]fs: There are 2 ways to shutdown:
+Stop Mafs: There are 2 ways to shutdown:
 .br
 .in 3n
 1. Unmount and remove the /srv/mfs_service file (can be rm and unmount too).
 .br
-2. Write halt into the /adm/ctl file. Unmount() the m[a]fs file system to keep it clean.
+2. Write halt into the /adm/ctl file. Unmount() the mafs file system to keep it clean.
 .in 0
 .sp
-In the first instance, the srv() process is driving the shutdown. It calls fsend(). rm /srv/mfs_service file does not wait for fsend() to finish. Hence, there is no way to ensure that any pending writes have been flushed to the disk. If the system is shutdown or restarted immediately, there is a high possibility that the filesystem will be in an inconsistent state. This is more probable when disk/mafs (asynchronous writes) is used.
+In the first instance, the srv() process is driving the shutdown. It calls fsend(). rm /srv/mfs_service file does not wait for fsend() to finish. Hence, there is no way to ensure that memory contents have been flushed to the disk. If the system is shutdown or restarted immediately, there is a very high possibility that the filesystem will be in an inconsistent state.
 .sp
-In the second instance, fsend() is called by the worker process. It does not return until all the pending writes have been flushed to the disk. It also removes the /srv/mfs_service file and also stops the srv() process. Hence, this is the preferred approach to shutting down the file system.
+In the second instance, fsend() is called by the worker process. It does not return until all the pending writes have been flushed to the disk. It also removes the /srv/mafs_service file and also stops the srv() process. Hence, this is the preferred approach to shutting down the file system.
 .sp
 There is no way to unmount() automatically on shutdown. The mount() and unmount() calls are client driven and it is not the responsibility of the server to find all the clients that mounted it. Just shutdown and let the respective clients deal with their mess.
 .sp
-The below command does not return until all the writes are written to the disk. So, could take a long time if you have a long writer queue. This is the proper way to shutdown the m[a]fs file system.
+The below command does not return until all the writes are written to the disk. So, could take a long time if you have a long writer queue. This is the proper way to shutdown the mafs file system.
 .sp
 	echo halt >> /n/mafs_myservice/adm/ctl
 .sp
@@ -1305,9 +1257,9 @@
 	Tdata 2
 	size 6001172505088
 	nblocks 11721040049
-	backup config 1 to 11721040048 5860520032
-	backup super 2 to 11721040047 5860520031
-	backup root 3 to 11721040046 5860520030
+	backup config 1 to 11721040048
+	backup super 2 to 11721040046
+	backup root 3 to 117210400464
 	service mafs_ddf_1
 
 	dd -if /dev/sdF1/fs -count 10 -skip 682 -bs 1
@@ -1322,43 +1274,43 @@
 	Tdata 2
 	size 6001172505088
 	nblocks 11721040049
-	backup config 1 to 11721040048 5860520032
-	backup super 2 to 11721040047 5860520031
-	backup root 3 to 11721040046 5860520030
+	backup config 1 to 11721040048
+	backup super 2 to 11721040046
+	backup root 3 to 11721040044
 	service m_ddf_1
 .fi
+\".sp
+\"Changing the magic phrase in the magic block. - the offsets and the block output format has changed.
+\".sp
+\".nf
+\"	disk/block /dev/sdF1/fs 0
+\"	Tmagic 1
+\"	mafs device
+\"	512
+\"
+\"	dd -if /dev/sdF1/fs -count 16 -iseek 256 -bs 1
+\"	mafs device
+\"	512
+\"	20+0 records in
+\"	20+0 records out
+\"
+\"	dd -if <{echo mafs device; echo 512; cat /dev/zero} -of /dev/sdF1/fs -count 18 -oseek 256 -bs 1
+\"	18+0 records in
+\"	18+0 records out
+\"
+\"	dd -if /dev/sdF1/fs -count 18 -iseek 256 -bs 1
+\"	mafs device
+\"	512
+\"	18+0 records in
+\"	18+0 records out
+\"
+\"	disk/block /dev/sdF1/fs 0
+\"	Tmagic 1
+\"	mafs device
+\"	512
+\".fi
 .sp
-Changing the magic phrase in the magic block.
 .sp
-.nf
-	disk/block /dev/sdF1/fs 0
-	Tmagic 1
-	mafs device
-	512
-
-	dd -if /dev/sdF1/fs -count 16 -iseek 256 -bs 1
-	mafs device
-	512
-	20+0 records in
-	20+0 records out
-
-	dd -if <{echo m[a]fs device; echo 512; cat /dev/zero} -of /dev/sdF1/fs -count 18 -oseek 256 -bs 1
-	18+0 records in
-	18+0 records out
-
-	dd -if /dev/sdF1/fs -count 18 -iseek 256 -bs 1
-	m[a]fs device
-	512
-	18+0 records in
-	18+0 records out
-
-	disk/block /dev/sdF1/fs 0
-	Tmagic 1
-	m[a]fs device
-	512
-.fi
-.sp
-.sp
 .ne 20
 .ft B
 Tests
@@ -1387,10 +1339,10 @@
 1. Initialize a disk for mafs.
 .br
 .ti 0
-2. Run mfs or mafs on that dsk.
+2. Run mafs on that dsk.
 .br
 .ti 0
-3. Stop mfs or mafs.
+3. Stop mafs.
 .br
 .ti 0
 4. Compare the contents with the expected contents (tests/test.0/blocks/*).
@@ -1483,45 +1435,15 @@
 		192.80 MB/s
 	dd -if /dev/zero -of /n/ramfs/file -count 700 -bs 1m
 
-	disk/mfs -r mfs_ramfs_file /n/ramfs/file
-	mount -c /srv/mfs_ramfs_file /n/mfs_ramfs_file
-	cat /dev/zero | tput -p > /n/mfs_ramfs_file/zeros.file
-		31.86 MB/s
-		31.53 MB/s
-		33.68 MB/s
-		34.98 MB/s
-		35.69 MB/s
-		36.13 MB/s
-		36.65 MB/s
-		37.17 MB/s
-		37.47 MB/s
-		36.58 MB/s
-		36.67 MB/s
-		36.93 MB/s
-		37.20 MB/s
-		37.55 MB/s
-		37.26 MB/s
-		36.91 MB/s
-		36.54 MB/s
-		36.25 MB/s
-		36.07 MB/s
-	echo halt >> /n/mfs_ramfs_file/adm/ctl; lc /srv
-	unmount /n/mfs_ramfs_file
-	rm /srv/mfs_ramfs_file
-
 	disk/mafs -r mafs_ramfs_file /n/ramfs/file
 	mount -c /srv/mafs_ramfs_file /n/mafs_ramfs_file
 	cat /dev/zero | tput -p > /n/mafs_ramfs_file/zeros.file # increase memunits for speed
-		57.94 MB/s
-		55.27 MB/s
-		46.67 MB/s
-		41.87 MB/s
-		39.00 MB/s
-		36.72 MB/s
-		35.18 MB/s
-		33.89 MB/s
-		32.81 MB/s
+		122.50 MB/s
+		122.13 MB/s
+		122.27 MB/s
+		122.28 MB/s
 	echo halt >> /n/mafs_ramfs_file/adm/ctl; lc /srv
+	unmount /n/mafs_ramfs_file
 
 	dd -if /dev/zero -of /n/ramfs/file -count 700 -bs 1m
 	hjfs -f /n/ramfs/file -r
@@ -1550,12 +1472,12 @@
 	ramfs -m /n/ramfs
 	touch /n/ramfs/file
 	dd -if /dev/zero -of /n/ramfs/file -count 700 -bs 1m
-	mount -c <{disk/mafs -s -r mafs_disk.file /n/ramfs/file <[0=1]} /n/mfs_ramfs_file
-	cat /dev/zero | tput -p > /n/mfs_ramfs_file/zeros.file
+	mount -c <{disk/mafs -s -r mafs_disk.file /n/ramfs/file <[0=1]} /n/mafs_ramfs_file
+	cat /dev/zero | tput -p > /n/mafs_ramfs_file/zeros.file
 		57.94 MB/s
 		55.27 MB/s
 		46.67 MB/s
-	echo halt >> /n/mfs_ramfs_file/adm/ctl; lc /srv
+	echo halt >> /n/mafs_ramfs_file/adm/ctl; lc /srv
 .fi
 .sp
 .sp
@@ -1564,7 +1486,7 @@
 Limitations
 .ft R
 .sp
-As we use packed structs to store data to the disk, a disk with m[a]fs is not portable to a machine using a different endian system.
+As we use packed structs to store data to the disk, a disk with mafs is not portable to a machine using a different endian system.
 .sp
 .sp
 .ft B
--- a/tests/test.9/blocks/1
+++ b/tests/test.9/blocks/1
@@ -6,7 +6,7 @@
 size 18
 pdblkno 6
 pqpath 6
-mtime 1669338040122404475
+mtime 1669339401173166884
 path 1
 version 0
 mode 20000000777
--- a/tests/test.9/blocks/11
+++ b/tests/test.9/blocks/11
@@ -6,7 +6,7 @@
 size 96
 pdblkno 6
 pqpath 6
-mtime 1669338040122873914
+mtime 1669339401173958057
 path 10
 version 0
 mode 20000000777
--- a/tests/test.9/blocks/13
+++ b/tests/test.9/blocks/13
@@ -6,7 +6,7 @@
 size 95
 pdblkno 8
 pqpath 8
-mtime 1669338040123366806
+mtime 1669339401174425942
 path 12
 version 0
 mode 444
--- a/tests/test.9/blocks/14
+++ b/tests/test.9/blocks/14
@@ -6,7 +6,7 @@
 size 20
 pdblkno 6
 pqpath 6
-mtime 1669338043066611061
+mtime 1669339404093905003
 path 14
 version 0
 mode 444
--- a/tests/test.9/blocks/15
+++ b/tests/test.9/blocks/15
@@ -6,7 +6,7 @@
 size 20
 pdblkno 6
 pqpath 6
-mtime 1669338043066611061
+mtime 1669339404093905003
 path 14
 version 0
 mode 444
--- a/tests/test.9/blocks/17
+++ b/tests/test.9/blocks/17
@@ -6,7 +6,7 @@
 size 0
 pdblkno 6
 pqpath 6
-mtime 1669338040124634932
+mtime 1669339401175679751
 path 16
 version 0
 mode 444
--- a/tests/test.9/blocks/19
+++ b/tests/test.9/blocks/19
@@ -6,7 +6,7 @@
 size 0
 pdblkno 8
 pqpath 8
-mtime 1669338040125132009
+mtime 1669339401176184009
 path 18
 version 0
 mode 444
--- a/tests/test.9/blocks/2
+++ b/tests/test.9/blocks/2
@@ -6,7 +6,7 @@
 size 120
 pdblkno 6
 pqpath 6
-mtime 1669338040124126065
+mtime 1669339401175173380
 path 2
 version 0
 mode 444
--- a/tests/test.9/blocks/20
+++ b/tests/test.9/blocks/20
@@ -6,7 +6,7 @@
 size 0
 pdblkno 0
 pqpath 0
-mtime 1669338040123627152
+mtime 1669339401174675504
 path 20
 version 0
 mode 20000000777
--- a/tests/test.9/blocks/21
+++ b/tests/test.9/blocks/21
@@ -6,7 +6,7 @@
 size 0
 pdblkno 0
 pqpath 0
-mtime 1669338040123627152
+mtime 1669339401174675504
 path 20
 version 0
 mode 20000000777
--- a/tests/test.9/blocks/22
+++ b/tests/test.9/blocks/22
@@ -6,7 +6,7 @@
 size 0
 pdblkno 20
 pqpath 20
-mtime 1669338041261986653
+mtime 1669339402312963275
 path 64
 version 0
 mode 20000000777
--- a/tests/test.9/blocks/23
+++ b/tests/test.9/blocks/23
@@ -6,7 +6,7 @@
 size 0
 pdblkno 20
 pqpath 20
-mtime 1669338041261986653
+mtime 1669339402312963275
 path 64
 version 0
 mode 20000000777
--- a/tests/test.9/blocks/24
+++ b/tests/test.9/blocks/24
@@ -6,7 +6,7 @@
 size 0
 pdblkno 22
 pqpath 64
-mtime 1669338041000000000
+mtime 1669339402000000000
 path 65
 version 0
 mode 666
--- a/tests/test.9/blocks/25
+++ b/tests/test.9/blocks/25
@@ -6,7 +6,7 @@
 size 5
 pdblkno 22
 pqpath 64
-mtime 1669338041266614638
+mtime 1669339402317073548
 path 65
 version 0
 mode 666
--- a/tests/test.9/blocks/26
+++ b/tests/test.9/blocks/26
@@ -6,7 +6,7 @@
 size 0
 pdblkno 20
 pqpath 20
-mtime 1669338041267567522
+mtime 1669339402318000113
 path 66
 version 0
 mode 20000000777
--- a/tests/test.9/blocks/27
+++ b/tests/test.9/blocks/27
@@ -6,7 +6,7 @@
 size 0
 pdblkno 20
 pqpath 20
-mtime 1669338041267567522
+mtime 1669339402318000113
 path 66
 version 0
 mode 20000000777
--- a/tests/test.9/blocks/28
+++ b/tests/test.9/blocks/28
@@ -6,7 +6,7 @@
 size 0
 pdblkno 26
 pqpath 66
-mtime 1669338041000000000
+mtime 1669339402000000000
 path 67
 version 0
 mode 666
--- a/tests/test.9/blocks/29
+++ b/tests/test.9/blocks/29
@@ -6,7 +6,7 @@
 size 5
 pdblkno 26
 pqpath 66
-mtime 1669338041271655596
+mtime 1669339402321854348
 path 67
 version 0
 mode 666
--- a/tests/test.9/blocks/30
+++ b/tests/test.9/blocks/30
@@ -6,7 +6,7 @@
 size 0
 pdblkno 26
 pqpath 66
-mtime 1669338041000000000
+mtime 1669339402000000000
 path 68
 version 0
 mode 666
--- /dev/null
+++ b/tests/test.9/blocks/31
@@ -1,0 +1,13 @@
+Tdentry 68 3
+name file2
+uid 10006
+gid -1
+muid 10006
+size 5
+pdblkno 26
+pqpath 66
+mtime 1669339402324595575
+path 68
+version 0
+mode 666
+test
--- /dev/null
+++ b/tests/test.9/blocks/34
@@ -1,0 +1,51 @@
+Tdentry 70 4
+name 2MB.file
+uid 10006
+gid -1
+muid 10006
+size 1048548
+pdblkno 32
+pqpath 69
+mtime 1665294406000000000
+path 70
+version 0
+mode 664
+direct blocks
+	0 36
+	1 0
+	2 0
+	3 0
+	4 0
+	5 0
+	6 0
+	7 0
+	8 0
+	9 0
+	10 0
+	11 0
+	12 0
+	13 0
+	14 0
+	15 0
+	16 0
+	17 0
+	18 0
+	19 0
+	20 0
+	21 0
+	22 0
+	23 0
+	24 0
+	25 0
+	26 0
+	27 0
+	28 0
+	29 0
+	30 0
+	31 0
+indirect blocks
+	0 0
+	1 0
+	2 0
+	3 0
+	4 0
--- /dev/null
+++ b/tests/test.9/blocks/35
@@ -1,0 +1,51 @@
+Tdentry 70 5
+name 2MB.file
+uid 10006
+gid -1
+muid 10006
+size 2056192
+pdblkno 32
+pqpath 69
+mtime 1665294406000000000
+path 70
+version 0
+mode 664
+direct blocks
+	0 36
+	1 41000
+	2 0
+	3 0
+	4 0
+	5 0
+	6 0
+	7 0
+	8 0
+	9 0
+	10 0
+	11 0
+	12 0
+	13 0
+	14 0
+	15 0
+	16 0
+	17 0
+	18 0
+	19 0
+	20 0
+	21 0
+	22 0
+	23 0
+	24 0
+	25 0
+	26 0
+	27 0
+	28 0
+	29 0
+	30 0
+	31 0
+indirect blocks
+	0 0
+	1 0
+	2 0
+	3 0
+	4 0
--- /dev/null
+++ b/tests/test.9/blocks/36
@@ -1,0 +1,37 @@
+Tdata 70 34 2048
+0 0123456789
+1 0123456789
+2 0123456789
+3 0123456789
+4 0123456789
+5 0123456789
+6 0123456789
+7 0123456789
+8 0123456789
+9 0123456789
+10 0123456789
+11 0123456789
+12 0123456789
+13 0123456789
+14 0123456789
+15 0123456789
+16 0123456789
+17 0123456789
+18 0123456789
+19 0123456789
+20 0123456789
+21 0123456789
+22 0123456789
+23 0123456789
+24 0123456789
+25 0123456789
+26 0123456789
+27 0123456789
+28 0123456789
+29 0123456789
+30 0123456789
+31 0123456789
+32 0123456789
+33 0123456789
+34 0123456789
+35 012345678
--- a/tests/test.9/blocks/4
+++ b/tests/test.9/blocks/4
@@ -6,7 +6,7 @@
 size 18
 pdblkno 6
 pqpath 6
-mtime 1669338040120817263
+mtime 1669339401162547192
 path 4
 version 0
 mode 444
--- a/tests/test.9/blocks/5
+++ b/tests/test.9/blocks/5
@@ -6,7 +6,7 @@
 size 18
 pdblkno 6
 pqpath 6
-mtime 1669338040120817263
+mtime 1669339401162547192
 path 4
 version 0
 mode 444
--- a/tests/test.9/blocks/7
+++ b/tests/test.9/blocks/7
@@ -6,7 +6,7 @@
 size 0
 pdblkno 20
 pqpath 20
-mtime 1669338040122617060
+mtime 1669339401173390117
 path 6
 version 0
 mode 20000000777
--- a/tests/test.9/blocks/9
+++ b/tests/test.9/blocks/9
@@ -6,7 +6,7 @@
 size 96
 pdblkno 6
 pqpath 6
-mtime 1669338040123111415
+mtime 1669339401174220386
 path 8
 version 0
 mode 20000000777