Since flash devices have non-standard requirements when it comes to reading/writing of data (such as the need to erase things, and in chunks, and only for a limited number of times), the Journalling Flash File System (JFFS) was designed to provide efficient persistent storage under Linux. The current version is JFFS2 (which supersedes JFFS1).
When using JFFS2 on large (128MB or larger) flash devices - the developer must be aware of the downsides. Since there is no indexing information stored on the flash media, each JFFS2 node contains full information about itself, but there is no central index. The index is the crucial part of any file system as it is used to quickly locate any piece of information (i.e., find all the files kept in a directory, find the physical flash address where the files data is stored, etc.). In JFFS2, the index is maintained in RAM and takes significant amount of it - a 128MB NAND would use about 4MB RAM in node tables. Roughly speaking, there is a in-RAM data structure for each on-flash node.
The in RAM index must be built on each mount. For this reason, JFFS2 must scan the flash media. And it is logically then the more data you have on flash, the longer is JFFS2 mount time and memory consumption. Namely, the above 2 characteristics linearly depend on the flash size (O(N), N - flash size). This can mean scan time at boot time gets longer every day of usage. Eg. when flash is empty it takes ~10 s to mount 20Mb of flash, later when there are some files present it takes > 30s and increasing. This is normal for JFFS2. The more data is in the flash, the longer is JFFS2 being mounted. This issue is being resolved in the development of JFFS3, and is available today by using the YAFFS filesystem.
There are a few steps before you can start playing with a JFFS2 image:
make and is found in: ./uclinux-dist/images/rootfs.jffs2)rootfs.jffs2) into flash with U-BootJFFS2 can be enabled in the uClinux kernel and U-Boot. Enabling JFFS2 in U-Boot allows U-Boot to access kernel images stored in the JFFS2 image.
The JFFS homepage can be found at http://sources.redhat.com/jffs2/.
The method for managing MTD partition tables is documented in the Partitioning document. Here we will focus on just using the default partition scheme which has a partition setup specifically for a root file system
Please consult the MTD document for relevant kernel settings for the higher MTD layers. If you plan on using JFFS2 as your root file system, these options will have to be built into your kernel and not as modules. The method for loading modules before mounting the root file system is not documented here and is left as an exercise for the user.
You will also need to enable support for the JFFS2 filesystem itself.x
File systems --->
Miscellaneous filesystems --->
<*> Journalling Flash File System v2 (JFFS2) support
(sub-options are up to you)
If you wish to program/create JFFS2 images on the board (rather than just loading them via U-Boot), you will need to enable the mtd-utils package. Specifically, you will need the flash_eraseall and mkfs.jffs2 programs.
After this is complete, you can do a make, and this will build the image files in the uClinux-dist directory images.
When the kernel boots up, you should see information about the relevant flash being detected and MTD partitions being created. If you do not see any such messages, you need to go back and review your kernel settings to make sure it matches your board.
For example, on the BF548-EZKIT, the parallel flash looks like:
physmap platform flash device: 02000000 at 20000000 cfi: mfr=0x89, id=0x891f physmap-flash.0: Found 1 x16 devices at 0x0 in 16-bit bank Intel/Sharp Extended Query Table at 0x010A Intel/Sharp Extended Query Table at 0x010A Intel/Sharp Extended Query Table at 0x010A Intel/Sharp Extended Query Table at 0x010A Intel/Sharp Extended Query Table at 0x010A Using buffer write method Using auto-unlock on power-up/resume cfi_cmdset_0001: Erase suspend on write enabled 3 cmdlinepart partitions found on MTD device physmap-flash.0 Creating 3 MTD partitions on "physmap-flash.0": 0x00000000-0x00040000 : "uboot" 0x00040000-0x00200000 : "kernel" 0x00200000-0x02000000 : "rootfs"
The SPI flash on the BF548-EZKIT looks like:
m25p80 spi0.1: m25p16 (2048 Kbytes) Creating 2 MTD partitions on "m25p80": 0x00000000-0x00040000 : "bootloader" 0x00040000-0x00100000 : "linux kernel" bfin-spi bfin-spi.0: Blackfin BF5xx on-chip SPI Contoller Driver, Version 1.0, regs_base @ 0xffc00500
And the NAND flash looks like:
BF5xx on-chip NAND FLash Controller Driver, Version 1.2 (c) 2007 Analog Devices, Inc. bf5xx-nand bf5xx-nand.0: page_size=256, data_width=8, wr_dly=3, rd_dly=3 NAND device: Manufacturer ID: 0x20, Chip ID: 0xda (ST Micro NAND 256MiB 3,3V 8-bit) Creating 2 MTD partitions on "NAND 256MiB 3,3V 8-bit": 0x00000000-0x00400000 : "Linux Kernel" 0x00400000-0x10000000 : "File System"
Assuming that you have followed the instructions above, and want to write the JFFS2 and kernel images to flash the following would be done:
rootfs.jffs2 is less than 3M, and will fit into mtd flash partition: rgetz@test:~/uClinux-dist> ls -lh ./images/rootfs.jffs2 -rw-r--r-- 1 rgetz users 961K 2005-08-09 17:12 ./images/rootfs.jffs2
This images is 961k, so it meets our requirement.
/tftpboot while for coLinux it is /svr/tftp:rgetz@test:~/uClinux-dist> cp ./images/rootfs.jffs2 /tftpboot/rootfs.jffs2 rgetz@test:~/uClinux-dist> cp ./images/vmlinux /tftpboot/vmlinux rgetz@test:~/uClinux-dist> cp ./images/vmImage /tftpboot/vmImage
stamp> tftpboot 0x1000000 rootfs.jffs2 stamp> protect off 0x20100000 0x203FFFFF stamp> erase 0x20100000 0x203FFFFF stamp> cp.b 0x1000000 0x20100000 $(filesize)
stamp> tftpboot 0x1000000 rootfs.jffs2 stamp> eeprom write 0x1000000 0x100000 $(filesize)
1985h, Depending on your Flash Type:stamp> md.b 0x20100000 0x02 20100000: 85 19
stamp> eeprom read 0x2000000 0x100000 0x2 stamp> md.b 0x2000000 0x02 0000000: 85 19
stamp> erase 0x20040000 0x200FFFFF stamp> tftp 0x1000000 vmImage stamp> cp.b 0x1000000 0x20040000 $(filesize)
stamp> mw.b 0x1000 0x0 $(SizeOfFlash) stamp> tftp 0x1000 vmImage stamp> eeprom write 0x1000 $(offset) $(SizeOfFlash)
If your flash is larger than your SDRAM, do something like:
stamp> mw.b 0x1000 0x0 $(half_SizeOfFlash) stamp> eeprom write 0x1000 $(kernel_start) $(half_SizeOfFlash) stamp> eeprom write 0x1000 $(half_SizeOfFlash) $(half_SizeOfFlash)
stamp> setenv bootargs root=/dev/mtdblock2 rw rootfstype=jffs2 stamp> setenv flashboot bootm 0x20040000 stamp> setenv bootcmd run flashboot stamp> save stamp> run bootcmd
stamp> setenv bootargs root=/dev/mtdblock2 rw rootfstype=jffs2 stamp> setenv flashboot 'eeprom read 0x1000000 0x40000 0x180000; bootm 0x1000000' stamp> setenv bootcmd run flashboot stamp> save stamp> run bootcmd
After a reboot, U-boot will automatically boot this new kernel (unless the countdown is aborted with a key press).
$(half_SizeOfFlash), $(kernel_start), $(offset), $(SizeOfFlash) are not U-Boot variables, and are placeholders for the actual size of flash (in hex), kernel start address, offset of where to store the file system or kernel in the Flash. You need to fill these numbers in by hand.
ls and fsload command can be used. This is not available for serial flash.stamp> ls drwxr-xr-x 0 Mon Aug 01 18:43:01 2005 bin drwxr-xr-x 0 Mon Aug 01 17:41:33 2005 dev drwxr-xr-x 0 Mon Aug 01 18:43:01 2005 etc drwxr-xr-x 0 Mon Aug 01 17:41:33 2005 home drwxr-xr-x 0 Mon Aug 01 17:41:33 2005 lib drwxr-xr-x 0 Mon Aug 01 17:41:33 2005 mnt drwxr-xr-x 0 Mon Aug 01 17:41:33 2005 proc drwxr-xr-x 0 Mon Aug 01 17:41:33 2005 root lrwxrwxrwx 3 Mon Aug 01 18:42:59 2005 sbin -> bin drwxr-xr-x 0 Mon Aug 01 17:41:33 2005 tmp drwxr-xr-x 0 Mon Aug 01 17:41:34 2005 usr drwxr-xr-x 0 Mon Aug 01 17:41:33 2005 var
stamp> fsload kernel stamp> bootm
fsload command, if a kernel image is inside the JFFS2 file system. This is not the case with vmImage! In case of abnormal power failure, it had better to put the kernel image into a separate MTD partition with read only option.
mtdblock0 instead of mtdblock2, the bootargs environment setting has to change. So in short:stamp> tftp 0x1000000 uImage stamp> setenv bootargs root=/dev/mtdblock0 rw stamp> bootm
The JFFS2 filesystem can be accessed in two ways in the uClinux kernel:
/mnt)Let's look at these two cases in more detail:
If the Generic uClinux RAM / ROM FS Support was enabled, the uImage kernel image still contains support for a ram-based filesystem. The ramfs partition is one higher than your highest flash partition. Because mtdblock0 contains the boot loader, mtdblock1 the kernel and mtdblock2 the JFFS2 filesystem, the ramfs is found on mtdblock3. So, to boot using the ram filesystem:
bootargs environment variable to your ramfs. In U-Boot:stamp> setenv bootargs root=/dev/mtdblock3 rw stamp> save
(save makes the change 'permanent' and is optional).
stamp> tftp 0x1000000 uImage stamp> bootm 0x1000000
mount -t jffs2 /dev/mtdblock2 /mnt
root:~> ls /mnt/ bin dev etc home lib mnt proc root sbin sys tmp usr var
cat /proc/mtd
This largely corresponds to booting the vmImage kernel which has already been flashed on the Blackfin, just now we upload a new one to ram.
stamp> tftp 0x1000000 vmImage
stamp> setenv bootargs root=/dev/mtdblock2 rw rootfstype=jffs2
stamp> bootm 0x1000000
root:~> cat /proc/mtd dev: size erasesize name mtd0: 00040000 00010000 "Bootloader" mtd1: 000c0000 00010000 "Kernel" mtd2: 00300000 00010000 "JFFS2" mtd3: 00000000 00001000 "EXT2fs"
root:~> mount /dev/mtdblock2 on / type jffs2 (rw,noatime) none on /proc type proc (rw,nodiratime) /dev/ram0 on /var type ramfs (rw)
The line containing mtd3: only exists if the Generic uClinux RAM / ROM FS Support was enabled and the vmImage kernel created manually using the mkimage tool. However, because this is a kernel-only image, you cannot mount and use it. If you boot uImage instead of vmImage, with the same bootargs, the same kernel is loaded into memory - but now including a ram-based filesystem, which you can mount using e.g.:
root:~> mount -t ext2 /dev/mtdblock3 /mnt root:~> ls /mnt/ bin home mnt sbin usr dev lib proc sys var etc lost+found root tmp
Sometimes it may be useful to mount the jffs2 image via loop on your development system. Here are the minimum configure options needed to do this:
Device Drivers --->
Memory Technology Devices (MTD) --->
<*> Memory Technology Device (MTD) support
[*] MTD partitioning support
<*> Direct char device access to MTD devices
<*> Caching block device access to MTD devices
Self-contained MTD device drivers --->
<*> Test driver using RAM
File systems --->
Miscellaneous filesystems --->
<*> Journalling Flash File System v2 (JFFS2) support
If you build these as modules, make sure you load everything:
# modprobe mtdchar # modprobe mtdblock # modprobe mtdram # modprobe jffs2
Since you cannot mount the image directly, you need to load it into the mtd ram test driver:
# dd if=jffs2.img of=/dev/mtd0 # mount -t jffs2 /dev/mtdblock0 /mnt/jffs2
Like magic, you should now be able to browse/modify/whatever the filesystem!
ftl_cs: FTL header not found.
This can be resolved by ensuring that “FTL (Flash Translation Layer) support” in the kernel config is not enabled.
Empty flash at 0x0001fffc ends at 0x00020000 CLEANMARKER node found at 0x00020000, not first node in block (0x00000000)
JFFS2 warning: (165) jffs2_sum_scan_sumnode: Summary node crc error, skipping summary information. CLEANMARKER node found at 0x00010000, not first node in block (0x00000000) CLEANMARKER node found at 0x00020000, not first node in block (0x00000000)
These situations can occur if you create a JFFS2 image with mkfs.jffs2 using the wrong value for the erase block size (the -e option). The default is 64KiB, because that's the smallest erase block size you're likely to encounter often, and creating an image with smaller eraseblock size than the actual hardware is harmless -- it just gives annoying messages, and delays your mount process. If you see the messages mentioned above, check the erase block size of your device (look in /proc/mtd if you don't know), and create your JFFS2 image for it with the correct -e option. [Partially copied form http://www.linux-mtd.infradead.org/doc/jffs2.html]
Example:
root:/> cat /proc/mtd dev: size erasesize name mtd0: 00040000 00040000 "bootloader(spi)" mtd1: 00100000 00040000 "linux kernel(spi)" mtd2: 00ec0000 00040000 "file system(spi)"
JFFS2 file system mounts can take up to several seconds, especially on large file systems with many files. There is one technique called Erase Block Summary (EBS) to significantly speed up the mount process.
The goal of EBS is to speed up the mount process. It stores summary information at the end of every erase block. At mount time it is no longer necessary to scan all nodes individually (and read all pages of the erase blocks), enough to read this “small” summary.
This summary information is stored in a JFFS2_FEATURE_RWCOMPAT_DELETE node. During mount process if there is no summary node at the end of an erase block, the original scan process will be executed.
This node is generated automatically if EBS enabled for written data, but you should also use the user space tool called sumtool to insert summary information after you created a JFFS2 image with mkfs.jffs2. [From http://www.linux-mtd.infradead.org/doc/jffs2.html]
JFFS2 image with Summary dedicated for an M25P128 Serial SPI flash
uclinux-dist-trunk/user/mtd-utils/mkfs.jffs2 -l -e 0x40000 -p -d uclinux-dist-trunk/romfs -D device_table-min.txt -o uclinux-dist-trunk/images/rootfs.jffs2 uclinux-dist-trunk/user/mtd-utils/sumtool -l -e 0x40000 -p -i uclinux-dist-trunk/images/rootfs.jffs2 -o uclinux-dist-trunk/images/rootfs-summary.jffs2
These steps are typically done by the Blackfin uClinux build system. You therefore only need to initiate make with following options, in case your target device requires a special erase block size.
make MTD_SUMTOOL_FLAGS=’-l -p -e 0x40000’ MKFS_JFFS2_FLAGS=’-l –p -e 0x40000’
Defaults are:
MTD_SUMTOOL_FLAGS = -l -p MKFS_JFFS2_FLAGS = -l -p
The Summary feature needs to be enabled during kernel configuration
File systems ---> Miscellaneous filesystems ---> <*> Journalling Flash File System v2 (JFFS2) support (0) JFFS2 debugging verbosity (0 = quiet, 2 = noisy) [*] JFFS2 write-buffering support [ ] Verify JFFS2 write-buffer reads [*] JFFS2 summary support (EXPERIMENTAL) [ ] JFFS2 XATTR support (EXPERIMENTAL) [ ] Advanced compression options for JFFS2
| JFFS2 | JFFS2 (SUMMARY) |
|---|---|
| 1.5 sec. | 0.24 sec. |
JFFS2 version 2.2. (NAND) (c) 2001-2006 Red Hat, Inc. m25p80 spi0.1: m25p128 (16384 Kbytes) Creating 3 MTD partitions on "m25p80": 0x00000000-0x00040000 : "bootloader(spi)" 0x00040000-0x00140000 : "linux kernel(spi)" 0x00140000-0x01000000 : "file system(spi)"
root:/> cat /proc/mtd dev: size erasesize name mtd0: 00040000 00040000 "bootloader(spi)" mtd1: 00100000 00040000 "linux kernel(spi)" mtd2: 00ec0000 00040000 "file system(spi)" root:/> flash_eraseall -j /dev/mtd2 Erasing 256 Kibyte @ e80000 -- 98 % complete. Cleanmarker written at e80000. root:/> cp /var/rootfs.jffs2 /dev/mtd2 root:/> time mount -t jffs2 /dev/mtdblock2 /mnt real 0m 1.50s user 0m 0.00s sys 0m 0.05s root:/> umount /mnt root:/> time mount -t jffs2 /dev/mtdblock2 /mnt real 0m 1.50s user 0m 0.00s sys 0m 0.06s root:/>
JFFS2 version 2.2. (NAND) (SUMMARY) (c) 2001-2006 Red Hat, Inc. m25p80 spi0.1: m25p128 (16384 Kbytes) Creating 3 MTD partitions on "m25p80": 0x00000000-0x00040000 : "bootloader(spi)" 0x00040000-0x00140000 : "linux kernel(spi)" 0x00140000-0x01000000 : "file system(spi)"
root:/> flash_eraseall -j /dev/mtd2 Erasing 256 Kibyte @ e80000 -- 98 % complete. Cleanmarker written at e80000. root:/> cp /var/rootfs-summary.jffs2 /dev/mtd2 root:/> time mount -t jffs2 /dev/mtdblock2 /mnt real 0m 0.24s user 0m 0.00s sys 0m 0.02s root:/> time umount /mnt real 0m 0.02s user 0m 0.00s sys 0m 0.02s root:/> time mount -t jffs2 /dev/mtdblock2 /mnt real 0m 0.24s user 0m 0.00s sys 0m 0.03s root:/> cd mnt root:/mnt> ls bin dev etc home lib mnt proc root sbin sys tmp usr var root:/mnt>