NFTL
From ESSLabWiki
Jump to: navigation, search
Independent Stuedy: NFTL
1 摘要
目前的隨身電子產品,如手機、隨身聽所用的儲存裝置大都是flash memory,但因為flash的特性,是無法重複寫同一塊記憶體位置做寫入的動作,必須事先erase該塊記憶體位置(將其充電)才能再做寫入的動作,因此一般我們所使用的檔案系統,如FAT16、FAT32、NTFS、ext2等…,將無法直接用在flash memory上。若我們想要沿用這些檔案系統,則必須透過一層Translation Layer來將Logical Block Address對應到實體的flash memory的位置,並透過一些機制能讓系統能把flash memory當作一般的硬碟一樣處理,我們稱這層為FTL(Flash Translation Layer)。
2 動機
因為FTL是用在NOR Flash上的機制,而NOR Flash在大容量的應用上並不如NAND flash划算,因此有NFTL(NAND Flash Translation Layer)的產生,NFTL主要想法與FTL相似,主要差別在於是用在NAND Flash上,以支援目前隨身電子產品對於容量上的需求。
目前對於NFTL的文件、系統架構並沒有相當足夠的資訊,因此我們藉此機會來trace NFTL的原始碼來了解,NFTL詳細的運作細節及系統架構,本文件將介紹NFTL在Flash上的Data structure、RAM上的Data structure、NFTL的READ / WRITE動作、Garbage Collection、Block management。(圖一)為NFTL在整個檔案系統中所扮演角色。
(圖一)
3 NAND flash的特性
在介紹NFTL之前,必須先對NAND有一些基本的了解,會幫助我們了解NFTL以及知道為什麼一般的file system無法用在flash上。以下是一個NAND flash memory的架構圖(圖二)
(圖二)NAND flash memory的架構圖
NAND flash由很多層的block組成,而block是erase的最小單位。一個Block通常包含了32個page,而page是read / write的單位,一個page的大小為512bytes(user space) + 16bytes(spare area)。其中user space是用來存放一般的data,spare area是用來儲存一些meta data作為管理file system用。
4 Major RAM-resident data structures and on-flash data structures employed by NFTL
NFTL主要的功能是將Logical Block Address對應到實體的flash memory address(物理块地址),藉此來達到能讓flash使用FAT等用在block device一類的file system。因為NAND flash的一些特性,必須在RAM上建構一些data structure及algorithm,並且在flash上儲存metadata作為NFTL初始時建構RAM中的data structure所用,才能達到此目的。因此在此我們要介紹NFTL在RAM上及flash上的data structure。
(1). Terminologies及NFTL之基本架構
因為NFTL的code中,用了許多term,在此必須先定義一些Terminologies,來幫助之後的說明。(可參考圖三)
· Erase Unit:erase的基本單位,即flash中的block。 (物理块)
· Virtual Unit:RAM中對應flash中block的單位。實際上只儲存對應的block在flash上的physical address(逻辑块)。
· Block Chain:NFTL將資料存在由block所組的chain中,該chain則稱作block chain。透過存放在erase unit上的metadata資訊來達成。
· Replace Unit:在block chain中,接在第一個block後的block都稱作Replace Unit (块链第一物理块之后块)。
· Virtual Unit Chain:在RAM中,透過EUNtalble、ReplUnitTable可以找到每個virtual unit屬於哪個block chain及他的replace unit之physical address。 (块链)
说明:一个 逻辑块上 对应 一个 块链 ,具体的逻辑块上的各个扇区 分别对应块链中 最后物理块的 相应扇区
(2). RAM-resident data structures (内存描述)
RAM上主要的data structure有下列幾項:
struct NFTLrecord {
__u16 lastEUN;
|
__u16 numfreeEUNs; |
|
__u16 LastFreeEUN; |
|
__u16 *EUNtable; |
|
__u16 *ReplUnitTable; |
unsigned int nb_blocks; |
|
struct nand_oobinfo oobinfo; |
};
其中:
· LastEUN代表flash中最後一個block的physical adderss(物理块号)。
· numfreeEUNs代表目前共有幾個free blocks。
· LastFreeEUN代表最後一個被找到的free block (物理块号)。
· *EUNtable是一個logical to physical的table,紀錄每個block所屬的chain的起始physical address。其index item代表logical address;data item代表physical address。而透過EUNtable我們可以找到該virtual unit對應的block所屬block chain的起始physical address。此table是存在RAM中。參考下圖。
· *ReplUnitTable是一個physical to physical的table,紀錄每個在chain中的block,其之後的block之physical adderss,以維持Virtual Unit Chain的結構。其index item代表目前的block的physical address;data item代表串在他後面的block的physical address。此table存在RAM中。
· nb_blocks代表Flash中共有幾個block。參考下圖。
· oobinfo則是用來儲存自flash中讀出的oob的information。
(3). on-flash data structures (介质存贮格式)
在Flash上的data structure主要則是存在Spare Area的oobinfo。OOB則是由bci (block control information)及uci(uni control information)組成,bci記錄每個page的status,uci則記錄每個block的information,詳細內容如下圖(圖四):
(圖四)oob中所有的資料
其中:
· nftl_bci內包含ECC(error correct code)及Status、Status1,而bci(block control information),是每個page一個,主要用來記錄每個page的status。
ECC是用來預防資料存取發生錯誤時所需的錯誤更正碼。
Status、Status1則是記錄每個sector的狀態。當寫入資料到user area時,同時將此資訊寫入spare area的oob.b中。而Status、Status1所存的資料是一樣的,其目的是避免在資料寫入時發生非預期的bit由1變成0。在uci方面也是相同的道理,之後不再贅述。
其狀態有下列四種:
SECTOR_FREE 0xff
SECTOR_USED 0x55
SECTOR_IGNORE 0x11 ?
SECTOR_DELETED 0x00 ?
· nftl_uci內包含nftl_uci0、nftl_uci1、nftl_uci2,而uci(unit control information)是記錄整個block的資訊,是每個block一個,他們在flash上的儲存方式如(圖五)
nftl_uci0包含VirtUnitNum及ReplUnitNum。
VirtUnitNum存每個block的Virtual address,以便在初始時建立EUNtable。
ReplUnitNum存接在此block之後的Replace Unit的physical address。
寫入flash的時機有下列幾種可能:1.在新增block到block chain中時寫入oob.u中。2.folding完成後,重新設定其 VirtUnitNum、ReplUnitNum等…。
nftl_uci1包含WearInfo、EraseMark。
WearInfo記錄該block被erase過的次數。
EraseMark則是用來確定該Block是否被erase過。在成功erase block後會將其內容寫為ERASE_MARK 0x3c69。
nftl_uci2包含FoldMark、unused。
FoldMark:我們在做Fold Chain時(从一个最长块链,各扇区合成一个块,擦除回收可用块),若要做inplace(不需另找中间空闲块,outplace需另找中间空闲块)時會先將其目標erase unit的FoldMark設為FOLD_MARK_IN_PROGRESS。
Unused決定做inplace fold chain後將此欄位全設為1。
(圖五)oob在block中存放的方式
其中,oob.u.a、oob.u.b、oob.u.c需要放在不同的page主要原因是,我們不一定會同時存取這三樣資訊,如果我們把他放在同一個page中,若我們先寫入oob.u.a,之後又想寫oob.u.c,此時我們就無法將oob.u.c寫入,除非我們將該block rease (1个扇区擦完后只能写一次)。
(4). 初始构建 (从介质存贮格式构建内存描述)
接著介紹NFTL的基本架構,在NFTL初始時,會讀取每個block中的metadata(oobinfo),然後在RAM中建構出一個EUNtalble、ReplUnitTable(稍後我們會詳細介紹)來模擬成一個Virtual Unit Chain。Virtual Unit Chain則是由一個以上的Virtual Unit所組成,virtual unit則是在RAM中用來對應flash中的erase unit,實際上virtual unit並不儲存資料,他只儲存所對應的erase unit的physical address,即ReplUnitTable的entry,而Virtual unit chain則是一個logical address指著virtual unit chain的第一個virtual unit的位置。如下圖(圖三)所示:
(圖三)Virtual Unit Chain與Block Chain的關係
5 Blocks management of NFTL
因為NAND flash的erase單位是block,所以對大多數的flash file system而言,管理block是主要的課題之一,以下介紹NFTL管理block的方式、如何找到free block以及如何選擇block去erase。
(1). How blocks are managed by NFTL?
主要透過RAM中的兩個table:EUNtable、ReplUnitTable來完成(EUNtable、ReplUnitTable的介紹可參考圖三及section4.1)其用法如圖七。
而ReplUnitTable另外記錄了每個Block的狀態,當我們想要知道某個block的狀態是FREE或是RESERVED時都是透過ReplUnitTable。而該資訊是在系統起始時所建立的。以下為ReplUnitTable所能記錄的狀態。
· BLOCK_NIL (=0xffff) 表示該block後面沒有串連別的block
· BLOCK_FREE (=0xfffe) 表示該為free block
· BLOCK_NOTEXPLORED (=0xfffd)只有在mounting NFTL時才用到。
· BLOCK_RESERVED (=0xfffc)表示該block壞掉或是為bios block。
· 非以上 为下一块的物理块号
ReplUnitTable最主要的功能是當run time時,我們可以透過在RAM中的ReplUnitTable知道哪些block是屬於同一個chain中的,也可以用來計算每個chain的長度等….
(圖七)Virtual Add.指的是Virtual unit在RAM中所在的位置。透過EUNtable找到Chain的實體起始位置,再透過ReplUnitTable找到Repl unit。在RAM中,整個chain的架構都是靠ReplUnitTable維持的。
(2). How to select free block in NFTL?
選擇free block對於wear-leveling是相當重要的一個動作,若我們一直選擇到相同的block來做讀寫其相對被抹除的次數也會大大提升,造成erase次數不平均的現象。
在MOUNT NFTL時,我們會將最後讀到的free block的physical address存到 LastFreeEUN,而我們在找Free Block時,會先看LastFreeEUN是否真的可用,若可用則使用該block;否則循序找其他free block。程式碼(NFTL_findfreeblock())簡述如下:
(3). How blocks are chosen to be erased?
如何選擇block被erase是個重要的問題,他不僅影響整個系統的效率,也可能造成erase次數不平均的現象,在此我們介紹NFTL的選擇block被erase的方法。
NFTL認為,最長的chain能夠free最多的block,並不理會block的erase次數。而找最長的chain也是以greedy的方式將整個flash找一次(在RAM中透過ReplUnitTable找),程式碼簡述如下:
6 NFTL initializes, handles reads, and handles writes
這邊介紹NFTL在系統初始時,如何將存在spare area的資訊鍵構成run time時RAM使用的資訊。
1. NFTL initializes
· Ini the EUNtable、ReplUnitTable
· 一個chain一個chain的循序讀取每個block的oob (oob.u.a/oob.u.b)。
· 建構 ReplUnitTable
· 將block status存到ReplUnitTable中。
· Erase unreferenced block(不在Chain中的Block)、計算free block個數
· 如果unreferenced block無法erase
ReplUnitTable[block] = BLOCK_RESERVED;
· 否則
ReplUnitTable[block] = BLOCK_FREE;
· numfreeEUNs++;
· LastFreeEUN= block
2. handles reads
直接找latest version的page做read,如何找latest version請參考section.9。
3. handles writes
· Findwriteunit()
若在所屬的Chain中後面的Block對應的page狀態為free則回傳該block的physical address。
若無法在所屬的Chain寫入則 Find free block,參考section.5.2 ,链入chain中。
若沒有free block則做fold chain,參考section.8。
· 找到可寫入的block則將對應的page之oob.b.status設為SECTOR_USED。
· 最後將Data及ECCinfo寫入
(圖九)當我們要更新block 11的第4個page時,我們會先看看他之後的block 22的第4個page是否為free。是則寫入;不是則找free block串在block 22,然後把資料寫到新的block的第4個page。(最后一版最新)
7 About wear-leveling algorithm of NFTL
因為flash的每個block有erase次數的限制,當某個block erase次數過多,可能會造成該block存取速度變慢,嚴重時甚至會造成該block毀損。因此我們希望能夠平均每個block erase的的次數,此機制稱為wear-leveling。
此版本的NFTL並沒有實作Wear-Leveling,只有預留一些資訊,如WearInfo等…,我想Wear-Leveling能夠在find free block時作free block的選擇來達到平均抹除次數的目的。
8 Garbage-collection algorithm of NFTL(垃圾回收)
由於flash在更新資料時,無法將資料重新寫回相同的位置,除非先將該位置erase才能再寫入,所以必須採用outplace的方式寫回資料,因此會產生許多不同版本的資料,存放在不同的block中,而舊版本的資料則是無用的,所以必須要有garbage-collection的機制,以下是garbage-collection在NFTL中的作法。(NFTL_makefreeblock()函数)
Find longest chain
在NFTL中,GC(garbage-collection)主要目的是要回收最多的invalid block,而NFTL greedy的認為最長的chain中,能回收最多的block。而找最長的chain是透過ReplUnitTable找出最長的Chain並將該起始位置傳給NFTL_foldchain()做回收的動作。
NFTL_foldchain()
判斷是否可做inplace fold chain?
有時我們是在write時發現chain中所對應的page皆已使用,所以必須先判斷是否可以做inplace fold其步驟如下。
讀取Chain中Block的每個page的oob.b,以每個page的sector 的status判斷可否inplace。
若可做inplace將targetEUN設為Chain的最後一個block之physical位置(物理块号);反之找一個free block當作targetEUN。
將last version的page對應其位置複製到targetEUN中,如(圖六)。
NFTL_formatblock()
Erase 沒用的Blocks
先讀出將被erase的block的oob information。
Erase該block。
將oob.u.c.WearInfo+1,寫回該block的spare area。
將此block在ReplUnitTable中的欄位設成BLOCK_NIL,並將numfreeEUNs+1
完成fold動作後,更新oob.u.a.VirtUnitNum、oob.u.a.ReplUnitTable。
oob.u.a.VirtUnitNum = thisVUC(該Chain原本的virtual address)。
oob.u.a.ReplUnitNum = 0xffff (BLOCK_NIL)
更新EUNtable、ReplUnitTable
ReplUnitTable[targetEUN]=block_NIL
EUNtable[thisVUC] = targetEUN
(圖六) fold chain示意圖,targetEUN的page一開始全為free
9 How do NFTL tell the latest version of a piece of data from the old versions of the data (i.e., dead data)?
前面我們提到,flash上更新data大都是使用outplace的方法,所以在我們讀取資料時可能會有許多不同版本的資料,而讀取最新版本的data對於大多數的flash file system都是很重要的問題。在此我們介紹NFTL讀取最新版本資料的方法。
當我們在要更新DATA(sector中的資料)時,會將block中第n個page寫到他的replace unit的第n個page,所以我們只需要找chain中最後一個狀態是SECTOR_USED的page就能夠保證他是latest version。如下圖(圖八)所示:
(圖八)圖中紅色粗體的page的資料為latest version
10 Partial page programming
Partial page programming是指flash上的page在還沒被erase前,又將其中某些bit由1改為0,如下圖(圖十)。這在flash上容易造成partial page programming後的資料不正確,而且對於flash的製造上會提高其成本,所以在新一代的flash是不支援partial page programming的。 因此一個flash的file system是否有使用partial page programming是一項值得拿來評估file system的指標。
(圖十) partial page programming
在NFTL上,由4.3時提到NFTL on-flash data structures,NFTL將每個flash上的block的前三個page的spare area分為oob.b、oob.u使用。其中第一個page的oob.u存VUN / RUN、第二個page的oob.u存erasemark、第三個page的oob.u存foldmark。而當NFTL完成garbage collection時,會將erase的block的erasemark寫為0x3c69,而當NFTL要將資料寫入第二個page時,會一起將該page的oob.b.status狀態改為SECTOR_USED,此時NFTL便做了partial page programming了。另外NFTL在產生一個新的chain或是將block加到chain後面時,會先將資料寫入page並在該page的oob.b中寫入status與ECC,最後才將VUN / RUN寫入oob.u..a中,因此若第二的page有使用到話,也會發生partial page programming。如下(圖十一)
(圖十一)oob.b、oob.u在block中所擺放方式及partial page programming所發生情況。