91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

flash存儲的內(nèi)容和代碼實現(xiàn)

Linux閱碼場 ? 來源: Linux閱碼場 ? 作者:尹忠凱 ? 2021-05-10 14:14 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

文章目錄

UBI簡介

flash存儲的內(nèi)容

代碼實現(xiàn)

將flash數(shù)據(jù)讀到內(nèi)存

組織數(shù)據(jù)結(jié)構(gòu)

volume & EBA子系統(tǒng)初始化

wear-leveling子系統(tǒng)初始化

UBI層操作

舉個例子

擦寫均衡

擦寫時機

擦寫條件

03 正文

UBI簡介

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

UBI全稱是Unsorted Block Images,上圖為UBI在系統(tǒng)中的層次結(jié)構(gòu),最下面是flash層(包括flash控制器,各個flash驅(qū)動代碼,spi-mem層等);MTD層是對flash層的抽象,一個flash可能被劃分成不同的分區(qū),每一個分區(qū)都會對應(yīng)一個MTD設(shè)備;UBI層是基于MTD層之上的更高層,UBI層抽象出一個個邏輯擦寫塊,每個邏輯擦寫塊都有一個物理擦寫塊與之前對應(yīng),有了這個映射,我們就可以加一些軟件算法,達到擦寫均衡的目的,從而提高flash的使用壽命;再往上是基于UBI層實現(xiàn)和各種文件系統(tǒng),比如UBIFS。

flash存儲的內(nèi)容

首先介紹幾個概念:

PEB:physical eraseblocks 也就是對應(yīng)flash上的一個擦寫塊

LEB:logical eraseblocks 軟件上的概念

Volume:卷

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

如上圖為flash中(或者說flash一個分區(qū)中)數(shù)據(jù)組織結(jié)構(gòu):

ubi層對flash的管理是以擦寫塊為單位的,LEB對應(yīng)軟件上的概念,PEB對應(yīng)flash上一個實實在在的擦寫塊,每一個LEB對應(yīng)一個PEB。

往上看多個LEB可以組成一個volume,也就是說,可以根據(jù)不同的功能,將LEB劃分到不同的卷中;其中valume-layout是一個ubi內(nèi)部使用的卷,用來存放該MTD設(shè)備上所劃分的各個卷的信息,其包含兩個LEB,它們存儲的內(nèi)容是一樣,互為備份。

往下看每個PEB的內(nèi)容包含3部分ech(erase counter header),vidh(volume identifier header),data。下面會介紹具體含義。

代碼實現(xiàn)

linux對UBI層的代碼實現(xiàn)大致可以總結(jié)為3個方面:

首先數(shù)據(jù)是存儲在flash中的,因此需要將flash中的相關(guān)信息讀到內(nèi)存中,同時也可以檢查出flash中的壞塊

數(shù)據(jù)讀到內(nèi)存后,需要按照內(nèi)部的邏輯關(guān)系組織起來(比如將正在使用的PEB放到紅黑樹上管理起來,空閑的PEB也放到紅黑樹上管理起來)

在內(nèi)存中有了這些數(shù)據(jù)的關(guān)系后,就可以對其進行操作(比如讀寫操作,volume增加,刪除,擴容等操作,擦寫均衡操作)

將flash數(shù)據(jù)讀到內(nèi)存

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

UBI初始化時代碼調(diào)用流程如上圖,最終會調(diào)用scan_all() 函數(shù), scan_all() 函數(shù)會遍歷該MTD設(shè)備

中的每一個PEB,從中讀出ech和vidh,它們的定義如下。

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

ech的定義如上,其中:

ec:表示該PEB被擦寫的次數(shù),借助該字段我們就能夠找出被擦寫次數(shù)最少的PEB,從而達到擦寫均衡的目的

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

data_offset:表示實際數(shù)據(jù)在該PEB中的偏移位置

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

vidh的定義如上,其中:

vol_id:表示該PEB屬于那一個volume

lmun:表示LEB在volume中的編號,該字段與PEB在MTD設(shè)備中的編號形成映射關(guān)系通過對MTD設(shè)備的每個PEB進行遍歷,可以得知各個PEB的情況,或是被使用的,或是空閑狀態(tài),或者已經(jīng)損壞,這些信息會被臨時記錄在struct ubi_attach_info 結(jié)構(gòu)中,遍歷過程中的具體細節(jié),可以參考scan_all() 函數(shù)。

組織數(shù)據(jù)結(jié)構(gòu)

遍歷PEB后,會將flash信息保存在臨時的結(jié)構(gòu)struct ubi_attach_info 中,接下來會將struct ubi_attach_info 中的臨時信息保存到全局結(jié)構(gòu)struct ubi_device *ubi_devices 中,代碼如下:

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

分為三個步驟,分別是對volume的初始化,對wear-leveling子系統(tǒng)的初始化,對eba(Eraseblock Association)子系統(tǒng)的初始化;下面我們分別看下。

volume & EBA子系統(tǒng)初始化

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

前面有介紹到volume-layout是UBI內(nèi)部使用的一個卷,其包含兩個LEB(互為備份),對應(yīng)PEB中的數(shù)據(jù)內(nèi)容如上圖,data(灰色)部分是一個struct ubi_vtbl_record 結(jié)構(gòu)數(shù)組,記錄了當(dāng)前UBI設(shè)備所有卷的信息, ubi_read_volume_table() 函數(shù)先遍歷臨時結(jié)構(gòu)struct ubi_attach_info 找出volumelayout所在PEB,然后 讀出struct ubi_vtbl_record 結(jié)構(gòu)數(shù)組并保存到內(nèi)存中,也就是struct ubi_device 的struct ubi_volume *volumes[] 字段中,初始化后的數(shù)組結(jié)構(gòu)如下圖,其中struct ubi_volume *volumes[] 是一個指針數(shù)組,數(shù)組中的每一個元素都是struct ubi_volume 結(jié)構(gòu)(詳細過程見ubi_read_volume_table() 函數(shù))。

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

在struct ubi_volume 結(jié)構(gòu)體中,有一個比較重要的字段struct ubi_eba_table *eba_tbl ,該字段記錄了當(dāng)前volume中所有LEB與PEB的映射關(guān)系,其中struct ubi_eba_entry *entries 是一個數(shù)組結(jié)構(gòu),每一個元素對應(yīng)一個struct ubi_eba_table 結(jié)構(gòu)體, struct ubi_eba_entry *entries 數(shù)

組的下標(biāo)對應(yīng)于LEB的編號,數(shù)組元素的內(nèi)容對應(yīng)EB的編號,這樣就將LEB與PEB關(guān)聯(lián)起來了(詳細過程見ubi_eba_init() 函數(shù))。

wear-leveling子系統(tǒng)初始化

在UBI中將PEB分為4種情況,正在使用、空閑狀態(tài)、需要擦除、已經(jīng)損壞,各個狀態(tài)的PEB被放到不同的紅黑樹中管理。在ubi_eba_init() 函數(shù)中,會先分配一個struct ubi_wl_entry 指針數(shù)組并存儲在sruct ubi_wl_entry **lookuptbl 字段中,數(shù)組下標(biāo)為PEB的編號,數(shù)組內(nèi)容記錄了PEB的擦寫次

數(shù)與編號信息,每一個PEB都有一個這樣的結(jié)構(gòu)與之對應(yīng)如下圖。

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

另外各個PEB還根據(jù)狀態(tài)放到不同的紅黑樹管理起來,上圖畫出了used, free, scrub三種狀態(tài)的紅黑樹,其中紅黑樹是以擦寫次數(shù)為順序排列的,最小的擦寫次數(shù)排列在最左邊,如果擦寫次數(shù)相同,則比較PEB的編號,編號小的排在樹的左邊,而對應(yīng)的值為struct ubi_wl_entry 指針數(shù)組中的一個元素。

調(diào)用ubi_eba_init() 函數(shù)后,wear-leveling子系統(tǒng)也就初始化完畢,在內(nèi)存中會形成上圖中的數(shù)組關(guān)系。

UBI層操作

經(jīng)過前面的初始化,各個數(shù)據(jù)的結(jié)構(gòu)關(guān)系已經(jīng)保存在內(nèi)存中了,因此UBI層的操作其實就是對內(nèi)存中這些數(shù)據(jù)的操作。

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

從用戶空間角度看,UBI初始化后會對應(yīng)三類字符設(shè)備,分別為/dev/ubi_ctrl 、/dev/ubix (x = 0, 1, 2.。.), /dev/ubix_y (x = 0, 1, 2.。., y = 0, 1, 2),它們對應(yīng)的操作函數(shù)如下代碼。

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設(shè)備(/deb/ubi0等)進行操作的,從UBI設(shè)備的角度可以看到不同的volume,因此可以對volume進行創(chuàng)建,刪除,擴容等操作。

ubi_ctrl_cdev_operations:是針對UBI層(/dev/ubi_ctrl)的操作,從該角度可以看到UBI設(shè)備,因此可以對UBI設(shè)備進行創(chuàng)建,刪除操作。

舉個例子

需求:假如我們想要對/dev/ubi1_0 這個volume進行擴容,我們應(yīng)用怎樣操作?

用戶空間將volume_id,size兩個參數(shù)傳遞到內(nèi)核空間

在內(nèi)核空間我們根據(jù)volume_id在struct ubi_volume *volumes[] 數(shù)組中找到volume的handler

因為需要擴容(要分配更多的LEB),所以要重新分配struct ubi_eba_table *eba_tbl 數(shù)組,并將舊數(shù)組中的數(shù)據(jù)拷貝到新數(shù)組中

對于新增的LEB,我們需要從free樹上申請,建立LEB到PEB的映射關(guān)系并保存到struct ubi_eba_table *eba_tbl 數(shù)組,另外還需要更新PEB中ech和vidh,表明該PEB屬于那個volume

上面這一系列操作是我自己的想法,并非kernel實現(xiàn)代碼(具體實現(xiàn)可以參數(shù)ubi_cdev_ioctl() 函數(shù))。這里想表達的意思是,在UBI初始化完成后,在內(nèi)存中已經(jīng)存在了各個volume,各個LEB/PEB之間的關(guān)系,因此對于UBI的操作,理論上我們是都可以完成的,所差的只是代碼實現(xiàn);程序=算法+數(shù)組結(jié)構(gòu),這里的數(shù)組結(jié)構(gòu)已經(jīng)有了,而算法就是UBI層的各種操作,這里的代碼其實每個人都可以實現(xiàn)的,只不過有好有壞,所幸kernel已經(jīng)幫我們實現(xiàn)了,我們可以參考學(xué)習(xí)。其實別人寫的文章只能提供個大概,真正的細節(jié)只有在源碼中才能獲得。

擦寫均衡

flash的擦寫塊都是有壽命限制的,如果頻繁的擦寫flash的某一個PEB,很快這個PEB就會損壞,而擦寫均衡的目的就是將擦除操作平均分配到整個flash,這樣就能提高flash的使用壽命。那怎樣將擦除操作平均分配到整個flash呢,要達到這個條件還是有些難度的,因此我們退一步,將條件修改為PEB的最大擦寫次數(shù)與最小次數(shù)的的差值小于某個值。

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

比如flash中包含20個PEB,其中數(shù)字表示該PEB被擦寫的次數(shù),我們約定擦寫次數(shù)的差值最大為15,現(xiàn)在flash中PEB的最小與最大擦寫次數(shù)分別為10、39,由于超過門限值,因此需要我們想一些方法,增加擦寫次數(shù)為10的PEB被擦寫的機會,減少擦寫次數(shù)為39的PEB被擦寫的機會,從而使整個flash的擦寫次數(shù)趨于平均。具體的實現(xiàn)后面會介紹。

擦寫時機

linux kernel會在下面兩個位置調(diào)用擦寫均衡:

wear-leveling子系統(tǒng)初始化完成時會檢查一次是否需要擦寫均衡,此時是一個初始狀態(tài),是檢查的一個時機。

當(dāng)要擦除某個PEB的時候,此時擦寫次數(shù)會增加,有可能達到擦寫均衡的要求,此時也是一個檢查的時機。

擦寫條件

除了上面的調(diào)用時機,擦寫均衡還有一些其它的條件限制,如下圖為擦寫均衡的流程圖:

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

當(dāng)scrub紅黑樹上有節(jié)點時,一定需要進行擦寫均衡。在遍歷flash的每個PEB時,如果發(fā)現(xiàn)在從flash中讀出的數(shù)據(jù)有位翻轉(zhuǎn)的情況,就會加上scrub標(biāo)志,并放到scrub紅黑樹上維護起來,表示該PEB需要被擦寫;在擦寫均衡時,先取出scrub樹最左邊節(jié)點e1,再從free樹中找一個合適的節(jié)點e2,然后讀取e1對應(yīng)PEB的數(shù)據(jù),如果讀取的數(shù)據(jù)還有問題,就會結(jié)束本次擦寫;如果沒有問題就會把e1數(shù)據(jù)copy到e2位置,并擦除e1數(shù)據(jù)完成本次擦寫均衡操作。

當(dāng)scrub樹上沒有節(jié)點時,會從used樹上取出最左邊節(jié)點e1,并從free樹上找一個合適的節(jié)點e2,然后檢查e2與e1的PEB擦寫次數(shù)的差值是否大于門限值,如果大于,則將e1數(shù)據(jù)copy到e2位置并擦除e1數(shù)據(jù)完成本次擦寫。為什么這樣做,原因是used樹中的節(jié)點已經(jīng)被初始化過(先整個擦除,然后寫入ech和vidh,后面再寫入數(shù)據(jù)也不需要擦寫)所以不會有擦除操作,在free樹上的節(jié)點,在被使用前需要擦除一次,所以把擦寫次數(shù)大的PEB放到used樹上減少被擦寫的機會,把擦寫次數(shù)小的節(jié)點放到free樹上增加被擦寫的機會,這樣就達到了擦寫均衡的目的。

另外在free樹上選擇一個合適的節(jié)點,什么是適合和節(jié)點?最簡單的方法就是從free樹的最右邊拿一上節(jié)點(擦寫次數(shù)最大的節(jié)點),然后與used樹上取下的最左邊的節(jié)點比較,看看差值是否超過門限值。但實際情況可能會更復(fù)雜些,如下代碼29行,是kernel中在free樹上選擇節(jié)點的方法,其限制了最大擦寫次數(shù)為free樹最左側(cè)節(jié)點 + WL_FREE_MAX_DIFF,看上面的注釋說在某些情況下會出現(xiàn)不斷擦寫某一個或幾個PEB的情況,所以作了這樣一個限制。(沒有想道是什么情況)

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

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

原文標(biāo)題:尹忠凱: 針對Flash的Linux UBI子系統(tǒng)代碼深度分析

文章出處:【微信公眾號:Linuxer】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • FlaSh
    +關(guān)注

    關(guān)注

    10

    文章

    1748

    瀏覽量

    155531
  • 存儲
    +關(guān)注

    關(guān)注

    13

    文章

    4791

    瀏覽量

    90066

原文標(biāo)題:尹忠凱: 針對Flash的Linux UBI子系統(tǒng)代碼深度分析

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    SPI NOR Flash和SPI NAND Flash存儲芯片的區(qū)別

    SPI NOR Flash與SPI NAND Flash并非相互替代,而是互補關(guān)系。SPI NOR勝在讀取速度快、使用簡單、可靠性高,是代碼存儲的理想選擇。SPI NAND則以其大容量
    的頭像 發(fā)表于 01-29 16:58 ?473次閱讀
    SPI NOR <b class='flag-5'>Flash</b>和SPI NAND <b class='flag-5'>Flash</b><b class='flag-5'>存儲</b>芯片的區(qū)別

    如何正確配置AG32 MCU,實現(xiàn)FLASH或者代碼加密?

    的SDK資料:海振遠科技為客戶提供豐富的開發(fā)資料和多款開發(fā)板可以選擇,方便用戶快速上手設(shè)計。 2、開發(fā)板資源: 二、如何正確配置AG32 MCU,實現(xiàn)FLASH或者代碼加密 AG32MCU的加密
    發(fā)表于 01-22 15:01

    Vivado+Vitis將程序固化的Flash的操作流程

    ZYNQ 的程序固化是指將程序代碼永久存儲到非易失性存儲器中,使系統(tǒng)上電后能自動加載運行的過程。主要固化方式:QSPI Flash固化:常用方式,容量小,如啟動
    的頭像 發(fā)表于 01-20 16:17 ?375次閱讀
    Vivado+Vitis將程序固化的<b class='flag-5'>Flash</b>的操作流程

    單片機Flash是什么類型

    存儲器)。 在過去,嵌入式系統(tǒng)一直使用ROM(EPROM)作為它們的存儲設(shè)備,Flash的出現(xiàn),全面代替了ROM(EPROM)在嵌入式系統(tǒng)中的地位,用作存儲Bootloader以及操作
    發(fā)表于 01-04 07:10

    國產(chǎn)SPI NOR Flash接口閃存介紹

    在當(dāng)今各類電子設(shè)備對存儲性能要求日益提升的背景下,SPI NOR Flash憑借其高速讀取、低功耗及靈活接口等優(yōu)勢,成為嵌入式系統(tǒng)代碼存儲的關(guān)鍵元件。GT25Q系列SPI NOR
    的頭像 發(fā)表于 12-26 11:51 ?453次閱讀

    CW32F030片上FLASH閃存存儲器物理區(qū)域的劃分

    片上 FLASH 閃存由兩部分物理區(qū)域組成:主 FLASH 存儲器和啟動程序存儲器。 1、主 FLASH
    發(fā)表于 12-23 08:28

    CW32L052 FLASH存儲器介紹

    。 擦寫保護 包括鎖定頁擦寫保護和PC 地址頁擦寫保護,處于保護狀態(tài)的頁面不能被擦寫,可避免 FLASH 內(nèi)容被意外改寫。 讀保護 以整片 FLASH 為保護對象,不支持單頁保護,可避免用戶
    發(fā)表于 12-05 08:22

    FLASH中的代碼是如何得到運行的呢

    。 ARM-cortex-A系列的SOC(比如Exynos4412):該類SOC更加復(fù)雜,通常有內(nèi)存管理單元(MMU),代碼存儲在nand flash中,程序運行時,需要先將代碼加載
    發(fā)表于 12-04 08:06

    STM32C011開發(fā)(3)----Flash操作

    STM32C011 系列微控制器內(nèi)置 Flash 存儲器,支持程序存儲與數(shù)據(jù)保存,具備頁面擦除、雙字寫入、讀寫保護等功能。本文將簡要介紹 STM32C011 的 Flash 結(jié)構(gòu)與特性
    的頭像 發(fā)表于 09-18 16:48 ?4922次閱讀
    STM32C011開發(fā)(3)----<b class='flag-5'>Flash</b>操作

    NAND Flash的基本原理和結(jié)構(gòu)

    NAND Flash是什么?NAND Flash(閃存)是一種非易失性存儲器技術(shù),主要用于數(shù)據(jù)存儲。與傳統(tǒng)的DRAM或SRAM不同,NAND Fla
    的頭像 發(fā)表于 09-08 09:51 ?7037次閱讀
    NAND <b class='flag-5'>Flash</b>的基本原理和結(jié)構(gòu)

    嵌入式系統(tǒng)中,FLASH 中的程序代碼必須搬到 RAM 中運行嗎?

    嵌入式系統(tǒng)里,FLASH 中的程序代碼并非必須搬到 RAM 中運行,這得由硬件配置、實際性能需求和應(yīng)用場景共同決定。就像很多低端單片機,無論是依賴片內(nèi) Flash 還是外掛的 SPI NOR
    的頭像 發(fā)表于 08-06 10:19 ?1366次閱讀
    嵌入式系統(tǒng)中,<b class='flag-5'>FLASH</b> 中的程序<b class='flag-5'>代碼</b>必須搬到 RAM 中運行嗎?

    Flash讀保護怎么實現(xiàn)?

    我們客戶要求要對代碼存儲區(qū)(code flash)增加外部讀保護機制 我在TRM手冊中只看到有flash 寫保護 讀保護應(yīng)該怎么實現(xiàn)
    發(fā)表于 07-30 07:30

    MCU片上Flash

    ? ? MCU片上Flash是微控制器內(nèi)部集成的非易失性存儲器,主要用于存儲程序代碼、常量數(shù)據(jù)及系統(tǒng)配置信息。其核心特性與功能如下: 一、定義與類型? 片上
    的頭像 發(fā)表于 05-06 14:26 ?1273次閱讀

    調(diào)試時Memory窗口中Flash內(nèi)容不更新的原因和解決辦法

    調(diào)試時在代碼中對Flash進行寫操作時(比如Bootloader對Code Flash進行升級操作,Application對Data Flash進行寫操作),Memory窗口中
    的頭像 發(fā)表于 04-01 09:18 ?1251次閱讀
    調(diào)試時Memory窗口中<b class='flag-5'>Flash</b><b class='flag-5'>內(nèi)容</b>不更新的原因和解決辦法

    NAND Flash與SD NAND的存儲扇區(qū)架構(gòu)差異

    NAND Flash?和?SD卡(SD NAND)的存儲扇區(qū)分配表都是用于管理存儲設(shè)備中扇區(qū)的分配信息。它們記錄了哪些扇區(qū)已被使用、哪些是空閑的,以及文件或數(shù)據(jù)與扇區(qū)的對應(yīng)關(guān)系,以便實現(xiàn)
    的頭像 發(fā)表于 03-13 15:20 ?1890次閱讀
    NAND <b class='flag-5'>Flash</b>與SD NAND的<b class='flag-5'>存儲</b>扇區(qū)架構(gòu)差異