 yaffs yaffs1 development notes yaffs yaffs1 development notes these notes relate to yaffs1 yaffs version 2 or yaffs2 is the current version of yaffs while many of the details below remain the same you can find up to date information split between the how yaffs works yaffs tuning and yaffs direct documents   build options yaffs1 can be built as either a kernel module ie a linux file system or as an application of course the goal is to build yaffs as a file system running on top of real nand flash but yaffs can be built to run on a ram emulation layer for inkernel testing without nand flash in the system building as an application allows the yaffsguts algorithms to be tested debugged in a more friendly debugging environment the test harness is in yaffsdevc trying it out yaffs1 can be built to run with either mtd or ram emulation or both the file system that interfaces to mtd is called yaffs  the file system that uses internal ram is called yaffsram  yaffs1 simultaneously supports both if they are enabled hack the makefile and change the kerneldir define to your kernel directory if you don t have mtd support in your kernel then you might need to turn off usemtd otherwise the yaffs module might not load type make clean make to build yaffs load yaffs as a module by typing  sbin insmod yaffso  ya gotta be root create a mount point eg mkdir mnt y to mount the ram emulation version of yaffs  mount t yaffsram none mnt y alternatively to mount the mtd version of yaffs  mount t yaffs dev mtd0 mnt y   yaffs1 data structures all data types are defined in yaffsgutsh yaffs1 uses the following major objects yaffsobject a yaffsobject can be a file directory symlink or hardlink the yaffsobjects know about their corresponding yaffsobjectheader in nand and the data for that object yaffsobjects also bind together the directory structure as follows parent pointer to the yaffsobject that is a parent of this yaffsobject in the directory structure siblings this field is used to link together a list of all the yaffsobjects in the same directory children if the object is a directory then children holds the head of the list of objects in the directory yaffstnode yaffstnodes form a tree structure that speeds up the search for data chunks in a file as the file grows in size the levels increase the tnodes are a constant size 32 bytes level  ie the lowest level comprise 16 2byte entries giving an index used to search for the chunkid tnodes at other levels comprise 8 4byte pointer entries to other tnodes lower in the tree yaffsdevice this holds the device context and is in some ways analogous to the vfs superblock it stores the data used to access the mtd as well as function pointers to access the nand data the tnodes and objects are allocated in groups to reduce memory allocation freeing overheads freed up tnodes and objects are kept in a free list and reused yaffsobject struct yaffsobjectstruct u8 fake 1 a fake object has no presence on nand u8 renameallowed 1 are we allowed to rename it u8 unlinkallowed 1 are we allowed to unlink it u8 dirty 1 the object needs to be written to flash u8 valid 1 when the file system is being loaded up this object might be created before the data is available ie file data records appear before the header u8 serial serial number of chunk in nand store here so we don t have to read back the old one to update u16 sum sum of the name to speed searching struct yaffsdevicestruct mydev the device i m on struct listhead hashlink list of objects in this hash bucket struct listhead hardlinks all the equivalent hard linked objects live on this list directory structure stuff struct yaffsobjectstruct parent my parent directory struct listhead siblings siblings in a directory also used for linking up the free list where s my data in nand int chunkid where it lives u32 objectid the object id value u32 stmode protection u32 stuid user id of owner u32 stgid group id of owner u32 statime time of last access u32 stmtime time of last modification u32 stctime time of last change yaffsobjecttype varianttype yaffsobjectvariant variant obvious stuff skipped fake renameallowed unlinkallowed are special flags for handling fake objects which live in the file system but do not live on nand currently there are only two such objects the root object and the lost found directory none of these may be renamed or unlinked serial sum see yaffsobjectheader dirty indicates that the object s contents has changed and a new yaffsobjectheader must be written to flash valid indicates that the object has been loaded up this is only used during scanning yaffsscan since we can know of an object s existance and thus need to create the object header before we encounter the associated yaffsobjectheader hashlink is a list of objects in the same hash bucket the four variants hold extra info files hold the file size and the top level and pointer to the tnode tree for the file directories hold a list of children objects symlinks hold a pointer to the alias string this is probably inefficient but that probably does not matter since we don t expect to see many of these hardlinks hold information to identify the equivalent object  file structure tnodes  file structures are done with a tiered indexing structure the file structure is maintained by a tree structure depending where it is in the tree each tree node  tnode  the blue things holds either if it is at the lowest level then 16 u16s which identify the page if it is at a higher level ie an internal tnode then 8 pointers to lowestlevel tnodes when the file starts out it is assigned only one lowlevel tnode when the file expands past what a single tnode can hold then it is assigned a second tnode and an internal node is added to point to the two tnodes as the file grows more lowlevel tnodes and high level tnodes are added traversing the tnode tree to find a particular page in a file is quite simple each internal tnode is selected from by using 3 bits of the page offset in the file the level  page resolves 4 bits for example finding page 0x235 ie the one starting at file position 0x46800 would proceed as follows 0x235 is 1000110101 partitioned as follows 1000110101 level bits selected value 3 or more if they exist 10 zero 2 9 to 7 100 binary 4 1 6 to 4 11 binary 3  3 to  101 binary 5 free tnodes are stored in a list when the list is exhausted more are allocated each tnode takes 32 bytes each file needs at least one level  tnode how many do we need a full 16mb file system needs at least 16mb 51216 2000 level zero tnodes more for internal tnodes more for files smaller than optimal the tree grows as required when the file is resized to a smaller size then it is pruned nand data data is stored on nand in chunks currently each chunk is the same size as a nand flash page ie 512 bytes 16 byte spare in the future we might decide to allow for different chunk sizes chunks can hold either a yaffsobjectheader this is the way a yaffsobject gets stored on nand a chunk of file data the 16 byte spare area contains 8 bytes of tags 6 bytes of ecc data 1 byte block status used to identify damaged blocks 1 byte data status currently unused the tags are made up as follows typedef struct unsigned chunkid 20 chunk number in file unsigned serialnumber 2 serial number for chunk unsigned bytecount 10 number of bytes of data used in this chunk unsigned objectid 18 the object id that this chunk belongs to unsigned ecc 12 ecc on tags unsigned unusedstuff 2 unused yaffstags a chunkid of zero indicates that this chunk holds a yaffsobjectheader a non zero value indicates that this is a data chunk and the position of the chunk in the file ie the first chunk at offset  has chunkid 1 see yaffsgutsc yaffsscan to see how this is done when a chunk is repalced eg file details changed or a part of a file was overwritten the new chunk is written before the old chunk is deleted this means that we don t lose data if there is a power loss after the new chunk is created but before the old one is discarded but it does mean that we can encounter the situation where we find both the old and the new chunks in flash the serialnumber is incremented each time the chunk is written 2 bits is sufficient to resolve any ambiguity bytecount applies only to data chunks and tells how many of the data bytes are valid objectid says which object this chunk belongs to ecc is used to perform error correction on the tags another ecc field is used to error correct the data yaffsobjectheader typedef struct yaffsobjecttype type apply to everything int parentobjectid u16 sum checksum of name char name yaffsmaxnamelength 1 thes following apply to directories files symlinks not hard links u32 stmode protection u32 stuid user id of owner u32 stgid group id of owner u32 statime time of last access u32 stmtime time of last modification u32 stctime time of last change file size applies to files only int filesize equivalent object id applies to hard links only int equivalentobjectid alias only applies to symlinks char alias yaffsmaxaliaslength 1 yaffsobjectheader a yaffsobjectheader is stored in nand for every yaffsobject type holds the type of yaffsobject file directory hardlink or symlink parentobject is the objectid of this object s parent name holds the object s name together these form the directory structure of the file system also worth mention is sum this is a checksum on the name which speeds directory searching ie when searching the directory we only compare the name for those entries where sum matches obvious stuff skipped equivalentobjectid is used by hardlinks a hardlink to an object uses this field to specify the object that this links to this way of doing things is a bit different than the normal linux way of doing things ie keeping the links distinct from the inode but is simpler and uses less space except for a few corner cases with hardlinks alias is used by symlinks to hold the symlink alias string this limits the size of the symlink alias in future we should expand yaffs1 to use data chunks to store aliases too long to fit into the yaffsobjectheader nand interface all nand access is performed via four functions pointed to by yaffsdevice at the moment a chunk is a page int writechunktonand struct yaffsdevicestruct dev int chunkinnand const u8 data yaffsspare spare int readchunkfromnand struct yaffsdevicestruct dev int chunkinnand u8 data yaffsspare spare int eraseblockinnand struct yaffsdevicestruct dev int blockinnand int initialisenand struct yaffsdevicestruct dev in the readxxx and writexxx functions the data and or spare pointers may be null in which case these data transfers are ignored a quick note about nand nand is not random access but page oriented thus we do all reads writes in pages each nand page holds 512 bytes of data and 16 spare bytes yaffs structures the spare area with tags used to identify what is stored in the data area there are 32 such pages to a block nand writes will only change 1 bits to  eg if a byte holds 10110011 and you write 11011010 to it you will get the logical and of the two values 10010010 the only way to get 1s again is to erase the entire block you may only write to a page a few times before erasing the entire block yaffs lives within these limitations each page only gets written to twice once when written and once when discarded ecc is normally used with nand to correct for single bit errors yaffs1 applies the ecc itself so the mtd should not do this the current mtd interfaces are not particularly well suited to yaffs1 and we will address the issue with the mtd group the mtd interface does not support pageoriented read write which yaffs1 would prefer  mkyaffs mkyaffs is the tool to format a nand mtd to be used for yaffs1 this is quite simple just erase all the undamaged blocks yaffs1 treats erased blocks as free empty space expected performance the following numbers should give an indication of the performance we should expect from yaffs1 as an example i ll use the following numbers since the hardware is capable of 50ns read write these numbers allow for some other ovberheads clearly though the performance can be degraded in various ways seek 10us page read 100ns byte write 100ns byte program 200us page erase 2ms block from this we can derive some higherlevel numbers operation time calculation read spare 12us seek 16 read read page 63 us seek 528 read write page 326 us seek 528 write program read page for verification discard page 212 us seek 16 write program overwrite page 538 us write page discard page erase overhead per page 63us erase 32 from this we can infer the following flash access times operation time calculation read 1mb file 013s about 75 mb s 2000 read page write 1mb clean system 053s about 18 mb s 2000 write page overwrite 1mb file no gc 108s about 09mb s 2000 overwrite page overwrite 1mb with 50 gc 24s about 4 mb s 2000 overwrite page 2000 page copy overwrite page 4000 erase overhead delete 1mb file 043s about 22 mb s 2000 discard page delete 1mb file with 50 gc 049s about 20mb s 2000 discard page 1000 erase overhead admin 23 may 2005 1236pm  