0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

flash存储的内容和代码实现

Linux阅码场 来源: Linux阅码场 作者:尹忠凯 2021-05-10 14:14 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

文章目录

UBI简介

flash存储的内容

代码实现

将flash数据读到内存

组织数据结构

volume & EBA子系统初始化

wear-leveling子系统初始化

UBI层操作

举个例子

擦写均衡

擦写时机

擦写条件

03 正文

UBI简介

f8dd2160-b03c-11eb-bf61-12bb97331649.png

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

flash存储的内容

首先介绍几个概念:

PEB:physical eraseblocks 也就是对应flash上的一个擦写块

LEB:logical eraseblocks 软件上的概念

Volume:卷

f8eb8f34-b03c-11eb-bf61-12bb97331649.png

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

ubi层对flash的管理是以擦写块为单位的,LEB对应软件上的概念,PEB对应flash上一个实实在在的擦写块,每一个LEB对应一个PEB。

往上看多个LEB可以组成一个volume,也就是说,可以根据不同的功能,将LEB划分到不同的卷中;其中valume-layout是一个ubi内部使用的卷,用来存放该MTD设备上所划分的各个卷的信息,其包含两个LEB,它们存储的内容是一样,互为备份。

往下看每个PEB的内容包含3部分ech(erase counter header),vidh(volume identifier header),data。下面会介绍具体含义。

代码实现

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

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

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

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

将flash数据读到内存

f8fbcf8e-b03c-11eb-bf61-12bb97331649.png

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

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

f915eff4-b03c-11eb-bf61-12bb97331649.png

ech的定义如上,其中:

ec:表示该PEB被擦写的次数,借助该字段我们就能够找出被擦写次数最少的PEB,从而达到擦写均衡的目的

vid_hdr_offset:表示vidh在该PEB中的偏移位置

data_offset:表示实际数据在该PEB中的偏移位置

f921ab00-b03c-11eb-bf61-12bb97331649.png

vidh的定义如上,其中:

vol_id:表示该PEB属于那一个volume

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 中,代码如下:

f9304db8-b03c-11eb-bf61-12bb97331649.png

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

volume & EBA子系统初始化

f939f3e0-b03c-11eb-bf61-12bb97331649.png

前面有介绍到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() 函数)。

f9442d42-b03c-11eb-bf61-12bb97331649.png

在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都有一个这样的结构与之对应如下图。

f94dd1a8-b03c-11eb-bf61-12bb97331649.png

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

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

UBI层操作

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

f95e8890-b03c-11eb-bf61-12bb97331649.png

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

f96bacd2-b03c-11eb-bf61-12bb97331649.png

f979907c-b03c-11eb-bf61-12bb97331649.png

ubi_vol_cdev_operations:是针对某个volume(/dev/ubi1_0等)来操作的,从volume的角度只能看到其中包含的PEB,因此它的操作也是围绕PEB进行的。

ubi_cdev_operations:是针对UBI设备(/deb/ubi0等)进行操作的,从UBI设备的角度可以看到不同的volume,因此可以对volume进行创建,删除,扩容等操作。

ubi_ctrl_cdev_operations:是针对UBI层(/dev/ubi_ctrl)的操作,从该角度可以看到UBI设备,因此可以对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的最大擦写次数与最小次数的的差值小于某个值。

f9d86a52-b03c-11eb-bf61-12bb97331649.png

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

擦写时机

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

wear-leveling子系统初始化完成时会检查一次是否需要擦写均衡,此时是一个初始状态,是检查的一个时机。

当要擦除某个PEB的时候,此时擦写次数会增加,有可能达到擦写均衡的要求,此时也是一个检查的时机。

擦写条件

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

f9f1deba-b03c-11eb-bf61-12bb97331649.png

当scrub红黑树上有节点时,一定需要进行擦写均衡。在遍历flash的每个PEB时,如果发现在从flash中读出的数据有位翻转的情况,就会加上scrub标志,并放到scrub红黑树上维护起来,表示该PEB需要被擦写;在擦写均衡时,先取出scrub树最左边节点e1,再从free树中找一个合适的节点e2,然后读取e1对应PEB的数据,如果读取的数据还有问题,就会结束本次擦写;如果没有问题就会把e1数据copy到e2位置,并擦除e1数据完成本次擦写均衡操作。

当scrub树上没有节点时,会从used树上取出最左边节点e1,并从free树上找一个合适的节点e2,然后检查e2与e1的PEB擦写次数的差值是否大于门限值,如果大于,则将e1数据copy到e2位置并擦除e1数据完成本次擦写。为什么这样做,原因是used树中的节点已经被初始化过(先整个擦除,然后写入ech和vidh,后面再写入数据也不需要擦写)所以不会有擦除操作,在free树上的节点,在被使用前需要擦除一次,所以把擦写次数大的PEB放到used树上减少被擦写的机会,把擦写次数小的节点放到free树上增加被擦写的机会,这样就达到了擦写均衡的目的。

另外在free树上选择一个合适的节点,什么是适合和节点?最简单的方法就是从free树的最右边拿一上节点(擦写次数最大的节点),然后与used树上取下的最左边的节点比较,看看差值是否超过门限值。但实际情况可能会更复杂些,如下代码29行,是kernel中在free树上选择节点的方法,其限制了最大擦写次数为free树最左侧节点 + WL_FREE_MAX_DIFF,看上面的注释说在某些情况下会出现不断擦写某一个或几个PEB的情况,所以作了这样一个限制。(没有想道是什么情况)

fa1d997e-b03c-11eb-bf61-12bb97331649.png

fa2f68ac-b03c-11eb-bf61-12bb97331649.png

原文标题:尹忠凯: 针对Flash的Linux UBI子系统代码深度分析

文章出处:【微信公众号:Linuxer】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FlaSh
    +关注

    关注

    10

    文章

    1715

    浏览量

    154743
  • 存储
    +关注

    关注

    13

    文章

    4704

    浏览量

    89583

原文标题:尹忠凯: 针对Flash的Linux UBI子系统代码深度分析

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    CW32L052 FLASH存储器介绍

    。 擦写保护 包括锁定页擦写保护和PC 地址页擦写保护,处于保护状态的页面不能被擦写,可避免 FLASH 内容被意外改写。 读保护 以整片 FLASH 为保护对象,不支持单页保护,可避免用户
    发表于 12-05 08:22

    FLASH中的代码是如何得到运行的呢

    。 ARM-cortex-A系列的SOC(比如Exynos4412):该类SOC更加复杂,通常有内存管理单元(MMU),代码存储在nand flash中,程序运行时,需要先将代码加载
    发表于 12-04 08:06

    高性能SPI NOR FLASH芯片ZB25VQ系列推荐

    在嵌入式系统、物联网设备及各类存储应用中,SPI NOR FLASH芯片因其接口简单、功耗低、读写速度快等特点,成为代码存储与数据缓存的常见选择。SPI NOR
    的头像 发表于 12-01 14:52 221次阅读

    广州唯创电子WT588F02系列Flash语音芯片:可重复擦写与高效能音频解决方案

    让智能设备拥有“可定制的声音”,Flash存储技术实现语音内容自由更换在智能设备功能日益丰富的今天,语音交互已成为提升用户体验的关键要素。广州唯创电子推出的WT588F02系列
    的头像 发表于 09-28 08:05 256次阅读
    广州唯创电子WT588F02系列<b class='flag-5'>Flash</b>语音芯片:可重复擦写与高效能音频解决方案

    STM32C011开发(3)----Flash操作

    STM32C011 系列微控制器内置 Flash 存储器,支持程序存储与数据保存,具备页面擦除、双字写入、读写保护等功能。本文将简要介绍 STM32C011 的 Flash 结构与特性
    的头像 发表于 09-18 16:48 3701次阅读
    STM32C011开发(3)----<b class='flag-5'>Flash</b>操作

    NAND Flash的基本原理和结构

    NAND Flash是什么?NAND Flash(闪存)是一种非易失性存储器技术,主要用于数据存储。与传统的DRAM或SRAM不同,NAND Fla
    的头像 发表于 09-08 09:51 5904次阅读
    NAND <b class='flag-5'>Flash</b>的基本原理和结构

    嵌入式系统中,FLASH 中的程序代码必须搬到 RAM 中运行吗?

    嵌入式系统里,FLASH 中的程序代码并非必须搬到 RAM 中运行,这得由硬件配置、实际性能需求和应用场景共同决定。就像很多低端单片机,无论是依赖片内 Flash 还是外挂的 SPI NOR
    的头像 发表于 08-06 10:19 1158次阅读
    嵌入式系统中,<b class='flag-5'>FLASH</b> 中的程序<b class='flag-5'>代码</b>必须搬到 RAM 中运行吗?

    Flash读保护怎么实现

    我们客户要求要对代码存储区(code flash)增加外部读保护机制 我在TRM手册中只看到有flash 写保护 读保护应该怎么实现
    发表于 07-30 07:30

    MCU片上Flash

        MCU片上Flash是微控制器内部集成的非易失性存储器,主要用于存储程序代码、常量数据及系统配置信息。其核心特性与功能如下: 一、定义与类型‌ 片上
    的头像 发表于 05-06 14:26 875次阅读

    调试时Memory窗口中Flash内容不更新的原因和解决办法

    调试时在代码中对Flash进行写操作时(比如Bootloader对Code Flash进行升级操作,Application对Data Flash进行写操作),Memory窗口中
    的头像 发表于 04-01 09:18 994次阅读
    调试时Memory窗口中<b class='flag-5'>Flash</b><b class='flag-5'>内容</b>不更新的原因和解决办法

    存储技术探秘 NAND Flash vs NOR Flash:藏在芯片里的&quot;门道之争&quot;

    门电路玄机 NOR Flash:Intel 1988 年革命性突破,终结 EPROM/EEPROM 垄断时代 NAND Flash:东芝 1989 年发布,开创 "低成本比特" 存储新纪元 共性特征
    的头像 发表于 03-18 12:06 1068次阅读

    NAND Flash与SD NAND的存储扇区架构差异

    NAND Flash 和 SD卡(SD NAND)的存储扇区分配表都是用于管理存储设备中扇区的分配信息。它们记录了哪些扇区已被使用、哪些是空闲的,以及文件或数据与扇区的对应关系,以便实现
    的头像 发表于 03-13 15:20 1596次阅读
    NAND <b class='flag-5'>Flash</b>与SD NAND的<b class='flag-5'>存储</b>扇区架构差异

    stm32f407的flash内容没有做任何事情,但是它的内容改变了,为什么?

    我的一个程序使用IAP。该应用程序从0x8020000开始。在应用程序正常工作一段时间后,应用程序将无法运行。我查看了不正常运行时FLASH内容,并将其与正常运行时FLASH内容
    发表于 03-07 07:52

    【半导体存储】关于NAND Flash的一些小知识

    保存代码及数据,分为闪型存储器 (Flash Memory)与只读存储器(Read-OnlyMemory),其中闪型存储器是主流,而闪型
    发表于 12-17 17:34

    Flash语音芯片相比OTP语音芯片的优势

    ‌。 1‌.可重复擦写‌:Flash语音芯片的最大特点是支持多次编程和擦除,这意味着用户可以根据需要随时更新语音内容实现定制化和灵活的语音交互。相比之下,OTP语音芯片只能编程一次,无法更改
    的头像 发表于 12-16 15:44 818次阅读