1
UBI Development
What is UBI
1. UBI不是一个Flash Translation Layer,它和FTL没有任何关系。
2. 工作在bare flashes,它不能工作在MMC, eMMC, SD, mini-SD, micro-SD, USB flash设备上;UBI工作于raw flash devices上,大部分出现在嵌入式设备上。
Overview
UBI全称"Unsorted Block Images"。它是工作于raw flash devices之上的volume管理系统,它管理一个单一physical flash设备上的多个logical volume,能够把I/O负载均匀的分发到flash chip上。
在一定意义上,UBI可以和Logical Volume Manager相比较。LVM映射logical sector到物理sectors,UBI映射logical eraseblcok到physical eraseblocks。但是除了映射,UBI还实现了wear-leveling和透明的I/O错误管理。
一个UBI volume是一组连续的logical eraseblocks(LEBs)。每一个逻辑eraseblcok可以被映射为任意的physical eraseblock。这个映射是由UBI管理,并且对上层隐藏了global wear-leveling机制(记录per-physical eraseblock erase counters 以及透明的移动more worn-out数据到less worn-out上)。
UBI volume在创建时确定尺寸大小,也可以在日后改变(volume是dynamic re-sizable)。UBI有user-space工具可以用来管理UBI volumes。
有两种UBI volume,dynamic和static。static volumes是只读的,内容由CRC-32 checksums保护;而dynamic volume是read-write,上层负责确保数据的完整性。
UBI处理坏块,上层不需要关心坏块管理。UBI有一个保留的physical eraseblocks pool,当一个physical eraseblock变成坏块,UBI透明的用一个好的physical block替换这个坏块。UBI把新出现的physical eraseblock的数据移动到好physical eraseblock。UBI volume对发生的事毫无察觉。 NAND flash在读写操作时可能会发生bit-flips。Bit-flips通过ECC checksums纠正,但是积累到一定数据可能会发生数据丢失。UBI会移动发生bit-flips的数据到另外一个physical eraseblocks。这个过程叫scrubbing。scrubbing过程是后台的,并且对上层透明。(以上两点客户要求使用UBI的主要原因)
下面是UBI主要功能的一个短列表:
1. UBI提供动态生成,删除或re-sized的volume;
2. UBI实现全flash设备的wear-leveling(比如,你写的一个UBI volume的逻辑块,可以写入flash chip的任何physical eraseblocks);
3. UBI透明的处理所有physical eraseblocks;
4. UBI通过bit-flips使得数据丢失的可能性最小化。
下面是MTD分区和UBI volumes的比较,他们有一些相似之处:
(客户很在意这个)
1. 都是由eraseblocks组成的 - UBI volumes是逻辑eraseblocks,而MTD分区是物理的。
2. 都支持下面三个基本操作 - read, write, erase
2
但是UBI volumes和MTD分区相比有如下优点:
1. UBI volumes没有eraseblock wear-leveling 限制,所以用户不需要考虑这个,上层软件实现更简单。
2. UBI volumes没有bad eraseblocks,这也使上层软件不需要做坏块管理,因此上层软件也更简单。
3. UBI volumes是动态的,可以创建,删除和动态resize,而MTD分区是静态的。
4. UBI 处理bit-flips,同样使得上层软件更简单。
5. UBI提供volume update操作which makes it easy to detect interrupted software updates and recover。
6. UBI 提供了原子逻辑块修改操作,这个操作保证在修改logical eraseblock的内容过程中,发生unclean reboots不会造成数据丢失; 这对于上层软件可能是非常有用的
7. UBI有一个un-map操作,un-maps一个逻辑eraseblock到physical eraseblock的映射。schedules the physical eraseblock for erasure and returns;这是非常快的并且使得上层软件避免实现他们自己的机制。
现在我们使用的gluebi是一个驱动,用来在MTD设备上模拟UBI volumes。这看起来很奇怪,因为UBI工作在MTD设备之上,而gluebi又在UBI上模拟另外一个MTD设备。但是这种做法可以使我们更灵活的使用各种文件系统的特性,比如我们现在的方案是把squashfs使用gluebi的驱动写入到一个UBI volume上。这样不仅发挥了squashfs优点(高压缩、只读),而且还能充分利用UBI的坏块管理机制,延长nand flash的寿命。
UBI在每一个非坏physical eraseblcok的起始位置,储存两个小的64-byte的头:
1.erase counter header(or EC header)包含physical eraseblock 的擦除计数和一些其它重要信息;
2.volume identifier header(or VID header)储存volume ID 和逻辑eraseblock(LEB)号,这两个信息可以确定这个PEB属于哪个volume,以及逻辑位置; VID还包含了其他的一些信息。
这就是为什么eraseblocks要小于physical eraseblock ——头占据了一部分flash空间。
所有的UBI headers 使用CRC-32保护,请查阅linux源码中的:drivers/mtd/ubi/ubi-media.h文件查看header的内容。
当UBI attach到一个MTD device,首先扫描它,读所有的headers,检查CRC-32 checksums,存储erase counters和logical-to-physical eraseblock映射信息到RAM。
当UBI删除一个PEB,它写EC header,包含增加的erase count value。这意味着PEBs一直有EC header,除了从删除结束到EC header被写入的这个空档,如果在这时发生了unclean reboot,造成EC header丢失。在这种情况下,UBI写一个新的EC header,erase counter为MTD device扫描后的平均erase counter。
当UBI关联一个PEB和LEB时,VID头被写入PEB中。让我们考虑下面操作发生时,头部发生的变化:
The LEB un-map操作就是取消LEB和PEB之间的关联,PEB被erasure。PEB
3
被擦除,EC header被写入,但是VID header并没有被写入。LEB map操作或者对un-mapped LEB的写操作:UBI首先找到一个 PEB然后写如VID header(EC header一定已经存在了)。注意,对于一个已经mapped LEB的写操作,直接把数据写入PEB而不会修改UBI headers。
UBI维护着两个per-PEB头因为它需要在不同的时间写不同信息到flash上:
在PEB删除后,EC头立刻写入PEB
当一个UBI关联一个PEB和LEB时,VID头写入PEB
当EC header写入PEB,UBI并不知道这个PEB要关联的volume ID和LEB number。这就是为什么UBI需要两个写操作,来写两个分离的headers
UBI volume table
volume table是on-flash数据结构,保存着这个 UBI设备上每一个volume的信息。volume table是一个volume table records的数组,每一个record包含以下信息:
volume size;
volume name;
volume type;
volume alignment;
update maker;
auto-resize flag;
CRC - 32 checksum for this record.
每一个record描述一个UBI volume,记录在volume table array的index对应着这个记录的volume ID,比如UBI volume0被volume table的record0描述。volume table内的records数目受限于LEB尺寸,但是不能大于128。这就意味着最大的volume数目不能大于128。
每当UBI volume被创建,删除,re-sized,re-named或者updated时,相应的volume table record被修改。UBI维护着两个volume table以维护掉电发生后的可用性。
Implementation details
olume table驻留在一个特定目标的UBI volume中,叫做layout volume。这个volume包含两个LEBS - 每一个对应一个volume table的copy。layout volume是一个内部的UBI volume,user不能看到也不能访问它。当读或者写layout volume时,UBI使用和正常user volumes相同的机制。
UBI在updating volume table内容时,使用下列算法。
准备volume table在内存中的内容
un-map layout volume的LEB0
写新的volume table到LEB0
un-map layout volume的LEB1
写新的voume table到LEB1
刷新UBI工作队列,确保un-mapped LEBs对应的PEBs被删除掉。
当attaching MTD设备时,UBI确保两个volume table拷贝是相同的。unclean reboot可能会导致他们不相同,这是UBI选择LEB0的内容copy到LEB1中(因为LEB0是新的)。如果有一个volume table被损坏了,UBI会从另外一个volume
4
table恢复过来
Minimum flash input/output unit
UBI使用flash的抽象模型。简而言之,从UBI的角度看,flash(MTD设备)包含着eraseblocks,这些eraseblocks可以是好的,也可以是坏的。没有一个好的eraseblock可以读,写或者删除。好的eraseblocks也可以被mark为bad。
flash read和write是有最小I/O unit尺寸的,这依赖于flash类型。
NOR flash通常有最小的I/O单位为1byte,因为NOR flash通常允许读写单个字节。一些NOR flash最小I/O unit可能为16或者32,比如带ECC的NOR flash。
NAND flashed通常有512,2048或者4096 bytes的最小I/O unit,对应着NAND page size。NAND flashed存储per-NAND page ECC到OOB area,意味着写整个NAND page以便计算ECC code,读整个NAND page以便校验ECC code
最小I/O单位对MTD设备来说是非常重要的,它影响很多事情,比如:
VID header的物理位置依赖于min. I/O unit。LEB的尺寸也依赖于它;通常来说,I/O unit越大,LEB越小,UBI flash空间开销越大,因为EC header和VID header都占用一个I/O unit
所有对LEBs的写都应该和min. I/O unit对齐,是min. I/O unit的倍数;reads没有这个限制,但是要记住,MTD级的所有读都是min. I/O unit的倍数; 只是上层通过buffering 读数据屏蔽了这个特点。
NAND flash sub-pages
像之前所说的,所有的UBI I/O必须是min. I/O unit,也就是NAND flash的page size。然而一些SLC NAND flashes允许更小的I/O units,这在MTD术语称为sub-pages。不是所有的NAND都有sub-pages。
MLC NANDs 没有sub-pages。
SLC NANDs通常有sub-pages。比如512-bytes NAND pages通常包含2x256-bytes的sub-pages,2048-byte NAND pages 包含4x256 bytes sub-pages。
SLC OneNAND chips,2048 bytes NAND page size有4x512-bytes sub-pages。
如果NAND flash支持sub-pages,那么ECC codes的计算可以以sub-page为单位,而不是per-NAND。在这种情况下可以read和write sub-pages单独的。
很明显,尽管NAND chip支持sub-pages,NAND controller可能disallow。事实上,如果管理flash的controller计算ECC是per-NAND,那么就不可能进行sub-page级的I/O操作。
使用sub-pages可以减少flash 空间开销,比如对于128KiB eraseblock,page size是2048-bytes。如果没有sub-pages,EC占据第一个2048,VID herder占据第二个2048,因此LEB size变成124KiB。反之支持sub-pages,UBI把EC 和VID分别放在第一和第二个512字节,所以LEB变成了126KiB。
Sub-pages仅仅在UBI内部使用,用来存放EC VID headers,UBI API不允许用户使用sub-page I/O unit。这是因为sub-page writes可能很慢,写一个sub-page,驱动可能会写整个NAND page,但是会把和本次操作无关的sub-pages都写入0xff。这也就是说写四个sub-pages可能比写整个NAND pages慢四倍。因此,UBI仅对headers使用sub-pages,但是在UBI API中不存在这个概念。
UBI header position
EC header存放在PEB的偏移0处,占据64bytes;VID header位于下一个min. I/O unit或者sub-page处,占据64 bytes。例如:
5
对于NOR flash,1 byte min. I/O unit,VID header位于PEB 64处
对于没有sub-pages的NAND flash,VID header位于第二个NAND page
对于有sub-pages的NAND flash,VID header位于第二个sub-page
Flash space overhead
UBI使用一定数量的flash space来保存管理信息,因此减少了flash device可供UBI用户使用的空间,这些开销包括:
2PEB用来存储volume table
1 PEB保留用来wear-leveling purpose
1 PEB 保留用来atomic LEB change操作
一定数据的PEBs被用来PEB handling;这适用NAND flash,但是不适用NOR flash;保留的PEBs百分比是可配置的,缺省是1%
Saving erase counters
当使用UBI时,储存erase counters 到flash media上很重要。也就是说,每个physical eraseblock有一个叫做erase counter header用来存储这个physical eraseblock被删除的次数。当然,保持这个erase counter不丢失也同样重要,这意味这你删除flash和写ubi image的工具要考虑erase counter。mtd-utils包含着ubuformat工具可以正确执行这些操作
How UBI flasher should work
以下是UBI flasher程序在删除flash或者flashing UBI images时要做的事:
首先,扫描整个flash来收集erase counter。也就是它读每一个PEB的EC header,检查每一个header的CRC32 checksum,保留erase counter到ram中。不需要读取VID headers。忽略掉bad PEBS。
计算平均erase counter。当PEBs的EC header被损坏或丢失时,用平均erase counter。这样的PEBs可能是由于unclean reboots引起的,当然数量不会太多。如果目标是删除flash,那么每个PEB被删除,正确的EC header被写到PEB中。EC header中应该包含增增加的erase counter。bad PEBs应该被忽略。对于NAND flashes, 当erasing或者writing时发生I/O错误时,PEB被标记为bad。如果目的是烧写UBI image,那么烧写工具应该对每一个PEB做如下工作:
1.从UBI image中读取这个PEB的内容到一个buffer中,buffer必须是min I/O unit倍数
2.把buffer中未填满的部分都写入0xff
3.删除PEB
4.改变buffer中的EC header
5.写这个buffer到physical eraseblock
在实践中,UBI image通常都小于UBI volume,因此flasher要正确的烧写PEBs,正确的处理删除的PEBs.
注意:
1.在写UBI image时,UBI image写到哪个eraseblocks是无所谓的,比如,image的第一个eraseblock可以写入第一个PEB,或者第二个,或者最后一个。
2.如果你实现一个产线UBI images烧写工具。那么flasher不需要改变EC headers,因为这是新的flash,所以每一个PEB的erase counter应该为0。这意味着产线flasher更简单。
6
如果你的UBI image 包含UBIFS file system,并且你的flash是NAND, you may have to drop 0xff bytes the end of input PEB data. this is very importtant, although not required for all NAND flashes. Sometimes a failure to do this may result in very unpleasant problems which might be diffcult to debug later. So we recommend to always do this.
原因是UBIFS对待仅包含oxff byte的NAND pages为free。例如,假定PEB的第一个NAND page有一些数据,第二个是empty,第三个有一些数据,第四个和其他的都是空的,在这种情况下,UBIFS认为从第四个 page开始的NANDpages是空闲的,并且会向这些page写数据。然而,如果flasher程序已经向这些pages写了0xff,结果导致他们被写了两次!然而,一些NAND flashes要求他们的NAND pages仅被写一次,即便这些数据包含的都是0xff bytes。
flash不得不做的是drop掉所有到PEB结尾的empty NAND pages。没必要drop掉所有的空NAND pages,仅需要最后一个。这就意味着flasher不需要扫描整个buffer,查找0xff。只需从buffer末尾开始查找知道第一个non-0xff byte,这是非常快的。
另外一个替代方法,是在生成UBIFS文件系统时使用mkfs.ubifs增加free space fixup选项。这将允许你的flasher不需要担心PEBs末尾的0xff。这在你使用一个产线烧写程序写一个UBI image时非常有用。
Marking eraseblocks as bad
这一节是针对那些允许出现坏块的NAND flashes和其他的flashes。UBI在两种情况下mark physical eraseblocks为坏块:
1. eraseblock写操作失败,在这种情况下,UBI把这个PEB的数据移到其他的PEB(data recovery),然后调用对这个PEB的诊断
2. 删除操作出现EIO error,在这种情况下,直接把PEB标记为坏块。
诊断是在后台处理的,目的是检测这个physical eraseblock是否真的坏了。写失败可能有多种原因,包括驱动的bugs或者上层file system 的bug(比如,文件系统多次写了同一个NAND page)。整个诊断过程包括如下步骤:
删除eraseblock;
读取eraseblock,确保仅包含0xff bytes;
写测试模式bytes;
读取eraseblock,检查模式串;
重复几个其他的模式(0xA5, 0x5A, 0x00)
如果eraseblock通过了torture test,那么不会被标记为坏块。注意,在诊断测试过程中,bit-flip发生是把eraseblock mark为坏块的很好理由,请参考torture_prb函数。
Scalability issues
不幸的是,UBI扩展性是和flash size线性相关的。UBI初始化时间线性依赖flash 的PEB数量。这意味着flash越大,UBI初始化的时间也越大。这个初始化时间也依赖flash的I/O速度同时轻微的依赖CPU速度,因为UBI在attach时会扫描MTD设备 - 它读取erase EC和VID headers从每个单个PEB;headers 很小,所以这意味对于NOR flash需要读取128 bytes per-PEB,而对NAND flash需要读取1~2NAND pages per-PEB;这当然远小于JFFS2 mount MTD设备所需的
7
读写数据量,所有UBI attaches MTD设备要远快于JFFS2在MTD设备上 mount一个文件系统。
UBI 为每一个EC和VID headers 计算CRC-32 checksum,这将消耗CPU,尽管这个flash I/O负载比较非常小。
Implementation details
一般来说,UBI需要三个表:
volume table:包含per-volume信息,比如volume 尺寸,类型等;
eraseblock association(EBA) table:包含logical to physical eraseblock映射信息;比如,当读一个LEB时,UBI首先查找对应的PEB number,然后读取这个PEB;
erase counter EC table:包含着每一个物理删除块的erase counter;UBI 磨损平衡子系统使用这个表来发现PEB的 erase counter。
volume table维护在flash上。它仅仅在UBI volumes被创建,删除和re-sized时改变。这种操作很少且对速度没有要求,UBI可以负担一个慢的简单的方法来管理volume table。
EBA和EC表在每次LEB被映射或者PEB被删除时都会改变,因此需要这两个表的管理方法要快而且高效。
UBI可以在flash上,维护EBA和EC tables。这无法避免的引入了journaling, journal replay, journal commit等等。换句话说,这将引入许多复杂性。但是这可以使得EBA和EC在算法上是可扩展的。
UBI的一个需求是on-flash上格式的简化,因为UBI作者不得不在boot-loader中读取UBI volumes,而在boot-loader的代码中有很严格的限制,基本上很难在boot-loader代码中加入复杂的journal scanning和replay code。
所以UBI没有在flash media上维护EBA和EC tables。而是在每次attach MTD设备时构造它。这意味着UBI不得不扫描整个flash,从每个PEB读取EC和VID header以便构造in-RAM EC和EBA tables。
这个设计的缺点是很差的可扩展性以及NAND flashes空间的负载(大约1.5~3%的flash空间,2KiB NAND page,128KiB eraseblock),优点是简单以及可靠性。
当然,可以创建UBI2,维护这些表在分离的flash area。UBI2将不和UBI兼容,因为他们有完全不同的on-flash格式,但是用户接口是完全一样的,这将保证UBI上层软件的兼容性。
Volume auto-resize
众所周知NAND chips有一定数目的physical eraseblocks被厂商mark为坏块。坏块随机的分布并且数据是不同的,尽管厂商通常保证前几个physical eraseblocks不是坏的并且坏块的总数不会超过一定的数目。比如,一个新的256MiB的oneNAND chips保证不超过40128KiB PEBs(当然,在使用过程中,这个数量会增加)。这大概是2%的flash size ,当需要创建一个UBI image用来在产线上刷如终端用户设备,你应该定义所有volume的确切尺寸。但是又有total flash size是依赖于初始坏块总数的,所以很难这么做。解决这个问题的一个明显方法是假定最坏的情况,当所有的chips都有一个bad PEBs的最大值。但是实际中,大部分chips仅仅有几个bad PEBs,远小于这个最大值。一
8
般来说,这没什么问题,这将增加可靠性,因为UBI一直使用设备上的所有PEBs。另一方面UBI无论如何要保留一定数目的physical eraseblocks用做坏块处理,缺省情况下是1%。所以上面提到的OneNAND chip将有%1 PEB保留给UBI,0~2%PEB不可以被使用。
但是有另外一个替代办法:一个volume可以有auto-resize mark,这意味着当UBI第一次运行时它的尺寸可以enlarged。在volume size调整后,UBI移除auto-resize标志后这个volume不能再re-sized。auto-resize flag存储在volume table仅仅一个volume可以被mark为auto-resize。
UBI operations
LEB un-map
LEB un-map操作的实现是ubi_leb_unmap() kernel API。从linux 内核2.6.29开始un-map操作通过UBI_IOCEBUNMAP ioctl命令暴露给user-space程序。这个ioctl应该被UBI volume character devices调用
LEB un-map操作:
首先un-maps LEB和相应的PEB
然后调度这个PEB的擦除并返回;
un-map不会等待擦除的结束;
PEB有UBI后台线程负责擦除
当读取一个un-mapped LEB时,UBI返回全0xff bytes,所以un-map操作可以被认为是一个非常快的erase operation。但是有一点需要注意。
假定你un-map LEB numL从PEB numP。因为P不是同步删除的,而是仅仅调度了删除操作,这可能在unclean reboots时给个”惊喜“;如果在P物理删除前恰好发生了reboot。在UBI再次attaches到MTD设备上时,会发现L仍然mapped到UBI。事实上,UBI将扫描整个MTD设备发现哪个P对应L,然后把这个映射加到EBA table。
但是一旦你写数据到numL,或者使用LEB map操作,numL映射一个新的PEB,老数据就变成了历史,因为即便此时发生了unclean reboot,UBI仍然会选择numL的最新映射。
Implementation details
这一节描述在发生unclean reboot后,UBI如何区分一个LEB的older和newer的PEB,假定我们un-map LEB L到PEB P1的映射,此时UBI调度了P1的erasure。然后我们向L写数据,意味着UBI找到另外一个PEB P2,映射L到P2,然后写数据到P2,如果在P1被物理删除前,发生unclean reboot,我们得到了2个PEBs(P1, P2)对应同一个LEB L
为了处理这种情况,UBI维护一个全局64-bit sequence number variable。这个可变序列号每次映射一个LEB时都会增加并且存储到PEB的VID header中,所以每一个VID header有一个唯一的序列号,序列号越大,VID越年轻。当UBI attach到MTD设备时,初始化全局sequence number为VID headers中的最大值加1。
在上面的情况,很显然UBI会选择higher sequence number (P2) 然后抛弃lower sequence number(P1)
注意:如果unclean reboot发生在,磨损平衡而执行的移动一个PEB数据到另
9
外一个PEB的过程中,或者atomic LEB change操作时发生。在这种情况下不能简单的选择新的PEB,必须确保新的数据是否已经写到new PEB。
LEB map
LEB map操作映射一个从前un-mapped 逻辑eraseblock到一个物理eraseblock。比如,如果要为LEB A映射,UBI首先发现相应的PEB,然后把VID header写入PEB,然后修正in-memory EBA table。VID header将指向LEB A,这个操作完成后,所有到LEB A的操作最终都会到mapped PEB
LEB映射操作是通过ubi_leb_map() UBI kernel API函数,或者通过UBI_IOCEBMAP ioctl
LEB map操作接受dtype类型参数,这个参数建议LEB将保存的数据类型,dtype有如下类型:
UBI_SHORTTERM - LEB存储的是短期数据,也就是这个数据很快就会被擦除;UBI将映射LEB到一个low erase counter的PEB。
UBI_SHORTTERM - LEB存储的是长期数据,UBI映射这个LEB到high erase counter的PEB。
UBI_UNKNOWN - 在大多数情况下使用,当你无法确定是否为长期或者短期
记住dtype仅仅是一个hint。如果无法确定,请使用UBI_UNKNOWN。
Stealth Project设计流程:
1.将我们生成的squashfs使用如下配置打包成gluebi驱动能工作的文件:
2.设置bootargs:root=/dev/mtdblock8 ubi.mtd=5 rootfstype=squashfs
root=/dev/mtdblock8 中的8为linux启动之后ubiattach后创建的新分区,在我们规划的最后一个分区之后,可以使用cat /proc/mtd查看。
ubi.mtd=5 其中5为我们规划分区中存储application的分区号
rootfstype 为实际的文件系统,即源文件系统类型
3.修改loader升级读写:
loader升级的时候,考虑到UBI的bad block管理以及启动扫描flash等特性,我们不采取直接升级gluebi volume的方式,而是采用往建立好的ubi volume上面写源文件系统的方式来操作。同时在loader校验数据的时候直接按ubi volume来读取和写入数据。
a. format application分区为ubi。
skyapi_syscall_system(SK_SYSCALL_MODE_SYNC,"ubiformat /dev/mtd5 -y", 0);
b. attach MTD device to UBI
skyapi_syscall_system(SK_SYSCALL_MODE_SYNC,"ubiattach /dev/ubi_ctrl -m 5", 0);
mode=ubi
image=$UBIIMG ##文件源:rootfs.squash
vol_id=0
vol_size=${vol_size}MiB ##vol_size为自动获取的squashfs文件大小
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize
10
c. 创建一个名为rootfs的volume,并使volume size尽量大
skyapi_syscall_system(SK_SYSCALL_MODE_SYNC,"ubimkvol /dev/ubi0 -N rootfs -m", 0);
d.使用以下interface将升级数据写入volume:
e.当要从flash上读出数据来校验时,使用以下interface read
/* lfx added 2014-05-31 */
static int ubi_write(char *ubi_vol, unsigned char *buffer, unsigned int size)
{
int fd = -1, ret;
long long bytes;
fd = open(ubi_vol, O_RDWR);
if (fd < 0)
{
printf("ERROR:[ubi_write] Open %s fail \n",*ubi_vol);
return 0;
}
bytes = size;
if (ioctl(fd, UBI_IOCVOLUP, &bytes))
{
close(fd);
printf("ERROR:[ubi_write] ioctl %s fail \n",*ubi_vol);
return 0;
}
ret = write(fd, buffer, size);
close(fd);
return ret;
}
static int ubi_read(char *ubi_vol, unsigned char *buffer, unsigned int size)
{
int fd = -1, ret;
fd = open(ubi_vol, O_RDONLY);
if (fd < 0)
{
printf("ERROR:[ubi_read] Open %s fail \n",*ubi_vol);
return 0;
}
ret = read(fd, buffer, size);
close(fd);
return ret;
}
11
注:在对UBI的attach操作之后,进行读写完一定要deattch,以保证操作流程的完整性。
附:User-space tools
root@sdk:~# ubiattach -help
ubiattach version 1.5.0 - a tool to attach MTD device to UBI.
Usage: ubiattach [
]
[-m ] [-d ] [-p ]
[--mtdn=] [--devn=]
[--dev-path=]
UBI control device defaults to /dev/ubi_ctrl if not supplied.
Example 1: ubiattach -p /dev/mtd0 - attach /dev/mtd0 to UBI
Example 2: ubiattach -m 0 - attach MTD device 0 (mtd0) to UBI
Example 3: ubiattach -m 0 -d 3 - attach MTD device 0 (mtd0) to UBI
and create UBI device number 3 (ubi3)
-d, --devn= the number to assign to the newly created UBI device
(assigned automatically if this is not specified)
-p, --dev-path= path to MTD device node to attach
-m, --mtdn= MTD device number to attach (alternative method, e.g
if the character device node does not exist)
-O, --vid-hdr-offset VID header offset (do not specify this unless you really
know what you are doing, the default should be optimal)
-h, --help print help message
-V, --version print program version
---------------------------------------------------------------------
root@sdk:~# ubidetach -help
ubidetach version 1.4.8 - tool to remove UBI devices (detach MTD devices from UBI)
Usage: ubidetach []
[-d ] [-m ] [-p 12
device>]
[--devn=] [--mtdn=]
[--dev-path=]
UBI control device defaults to /dev/ubi_ctrl if not supplied.
Example 1: ubidetach -p /dev/mtd0 - detach MTD device /dev/mtd0
Example 2: ubidetach -d 2 - delete UBI device 2 (ubi2)
Example 3: ubidetach -m 0 - detach MTD device 0 (mtd0)
-d, --devn= UBI device number to delete
-p, --dev-path= or alternatively, MTD device node path to detach
-m, --mtdn= or alternatively, MTD device number to detach
-h, --help print help message
-V, --version print program version
---------------------------------------------------------------------
root@sdk:~# ubimkvol -help
ubimkvol version 1.5.0 - a tool to create UBI volumes.
Usage: ubimkvol [-h] [-a ] [-n ] [-N ]
[-s ] [-S ] [-t ] [-V] [-m]
[--alignment=][--vol_id=] [--name=]
[--size=] [--lebs=] [--type=] [--help]
[--version] [--maxavsize]
Example: ubimkvol /dev/ubi0 -s 20MiB -N config_data - create a 20 Megabytes volume
named "config_data" on UBI device /dev/ubi0.
-a, --alignment= volume alignment (default is 1)
-n, --vol_id= UBI volume ID, if not specified, the volume ID
will be assigned automatically
-N, --name= volume name
-s, --size= volume size volume size in bytes, kilobytes (KiB)
or megabytes (MiB)
-S, --lebs= alternative way to give volume size in
13
logical
eraseblocks
-m, --maxavsize set volume size to maximum available size
-t, --type= volume type (dynamic, static), default is dynamic
-h, -?, --help print help message
-V, --version print program version
---------------------------------------------------------------------
root@sdk:~# ubiformat -help
ubiformat version 1.5.0 - a tool to format MTD devices and flash UBI images
Usage: ubiformat [-s ] [-O ] [-n]
[-f ] [-S ] [-e ] [-x ] [-y] [-q] [-v] [-h] [-v]
[--sub-page-size=] [--vid-hdr-offset=] [--no-volume-table]
[--flash-image=] [--image-size=] [--erase-counter=]
[--ubi-ver=] [--yes] [--quiet] [--verbose] [--help] [--version]
Example 1: ubiformat /dev/mtd0 -y - format MTD device number 0 and do
not ask questions.
Example 2: ubiformat /dev/mtd0 -q -e 0 - format MTD device number 0,
be quiet and force erase counter value 0.
-s, --sub-page-size= minimum input/output unit used for UBI
headers, e.g. sub-page size in case of NAND
flash (equivalent to the minimum input/output
unit size by default)
-O, --vid-hdr-offset= offset if the VID header from start of the
physical eraseblock (default is the next
minimum I/O unit or sub-page after the EC
header)
-n, --no-volume-table only erase all eraseblock and preserve erase
counters, do not write empty volume table
-f, --flash-image= flash image file, or '-' for stdin
-S, --image-size= bytes in input, if not reading from file
-e, --erase-counter= use as the erase counter value for all
14
eraseblocks
-x, --ubi-ver= UBI version number to put to EC headers
(default is 1)
-Q, --image-seq= 32-bit UBI image sequence number to use
(by default a random number is picked)
-y, --yes assume the answer is "yes" for all question
this program would otherwise ask
-q, --quiet suppress progress percentage information
-v, --verbose be verbose
-h, -?, --help print help message
-V, --version print program version
---------------------------------------------------------------------
root@sdk:~# ubinfo -help
ubinfo version 1.4.8 - a tool to print UBI information.
Usage 1: ubinfo [-d ] [-n | -N ] [-a] [-h] [-V]
[--vol_id= | --name ] [--devn ] [--all] [--help] [--version]
Usage 2: ubinfo [-a] [-h] [-V] [--all] [--help] [--version]
Usage 3: ubinfo [-h] [-V] [--help] [--version]
Example 1: ubinfo - (no arguments) print general UBI information
Example 2: ubinfo -d 1 - print information about UBI device number 1
Example 3: ubinfo /dev/ubi0 -a - print information about all volumes of UBI
device /dev/ubi0
Example 4: ubinfo /dev/ubi1_0 - print information about UBI volume /dev/ubi1_0
Example 5: ubinfo -a - print all information
-d, --devn= UBI device number to get information about
-n, --vol_id= ID of UBI volume to print information about
-N, --name= name of UBI volume to print information about
-a, --all print information about all devices and volumes,
or about all volumes if the UBI device was
15
specified
-h, --help print help message
-V, --version print program version
---------------------------------------------------------------------
root@sdk:~# mtdinfo -help
mtdinfo version 1.4.8 - a tool to print MTD information.
Usage: mtdinfo [--map | -M] [--ubi-info | -u]
mtdinfo --all [--ubi-info | -u]
mtdinfo [--help | --version]
Options:
-u, --ubi-info print what would UBI layout be if it was put
on this MTD device
-M, --map print eraseblock map
-a, --all print information about all MTD devices
Note: `--all' may give less info per device
than, e.g., `mtdinfo /dev/mtdX'
-h, --help print help message
-V, --version print program version
Examples:
mtdinfo /dev/mtd0 print information MTD device /dev/mtd0
mtdinfo /dev/mtd0 -u print information MTD device /dev/mtd0
and include UBI layout information
mtdinfo -a print information about all MTD devices
---------------------------------------------------------------------
root@sdk:~# ubiupdatevol -help
ubiupdatevol version 1.4.8 - a tool to write data to UBI volumes.
Usage: ubiupdatevol [-t] [-s ] [-h] [-V] [--truncate]
[--size=] [--help] [--version]
Example 1: ubiupdatevol /dev/ubi0_1 fs.img - write file "fs.img" to UBI volume /dev/ubi0_1
Example 2: ubiupdatevol /dev/ubi0_1 -t - wipe out UBI volume /dev/ubi0_1
-t, --truncate truncate volume (wipe it out)
16
-s, --size= bytes in input, if not reading from file
-h, --help print help message
-V, --version print program version