Linux 0.11源碼閱讀筆記-文件管理 文件系統 生磁碟 未安裝文件系統的磁碟稱之為生磁碟,生磁碟也可以作為文件讀寫,linux中一切皆文件。 磁碟分區 生磁碟可以被分區,分區中可以安裝文件系統,常見的文件系統有fat32、ext2、ext4等。分區後的磁碟結構佈局如下圖,其中主引導扇區記錄了分 ...
Linux 0.11源碼閱讀筆記-文件管理
文件系統
生磁碟
未安裝文件系統的磁碟稱之為生磁碟,生磁碟也可以作為文件讀寫,linux中一切皆文件。
磁碟分區
生磁碟可以被分區,分區中可以安裝文件系統,常見的文件系統有fat32、ext2、ext4等。分區後的磁碟結構佈局如下圖,其中主引導扇區記錄了分區信息,並且包含引導代碼可用於引導操作系統。
文件系統
分區內可以安裝指定文件系統,同一磁碟多個分區文件系統不要求相同。MINIX文件系統佈局如下:
- 引導塊:若作為引導分區,將存放操作系統的引導程式代碼,否則空置。
- 超級塊:用於存放磁碟設備上文件系統結構的信息,說明各部分的大小。
- i節點點陣圖:標記i節點數據元素是否被使用
- 邏輯塊點陣圖:標記磁碟數據塊是否被使用
- i節點區:用於存放inode節點數據,一個文件對應一個inode節點,inode節點存儲文件屬性數據。
- 數據區:以固定大小盤塊(1k)為單位進行動態分配和回收,用於存儲數據,類似記憶體分頁。
超級塊
用於存放磁碟設備上文件系統結構的信息,說明各部分的大小。
圖中列出的數據包含兩部分:出現在盤上和記憶體中的欄位和僅在記憶體中使用的欄位,僅在記憶體中使用的欄位是內核讀取超級塊後所附加的一些用於管理使用的欄位信息。
inode節點
inode節點保存對應文件的屬性信息,其中i_zone數組使用類似多級頁表的方式維護文件數據塊,即記錄文件邏輯塊到物理塊之間的映射關係。
i_zone數組
i_zone數組包含直接盤塊號、一次間接盤塊號和二次間接盤塊號。一次盤塊號可視為單級頁表,一次間接盤塊號可視為二級頁表、二次間接盤塊號可視為三級頁表。
這種處理方式的好處在於,對於小文件,通過直接塊號可快速定位數據塊;對於中等類型的文件,一次間接塊可以維護較多數據塊的同時,具有較快的訪問速度;對於大型文件,二次間接盤塊號可以維護大量磁碟塊,但訪問速度較慢。
記憶體多級頁表與i_zone直接區別:不同進程具有固定大小的虛地址空間,並且對其整個虛地址空間的記憶體,都有可能訪問到,因此使用多級頁表。文件系統記憶體在很多大小不一的文件,綜合考慮對不同大小文件的特點,使用1-3級磁碟塊表可以分別處理小、中、大文件。
目錄結構
- 樹形目錄結構
文件系統目錄結構為樹形,根節點為根目錄,目錄可以指向若幹個子目錄或子文件。
- 文件查找過程
通過文件inode節點,可以定位文件數據塊,那如何通過文件路徑定位到具體文件?
文件系統主要包含文件和目錄兩種文件,目錄是一種特殊的文件,其文件內容存儲其目錄下文件名->inode節點號的映射信息。文件查找開始於根目錄,根目錄號固定為0,不需要查找即可直接打開。
舉例說明文件查找過程,給定存在路徑/name1/name2/name3
查找具體文件過程:
1)通過根節點inode號,打開根目錄,讀取其文件內容,即目錄下文件名->inode節點號映射表,找到name1目錄inode節點號n1
2)通過name1的inode號n1,打開name1目錄,讀取其文件內容,即目錄下文件名->inode節點號映射表,找到name1目錄inode節點號n2
3)通過name2的inode號n2,打開name2目錄,讀取其文件內容,即目錄下文件名->inode節點號映射表,找到name3目錄inode節點號n3
4)通過name3的inode號n3,打開name3文件
- 文件數據塊定位過程
1)打開文件:先通過文件查找找到文件inode節點號,然後打開文件,即讀取inode至記憶體。
2)定位數據塊:通過文件inode節點,訪問其i_zone數組,進一步可以定位具體的數據所在磁碟塊號。
文件鏈接
- 硬鏈接
硬鏈接,在指定目錄文件中,生成一個文件,即建立文件名->inode節點號的映射。不同之處在於,硬鏈接文件的inode號是其它文件的inode號,即多個文件共用一個inode。多個文件共用inode節點時,會引起inode節點引用計數增加。
硬鏈接示意圖如下。
- 軟鏈接(符號鏈接)
軟鏈接,在指定目錄文件中,生成一個文件,建立文件名->文件路徑的映射。軟鏈接文件項不直接指向被指向文件的inode號,而是記錄其文件路徑。符號鏈接不直接共用inode,不會引起inode節點引用計數增加。
打開軟鏈接文件時,先獲取其指向的文件路徑,再通過指向的文件路徑打開文件。
軟鏈接文件示意圖如下,其中藍色線表示軟鏈接。
- 刪除被鏈接文件
硬鏈接:多個文件指向同一個inode節點,引用計數等於文件數量,刪除其中一個文件,只會導致引用計數減小1,引用計數為零時,文件才會被刪除。
軟鏈接:刪除軟鏈接,不會對被指向文件產生任何影響;刪除被指向文件,軟鏈接可能會失效。
高速緩存
高速緩存是內核訪問磁碟文件系統數據的必經之道,高速緩存用於解決CPU速度與磁碟IO速度不匹配的問題。因為CPU速度與磁碟IO速度差距較大,CPU同步讀寫磁碟數據,會導致CPU性能的浪費。
內核維護一個高速緩衝區池,按塊使用和管理,可用於緩存磁碟數據,提高訪問磁碟數據的性能。
buffer.c文件包含實現高速緩衝區的程式。內核代碼通過指定設備號和邏輯塊號來調用塊讀寫函數。這些介面函數有,bread()、breada()、bread_page()。
- bread:塊讀取函數
- breada:塊提前預讀函數
- bread_page:頁塊讀取函數,一個記憶體頁通常為4k大小、磁碟塊通常為1k大小
文件系統相關函數
文件系統底層函數
該部分函數用於處理文件系統的元數據,包括超級塊、點陣圖、inode節點等。該部分函數被內核其它部分代碼調用,不是提供給用戶代碼調用的系統調用介面。
文件系統底層處理函數包含在以下5個文件中:
-
bitmap.c:包含對i節點點陣圖和邏輯塊點陣圖進行釋放和占用處理函數,free_inode()、new_inode()、free_block()、new_block()
-
truncate.c:對數據文件長度截斷為0的函數truncate(),可釋放文件所有數據塊。
-
inode.c:包含分配釋放inode節點函數iget()和iput(),以及根據inode節點,獲取文件邏輯塊號函數bmap()。
-
namei.c:包含函數namei(),獲取指定路徑的inode節點
-
super.c:包的程式專門用於處理系統超級塊,包括函數get_super()、free_super()等。還包括幾個文件系統載入/卸載處理函數和系統調用,如sys_mount()等。
下圖展示了文件系統不同部分對應的底層處理函數:
文件中數據的訪問操作
該部分函數用於處理文件的讀、寫操作。
- 文件數據訪問函數
用戶程式調用read()、write()函數讀寫文件,read()、write()函數根據文件類型與其所在設備,進一步調用設備對應的讀寫函數如read_pipe()、write_pipe()等。
- 打開文件使用的內核數據結構
內核使用文件結構file、文件表file_table[]和記憶體中的i節點表inode_table[]來管理對文件的操作訪問。
- 文件指針數組。進程使用一個文件指針數組管理打開的文件,其中的文件指針(下標號)指向文件表中對應的文件結構file。每個進程有自己的文件指針數組。
- 文件表:表項為file數據,用於在文件句柄於記憶體i節點項之間建立關係,其包含文件類型、訪問屬性、讀寫指針、文件句柄引用計數等信息。因為不同進程可能使用不同的訪問模式打開同一文件,並且需要單獨的讀寫指針等數據。所有進程共用文件表(file_table)。
- 記憶體i節點表:表項存儲i節點信息,存儲所有進程打開文件的i節點信息。所有進程共用記憶體i節點表。
思考:文件描述符指向file結構、file結構指向記憶體inode節點,允許存在多對一的情況。什麼場景會存在多個文件描述符指向同一個file結構;什麼場景存在多個file結構指向同一個記憶體inode節點。
open同一個文件:多個file數據指向同一inode節點
dul同一文件描述符:多個文件描述符指向同一文件表項—file數據。
fork進程:僅複製文件描述符表
內核數據結構
file數據結構
文件和目錄管理系統調用
- open.c:實現文件管理相關的系統調用。主要包括創建、打開、關閉和屬性修改。
- exec.c:實現對二進位可執行文件和shell腳本文件的載入與執行,其中主要的函數為do_execve(),是exec()函數簇的主要實現函數。
- fcntl.c:實現文件系統控制調用fcntl()和文件描述符的複製系統調用dup()、dup2()。dup主要用於多個文件描述符指向同一file結構的場景。
- ioctl.c:實現輸入/輸出控制系統調用ioctl。主要調用tty_ioctl()函數,對終端io進行控制。
- stat.c:實現取文件狀態信息系統調用stat()和fstat。
總結
- MINIX文件系統空閑inode節點項和空閑磁碟塊均通過點陣圖管理,點陣圖記錄對應項是否空閑。
- 硬鏈接和軟鏈接的區別在於,鏈接是直接指向inde節點,還是通過指向其他文件路徑間接指向inode節點。
- linux內核具有io高速緩衝區,用於緩存磁碟數據,提高磁碟數據的訪問效率。
- 打開文件內核數據結構具有三級映射關係:文件描述符->file數據->記憶體inode節點。open同一文件,多個file指向同一記憶體inode;dup文件描述符,多個文件描述符指向同一file。