Linux3.4.72内核支持UBI文件系统 (二)

在上篇文章中我的Linux kernel 已经支持了ubi和ubifs。这篇文章主要介绍如何制作ubifs,已经在制作过程中遇到的问题。

首先我希望是在nand flash上运行UBIFS。所以需要Linux kernel 支持nand的驱动。其实支持nand的驱动是比较复杂的,但是由于我用的s3c2440的芯片,所以移植过程中只需要配置linux kernel 使其支持nand驱动即可. 方法:make menuconfig

Device Drivers  --->

Memory Technology Device (MTD) support --->

NAND Device Support --->                                   

                                          <*>   NAND Flash support for Samsung S3C SoCs  

                                           [ ]     Samsung S3C NAND driver debug                       、

[ ]     Samsung S3C NAND Hardware ECC                            

[ ]   Samsung S3C NAND IDLE clock stop         

这样Linux kernel 就已经支持nandflash了。 但是这里需要注意 nandflash的校验方式。在后面会提到,为什么我没有选择硬件校验(Samsung S3C NAND Hardware ECC)。    

NandFlash驱动加载成功的log:

S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c24xx-nand s3c2440-nand: Tacls=1, 10ns Twrph0=3 30ns, Twrph1=1 10ns
s3c24xx-nand s3c2440-nand: NAND soft ECC
NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
Scanning device for bad blocks
Creating 3 MTD partitions on "NAND":
0x000000000000-0x000000200000 : "Boot Agent"
0x000000200000-0x000000600000 : "S3C2410 flash partition 1"
0x000000600000-0x00000c600000 : "S3C2410 flash partition 2"
UBI: attaching mtd2 to ubi0
UBI: physical eraseblock size:   131072 bytes (128 KiB)
UBI: logical eraseblock size:    126976 bytes
UBI: smallest flash I/O unit:    2048
UBI: sub-page size:              512
UBI: VID header offset:          2048 (aligned 2048)
UBI: data offset:                4096
UBI: max. sequence number:       0
UBI: volume 0 ("rootfs") re-sized from 826 to 1232 LEBs
UBI: attached mtd2 to ubi0
UBI: MTD device name:            "S3C2410 flash partition 2"

 log信息中的显示这块实验开发板上的 nand芯片的信息。其实这些nand信息的都是从nand  flash中读取出来的。 log的下半部分是ubi的挂载信息。当然写这篇博客的时候我已经挂载ubifs成功了。

如果想自定义MTD partitions的信息可以在common-smdk.c中进行更改。当然如果你要改区域大小不要忘记同步u-boot中的mtd信息。

ok,下一话题,如何制作UBI, UBIFS?

How do I create an UBIFS image?

Creating UBIFS images might be a little trickier than creating JFFS2 images. First of all, you have to understand that UBIFS works on top of UBI which works on top or MTD which basically represents your raw flash. This means, that if you need to create an image which should be flashed to the raw flash, you should first create an UBIFS image, then UBI image. In other words, the process has 2 steps.

However, as described here, UBI has a volume update facility and there is an ubiupdatevol utility for this. So you may update UBI volumes on your running system as well. In this case you only need an UBIFS image, and you do not have to make the UBI image, i.e., the process has only 1 step in this case.

Moreover, you may even build the image on your target system and write it directly to your UBI volume - just specify the volume character device as the output file to mkfs.ubifs.

So, there are 2 utilities:

mkfs.ubifs which creates UBIFS images;
ubinize which creates UBI images out of UBIFS images.
And depending on the needs you use either mkfs.ubifs or mkfs.ubifs plus ubinize. Choose the former if you are going to upload the update UBIFS image on your target and then update the UBI volume using ubiupdatevol. Choose the latter if you are going to flash the image to raw flash, e.g., at the factory.

The UBI and UBIFS images depend on parameters of the flash they are going to be used on. Namely, you have to know the following characteristics of the flash before creating images:

MTD partition size;
flash physical eraseblock size;
minimum flash input/output unit size;
for NAND flashes - sub-page size;
logical eraseblock size.
If you run Linux kernel version 2.6.30 or higher, or you have the MTD sysfs support back-ported, then you may find all these parameters by running the mtdinfo tool with -u parameter. Of course, the tool has to be run on the target system.

Please, refer this for more information about how to find these parameters.

And optionally, you should decide which compression algorithm you want to use for the file-system. UBIFS supports zlib and LZO (default) at the moment (see here). There is also favor LZO mkfs.ubifs compression method. Generally, zlib compresses better, but it is slower on both compression and decompression. So this is a trade-off between space savings and speed. The best idea is to try both and choose the one which is more appropriate for you. Here you may find compression test results for ARM platform. Alternatively, the compression may be switched off. See "-x" option of the mkfs.ubifs utility.

There are other advanced file-system and UBI characteristics which may be altered with various options of the tools. Use them only if you understand what they do.

The below example demonstrates how to create an UBI/UBIFS image for a 256MiB SLC OneNAND flash chip with 128KiB physical eraseblocks, 2048-byte NAND pages, and 512-byte sub-pages (this means that it allows to do 4x512 bytes writes to the same NAND page, which is quite typical for SLC flashes). The resulting image will have only one UBI volume storing UBIFS file-system.

$ mkfs.ubifs -q -r root-fs -m 2048 -e 129024 -c 2047 -o ubifs.img
$ ubinize -o ubi.img -m 2048 -p 128KiB -s 512 ubinize.cfg
where ubinize.cfg contains:

$ cat ubinize.cfg
[ubifs]
mode=ubi
image=ubifs.img
vol_id=0
vol_size=200MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize
Some comments about what the options mean:

-r root-fs: tells mkfs.ubifs to create an UBIFS image which would have identical contents as the local root-fs directory;
-m 2048: tells mkfs.ubifs that the minimum input/output unit size of the flash this UBIFS image is created for is 2048 bytes (NAND page in this case);
-e 129024: logical eraseblock size of the UBI volume this image is created for;
-c 2047: specifies maximum file-system size in logical eraseblocks; this means that it will be possible to use the resulting file-system on volumes up to this size (less or equivalent); so in this particular case, the resulting FS may be put on volumes up to about 251MiB (129024 multiplied by 2047); See this section for more details.
-p 128KiB: tells ubinize that physical eraseblock size of the flash chip the UBI image is created for is 128KiB (128 * 1024 bytes);
-s 512: tells ubinize that the flash supports sub-pages and sub-page size is 512 bytes; ubinize will take this into account and put the VID header to the same NAND page as the EC header.
The ubinize utility requires volumes description file. Please, refer this section for more ubinize usage information.

In the example, the ubinize.cfg file tells ubinize to create an UBI image which has a singe 200MiB dynamic volume with ID 0, and name "rootfs". The configuration file also sets the "autoresize" volume flag, which means that the volume will be automatically enlarged by UBI to have the maximum possible size when it runs for the first time. See here for more information about what the auto-resize feature is. And because we specified "-c 2047" mkfs.ubifs option, UBIFS will also automatically re-size on the first mount. So the end result will be that you have one single volume of maximum possible size, and UBIFS spans whole volume.

Please, run ubinize -h and mkfs.ubifs -h for more information and for more possibilities to tweak the generated images.

Here is one more example for a 32MiB NOR flash with 128KiB physical eraseblock size.

$ mkfs.ubifs -q -r root-fs -m 1 -e 130944 -c 255 -o ubifs.img
$ ubinize -o ubi.img -m 1 -p 128KiB ubinize.cfg
where ubinize.cfg contains:

$ cat ubinize.cfg
[ubifs]
mode=ubi
image=ubifs.img
vol_id=0
vol_size=30MiB
vol_type=dynamic
vol_name=rootfs
vol_alignment=1
vol_flags=autoresize
And one more example for a 512MiB MLC NAND flash with 128KiB physical eraseblock size, 2048 bytes NAND page size and no sub-page write support.

$ mkfs.ubifs -q -r root-fs -m 2048 -e 126976 -c 4095 -o ubifs.img
$ ubinize -o ubi.img -m 2048 -p 128KiB ubinize.cfg
where ubinize.cfg contains:

$ cat ubinize.cfg
[ubifs]
mode=ubi
image=ubifs.img
vol_id=0
vol_size=450MiB
vol_type=dynamic
vol_name=rootfs
vol_alignment=1
vol_flags=autoresize
To flash UBI images, please use the ubiformat utility (see here) or use/implement a proper custom flasher program. (here you may find some hints). Please, read this section for more information why you should use ubiformat.
上面就是官网( http://www.linux-mtd.infradead.org/faq/ubifs.html)上的内容。如果当你读一遍上面的内容后还是没理解,那么建议你系统的学习官网中ubi和ubifs。

为了方便创建ubi和ubifs的镜像,可以使用buildroot 工具,这是一个开源的工具,方便快速的创建嵌入式系统。官方地址:http://buildroot.uclibc.org/

buildroot 支持make menuconfig这种图形配置的方法。

配置UBI的方法:make menuconfig

Filesystem images  --->

[*] tar the root filesystem                                                  
        Compression method (no compression)  --->                             
       ()    other random options to pass to tar                                   
  [*] ubifs root filesystem                                                    
(0x1f000) logical eraseblock size          
   // 这就是官网中提到的LEB                                  
  (0x800) minimum I/O unit size                  
                             
  (1000) maximum logical eraseblock count
   // Nand支持的最大LEB的个数                                       
        ubifs runtime compression (lzo)  --->                                   
       Compression method (no compression)  --->                              
 ()    Additional mkfs.ubifs options          

======================================================================                                 
 [*]   Embed into an UBI image                                                 
  (0x20000) physical eraseblock size          
// 这就是官网中提到PEB                               
  (2048)  sub-page size                                  
// sub-page                      
  ()      Additional ubinize options
//如何希望支持额外的命令,就在这里添加就好

上面的参数就是符合我的开发板上的nandflash制作UBIFS的镜像。其实上面这种配置实际是配置了ubi.mkfs 和ubinize这两个工具的参数,我已经用===分隔开,上面的就是

mkfs.ubifs的参数,下面的是ubinize的参数。

配置好后,直接执行make 命令,就会在output/image/ 下面生成rootfs.ubifs 和rootfs.ubi 。  这两文件分别是由ubi.mkfs和ubinize生成的。

网上有很多blog介绍如何烧写这个两个文件到nandflash中。这里就不主要介绍了。由于我的嵌入式系统中并没有其他的文件系统,所以不能从文件系统状态下进行对nandflash的烧写。所以只能在u-boot下对nandflash 的S3C2410 flash partition 2区域进行烧写。但是我的u-boot使用的TQ提供好的,版本太旧,不支持ubi的烧写命令,只支持nand的命令,所以这里就只能用nand write.e 烧写rootfs.ubi。

Why do I have to use ubiformat?
The first obvious reason is that ubiformat preserves erase counters, so you do not lose your wear-leveling information when flashing new images.
The other reason is more subtle, and specific to NAND flashes which have ECC calculation algorithm which produces ECC code not equivalent to all 0xFF bytes if the NAND page contains only 0xFF bytes. Consider an example.
We erase whole flash, so everything is 0xFF'ed now.
We write an UBI/UBIFS image to flash using nandwrite.
Some eraseblocks in the UBIFS image may contain several empty NAND pages at the end, and UBIFS will write to them when it is run.
The nandwrite utility writes whole image, and it explicitly writes 0xFF bytes to those NAND pages.
The ECC checksums are calculated for these 0xFF'ed NAND pages and are stored in the OOB area. The ECC codes are not 0xFF'ed. This is often the case for HW ECC calculation engines, and it is difficult to fix this. Normally, ECC codes should be 0xFF'ed for such pages.
When later UBIFS runs, it writes data to these NAND pages, which means that a new ECC code is calculated, and written on top of the existing one (unsuccessfully, of course). This may trigger an error straight away, but usually at this point no error is triggered.
At some point UBIFS is trying to read from these pages, and gets and an ECC error (-EBADMSG = -74).
In fewer words, ubiformat makes sure that every NAND page is written once and only once after the erasure. If you use nandwrite, some pages are written twice - once by nandwrite, and once by UBIFS.
If you can not use ubiformat, an alternative is to set the "free space fixup" flag when generating the UBIFS image (see here).

上面在配置kernel的nandflash选项的时,没有使用nandflash的NAND_ECC_HW,而是使用NAND_ECC_SOFT。原因就是我用的u-boot nand驱动采用的是NAND_ECC_SOFT软校验。所以kernel中的软校验算法和u-boot中的软校验算法必须一致。否则在对ubifs scan的时候会出现:

UBI error: ubi_io_read: error -74 (ECC error) while reading 4096 bytes from PEB 2:4096, read 4096 bytes
UBI error: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 3:4096, read 126976 bytes
UBI error: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 4:4096, read 126976 bytes
UBI error: ubi_io_read: error -74 (ECC error) while reading 11 bytes from PEB 10:4207, read 11 bytes
UBIFS error (pid 1): ubifs_leb_read: reading 11 bytes from LEB 8:111 failed, error -74
VFS: Cannot open root device "ubi0:rootfs" or unknown-block(0,0): error -74

说起这个-74 的错误真的是很头疼,因为MTD的技术手册上说,有很多原因会导致这个问题,所以很难trace。

我的nandflash的型号是 K9F2G08U0B 。nandflash 芯片参数:

• Automatic Program and Erase
- Page Program : (2K + 64)Byte
- Block Erase : (128K + 4K)Byte

从上面的信息可以知道:physical eraseblock size  是128K,至于后面加的那4K是nandflash的oob区域的大小,而ubi不会去对这块区域进行操作,所以这里不用管它。physical eraseblock size  就是128K。 因为这个nand的芯片不支持sub-page,所以sub-pag size就是 page size,即2K(64Byte就是OOB).

LEB的确定根据nandflash是否支持sub-page program有关系。由于我这个nand芯片是不支持sub-page的,所以只能将ubi的 EC 数据和 VID 分别存放在每个erase block的前两页。所以 LEB = 128K - 2K(EC)-2K(VID) = 124K = 126976。 minimum I/O unit size 就是这个ubifs可以在多到的volume上进行操作。我设置的是1000,所以ubifs可以进行操作volume的空间是1000*124K。也就是ubifs的极限。

如果nandflash支持sub-page program,并且sub-page是512字节, 那么一个page就包含4个sub-page,而 EC和VID的大小就是512Byte.所以可以将EC和VID存在一个page中的前两个sub-page中,那么只要一个page就将EC和VID存储了。 所以LEB= 128k-2K=126K=129024(这个page中既有EC又有VID)。这样一个block就节省了2k,所以支持sub-page的nandflash,ubi的空间会更大。

LEB = 129024

minimum I/O unit size  =0x200

physical eraseblock size  = 0x20000

sub-page size=0x200

log信息

Scanning device for bad blocks
Creating 3 MTD partitions on "NAND":
0x000000000000-0x000000200000 : "Boot Agent"
0x000000200000-0x000000600000 : "S3C2410 flash partition 1"
0x000000600000-0x00000c600000 : "S3C2410 flash partition 2"
UBI: attaching mtd2 to ubi0
UBI: physical eraseblock size:   131072 bytes (128 KiB)
UBI: logical eraseblock size:    126976 bytes
UBI: smallest flash I/O unit:    2048
UBI: sub-page size:              512
UBI: VID header offset:          2048 (aligned 2048)
UBI: data offset:                4096
UBI: max. sequence number:       0
UBI: volume 0 ("rootfs") re-sized from 826 to 1232 LEBs
UBI: attached mtd2 to ubi0
UBI: MTD device name:            "S3C2410 flash partition 2"
UBI: MTD device size:            192 MiB
UBI: number of good PEBs:        1536
UBI: number of bad PEBs:         0
UBI: number of corrupted PEBs:   0
UBI: max. allowed volumes:       128
UBI: wear-leveling threshold:    4096
UBI: number of internal volumes: 1
UBI: number of user volumes:     1
UBI: available PEBs:             0
UBI: total number of reserved PEBs: 1536
UBI: number of PEBs reserved for bad PEB handling: 300
UBI: max/mean erase counter: 1/0
UBI: image sequence number:  144854457
UBI: background thread "ubi_bgt0d" started, PID 722
mousedev: PS/2 mouse device common for all mice
cpuidle: using governor ladder
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
s3c24xx_serial_startup: port=50000000 (f7000000,c0367798)
requesting tx irq...
s3c24xx_serial_startup ok
udivslot = 0808 (div 2)
config: 8bits/char
setting ulcon to 00000003, brddiv to 26, udivslot 00000808
uart: ulcon = 0x00000003, ucon = 0x00000bc5, ufcon = 0x00000051
name =ubi0:rootfs
UBIFS: mounted UBI device 0, volume 0, name "rootfs"
UBIFS: file system size:   125579264 bytes (122636 KiB, 119 MiB, 989 LEBs)
UBIFS: journal size:       9023488 bytes (8812 KiB, 8 MiB, 72 LEBs)
UBIFS: media format:       w4/r0 (latest is w4/r0)
UBIFS: default compressor: lzo
UBIFS: reserved for root:  0 bytes (0 KiB)
VFS: Mounted root (ubifs filesystem) on device 0:9.
udivslot = 0808 (div 2)
config: 8bits/char
setting ulcon to 00000003, brddiv to 26, udivslot 00000808
uart: ulcon = 0x00000003, ucon = 0x00000bc5, ufcon = 0x00000051
can't open /dev/null: No such file or directory
can't open /dev/null: No such file or directory
can't open /dev/null: No such file or directory
can't open /dev/null: No such file or directory
can't open /dev/null: No such file or directory
can't open /dev/null: No such file or directory
udivslot = 0808 (div 2)
config: 8bits/char
setting ulcon to 00000003, brddiv to 26, udivslot 00000808
uart: ulcon = 0x00000003, ucon = 0x00000bc5, ufcon = 0x00000051 
Starting logging:  
Starting network...
ip: socket: Function not implemented
ip: socket: Function not implemented
can't open /dev/ttyS0: No such file or directory
can't open /dev/ttyS0: No such file or directory
挂载成功后出现can't open /dev/ttyS0: No such file or directory的错误。 如果想正常的进入终端操作,还需要两部分。

1.在samsung.c中   #define S3C24XX_SERIAL_NAME "ttySAC",所以最终在/dev/ 下面会生成 ttySAC0这个设备节点。 所以需要更改 buildroot中的设置。

System configuration --->

[*] Run a getty (login prompt) after boot

 getty options  ---> 

(ttyS0) TTY port

在这里讲ttyS0 更改为 ttySAC0,。 

2.只有上面那一步还是会出现问题 can't open /dev/ttySAC0: No such file or directory,这次就知道了,原来dev下面没有这个设备节点。所以说明 udev没有运行。事实上有一些出入,我使用的busybox中提供的是mdev,它是适合嵌入式设备的。用法与udev相同。设置方法:

在output/etc/init.d/rc.S 文件中添加下面这段命令:

mount -t proc proc /proc
mount -t sysfs sysfs /sys
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

为什么添加这段,查看busybox 中mdev.txt有详细解释。 

这样 在重新编译buildroot ,生成rootfs.ubi,烧写进 mtd2 的分区中,启动,就可以进入终端下面了。

默认情况下,是需要输入用户root,然后就能看到久违的‘# ’了。


到此UBI的移植工作就完成了,也已经进入终端下,只有这样才能对其他的设备进行移植。 总结其中最难得地方就是 nand 校验的设置,由于u-boot中的nand校验方式和kernel中的不同,浪费了很多时间去查找。






你可能感兴趣的:(Linux,kernel)