After you have added a map driver and chosen the right chip driver, you're all set to let higher layers use the flash. User-space applications that perform file I/O need to view the flash device as if it were a disk, whereas programs that desire to accomplish raw I/O access the flash as if it were a character device. The MTD layer that achieves these and more is called User Modules, as shown in Figure 17.1. Let's look at the components constituting this layer.
Block Device Emulation
The MTD subsystem provides a block driver called mtdblock that emulates a hard disk over flash memory. You can put any filesystem, say EXT2, over the emulated flash disk. Mtdblock hides complicated flash access procedures (such as preceding a write with an erase of the corresponding sector) from the filesystem. Device nodes created by mtdblock are named /dev/mtdblock/X, where X is the partition number. To create an EXT2 filesystem on the pda_fs partition of the handheld, as shown in Figure 17.2, do the following:
bash> mkfs.ext2 /dev/mtdblock/2 Create an EXT2 filesystem on the second partition bash> mount /dev/mtdblock/2 /mnt Mount the partition
As you will soon see, it's a much better idea to use JFFS2 rather than EXT2 to hold files on flash filesystem partitions.
The File Translation Layer (FTL) and the NAND File Translation Layer (NFTL) perform a transformation called wear leveling. Flash memory sectors can withstand only a finite number of erase operations (in the order of 100,000). Wear leveling prolongs flash life by distributing memory usage across the chip. Both FTL and NFTL provide device interfaces similar to mtdblock over which you can put normal filesystems. The corresponding device nodes are named /dev/nftl/X, where X is the partition number. Certain algorithms used in these modules are patented, so there could be restrictions on usage.
Char Device Emulation
The mtdchar driver presents a linear view of the underlying flash device, rather than the block-oriented view required by filesystems. Device nodes created by mtdchar are named /dev/mtd/X, where X is the partition number. You may update the bootloader partition of the handheld as shown in Figure 17.2, by using dd over the corresponding mtdchar interface:
bash> dd if=bootloader.bin of=/dev/mtd/0
An example use of a raw mtdchar partition is to hold POST error logs generated by the bootloader on an embedded device. Another use of a char flash partition on an embedded system is to store information similar to that present in the CMOS or the EEPROM on PC-compatible systems. This includes the boot order, power-on password, and Vital Product Data (VPD) such as the device serial number and model number.
Journaling Flash File System (JFFS) is considered the best-suited filesystem for flash memory. Currently, version 2 (JFFS2) is in use, and JFFS3 is under development. JFFS was originally written for NOR flash chips, but support for NAND devices is merged with the 2.6 kernel.
Normal Linux filesystems are designed for desktop computers that are shut down gracefully. JFFS2 is designed for embedded systems where power failure can occur abruptly, and where the storage device can tolerate only a finite number of erases. During flash erase operations, current sector contents are saved in RAM. If there is a power loss during the slow erase process, entire contents of that sector can get lost. JFFS2 circumvents this problem using a log-structured design. New data is appended to a log that lives in an erased region. Each JFFS2 node contains metadata to track disjoint file locations. Memory is periodically reclaimed using garbage collection. Because of this design, flash writes do not have to go through a save-erase-write cycle, and this improves power-down reliability. The log-structure also increases flash life span by spreading out writes.
To create a JFFS2 image of a tree living under /path/to/filesystem/ on a flash chip having an erase size of 256KB, use mkfs.jffs2 as follows:
bash> mkfs.jffs2 -e 256KiB –r /path/to/filesystem/ -o jffs2.img
JFFS2 includes a garbage collector (GC) that reclaims flash regions that are no longer in use. The garbage collection algorithm depends on the erase size, so supplying an accurate value makes it more efficient. To obtain the erase size of your flash partitions, you may seek the help of /proc/mtd. The output for the Linux handheld shown in Figure 17.2 is as follows:
bash> cat /proc/mtd dev: size erasesize name mtd0: 00100000 00040000 "pda_btldr" mtd1: 00200000 00040000 "pda_krnl" mtd2: 01400000 00040000 "pda_fs"
JFFS2 supports compression. Enable appropriate options under CONFIG_JFFS2_COMPRESSION_OPTIONS to choose available compressors, and look at fs/jffs2/compr*.c for their implementations.
Note that JFFS2 filesystem images are usually created on the host machine where you do cross-development and then transferred to the desired flash partition on the target device via a suitable download mechanism such as serial port, USB, or NFS. More on this in Chapter 18, "Embedding Linux."
The implementation of JFFS2 in the 2.6 kernel includes features to work with the limitations of NAND flash, but Yet Another Flash File System (YAFFS) is a filesystem that is designed to function under constraints specific to NAND memory. YAFFS is not part of the mainline kernel, but some embedded distributions prepatch their kernels with support for YAFFS2, the current version of YAFFS.
You can download YAFFS2 source code and documentation from www.yaffs.net.