個人學習-Linux文件系統架構

来源:https://www.cnblogs.com/Albert-lihai/archive/2022/09/15/16698201.html
-Advertisement-
Play Games

個人學習-Linux文件系統架構 1. 參考文章 [1]https://blog.csdn.net/Holy_666/article/details/86532671 [2]CSDN博主土豆西瓜大芝麻:[Linux的VFS詳解]:https://blog.csdn.net/jinking01/art ...


個人學習-Linux文件系統架構

1. 參考文章

[1]https://blog.csdn.net/Holy_666/article/details/86532671

[2]CSDN博主土豆西瓜大芝麻:[Linux的VFS詳解]:https://blog.csdn.net/jinking01/article/details/90669534

[3]深入理解 Linux的 I/O 系統:https://z.itpub.net/article/detail/9595A9A27188FF73810F07F00DAA08ED

[4]Linux嵌入式的知乎專欄:https://zhuanlan.zhihu.com/p/505338841

[5]博客園博主[李大嘴]:[字元設備和塊設備的區別]https://www.cnblogs.com/qlee/archive/2011/07/27/2118406.html

[6]博客園博主[賽艇隊長]:[Linux文件系統詳述]https://www.cnblogs.com/bellkosmos/p/detail_of_linux_file_system.html

[7]StackExchange:[What are directories, if everything on Linux is a file?]

[8] [The Linux Documentation Project: Filesystem]http://www.tldp.org/LDP/tlk/fs/filesystem.html#tth_sEc9.1.4)

2. 概述:

本文主要從四個角度對Linux文件系統進行總結整理;

  1. Linux文件系統的組織方式;

  2. Linux的VFS機制和統一文件模型(common file model);

  3. Linux系統IO緩衝機制;

3. Linux文件組織方式:

3.1 基礎知識:

​ 老調重彈:Linux設計的思路,就是一切皆文件,因此Linux中的一切文件都以文件格式保存,而文件根據各自不同的功能分為一下幾類:

  1. 普通文件:

    -,常規的文件類型,在Linux中,以.開頭的文件為隱藏文件;

  2. 目錄文件;

    d, 目錄文件,目錄文件實際包含兩部分Inode和entry(實際所有文件都是這樣,不同的是,目錄中保存了相關文件的信息);

    Linux通過Inode結構體存儲目錄的基礎信息,系統調用stat(),用來訪問這個結構和相應信息。

​ (圖1 源自引用文獻[7])

  1. 字元設備文件;

    ​ c, character device,字元設備是以字元為最小單位進行數據交互的文件,用以驅動字元交互的應用,如鍵盤(有文章提到oracle是以字元為格式進行數據傳輸的,記個ToDo);

    ​ 而對於字元設備而言,僅支持順序訪問數據,不支持隨機訪問。

  2. 塊設備文件;

    B,block device driver

    ​ 塊設備傳輸,實際是以固定大小進行數據傳輸的文件類型,和字元設備不同的是,block支持我們對設備隨機訪問。最典型的例子即硬碟,操作系統/資料庫/其他和磁碟交互應用,實際可以根據自己的規則,去隨機訪問磁碟的位置,去在該位置寫入數據。而通過塊設備進行讀寫時,也需要以bolck為最小單位進行操作(實際上,無論是OS還是DBS,都是以Page去容納多個Block,然後通過Page進行數據載入,然後以block進行數據解析的)

  3. 符號鏈接;(軟鏈接,硬鏈接實際是生成了一個相應文件,該文件名和原始文件名指向同一個inode):

    ​ 符號鏈接可以理解成一種快捷方式,允許我們通過符號鏈接快速訪問目標文件。

  4. 套接字;

    S,socket,用於網路通信的文件,通過套接字API形成的一個簡單協議族,成對出現進行通信。

  5. 管道;

    ​ P,進行進程間通信的文件,將一個進程的輸出,通過管道,輸入到另一個文件。

3.2 文件系統的基本組成

​ (Note: 本部分僅介紹基礎部分,磁碟分區,初始化,數據在磁碟上的組織後續再進行補充)

​ Linux操作系統支持很多不同的文件系統,ext2,ext3,XFS,FAT等等,而Linux把對不同文件系統的訪問,交給VFS(virtual file system)來進行。

​ Linux的文件系統會為每個文件分配兩個數據結構:

​ 索引節點(index node) 和 目錄項(directory entry),用來記錄文件的元信息(meta data)如inode編號,文件大小,訪問許可權,修改時間,磁碟位置等。索引節點和磁碟上的每個物理文件相對應,而索引節點本身,也存儲在磁碟上。

​ 目錄項(directory entry)用來記錄文件的名字,索引節點指針,和其他目錄項的層次關係。多個目錄項關聯起來,就形成了目錄結構,和索引節點不同,目錄項是由內核維護的數據結構,緩存在記憶體中;(note:實際上系統啟動時,會將相應的數據,載入到樹形結構中,維護在記憶體中)

目錄項的結構體,dentry

struct dentry {
     atomic_t d_count;        /* 目錄項引用計數器 */
     unsigned int d_flags;    /* 目錄項標誌 */
     struct inode  * d_inode;   /* 與文件名關聯的索引節點 */
     struct dentry * d_parent;       /* 父目錄的目錄項 */
     struct list_head d_hash;        /* 目錄項形成的哈希表 */
     struct list_head d_lru;         /*未使用的 LRU 鏈表 */
     struct list_head d_child;       /*父目錄的子目錄項所形成的鏈表 */
     struct list_head d_subdirs;     /* 該目錄項的子目錄所形成的鏈表*/
     struct list_head d_alias;       /* 索引節點別名的鏈表*/
     int d_mounted;                  /* 目錄項的安裝點 */
     struct qstr d_name;             /* 目錄項名(可快速查找) */
     unsigned long d_time;           /* 由 d_revalidate函數使用 */
     struct dentry_operations  *d_op; /* 目錄項的函數集*/
     struct super_block * d_sb;      /* 目錄項樹的根 (即文件的超級塊)*/
     unsigned long d_vfs_flags; 
     void * d_fsdata;                /* 具體文件系統的數據 */
     unsigned char d_iname[DNAME_INLINE_LEN]; /* 短文件名 */
};

通過stat訪問得到的Inode信息

     struct stat { /* when _DARWIN_FEATURE_64_BIT_INODE is NOT defined */
         dev_t    st_dev;    /* device inode resides on */
         ino_t    st_ino;    /* inode's number */
         mode_t   st_mode;   /* inode protection mode */
         nlink_t  st_nlink;  /* number of hard links to the file */
         uid_t    st_uid;    /* user-id of owner */
         gid_t    st_gid;    /* group-id of owner */
         dev_t    st_rdev;   /* device type, for special file inode */
         struct timespec st_atimespec;  /* time of last access */
         struct timespec st_mtimespec;  /* time of last data modification */
         struct timespec st_ctimespec;  /* time of last file status change */
         off_t    st_size;   /* file size, in bytes */
         quad_t   st_blocks; /* blocks allocated for file */
         u_long   st_blksize;/* optimal file sys I/O ops blocksize */
         u_long   st_flags;  /* user defined flags for file */
         u_long   st_gen;    /* file generation number */
     };

而索引節點,目錄項,以及文件數據間的關係可以用如下結構來表示

​ (圖2 源自引用4)

4. 虛擬文件系統(Virtual File Switch)

當一個用戶應用,通過系統調用函數進行數據讀寫時會發生什麼?

fopen("~");
fwrite("~");
fclose("~");

​ 在我們的直覺上,會認為用戶空間的代碼,通過調用庫函數喚起系統調用,然後交於OS File System直接寫入磁碟(在考慮buffer,page,block,機制後)。但是實際上Linux實際上是將系統調用交付於VFS,即虛擬文件系統,然後由VFS執行後續操作的。

​ (圖3 源自引用2)

​ 這樣做有什麼價值呢?如上文所述,Linux存在不同的file system operator,這些不同的文件系統暴漏給上層的介面可能是不同的,如果將這些介面都提供給OS SCI(stsrem call interface),系統調用會過於複雜。而VFS在文件系統和系統調用間提供了一個抽象層,讓系統調用的POSIX API和不同存儲設備的具體介面實現了分離,實現了一次解耦。

​ (圖4 源自引用2)

4.1 統一文件模型(common file model)

​ 由於VFS將不同的底層介面抽象了統一的標準給系統調用,系統調用層便可以用上文提到的Inode,entry模型將所有文件的模型進行統一。實際上正是VFS層提供了統一的文件模型。

​ VFS通過四種標準模型來構建統一文件模型:

(1)superblock: 存儲文件系統的基本元數據(可以理解成 meta of meta,這詞兒沒查過,是我現編的)。如文件系統的類型,大小,狀態,一起其他元數據的相關信息。

(2)index node(inode):一個用來保存文件相關的元數據。

(3)directory entry: 保存文件名稱和inode的對應關係;

每個dentry存在三種狀態:

  • Used: 和一個inode關聯,正被使用,不能被損壞和丟棄;
  • Unused: 和inode關聯,處於被緩存狀態,沒有被vfs使用;
  • negative: 沒有和具體的inode關聯(實際相當於一個無效路徑);

由於dentry實際是載入在記憶體里的,系統會對dentry存在優化策略:

1.used dentrie list:把使用的dentry串成一個鏈表;

2.LRU鏈表:(least recently used)鏈表,實際就是最常見的頁面置換演算法,找出最久沒有使用的entry,把它從記憶體中釋放。

3.hash table:用哈希表,來維持dentry的高速查詢;

(4) file: 一組邏輯上相關聯的數據,實際就是我們通過open函數返回的數據類型,在我們使用open打開函數後,就從磁碟中載入了對於的數據至記憶體,VFS將數據保存至File模型中,和進程,用戶強關聯。其中包含了打開的flag,文件名稱,當前的便宜。最重要的欄位就是f_op,指向了當前文件所支持的操作集合;

struct file {
    struct dentry *f_dentry;
    struct vfsmount *f_vfsmnt;
    struct file_operations *f_op;
    mode_t f_mode;
    loff_t f_pos;
    struct fown_struct f_owner;
    unsigned int f_uid, f_gid;
    unsigned long f_version;
    ...
}

5. 系統IO

​ 本部分主要討論系統IO和緩衝區之間的交互;

傳統的(無緩存)文件讀寫方式

![截屏2022-09-15 22.12.33](/Users/alberthaoluchen/Library/Application Support/typora-user-images/截屏2022-09-15 22.12.33.png)

1.用戶進程通過read()向kernel進行系統調用,切換上下文,到內核空間。

2.CPU將數據從硬碟or主存拷貝至kernel到讀緩衝區;

3.CPU將讀緩衝區的數據拷貝回用戶緩衝區;

4.上下文從kernelspace 切換回UserSpace,read調用執行返回;

用戶態 <---> 內核態切換兩次;

拷貝操作,兩次;

用戶態的切換和系統拷貝,被切開,相較於連續的操作,這種間斷式的操作更耗時;

高性能優化的I/O

PageCache

​ 頁緩存技術,通過每次從磁碟讀取一個Page單位的數據至緩存,來減少對磁碟的讀寫,來提高系統效率;

​ 當我們進行順序讀寫時,頁緩存能極大提高我們的讀寫速度(實際就是直接在memory上讀寫);

頁緩存的優化策略:

讀策略:

  • 當我們執行read操作時,判斷數據在PageCache上嗎?如果在,我們就不對磁碟進行讀操作;
  • 如果不在,調度I/O去讀磁碟數據,除了目標文件所在的Page外,還會讀多個連續頁到頁緩存中;

寫策略:

​ 當我們執行寫操作時,先寫進頁緩存,此時我們把目標頁標記為臟頁(dirty page),並把這個頁加入臟頁鏈表;

flusher會周期性的回寫臟頁到磁碟,當磁碟數據和記憶體一致時,清楚臟頁標記,

當滿足以下條件時,臟頁會被寫入記憶體:

  • 空閑記憶體低於一個特定閾值;
  • 臟頁在記憶體駐留時間超過閾值時(LRU)
  • 用戶進程調用sync()和fsync()時;

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 業務模塊介紹 現在我們對整體的業務進行介紹以及演示 5. 全鏈路整體架構 上面介紹了為什麼需要全鏈路壓測,下麵來看下全鏈路壓測的整體架構。 ​ 整體架構如下主要是對壓測客戶端的壓測數據染色,全鏈路中間件識別出染色數據,並將正常數據和壓測數據區分開,進行數據隔離,這裡主要涉及到mysql資料庫,Rab ...
  • MyBatis 通過使用內置的日誌工廠提供日誌功能。 在這裡我們對STDOUT_LOGGING和LOG4J進行學習。 一、STDOUT_LOGGING 1.什麼是STDOUT_LOGGING STDOUT_LOGGING是MyBatis的標準日誌配置。STDOUT_LOGGING的使用無需其他的依賴 ...
  • 從提升性能角度來說 提升了對CPU的使用效率:目前生產的伺服器大多數都是多核,標配的機器都是 8C/16G。操作系統會將不同的線程分配給不同的核心處理,理論上,有多少核心就有多少個線程並行執行。如果沒有併發編程,CPU的利用率將極大的浪費,假設當前正在處理耗時的 I/O 操作,那麼整個CPU就會處於... ...
  • 大家好,我是三友~~ 在對於讀寫鎖的認識當中,我們都認為讀時加讀鎖,寫時加寫鎖來保證讀寫和寫寫互斥,從而達到讀寫安全的目的。但是就在我翻Eureka源碼的時候,發現Eureka在使用讀寫鎖時竟然是在讀時加寫鎖,寫時加讀鎖,這波操作屬實震驚到了我,於是我就花了點時間研究了一下Eureka的這波操作。 ...
  • DotnetZip使用方法見此文章https://www.cnblogs.com/pengze0902/p/6124659.html在netframework環境下,使用上面文章中的設置Encoding為Default的方法即可解決中文亂碼問題 但是當我使用.net6創建控制台項目並採用上述代碼時, ...
  • iNeuOS工業互聯網操作系統面向:儀器儀錶、雙碳環保、核能科學與工程和鋼鐵冶金領域頒發第一批技術認證資質,一共21名同志在項目實施過程中表現突出,從iNeuOS的應用、開發及項目過程中的交流都大大促進了項目保質保量的快速交付,特此頒發應用實施和二次開發工程認證。 ...
  • 一:背景 1. 講故事 前段時間有位朋友在微信上找到我,說他的程式出現了記憶體泄漏,能不能幫他看一下,這個問題還是比較經典的,加上好久沒上非托管方面的東西了,這篇就和大家分享一下,話不多說,上 WinDbg 說話。 二:WinDbg 分析 1. 到底是哪裡的泄漏 好的開始就是成功的一半,否則就南轅北轍 ...
  • sed高階用法 sed編輯器 sed是一種流編輯器,流編輯器會在編輯器處理數據之前基於預先提供的一組規則來編輯數據流。 1.sed編輯器工作流程 sed編輯器可以根據命令來處理數據流中的數據,這些命令要麼從命令行中輸入,要麼存儲在一個命令文本文件中。 sed的工作流程主要包括讀取、執行和顯示三個過程 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...