Linux下jffs2根文件系統製作

4.1 jffs2文件系統簡介

JFFS2全名是 Journalling Flash File System Version2,是Redhat公司開發的Flash的文件系統,其前身是JFFS, 最早只支援Norflash, 自2.6版以後開始支援NAND Flash,其功能就是管理在MTD設備上實現的日誌型文件系統,極適合使用於嵌入式系統。與其他的存儲設備存儲方案相比,JFFS2並不準備提供讓傳統文件系統也可以使用此類設備的轉換層。它只會直接在MTD設備上實現日誌結構的文件系統。JFFS2會在安裝的時候,掃描MTD設備的日誌內容,並在RAM中重新建立文件系統結構本身。除了提供具有斷電可靠性的日誌結構文件系統,JFFS2還會在它管理的MTD設備上實現“損耗平衡”和“數據壓縮”等特性。下面是JFFS2的不足之處:
JFFS2 的掛載(mount)過程需要對Flash從頭到尾的掃描,這個過程是很慢的,我們在測試中現掛載一個 16M 的閃存有時需要半分鐘以上的時間
JFFS2 在分區的空間使用率比較大後,數據的讀寫非常緩慢
JFFS2 對磨損平衡是用概率的方法來解決的,這很難保證磨損平衡的確定性。在某些情況下,可
能造成對擦寫塊不必要的擦寫操作;在某些情況下,又會引起對磨損平衡調整的不及時。
JFFS2沒有write-back機制,不能將資料暫存於緩存(cache), 以致於flash I/O的動作頻繁.

JFFS2是針對早起的Norflash和小頁(頁大小<4K)的Nandflash設計的,並不適合大頁的Nandflash。
所以我們一般在Norflash上使用JFFS2文件系統,而現在普遍使用的大頁Nandflash並不適用它。
4.2 根文件系統鏡像文件製作
我們可以使用mtd-utils源碼編譯出來的mkfs.jffs2工具,將根文件系統樹目錄製作成jffs2根文件系統
鏡像。在開始製作鏡像之前,我們先看看mkfs.jffs2的使用說明:

我們可以使用mtd-utils源碼編譯出來的mkfs.jffs2工具,將根文件系統樹目錄製作成jffs2根文件系統
鏡像。在開始製作鏡像之前,我們先看看mkfs.jffs2的使用說明:
zhanghang@ubuntu:~/fl2440/linux$ mkfs.jffs2 -h
mkfs.jffs2: error!: Usage: mkfs.jffs2 [OPTIONS]
Make a JFFS2 file system image from an existing directory tree

Options:
  -p, --pad[=SIZE]        Pad output to SIZE bytes with 0xFF. If SIZE is
                          not specified, the output is padded to the end of
                          the final erase block//指定jffs2文件系統鏡像的填充大小
  -r, -d, --root=DIR      Build file system from directory DIR (default: cwd)//指定根文件系統目錄樹的路徑
  -s, --pagesize=SIZE     Use page size (max data node size) SIZE.
                          Set according to target system's memory management
                          page size (default: 4KiB)//指定Nandflash的頁大小
  -e, --eraseblock=SIZE   Use erase block size SIZE (default: 64KiB)//指定Nandflash的塊大小
  -c, --cleanmarker=SIZE  Size of cleanmarker (default 12)
  -m, --compr-mode=MODE   Select compression mode (default: priortiry)
  -x, --disable-compressor=COMPRESSOR_NAME
                          Disable a compressor
  -X, --enable-compressor=COMPRESSOR_NAME
                          Enable a compressor
  -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME
                          Set the priority of a compressor
  -L, --list-compressors  Show the list of the avaiable compressors
  -t, --test-compression  Call decompress and compare with the original (for test)
  -n, --no-cleanmarkers   Don't add a cleanmarker to every eraseblock//指定不添加清除標記
  -o, --output=FILE       Output to FILE (default: stdout)//指定製作出來的根文件系統鏡像文件名
  -l, --little-endian     Create a little-endian filesystem
  -b, --big-endian        Create a big-endian filesystem
  -D, --devtable=FILE     Use the named FILE as a device table file
  -f, --faketime          Change all file times to '0' for regression testing
  -q, --squash            Squash permissions and owners making all files be owned by root
  -U, --squash-uids       Squash owners making all files be owned by root
  -P, --squash-perms      Squash permissions on all files
      --with-xattr        stuff all xattr entries into image
      --with-selinux      stuff only SELinux Labels into jffs2 image
      --with-posix-acl    stuff only POSIX ACL entries into jffs2 image
  -h, --help              Display this help text
  -v, --verbose           Verbose operation
  -V, --version           Display version information
  -i, --incremental=FILE  Parse FILE and generate appendage output for it

先看看之前做好的根文件系統大小:

zhanghang@ubuntu:~/fl2440/linux$ du -sh rootfs
12M     rootfs
zhanghang@ubuntu:~/fl2440/linux$ mkfs.jffs2 -n -s 2048 -e 128KiB -d ./rootfs -o rootfs-jffs2.bin  // 製作根文件系統時不進行填充
zhanghang@ubuntu:~/fl2440/linux$ mkfs.jffs2 -n -s 2048 -e 128KiB -d ./rootfs -o rootfs-jffs2.bin --pad=0xa00000 //// 製作根文件系統時進行填充

具體作用如下:

-n 指明不添加清除標記(nand flash 有自己的校檢塊,存放相關的信息),如果掛載後會出現
下面類似警告信息,則加上-n 就會消失:
s 指定Nandflash的頁大小爲2KB
-e 指定Nandflash的擦除塊大小爲128KB
-d 指定根文件系統目錄樹的路徑 爲./rootfs
-o 指定製作生成的根文件系統鏡像文件名爲 rootfs-jffs.bin,該文件需要u-boot燒錄到
Nandflash的相應分區
–pad=0xa00000 將製作的根文件系統鏡像(rootfs-jffs2.bin)文件大小用0xFF填充爲–pad指
定的值。如果在製作根文件系統的不填充的話,Linux掛載啓動根文件系統時將會出現下面警告
信息。

我們在之前的Linux內核Nandflash分區修改裏將rootfs分區大小設置爲40M,所以這裏的–pad值
應該爲0x280000。但如果使用0x2800000,則根文件系統鏡像的大小就爲40M,這樣u-boot下載燒
錄的時間較長,另外如果在Nandflash上燒錄該鏡像文件的分區存在壞塊的話,則在u-boot裏用nand
write燒錄時會跳過壞塊溢出到下一個分區空間中去,從而佔用了下一個空間的使用,系統就會出錯。這
裏我們將填充大小值設置爲10M是也可以解決上面jffs2_scan_eraseblock拋出的警告信息,之所以將
填充大小設置爲10M是因爲不進行填充時製作的根文件系統鏡像大小爲6.3M,這個值的大小根據分區
大小和根文件系統目錄樹的實際大小進行調整。

4.3 內核配置和編譯

zhanghang@ubuntu:~/fl2440/linux$ cd linux-3.0/
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ export TERM=vt100
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ make menuconfig
General setup --->
		[ ] Automatically append version information to the version string 取消這個選項減少內核大小
		[ ] Support for paging of anonymous memory (swap) Nandflash不需要swap分區,如果是PC上的硬盤則需要swap分區
		<*> Kernel .config support
		[ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support 一定要取消initramfs的支持,否則內核找到initramfs則直接使用initramfs啓動
		[*] Configure standard kernel features (expert users) ---> 添加這個選項
		[*] Embedded system 添加這個選項
File systems --->
		< > Second extended fs support 取消PC端用的ext2文件系統支持,減少內核大小
		< > Ext3 journalling file system support 取消PC端用的ext3文件系統支持,減少內核大小
		< > The Extended 4 (ext4) filesystem 取消PC端用的ext4文件系統支持,減少內核大小
		< > Kernel automounter version 4 support (also supports v3) 取消這個選項減少內核大小
		< > FUSE (Filesystem in Userspace) support 取消這個選項減少內核大小
		CD-ROM/DVD Filesystems --->
				< > ISO 9660 CDROM file system support 取消這個光驅光盤選項,減少內核大小
				< > UDF file system support 取消這個光驅光盤選項,減少內核大小
		DOS/FAT/NT Filesystems --->
				<*> MSDOS fs support
				<*> VFAT (Windows-95) fs support 添加Windows的FAT文件系統支持,U盤或SD卡中會使用
				(437) Default codepage for FAT
				(iso8859-1) Default iocharset for FAT
				<*> NTFS file system support 添加Windows的NTFS文件系統支持,U盤或SD卡中會使用
				[ ] NTFS debugging support
				[*] NTFS write support
		Pseudo filesystems --->
				<*> Userspace-driven configuration filesystem 添加sysfs僞文件系統支持
		[*] Miscellaneous filesystems --->
				<*> Journalling Flash File System v2 (JFFS2) support 添
加JFFS2文件系統支持
				(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其他文件系統如果不需要的話都不要選
				< > Compressed ROM file system support (cramfs) 如果不用的話,取消cramfs文件系統的支持
				< > SquashFS 4.0 - Squashed file system support 如果不用的話,取消SquashFS文件系統的支持
				< > ROM file system support 如果不用的話,取消ROM文件系統的支持
[*] Network File Systems --->
		<*> NFS client support
		[*] NFS client support for NFS version 3
		[*] NFS client support for the NFSv3 ACL protocol extension
		[ ] NFS client support for NFS version 4
		[*] Root file system on NFS
		將其他不需要的網絡文件系統都不要選
		< > NFS server support
		< > Ceph distributed file system (EXPERIMENTAL)
		< > CIFS support (advanced network filesystem, SMBFS successor)
		< > NCP file system support (to mount NetWare volumes)
		< > Coda file system support (advanced network fs)
		< > Andrew File System support (AFS) (EXPERIMENTAL)
Partition Types --->
		[ ] PC BIOS (MSDOS partition tables) support 取消這個選項減少內核大小
-*- Native language support ---> U盤的掛載可能需要下面這些語言編碼的支持,譬如簡體中文的CP936和GB2312等
		(iso8859-1) Default NLS Option
		<*> Codepage 437 (United States, Canada)
		<*> Simplified Chinese charset (CP936, GB2312)
		<*> Traditional Chinese charset (Big5)
		<*> ASCII (United States)
		<*> NLS ISO 8859-1 (Latin 1; Western European Languages)
		<*> NLS UTF-8
		其他語言如果不需要全部不要選

因爲禁用了initramfs重新編譯Linux內核,新編譯的內核不包含根文件系統所以文件較小。

  CC      sound/usb/caiaq/snd-usb-caiaq.mod.o
  LD [M]  sound/usb/caiaq/snd-usb-caiaq.ko
  CC      sound/usb/snd-usb-audio.mod.o
  LD [M]  sound/usb/snd-usb-audio.ko
  CC      sound/usb/snd-usbmidi-lib.mod.o
  LD [M]  sound/usb/snd-usbmidi-lib.ko
Image Name:   Linux Kernel
Created:      Mon Apr 29 04:56:04 2019
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    2403520 Bytes = 2347.19 kB = 2.29 MB
Load Address: 30008000
Entry Point:  30008040
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ du -h linuxrom-s3c2440.bin 
2.3M    linuxrom-s3c2440.bin

4.4 u-boot系統燒錄和環境變量配置
因爲使用jffs2根文件系統啓動的Linux內核不包含根文件系統,所以u-boot燒錄Linux系統時需要同時
燒錄linux內核鏡像(linuxrom-s3c2440.bin)和根文件系統鏡像(rootfs-jffs2.bin),此外還要通過
bootargs環境變量告訴Linux內核根文件系統所在的位置。這裏Linux內核、根文件系統的燒錄地址、
bootargs傳參應該與Linux內核裏的Nandflash分區表相一致:
在這裏插入圖片描述

u-boot的燒錄地址應該是 0,大小不超過1M。該分區對應Linux內核分區表的/dev/mtdblock0;Linux內核的燒錄地址應該是0x100000(1M的偏移量處),大小不超過15M。該分區對應Linux內核分區表的/dev/mtdblock1;根文件系統鏡像的燒錄地址應該是0x1000000(16M的偏移量處),大小不超過40M。該分區對應Linux內核分區表的/dev/mtdblock2;

燒錄Linux內核命令

[fl2440@lingyun]# tftp 30008000 linuxrom-s3c2440.bin 先將Linux內核下載到內存地址30008000上去
[fl2440@lingyun]# nand erase 100000 F00000 將Nandflash上Linux內核分區(即1M開始總共15M的空間)全部擦除
[fl2440@lingyun]# nand write 30008000 100000 400000 將Linux內核寫入到Nandflash上的Linux內核分區上去

燒錄根文件系統命令

[fl2440@lingyun]# tftp 30008000 rootfs-jffs2.bin 先將根文件系統下載到內存地址30008000上去
[fl2440@lingyun]# nand erase 1000000 2800000 將Nandflash上根文件系統分區(即16M開始總共40M的空間)全部擦除
[fl2440@lingyun]# nand write 30008000 1000000 $filesize 將根文件系統寫入到Nandflash上的根文件系統分區上去

設置bootcmd和bootargs參數:
開發板上電或重啓運行u-boot時,如果不按任意鍵u-boot將進入正常加載模式,這時他將讀取環境變量bootcmd來啓動引導Linux內核。Linux內核是被燒錄到Nandflash的0x100000位置上,所以uboot啓動系統需要從該位置讀取內核文件到內存相應位置中去,並且讀取字節數應該不小於燒錄的Linux鏡像文件大小,否則系統將啓動失敗。根文件系統則通過bootargs參數告訴Linux內核,Linux內核在啓動後根據該參數掛載相應的根文件系統,如果bootargs參數出錯也將導致系統啓動失敗。

[fl2440@lingyun]# set bootcmd 'nand read 30008000 100000 400000; bootm 30008000'
[fl2440@lingyun]# set bootargs 'console=tty0 console=ttyS0,115200
root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7'
[fl2440@lingyun]# save

bootargs的參數解析如下:
console=tty0 指定內核控制終端爲LCD,內核啓動信息輸出到LCD上;
console=ttyS0,115200 指定內核控制終端也爲第一個串口,使用波特率115200,這樣內核啓動信
息也打印到第一個串口上;
root=/dev/mtdblock2 指定根文件系統存放在mtdblock2上,該值應該與u-boot燒錄位置、Linux
內核分區保持一致;如果錯誤則Linux內核會因找不到根文件系統而啓動失敗;
rootfstype=jffs2 指定根文件系統類型爲jffs2,如果該參數錯誤則內核啓動失敗;
init=/linuxrc 指定init進程執行/linuxrc這個程序,他會解析並執行/etc/inittab下的命令;
mem=64M u-boot告訴Linux內核有64M的內存;
rw 根文件系統以讀寫的形式掛載;
noinitrd 沒有使用initrd;
loglevel=7 定義內核printk的打印級別爲7,即所有信息都通過console打印出來;

登錄開發板,jffs2不同於initramfs,jffs2在nandflash上,掉電數據不會丟失。

...
usb 1-1: new full speed USB device number 4 using s3c2410-ohci
usb 1-1: device not accepting address 4, error -62
usb 1-1: new full speed USB device number 5 using s3c2410-ohci
usb 1-1: device not accepting address 5, error -62
hub 1-0:1.0: unable to enumerate USB device on port 1
dm9000 dm9000: eth0: link down

Default Logon Username: root Password: 123456
LingYunFL2440 login: dm9000 dm9000: eth0: link up, 100Mbps, full-duplex, lpa 0xCDE1
root
Password: 
~ >: ls
apps     dev      init     mnt      sbin     usr
bin      etc      lib      proc     sys      var
data     info     linuxrc  root     tmp
~ >: vim aaa
nnnnnnnnnnn
aaa      data     info     linuxrc  root     tmp
apps     dev      init     mnt      sbin     usr
bin      etc      lib      proc     sys      var
~ >: reboot
...
usb 1-1: device not accepting address 4, error -62
usb 1-1: new full speed USB device number 5 using s3c2410-ohci
usb 1-1: device not accepting address 5, error -62
hub 1-0:1.0: unable to enumerate USB device on port 1
dm9000 dm9000: eth0: link up, 100Mbps, full-duplex, lpa 0xCDE1

Default Logon Username: root Password: 123456
LingYunFL2440 login: root
Password: 
Login incorrect
LingYunFL2440 login: 
LingYunFL2440 login: root
Password: 
~ >: ls
aaa      data     info     linuxrc  root     tmp
apps     dev      init     mnt      sbin     usr
bin      etc      lib      proc     sys      var

因爲JFFS2是建立在Nandflash上的根文件系統,在該文件系統路徑下所有的文件修改掉電後都不會丟
失。所以我們在根路徑下創建aaa文件後,把開發板重啓發現該文件還存在。

~ >: mount
rootfs on / type rootfs (rw)
/dev/root on / type jffs2 (rw,relatime)
proc on /proc type proc (rw,relatime)
usbfs on /proc/bus/usb type usbfs (rw,relatime)
tmpfs on /dev type tmpfs (rw,relatime)
ramfs on /tmp type ramfs (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,mode=600)

4.6 普通分區jffs2掛載
jffs2除了可以製作成根文件系統使用以外,我們也可以在系統成功啓動後,將其他分區以jffs2文件系統
類型掛載使用。

~ >: dmesg | grep mtdblock //通過dmesg命令查看內核的分區情況
root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7
0x000000000000-0x000000100000 : "mtdblock0 u-boot 1MB"
0x000000100000-0x000001000000 : "mtdblock1 kernel 15MB"
0x000001000000-0x000003800000 : "mtdblock2 rootfs 40MB"
0x000003800000-0x000008800000 : "mtdblock3 apps 80MB"
0x000008800000-0x00000d800000 : "mtdblock4 data 80MB"
0x00000d800000-0x000010000000 : "mtdblock5 backup 40MB"
~ >: cat /proc/partitions//查看Linux內核分區表
major minor  #blocks  name

  31        0       1024 mtdblock0
  31        1      15360 mtdblock1
  31        2      40960 mtdblock2
  31        3      81920 mtdblock3
  31        4      81920 mtdblock4
  31        5      40960 mtdblock5
~ >:  ls -l /dev/mtdblock*//查看分區對應的塊設備
brw-rw----    1 root     root       31,   0 Jan  1 00:00 /dev/mtdblock0
brw-rw----    1 root     root       31,   1 Jan  1 00:00 /dev/mtdblock1
brw-rw----    1 root     root       31,   2 Jan  1 00:00 /dev/mtdblock2
brw-rw----    1 root     root       31,   3 Jan  1 00:00 /dev/mtdblock3
brw-rw----    1 root     root       31,   4 Jan  1 00:00 /dev/mtdblock4
brw-rw----    1 root     root       31,   5 Jan  1 00:00 /dev/mtdblock5

這裏我們以 mtdblock5 爲例將其以jffs2文件系統格式掛載到 /info 掛載點上:

~ >: flash_eraseall /dev/mtd5
Erasing 128 Kibyte @ 2800000 - 100% complete.//將mtdblock5分區全部擦除
~ >: mount -t jffs2 /dev/mtdblock5 /info/
~ >: mount
rootfs on / type rootfs (rw)
/dev/root on / type jffs2 (rw,relatime)
proc on /proc type proc (rw,relatime)
usbfs on /proc/bus/usb type usbfs (rw,relatime)
tmpfs on /dev type tmpfs (rw,relatime)
ramfs on /tmp type ramfs (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,mode=600)
/dev/mtdblock5 on /info type jffs2 (rw,relatime)
~ >: cd info/
/info >: touch mmm
/info >: ls
mmm
/info >: cd
~ >: reboot
~ >: cd info/
/info >: ls
/info >: cd 
~ >: mount -t jffs2 /dev/mtdblock5 /info/
mount: mounting /dev/mtdblock5 on /info/ failed: Device or resource busy
~ >: ls
apps     dev      init     mnt      sbin     usr
bin      etc      lib      proc     sys      var
data     info     linuxrc  root     tmp
~ >: cd info/
/info >: ls
mmm

系統重啓後,並不會自動掛載/dev/mtdblock5到/info路徑下,這時我們還是需要用命令手動掛載才能
看到/info路徑下的haha文件存在。
這時我們可以寫一個shell腳本,使系統啓動時直接掛在mtdblock5到info下

~ >:  cd etc/init.d/
/etc/init.d >: vim S_mount_block_5
#!bin/sh
mount -t jffs2 /dev/mtdblock5 /info/
/etc/init.d >: chmod a+x S_mount_block_5 

這樣,每次系統啓動就會將mtdblock5掛在在info下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章