日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

F2FS源码分析-2.1 [F2FS 读写部分] F2FS文件数据组织方式以及物理地址的映射

發(fā)布時(shí)間:2023/12/8 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 F2FS源码分析-2.1 [F2FS 读写部分] F2FS文件数据组织方式以及物理地址的映射 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

F2FS源碼分析系列文章

主目錄
一、文件系統(tǒng)布局以及元數(shù)據(jù)結(jié)構(gòu)
二、文件數(shù)據(jù)的存儲(chǔ)以及讀寫
  • F2FS文件數(shù)據(jù)組織方式
  • 一般文件寫流程
  • 一般文件讀流程
  • 目錄文件讀流程(未完成)
  • 目錄文件寫流程(未完成)
  • 三、文件與目錄的創(chuàng)建以及刪除(未完成)
    四、垃圾回收機(jī)制
    五、數(shù)據(jù)恢復(fù)機(jī)制
    六、重要數(shù)據(jù)結(jié)構(gòu)或者函數(shù)的分析

    文件數(shù)據(jù)的保存以及物理地址的映射

    文件數(shù)據(jù)的組織方式一般時(shí)被設(shè)計(jì)為inode-data模式,即 每一個(gè)文件都具有一個(gè)inode,這個(gè)inode記錄data的組織關(guān)系,這個(gè)關(guān)系稱為文件結(jié)構(gòu)。例如用戶需要訪問A文件的第1000個(gè)字節(jié),系統(tǒng)就會(huì)先根據(jù)A文件的路徑找到的A的inode,然后從inode找到第1000個(gè)字節(jié)所在的物理地址,然后從磁盤讀取出來。那么F2FS的文件結(jié)構(gòu)是怎么樣的呢?

    如上圖,F2FS中的一個(gè)inode,包含兩個(gè)主要部分: metadata部分,和數(shù)據(jù)塊尋址部分。我們重點(diǎn)觀察數(shù)據(jù)塊尋址部分,分析inode時(shí)如何將數(shù)據(jù)塊索引出來。在圖中,數(shù)據(jù)塊尋址部分包含direct pointers,single-indirect,double-indirect,以及triple-indirect。它們的含義分別是:

    direct pointer: inode內(nèi)直接指向數(shù)據(jù)塊(圖右上角Data)的地址數(shù)組,即inode->data模式

    single-indirect pointer: inode記錄了兩個(gè)single-indirect pointer(圖右上角Direct node),每一個(gè)single-indirect pointer存儲(chǔ)了多個(gè)數(shù)據(jù)塊的地址,即inode->direct_node->data模式

    double-indirect: inode記錄了兩個(gè)double-indirect pointer(圖右上角indirect node),每一個(gè)double-indirect pointer記錄了許多single-indirect pointer,每一個(gè)single-indirect pointer指向了數(shù)據(jù)塊,即inode->indirect_node->direct_node->data模式

    triple-indirect: inode記錄了一個(gè)triple-indirect pointer(圖右上角indirect node),每一個(gè)triple-indirect pointer記錄了許多double-indirect pointer,每一個(gè)double-indirect pointer記錄了許多single-indirect pointer,最后每一個(gè)single-indirect pointer指向了數(shù)據(jù)塊。即inode->indirect_node->indirect_node->direct_node->data模式

    因此,我們可以發(fā)現(xiàn),F2FS的inode結(jié)構(gòu)采取indirect_node,首先在inode內(nèi)部尋找物理地址,如果找不到再去direct_node找,層層深入。

    f2fs_node的結(jié)構(gòu)以及作用

    根據(jù)上面的分析,我們可以發(fā)現(xiàn)一個(gè)對(duì)于一個(gè)較大的文件,它可能包含inode以外的node,去保存一些間接尋址的信息。single-indirect pointer記錄的是數(shù)據(jù)塊的地址,而double-indirect pointer記錄的是single-indirect pointer的地址,triple-indirect pointer記錄的double-indirect pointer地址。在F2FS中,

    inode對(duì)應(yīng)的是f2fs_inode結(jié)構(gòu),包含了多個(gè)direct pointer指向數(shù)據(jù)塊物理地址;

    single-indirect pointer對(duì)應(yīng)的是direct_node結(jié)構(gòu),包含了多個(gè)direct pointer指向物理地址;

    double-indirect pointer對(duì)應(yīng)的是indirect_node結(jié)構(gòu),包含了多個(gè)指向direct_node的地址;

    triple-indirect pointer對(duì)應(yīng)的也是indirect_node結(jié)構(gòu),包含了多個(gè)指向indirect_node的地址

    接下來我們逐個(gè)分析F2FS每一個(gè)node的具體數(shù)據(jù)結(jié)構(gòu)。

    基本node結(jié)構(gòu)

    為了方便F2FS的對(duì)node的區(qū)分和管理,f2fs_inode和direct_node以及indirect_node都使用了同一個(gè)數(shù)據(jù)結(jié)構(gòu)f2fs_node進(jìn)行描述,并通過union的方式,將f2fs_node初始化成不同的node形式,它的結(jié)構(gòu)如下:

    struct f2fs_node {union {struct f2fs_inode i;struct direct_node dn;struct indirect_node in;};struct node_footer footer; // footer用于記錄node的類型 } __packed;struct node_footer {__le32 nid; /* node id */__le32 ino; /* inode nunmber */__le32 flag; /* include cold/fsync/dentry marks and offset */__le64 cp_ver; /* checkpoint version */__le32 next_blkaddr; /* next node page block address */ } __packed;

    其中起到區(qū)分是哪一種node的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)是node_footer。如果node_footer的nid和ino相等,則表示這是一個(gè)f2fs_inode結(jié)構(gòu),如果不相等,則表示這是一個(gè)direct_node或者indirect_node。

    f2fs_inode結(jié)構(gòu)

    我們先看f2fs_inode的結(jié)構(gòu),省略其他元數(shù)據(jù)的信息,重點(diǎn)關(guān)注文件如何索引的,結(jié)構(gòu)如下:

    struct f2fs_inode {...__le32 i_addr[DEF_ADDRS_PER_INODE]; // DEF_ADDRS_PER_INODE=923__le32 i_nid[DEF_NIDS_PER_INODE]; // DEF_NIDS_PER_INODE=5... } __packed;

    i_addr數(shù)組就是前面提及的direct pointer,數(shù)組的下標(biāo)是文件的邏輯位置,數(shù)組的值就是flash設(shè)備的物理地址。例如文件的第一個(gè)頁就對(duì)應(yīng)i_addr[0],第二個(gè)頁就對(duì)應(yīng)i_addr[1],而i_addr[0]和i_addr[1]所記錄的物理地址,就是文件第一個(gè)頁(page)和第二個(gè)頁的數(shù)據(jù)的物理地址,系統(tǒng)可以將兩個(gè)物理地址提交到flash設(shè)備,將數(shù)據(jù)讀取出來。

    我們可以發(fā)現(xiàn)i_addr的數(shù)組長(zhǎng)度只有923,即一個(gè)f2fs_inode只能直接索引到923個(gè)頁/塊的地址(約3.6MB),對(duì)于大于3.6MB的文件,就需要使用間接尋址。f2fs_inode的i_nid數(shù)組就是為了間接尋址而設(shè)計(jì),i_nid數(shù)組是一個(gè)長(zhǎng)度為5的數(shù)組,可以記錄5個(gè)node的地址。其中

    i_nid[0]和i_nid[1]記錄的是direct_node的地址,即對(duì)應(yīng)前述的single-indirect pointer。

    i_nid[2]和i_nid[3]記錄的是indirect_node的地址,這兩個(gè)indirect_node記錄的是direct_node的地址,即對(duì)應(yīng)前述的double-indirect pointer。

    i_nid[4]記錄的是indirect_node的地址,但是這個(gè)indirect_node記錄的是indirect_node的地址,即前述的triple-indirect pointer。

    direct_node和indirect_node結(jié)構(gòu)

    direct_inode以及indirect_inode的結(jié)構(gòu)如下所示,direct_node記錄的是數(shù)據(jù)塊的地址,indirect_inode記錄的是node的id,系統(tǒng)可以通過nid找到對(duì)應(yīng)的node的地址。

    struct direct_node {__le32 addr[ADDRS_PER_BLOCK]; // ADDRS_PER_BLOCK=1018 } __packed;struct indirect_node {__le32 nid[NIDS_PER_BLOCK]; // NIDS_PER_BLOCK=1018 } __packed;

    Wandering Tree問題

    在第一章的第一節(jié)提到,F2FS的設(shè)計(jì)是為了解決wandering tree的問題,那么現(xiàn)在的設(shè)計(jì)是如何解決這個(gè)問題的呢。假設(shè)一個(gè)文件發(fā)生更改,修改了direct_node里面的某一個(gè)block的數(shù)據(jù),根據(jù)LFS的異地更新特性,我們需要給更改后的數(shù)據(jù)一個(gè)新的block。傳統(tǒng)的LFS需要將這個(gè)新的block的地址一層層網(wǎng)上傳遞,直到inode結(jié)構(gòu)。而F2FS的設(shè)計(jì)是只需要將direct_node對(duì)應(yīng)位置的addr的值更新為新block的地址,從而沒必要往上傳遞,因此解決了wandering tree的問題。

    普通文件數(shù)據(jù)的保存

    從上節(jié)描述可以知道,一個(gè)文件由一個(gè)f2fs_inode和多個(gè)direct_inode或者indirect_inode所組成。當(dāng)系統(tǒng)創(chuàng)建一個(gè)文件的時(shí)候,它會(huì)首先創(chuàng)建一個(gè)f2fs_inode寫入到flash設(shè)備,然后用戶往該文件寫入第一個(gè)page的時(shí)候,會(huì)將數(shù)據(jù)寫入到main area的一個(gè)block中,然后將該block的物理地址賦值到f2fs_inode->i_addr[0]中,這樣就完成了Node-Data的管理關(guān)系。隨著對(duì)同一文件寫入的數(shù)據(jù)的增多,會(huì)逐漸使用到其他類型的node去保存文件的數(shù)據(jù)。

    經(jīng)過上面的分析,我們可以計(jì)算F2FS單個(gè)文件的最大尺寸:

  • f2fs_inode 直接保存了923個(gè)block的數(shù)據(jù)的物理地址
  • f2fs_inode->i_nid[0~1] 保存了兩個(gè) direct_node 的地址,這里可以保存 2 x 1018個(gè)block的數(shù)據(jù)
  • f2fs_inode->i_nid[2~3] 保存了兩個(gè)indirect_node 的地址,這兩個(gè)其中2個(gè)indirect_node保存的是 direct_node 的nid,因此可以保存 2 x 1018 x 1018個(gè)block的數(shù)據(jù);
  • f2fs_inode->i_nid[4] 保存了一個(gè)indirect_node 的地址,這個(gè)indirect_node保存的是 indirect_node 的nid,因此可以保存 1018 x 1018 x 1018個(gè)頁的數(shù)據(jù)
  • 可以得到如下計(jì)算公式:
    4KB x (923 + 2 x 1018 + 2 x 1018 x 1018 + 1 x 1018 x 1018 x 1018) = 3.93TB
    因此F2FS單個(gè)文件最多了保存3.93TB數(shù)據(jù)。

    內(nèi)聯(lián)文件數(shù)據(jù)的保存

    從上節(jié)可以知道,文件的實(shí)際數(shù)據(jù)是保存在f2fs_inode->i_addr對(duì)應(yīng)的物理塊當(dāng)中,因此即使一個(gè)很小的文件,如1個(gè)字節(jié)的小文件,也需要一個(gè)node和data block才能實(shí)現(xiàn)正常的保存和讀寫,也就是需要8KB的磁盤空間去保存一個(gè)尺寸為1字節(jié)的小文件。而且f2fs_inode->i_addr[923]里面除了f2fs_inode->i_addr[0]保存了一個(gè)物理地址,其余的922個(gè)i_addr都被閑置,造成了空間的浪費(fèi)。

    因此F2FS為了減少空間的使用量,使用內(nèi)聯(lián)(inline)文件減少這些空間的浪費(fèi)。它的核心思想是當(dāng)文件足夠小的時(shí)候,使用f2fs_inode->i_addr數(shù)組直接保存數(shù)據(jù)本身,而不單獨(dú)寫入一個(gè)block中,再進(jìn)行尋址。因此,如上面的例子,只有1個(gè)字節(jié)大小的文件,只需要一個(gè)f2fs_inode結(jié)構(gòu),即4KB,就可以同時(shí)將node信息和data信息同時(shí)保存,減少了一半的空間使用量。

    根據(jù)上述定義,可以計(jì)算得到多大的文件可以使用內(nèi)聯(lián)的方式進(jìn)行保存,f2fs_inode有尺寸為923的用于保存數(shù)據(jù)物理地址的數(shù)組i_addr,它的數(shù)據(jù)類型是__le32,即4個(gè)字節(jié)。保留一個(gè)數(shù)組成員另做它用,因此內(nèi)聯(lián)文件最大尺寸為: 922 * 4 = 3688字節(jié)。

    文件讀寫與物理地址的映射的例子

    Linux的文件是通過page進(jìn)行組織起來的,默認(rèn)page的size是4KB,使用index作為編號(hào)。

    一個(gè)小文件訪問例子

    例如一個(gè)size=10KB的文件,需要3個(gè)page去保存數(shù)據(jù),這3個(gè)page的編號(hào)是0,1,2。當(dāng)用戶訪問這個(gè)文件的第2~6kb的數(shù)據(jù)的時(shí)候,系統(tǒng)就會(huì)計(jì)算出數(shù)據(jù)保存在page index = 0和1的page中,然后根據(jù)文件的路徑找到對(duì)應(yīng)的f2fs_inode結(jié)構(gòu),page index = 0和1即對(duì)應(yīng)f2fs_inode的i_addr[0]和i_addr[1]。系統(tǒng)進(jìn)而從這兩個(gè)i_addr讀取物理地址,提交到flash設(shè)備將數(shù)據(jù)讀取出來。

    一個(gè)大文件訪問例子

    假設(shè)用戶需要讀取文件第4000個(gè)頁(page index = 3999)的數(shù)據(jù),
    第一步: 那么首先系統(tǒng)會(huì)根據(jù)文件路徑找到對(duì)應(yīng)的f2fs_inode結(jié)構(gòu)
    第二步: 由于4000 >(923 + 1018 + 1018),f2fs_inode->i_addr和f2fs_inode->nid[0]和nid[1]都無法滿足需求,因此系統(tǒng)根據(jù)f2fs_inode->nid[2]找到對(duì)應(yīng)的 indirect_node的地址
    第三步: indirect_node保存的是direct_node的nid數(shù)組,由于 4000 - 923 - 1018 - 1018 = 1041,而一個(gè)direct_node只能保存1018個(gè)block,因此可以知道數(shù)據(jù)位于indirect_node->nid[1]對(duì)應(yīng)的direct_node中
    第四步: 計(jì)算剩下的的偏移(4000-923-1018-1018-1018=23)找到數(shù)據(jù)的物理地址位于該direct_node的direct_node->addr[23]中。

    總結(jié)

    以上是生活随笔為你收集整理的F2FS源码分析-2.1 [F2FS 读写部分] F2FS文件数据组织方式以及物理地址的映射的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。