YAFFS, short for "Yet Another Flash File System," is a fast robust file system for NAND and NOR Flash. YAFFS has been around for several years, mainly used with embedded systems and consumer devices. But YAFFS hasn't gained much traction, at least not until the release of YAFFS2.
All flash file systems, with YAFFS2 not being an exception, have to support standard features such as wear leveling and to be power-down resistant. Contrary to JFFS2, YAFFS2 as well as well as UBIFS, was initially designed for NAND flash even though it will work with NOR too, which has some peculiar characteristics. The differences between NAND and NOR flash are numerous and full comparison is beyond the scope of this article, but as far as flash file system is concerned the following ones are the most important:
- Capacity.NAND flash tends to be much bigger than NOR; 16MB-512MB vs. 1MB-32MB
- Access interface. Random access for NOR vs. serial access for NAND
- Speed. NAND is faster, especially for write and erase operations
- Reliability. NAND devices are allowed to ship with bad blocks
YAFFS was designed with the above NAND characteristics in mind. To improve mount time of large flash devices, YAFFS2 will try to save the RAM summary of the file system status on shutdown, which can save the scan time. It only writes to the flash sequentially in order to be complient with modern NAND specifications. YAFFS2 uses out-of-band OOB flash data to mark and skip bad blocks.
Core YAFFS2 algorithms dealing with flash were developed as a user space application. This code resides in yaffs_guts.[ch]. This clear separation between OS dependent and independent parts makes YAFFS2 very portable. It was initially developed for Linux but later was successfully ported to WinCE, eCOS, pSOS and VxWorks. It is even supported by some bootloaders, such as U-Boot.
As most flash file systems, YAFFS2 is a log structured file system which allows it to write to flash storage sequentially. The entries in the log are either data or header chunks. Each chunk has a tag associated with it with the following information: object id, chunk id, sequencer number, byte count and some additional fields.
- Object id identifies which object, i.e. inode or dentry, the chunk belongs to.
- Chunk id along whith byte count give the location of the chunk inside the object.
- Sequence number is used to indicate obsolete chunks as YAFFS2 cannot modify an existing one -- each chunk has to be written only once. Sequence number is incremented when a new block (that is, a flash unit of erasure) is allocated for usage thus allowing to sort chunks in chronological order.
When file is modified, instead of changing the information directly in the storage as most file systems do, YAFFS2 writes a new chunk to the log. Over time, some flash blocks will have a certain number of deleted, i.e. obsolete, chunks which need to be garbage collected. Garbage collection process finds a suitable block depending on the number of available erased blocks -- it will try harder by processing even blocks with small number of obsolete chunks going into something called "aggressive mode" if there are too few. When a block worth collecting is found it will iterate through all its chunks and copy these that are in use to a new block. After that the block can be erased. YAFFS2 uses various data RAM structures in order to increase performance. For example, YAFFS2 holds a tree of chunks for each file which allows to find quickly data chunks that belong to the file. For each flash device there is a data structure that describes block information, including state of each chunk of that block.
Using YAFFS2 is straightforward. Assuming you already patched the kernel, just erase your MTD partition using:
and mount it as YAFFS using:
mount -t yaffs /dev/mtd[x] /mnt/flash
You can copy files to it right away and YAFFS2 will take care of everything. It is also possible to create a YAFFS2 image offline using "mkyaffs2image" utility, but the former option is preferrable as YAFFS2 will properly use the OOB bits it is responsible for.