天天看點

鴻蒙核心源碼分析(挂載目錄篇) | 為何檔案系統需要挂載 | 百篇部落格分析OpenHarmony源碼 | v65.02

鴻蒙核心源碼分析(挂載目錄篇) | 為何檔案系統需要挂載 | 百篇部落格分析OpenHarmony源碼 | v65.02

百篇部落格系列篇.本篇為:

v65.xx 鴻蒙核心源碼分析(挂載目錄篇) | 為何檔案系統需要挂載

檔案系統相關篇為:

  • v62.xx 鴻蒙核心源碼分析(檔案概念篇) | 為什麼說一切皆是檔案
  • v63.xx 鴻蒙核心源碼分析(檔案系統篇) | 用圖書管理說檔案系統
  • v64.xx 鴻蒙核心源碼分析(索引節點篇) | 誰是檔案系統最重要的概念
  • v65.xx 鴻蒙核心源碼分析(挂載目錄篇) | 為何檔案系統需要挂載
  • v66.xx 鴻蒙核心源碼分析(根檔案系統) | 先挂到

    /

    上的檔案系統
  • v67.xx 鴻蒙核心源碼分析(字元裝置篇) | 位元組為機關讀寫的裝置
  • v68.xx 鴻蒙核心源碼分析(VFS篇) | 檔案系統和諧共處的基礎
  • v69.xx 鴻蒙核心源碼分析(檔案句柄篇) | 你為什麼叫句柄 ?
  • v70.xx 鴻蒙核心源碼分析(管道檔案篇) | 如何降低資料流動成本

關于檔案系統的介紹已經寫了三篇,但才剛剛開始,其中的 [檔案系統篇] 一定要閱讀,用生活中的場景去解釋計算機各子產品設計的原理和運作機制是整個系列篇最大的特點,計算機檔案系統相關概念是非常的多的,若不還原其本質,不跳出這些概念去看問題是很難了解它為什麼要弄這麼些東東出來讓你頭大. 反之,如果搞明白了這些概念背後的真相你想忘記它們都很難,問題是經不起追問的, 多追問幾個為什麼就會離本源越來越近.

前幾篇中追問了以下幾個問題:

  • 對核心來說

    inode

    真的是唯一的嗎? 答案是否定的,使用電腦的經驗告訴我們,當把電腦硬碟拆下來挂到其他電腦上時,裡面的資料一樣能通路,并沒有讓你一切重來,而

    inode

    是存放硬碟上的,你沒有辦法讓已編好序号的

    inode

    按你的邏輯重排,這不合理更不科學. 是以結論是

    inode

    的全局唯一性不是不想做,而是壓根臣妾做不到啊.

    inode

    唯一性僅限于某個檔案系統的内部.
  • 經驗還告訴我們硬碟可以有多個分區,每個分區可以被格式化成不同的檔案系統.(例如:C槽:

    NTF

    ,D盤

    FAT32

    ,E盤

    ext

    ),資料可以互相拷貝,毫無障礙.不同的檔案系統是如何實作檔案遷移到呢 ? 具體實作細節是怎樣的 ?

如果想明白了這些問題, 就能逆向倒推為什麼要有目錄,為什麼需要挂載使用, 為什麼需要根檔案系統.一切将是水到渠成 .

先說目錄,從核心視角看目錄可不能像普通老百姓從使用者視角去看,目錄是為了屏蔽檔案系統之間的差異而設計出來的概念,也就說必須在

inode

的局部唯一性之上存在一個全局唯一性才能解決統一性問題.目錄從更大尺度上去相容并蓄各檔案系統.

那它是如何解決的呢?

  • 首先各個檔案系統記錄了自己内部目錄層級關系的,這個在 檔案系統篇 | 目錄項 中已經說過了. 這種關系是絕對的但也是相對的,絕對是對内,相對是對外. 例如:

    A檔案系統内部如下:

    ├─古龍系列 inode id : 789
    │  ├─小李飛刀 inode id : 56
    │  ├─楚留香 inode id : 342
    │  └─陸小鳳 inode id : 432
    └─金庸系列 inode id : 5567
        ├─倚天屠龍記 inode id : 89
        ├─射雕英雄傳 inode id : 1212
        └─笑傲江湖 inode id : 567843
               
    B檔案系統内部如下:
    ├─席絹系列  : inode id : 87 
    │  ├─上錯花轎嫁對郎 : inode id : 89 
    │  ├─吻上你的心 : inode id : 789 
    │  └─紅袖招 : inode id : 56 
    └─瓊瑤系列 : inode id : 321 
        ├─在水一方 : inode id : 234 
        ├─梅花三弄 : inode id : 5678 
        ├─煙雨濛濛 : inode id : 987 
        └─還珠格格 : inode id : 23 
               
    其中

    789

    ,

    89

    兩個檔案系統中都用到了,但它們在内部是唯一的.在A檔案系統中通過

    789

    就能找到

    56

    ,

    342

    ,

    432

    ,并且能得到相對路徑: 古龍系列/小李飛刀,古龍系列/楚留香 .也就是說拿着

    inode

    隻要進入了本檔案系統地盤,那都不叫事,事都能給你辦的妥妥的. 那如何才能進入而且不會搞錯呢?

挂載目錄

答案就是: 挂載目錄,也叫挂載點,集體統一指揮的前提是需要先回歸集體.如果已經有一顆目錄樹,将你們的目錄樹挂上來形成一顆更大的樹不就統一了嗎? 例如已有:

├─小說系列 inode id : 2
│  ├─武俠小說 inode id : 13
│  ├─言情小說 inode id : 14
           

其實它也是個檔案系統,叫根檔案系統, 它的

inode

也是獨立的, 并且能得到相對路徑

小說系列/武俠小說

,

小說系列/武俠小說

通過兩個

mount

動作, 将它變成如下所示

├─小說系列 (根檔案系統)
    ├─武俠小說 (根檔案系統)
    │  ├─古龍系列 (A檔案系統)
    │  │  ├─小李飛刀
    │  │  ├─楚留香
    │  │  └─陸小鳳
    │  └─金庸系列 (A檔案系統)
    │      ├─倚天屠龍記
    │      ├─射雕英雄傳
    │      └─笑傲江湖
    └─言情小說 (根檔案系統)
        ├─席絹系列 (B檔案系統)
        │  ├─上錯花轎嫁對郎
        │  ├─吻上你的心
        │  └─紅袖招
        └─瓊瑤系列 (B檔案系統)
            ├─在水一方
            ├─梅花三弄
            ├─煙雨濛濛
            └─還珠格格
           

哦,原來整顆目錄樹是由這三個檔案系統像搭積木一樣拼接起來.而兩個檔案系統的銜接點,必然會産生一個新的概念出來, 這個概念就是 挂載點,也叫 挂載目錄

Mount

可以猜測到的是挂載點的描述結構體中必有兩個檔案系統接駁點

inode

的資訊,挂鈎和脫鈎的操作也隻屬于它專有.具體如下:

//挂載操作
struct MountOps {
    int (*Mount)(struct Mount *mount, struct Vnode *vnode, const void *data);//挂載
    int (*Unmount)(struct Mount *mount, struct Vnode **blkdriver);//解除安裝
    int (*Statfs)(struct Mount *mount, struct statfs *sbp);//統計檔案系統的資訊,如該檔案系統類型、總大小、可用大小等資訊
};
struct Mount {
    LIST_ENTRY mountList;              /* mount list */			 //通過本節點将Mount挂到全局Mount連結清單上
    const struct MountOps *ops;        /* operations of mount */ //挂載操作函數	
    struct Vnode *vnodeBeCovered;      /* vnode we mounted on */ //要被挂載的節點 即 /bin1/vs/sd 對應的 vnode節點
    struct Vnode *vnodeCovered;        /* syncer vnode */		 //要挂載的節點	即/dev/mmcblk0p0 對應的 vnode節點
    LIST_HEAD vnodeList;               /* list of vnodes */		//連結清單表頭
    int vnodeSize;                     /* size of vnode list */	//節點數量
    LIST_HEAD activeVnodeList;         /* list of active vnodes */	//激活的節點連結清單
    int activeVnodeSize;               /* szie of active vnodes list *///激活的節點數量
    void *data;                        /* private data */	//私有資料,可使用這個成員作為一個指向它們自己内部資料的指針
    uint32_t hashseed;                 /* Random seed for vfs hash */ //vfs 哈希随機種子
    unsigned long mountFlags;          /* Flags for mount */	//挂載标簽
    char pathName[PATH_MAX];           /* path name of mount point */	//挂載點路徑名稱  /bin1/vs/sd
    char devName[PATH_MAX];            /* path name of dev point */		//裝置名稱 /dev/mmcblk0p0
};
           

解讀

  • mountList

    : 挂載點由雙向連結清單全局統一管理
  • vnodeBeCovered

    :,記錄挂到根檔案系統的哪個節點上.
  • vnodeCovered

    : 裝置也是一種檔案,也被統一管理,統一在

    /dev

    目錄下,核心會給裝置的每個分區配置設定一個

    vnode

    節點,一個分區對應一個檔案系統,裝置檔案後續有專門的介紹,此處不展開.
  • vnodeList

    : 指的是A/B檔案系統的節點連結清單,由挂載點結構體記錄.
  • activeVnodeList

    :

    A

    檔案系統節點的使用情況,統一由雙向連結清單管理.
  • activeVnodeSize

    :

    A

    檔案系統已被使用的節點數
  • data

    這是檔案系統的私有資料,跟 索引節點篇 | Vnode -> data 一樣了解.
  • pathName

    :這個很重要,記錄了

    小說系列/武俠小說

    ,因為檔案的絕對路徑是拼接起來的,以

    小說系列/武俠小說/古龍系列/小李飛刀

    這個完整的路徑來說,它是由

    小說系列/武俠小說

    (根檔案系統提供) +

    古龍系列/小李飛刀

    (A檔案系統提供) 這兩部分拼成的.
  • devName

    :一般名稱類似于

    mmcblk0p0

    =

    mmc

    +

    block0

    +

    Partition0

    • mmc

      :

      MultiMediaCard

      可了解為硬碟
    • block0

      : 0号塊裝置
    • Partition

      :0号分區,一個分區上安裝一個檔案系統.
  • MountOps ops

    : 每個檔案系統挂載方式是不用的,都需要實作這幾個接口(挂載,解除安裝,統計).
    // 檔案系統 proc 對 MountOps 接口實作
    const struct MountOps procfs_operations = {
        .Mount = VfsProcfsMount,//裝載
        .Unmount = NULL,
        .Statfs = VfsProcfsStatfs,//統計資訊
    };
    //檔案系統 fat 對MountOps 接口實作
    struct MountOps fatfs_mops = {
        .Mount = fatfs_mount,
        .Unmount = fatfs_umount,
        .Statfs = fatfs_statfs,
    };
    //檔案系統 jffs 對MountOps 接口實作
    const struct MountOps jffs_operations = {
      .Mount = VfsJffs2Bind,
      .Unmount = VfsJffs2Unbind,
      .Statfs = VfsJffs2Statfs,
    };
               

問題

上面提到 挂載就需要一個已經存在的檔案系統提供目錄,也就是根檔案系統,但根檔案系統又是怎麼來的呢?

百篇部落格分析.深挖核心地基

給鴻蒙核心源碼加注釋過程中,整理出以下文章。内容立足源碼,常以生活場景打比方盡可能多的将核心知識點置入某種場景,具有畫面感,容易了解記憶。說别人能聽得懂的話很重要! 百篇部落格絕不是百度教條式的在說一堆诘屈聱牙的概念,那沒什麼意思。更希望讓核心變得栩栩如生,倍感親切.确實有難度,自不量力,但已經出發,回頭已是不可能的了。 😛

與代碼有bug需不斷debug一樣,文章和注解内容會存在不少錯漏之處,請多包涵,但會反複修正,持續更新,

.xx

代表修改的次數,精雕細琢,言簡意赅,力求打造精品内容。

編譯建構 基礎工具 加載運作 程序管理

編譯環境篇

編譯過程篇

環境腳本篇

建構工具篇

gn應用篇

忍者ninja篇

雙向連結清單篇

位圖管理篇

用棧方式篇

定時器篇

原子操作篇

時間管理篇

ELF格式篇

ELF解析篇

靜态連結篇

重定位篇

程序映像篇

程序管理篇

程序概念篇

Fork篇

特殊程序篇

程序回收篇

信号生産篇

信号消費篇

Shell編輯篇

Shell解析篇

程序通訊 記憶體管理 前因後果 任務管理

自旋鎖篇

互斥鎖篇

程序通訊篇

信号量篇

事件控制篇

消息隊列篇

記憶體配置設定篇

記憶體管理篇

記憶體彙編篇

記憶體映射篇

記憶體規則篇

實體記憶體篇

總目錄

排程故事篇

記憶體主奴篇

源碼注釋篇

源碼結構篇

靜态站點篇

時鐘任務篇

任務排程篇

任務管理篇

排程隊列篇

排程機制篇

線程概念篇

并發并行篇

系統調用篇

任務切換篇

檔案系統 硬體架構

檔案概念篇

檔案系統篇

索引節點篇

挂載目錄篇

根檔案系統

字元裝置篇

VFS篇

檔案句柄篇

管道檔案篇

彙編基礎篇

彙編傳參篇

工作模式篇

寄存器篇

異常接管篇

彙編彙總篇

中斷切換篇

中斷概念篇

中斷管理篇

繼續閱讀