mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 12:08:19 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			202 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 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
 | |
| in YAFFS2 mode (CONFIG_YAFFS_YAFFS2).
 | |
| 
 | |
| 
 | |
| 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.
 | |
| 
 | |
| 
 | |
| Terminology
 | |
| -----------
 | |
| 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
 | |
| tags.
 | |
| 
 | |
| 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
 | |
| collection.
 | |
| 
 | |
| 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
 | |
| practical.
 | |
| 
 | |
| 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).
 | |
| 
 | |
| Bootloaders
 | |
| -----------
 | |
| 
 | |
| A bootloader using YAFFS needs to know how MTD is laying out the OOB
 | |
| so that it can skip bad blocks.
 | |
| 
 | |
| YAFFS Tracing
 | |
| -------------
 |