针对Flash的Linux UBI子系统是怎样的

发布时间:2021-09-27 16:26:38 作者:柒染
来源:亿速云 阅读:192

这篇文章给大家介绍针对Flash的Linux UBI子系统是怎样的,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

正文

UBI简介

针对Flash的Linux UBI子系统是怎样的

UBI全称是Unsorted Block  Images,上图为UBI在系统中的层次结构,最下面是flash层(包括flash控制器,各个flash驱动代码,spi-mem层等);MTD层是对flash层的抽象,一个flash可能被划分成不同的分区,每一个分区都会对应一个MTD设备;UBI层是基于MTD层之上的更高层,UBI层抽象出一个个逻辑擦写块,每个逻辑擦写块都有一个物理擦写块与之前对应,有了这个映射,我们就可以加一些软件算法,达到擦写均衡的目的,从而提高flash的使用寿命;再往上是基于UBI层实现和各种文件系统,比如UBIFS。

flash存储的内容

首先介绍几个概念:

针对Flash的Linux UBI子系统是怎样的

如上图为flash中(或者说flash一个分区中)数据组织结构:

代码实现

linux对UBI层的代码实现大致可以总结为3个方面:

首先数据是存储在flash中的,因此需要将flash中的相关信息读到内存中,同时也可以检查出flash中的坏块

数据读到内存后,需要按照内部的逻辑关系组织起来(比如将正在使用的PEB放到红黑树上管理起来,空闲的PEB也放到红黑树上管理起来)

在内存中有了这些数据的关系后,就可以对其进行操作(比如读写操作,volume增加,删除,扩容等操作,擦写均衡操作)

将flash数据读到内存

针对Flash的Linux UBI子系统是怎样的

UBI初始化时代码调用流程如上图,最终会调用scan_all() 函数, scan_all() 函数会遍历该MTD设备

中的每一个PEB,从中读出ech和vidh,它们的定义如下。

针对Flash的Linux UBI子系统是怎样的

ech的定义如上,其中:

针对Flash的Linux UBI子系统是怎样的

lmun:表示LEB在volume中的编号,该字段与PEB在MTD设备中的编号形成映射关系通过对MTD设备的每个PEB进行遍历,可以得知各个PEB的情况,或是被使用的,或是空闲状态,或者已经损坏,这些信息会被临时记录在struct  ubi_attach_info 结构中,遍历过程中的具体细节,可以参考scan_all() 函数。

组织数据结构

遍历PEB后,会将flash信息保存在临时的结构struct ubi_attach_info 中,接下来会将struct ubi_attach_info  中的临时信息保存到全局结构struct ubi_device *ubi_devices 中,代码如下:

针对Flash的Linux UBI子系统是怎样的

分为三个步骤,分别是对volume的初始化,对wear-leveling子系统的初始化,对eba(Eraseblock  Association)子系统的初始化;下面我们分别看下。

volume & EBA子系统初始化

针对Flash的Linux UBI子系统是怎样的

前面有介绍到volume-layout是UBI内部使用的一个卷,其包含两个LEB(互为备份),对应PEB中的数据内容如上图,data(灰色)部分是一个struct  ubi_vtbl_record 结构数组,记录了当前UBI设备所有卷的信息, ubi_read_volume_table() 函数先遍历临时结构struct  ubi_attach_info 找出volumelayout所在PEB,然后 读出struct ubi_vtbl_record  结构数组并保存到内存中,也就是struct ubi_device 的struct ubi_volume *volumes[]  字段中,初始化后的数组结构如下图,其中struct ubi_volume *volumes[] 是一个指针数组,数组中的每一个元素都是struct  ubi_volume 结构(详细过程见ubi_read_volume_table() 函数)。

针对Flash的Linux UBI子系统是怎样的

在struct ubi_volume 结构体中,有一个比较重要的字段struct ubi_eba_table *eba_tbl  ,该字段记录了当前volume中所有LEB与PEB的映射关系,其中struct ubi_eba_entry *entries  是一个数组结构,每一个元素对应一个struct ubi_eba_table 结构体, struct ubi_eba_entry *entries 数

组的下标对应于LEB的编号,数组元素的内容对应EB的编号,这样就将LEB与PEB关联起来了(详细过程见ubi_eba_init() 函数)。

wear-leveling子系统初始化

在UBI中将PEB分为4种情况,正在使用、空闲状态、需要擦除、已经损坏,各个状态的PEB被放到不同的红黑树中管理。在ubi_eba_init()  函数中,会先分配一个struct ubi_wl_entry 指针数组并存储在sruct ubi_wl_entry **lookuptbl  字段中,数组下标为PEB的编号,数组内容记录了PEB的擦写次

数与编号信息,每一个PEB都有一个这样的结构与之对应如下图。

针对Flash的Linux UBI子系统是怎样的

另外各个PEB还根据状态放到不同的红黑树管理起来,上图画出了used, free,  scrub三种状态的红黑树,其中红黑树是以擦写次数为顺序排列的,最小的擦写次数排列在最左边,如果擦写次数相同,则比较PEB的编号,编号小的排在树的左边,而对应的值为struct  ubi_wl_entry 指针数组中的一个元素。

调用ubi_eba_init() 函数后,wear-leveling子系统也就初始化完毕,在内存中会形成上图中的数组关系。

UBI层操作

经过前面的初始化,各个数据的结构关系已经保存在内存中了,因此UBI层的操作其实就是对内存中这些数据的操作。

针对Flash的Linux UBI子系统是怎样的

从用户空间角度看,UBI初始化后会对应三类字符设备,分别为/dev/ubi_ctrl 、/dev/ubix (x = 0, 1, 2...),  /dev/ubix_y (x = 0, 1, 2..., y = 0, 1, 2),它们对应的操作函数如下代码。

针对Flash的Linux UBI子系统是怎样的

针对Flash的Linux UBI子系统是怎样的

举个例子

需求:假如我们想要对/dev/ubi1_0 这个volume进行扩容,我们应用怎样操作?

用户空间将volume_id,size两个参数传递到内核空间

在内核空间我们根据volume_id在struct ubi_volume *volumes[] 数组中找到volume的handler

因为需要扩容(要分配更多的LEB),所以要重新分配struct ubi_eba_table *eba_tbl  数组,并将旧数组中的数据拷贝到新数组中

对于新增的LEB,我们需要从free树上申请,建立LEB到PEB的映射关系并保存到struct ubi_eba_table *eba_tbl  数组,另外还需要更新PEB中ech和vidh,表明该PEB属于那个volume

上面这一系列操作是我自己的想法,并非kernel实现代码(具体实现可以参数ubi_cdev_ioctl()  函数)。这里想表达的意思是,在UBI初始化完成后,在内存中已经存在了各个volume,各个LEB/PEB之间的关系,因此对于UBI的操作,理论上我们是都可以完成的,所差的只是代码实现;程序=算法+数组结构,这里的数组结构已经有了,而算法就是UBI层的各种操作,这里的代码其实每个人都可以实现的,只不过有好有坏,所幸kernel已经帮我们实现了,我们可以参考学习。其实别人写的文章只能提供个大概,真正的细节只有在源码中才能获得。

擦写均衡

flash的擦写块都是有寿命限制的,如果频繁的擦写flash的某一个PEB,很快这个PEB就会损坏,而擦写均衡的目的就是将擦除操作平均分配到整个flash,这样就能提高flash的使用寿命。那怎样将擦除操作平均分配到整个flash呢,要达到这个条件还是有些难度的,因此我们退一步,将条件修改为PEB的最大擦写次数与最小次数的的差值小于某个值。

针对Flash的Linux UBI子系统是怎样的

比如flash中包含20个PEB,其中数字表示该PEB被擦写的次数,我们约定擦写次数的差值最大为15,现在flash中PEB的最小与最大擦写次数分别为10、39,由于超过门限值,因此需要我们想一些方法,增加擦写次数为10的PEB被擦写的机会,减少擦写次数为39的PEB被擦写的机会,从而使整个flash的擦写次数趋于平均。具体的实现后面会介绍。

擦写时机

linux kernel会在下面两个位置调用擦写均衡:

擦写条件

除了上面的调用时机,擦写均衡还有一些其它的条件限制,如下图为擦写均衡的流程图:

针对Flash的Linux UBI子系统是怎样的

针对Flash的Linux UBI子系统是怎样的

针对Flash的Linux UBI子系统是怎样的

关于针对Flash的Linux UBI子系统是怎样的就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

推荐阅读:
  1. 嵌入式文件系统简介(一) —— Linux MTD设备文件系
  2. 编写一个陌生的linux驱动的技巧

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

linux flash

上一篇:Linux 5.13增加冷却驱动是否能为英特尔CPU降频

下一篇:如何查看Linux的版本信息

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》