blob: 3851e360d817dbcf3e3f4a9acdc1d36d10a31d46 [file] [log] [blame]
Welcome to YAFFS, the first file system developed specifically for NAND flash.
It is now YAFFS2 - original YAFFS (AYFFS1) only supports 512-byte page
NAND and is now deprectated. YAFFS2 supports 512b page in 'YAFFS1
compatibility' mode (CONFIG_YAFFS_YAFFS1) and 2K or larger page NAND
A note on licencing
YAFFS is available under the GPL and via alternative licensing
arrangements with Aleph One. If you're using YAFFS as a Linux kernel
file system then it will be under the GPL. For use in other situations
you should discuss licensing issues with Aleph One.
Page - NAND addressable unit (normally 512b or 2Kbyte size) - can
be read, written, marked bad. Has associated OOB.
Block - Eraseable unit. 64 Pages. (128K on 2K NAND, 32K on 512b NAND)
OOB - 'spare area' of each page for ECC, bad block marked and YAFFS
tags. 16 bytes per 512b - 64 bytes for 2K page size.
Chunk - Basic YAFFS addressable unit. Same size as Page.
Object - YAFFS Object: File, Directory, Link, Device etc.
YAFFS design
YAFFS is a log-structured filesystem. It is designed particularly for
NAND (as opposed to NOR) flash, to be flash-friendly, robust due to
journalling, and to have low RAM and boot time overheads. File data is
stored in 'chunks'. Chunks are the same size as NAND pages. Each page
is marked with file id and chunk number. These marking 'tags' are
stored in the OOB (or 'spare') region of the flash. The chunk number
is determined by dividing the file position by the chunk size. Each
chunk has a number of valid bytes, which equals the page size for all
except the last chunk in a file.
File 'headers' are stored as the first page in a file, marked as a
different type to data pages. The same mechanism is used to store
directories, device files, links etc. The first page describes which
type of object it is.
YAFFS2 never re-writes a page, because the spec of NAND chips does not
allow it. (YAFFS1 used to mark a block 'deleted' in the OOB). Deletion
is managed by moving deleted objects to the special, hidden 'unlinked'
directory. These records are preserved until all the pages containing
the object have been erased (We know when this happen by keeping a
count of chunks remaining on the system for each object - when it
reaches zero the object really is gone).
When data in a file is overwritten, the relevant chunks are replaced
by writing new pages to flash containing the new data but the same
Pages are also marked with a short (2 bit) serial number that
increments each time the page at this position is incremented. The
reason for this is that if power loss/crash/other act of demonic
forces happens before the replaced page is marked as discarded, it is
possible to have two pages with the same tags. The serial number is
used to arbitrate.
A block containing only discarded pages (termed a dirty block) is an
obvious candidate for garbage collection. Otherwise valid pages can be
copied off a block thus rendering the whole block discarded and ready
for garbage collection.
In theory you don't need to hold the file structure in RAM... you
could just scan the whole flash looking for pages when you need them.
In practice though you'd want better file access times than that! The
mechanism proposed here is to have a list of __u16 page addresses
associated with each file. Since there are 2^18 pages in a 128MB NAND,
a __u16 is insufficient to uniquely identify a page but is does
identify a group of 4 pages - a small enough region to search
exhaustively. This mechanism is clearly expandable to larger NAND
devices - within reason. The RAM overhead with this approach is approx
2 bytes per page - 512kB of RAM for a whole 128MB NAND.
Boot-time scanning to build the file structure lists only requires
one pass reading NAND. If proper shutdowns happen the current RAM
summary of the filesystem status is saved to flash, called
'checkpointing'. This saves re-scanning the flash on startup, and gives
huge boot/mount time savings.
YAFFS regenerates its state by 'replaying the tape' - i.e. by
scanning the chunks in their allocation order (i.e. block sequence ID
order), which is usually different form the media block order. Each
block is still only read once - starting from the end of the media and
working back.
YAFFS tags in YAFFS1 mode:
18-bit Object ID (2^18 files, i.e. > 260,000 files). File id 0- is not
valid and indicates a deleted page. File od 0x3ffff is also not valid.
Synonymous with inode.
2-bit serial number
20-bit Chunk ID within file. Limit of 2^20 chunks/pages per file (i.e.
> 500MB max file size). Chunk ID 0 is the file header for the file.
10-bit counter of the number of bytes used in the page.
12 bit ECC on tags
YAFFS tags in YAFFS2 mode:
4 bytes 32-bit chunk ID
4 bytes 32-bit object ID
2 bytes Number of data bytes in this chunk
4 bytes Sequence number for this block
3 bytes ECC on tags
12 bytes ECC on data (3 bytes per 256 bytes of data)
Page allocation and garbage collection
Pages are allocated sequentially from the currently selected block.
When all the pages in the block are filled, another clean block is
selected for allocation. At least two or three clean blocks are
reserved for garbage collection purposes. If there are insufficient
clean blocks available, then a dirty block ( ie one containing only
discarded pages) is erased to free it up as a clean block. If no dirty
blocks are available, then the dirtiest block is selected for garbage
Garbage collection is performed by copying the valid data pages into
new data pages thus rendering all the pages in this block dirty and
freeing it up for erasure. I also like the idea of selecting a block
at random some small percentage of the time - thus reducing the chance
of wear differences.
YAFFS is single-threaded. Garbage-collection is done as a parasitic
task of writing data. So each time some data is written, a bit of
pending garbage collection is done. More pages are garbage-collected
when free space is tight.
Flash writing
YAFFS only ever writes each page once, complying with the requirements
of the most restricitve NAND devices.
Wear levelling
This comes as a side-effect of the block-allocation strategy. Data is
always written on the next free block, so they are all used equally.
Blocks containing data that is written but never erased will not get
back into the free list, so wear is levelled over only blocks which
are free or become free, not blocks which never change.
Some helpful info
Formatting a YAFFS device is simply done by erasing it.
Making an initial filesystem can be tricky because YAFFS uses the OOB
and thus the bytes that get written depend on the YAFFS data (tags),
and the ECC bytes and bad block markers which are dictated by the
hardware and/or the MTD subsystem. The data layout also depends on the
device page size (512b or 2K). Because YAFFS is only responsible for
some of the OOB data, generating a filesystem offline requires
detailed knowledge of what the other parts (MTD and NAND
driver/hardware) are going to do.
To make a YAFFS filesystem you have 3 options:
1) Boot the system with an empty NAND device mounted as YAFFS and copy
stuff on.
2) Make a filesystem image offline, then boot the system and use
MTDutils to write an image to flash.
3) Make a filesystem image offline and use some tool like a bootloader to
write it to flash.
Option 1 avoids a lot of issues because all the parts
(YAFFS/MTD/hardware) all take care of their own bits and (if you have
put things together properly) it will 'just work'. YAFFS just needs to
know how many bytes of the OOB it can use. However sometimes it is not
Option 2 lets MTD/hardware take care of the ECC so the filesystem
image just had to know which bytes to use for YAFFS Tags.
Option 3 is hardest as the image creator needs to know exactly what
ECC bytes, endianness and algorithm to use as well as which bytes are
available to YAFFS.
mkyaffs2image creates an image suitable for option 3 for the
particular case of yaffs2 on 2K page NAND with default MTD layout.
mkyaffsimage creates an equivalent image for 512b page NAND (i.e.
yaffs1 format).
A bootloader using YAFFS needs to know how MTD is laying out the OOB
so that it can skip bad blocks.
YAFFS Tracing