磁盤的訪問方式
- CHS(柱面,磁頭,扇區) 法(磁盤硬件查找):
- 確定柱面(C)
磁頭臂移動到對應的柱面位置。例如,柱面號為 5,則磁頭移動到第 5 個磁道組 - 選擇磁頭(H)
激活對應的磁頭(即選擇具體的盤面)。例如,磁頭號為 0 表示第一個盤面 - 定位扇區(S)
等待磁盤旋轉,直到目標扇區轉到磁頭下方。例如,扇區號為 3 表示讀取當前磁道的第 3 個扇區
操作系統拿到 CHS 地址之后,會將其轉換成 LBA 地址,一般而言,操作系統和硬盤交互時,基本單位為 4KB,也就是 8 個連續的扇區,作為一個塊,后續操作系統只需要提供塊號,然后磁盤自動向后數 8 個就可以訪問到一整個塊了,如:提供的塊號為 2,通過 2*8 得到第一個這個塊的第一個扇區為 16,然后自動向后數 8 個這個就是整個塊了
- LBA 法(操作系統抽象后):
LBA=(C×Hmax+H)×Smax+(S?1)
- Hmax:每個柱面的最大磁頭數
- SmaxSmax:每個磁道的最大扇區數
- 扇區號 S 需減 1(因 LBA 從 0 開始,而 CHS 扇區從 1 開始)
對磁盤的管理就變成了對 LBA 地址的管理,然后通過將硬盤整個硬盤分成很多個分區進行更好的管理
文件系統是系統底層對文件進行管理的
常見文件系統:ext4 exfat fat32
VFS 虛擬文件系統是文件系統的抽象層,隱藏了底層文件系統的實現,用于對外提供接口用于文件管理,在操作系統中通常以一個內核軟件層的形式存在,它位于操作系統內核和底層文件系統之間
磁盤文件系統
在硬盤中會存在多個分區,這些分區內部又被分成了多個組,每個分組內部都會有超級塊、分區描述符、塊位圖、inode 表、inode 位圖、數據塊
在每個分區的內部分組,然后寫入文件系統的管理數據的過程叫做格式化
bootblock
磁盤中用于引導操作系統加載和啟動最小指令集或代碼,同時也可能包含了磁盤分區表和磁盤狀態信息
在 MBR 中,通常只有一個 Boot Block 位于整個磁盤的開始部分,而不是每個分區都有,而在 GPT 中,每個分區都有類似于 boot block 這樣用于引導分區內容的分區引導記錄(PBR),但 PBR 和傳統的 boot block 有一定區別
超級塊
超級塊是存儲對應整個分區的文件系統相關情況,它包含了文件系統的全局信息,記錄的信息主要有:block 和 inode 的總量,未使用的 block 和 inode 的數量,一個 block 和 inode 的大小,最近一次掛載的時間,最近一次寫入數據的時間,最近一次檢驗磁盤的時間等其他文件系統的相關信息。并不是所有塊組都有超級塊,由于超級塊是全局性的,因此可以不用每個分區都設置超級塊,通常為了確保數據的可靠性,會在文件系統的多個位置進行備份。Super Block的信息被破壞,可以說整個文件系統結構就被破壞了,整個分區就掛掉了
數據塊
用于存放文件數據,文件的數據被打散分布在磁盤上,類似一個數組,數組里面可以直接存放數據,也可以存放指向下一個數組的指針,用來間接存儲文件
GDT 塊組描述符
描述的是一整個塊組的具體屬性,如塊組起始位置、大小、包含的塊數等,塊組描述符還描述了塊組內部的布局,包括inode表、數據塊和空閑塊的分布
塊位圖
用于記錄數據塊中哪些被占用,哪些沒有
在申請空間時,文件系統先對位圖進行檢查,若有剩余空間,則將這些空間標記為已分配,一旦位圖更新,文件系統將會實際將這些空間分配,最后文件系統把這些文件的頭指針返回給請求者
inode 位圖
記錄 inode 中哪些被占用,哪些沒有
分配 inode 位圖的過程:
- 掃描inode位圖,查找一個空閑的位(即值為0的位)
- 將找到的空閑位標記為已使用(即將該位設置為1)
- 將新文件的元數據信息寫入對應的inode中
- 文件刪除時先將元數據和 inode 位圖的關聯斷開,然后將 inode 的相應位置標記為空閑
inode 表
用于存放文件的屬性,如所有者,文件大小,修改時間等,inode 中不僅保存著文件的屬性,還有一個 datablock 數組,數組中保存著文件占據了哪些塊,數據塊中也不僅僅只是數據,還有可能是指向實際數據位置的指針,或者指針的指針等,通過建立多級指針來間接映射來管理更大的空間,從而可以建立更大的文件。但是這種方式降低了磁盤的尋址效率
inode 內部并沒有文件名,在內核層面,每個文件都有一個 inode number,通過這個來標識文件,可以通過 ls -i 命令來查看文件的 inode 號
inode 編號是以分區為單位的,而不是以分組為單位的,因為 inode 在分區內部不能重復,但是在另一個分區內可能會有與該分區重復的 inode,因此inode 不能跨分區訪問
有多少文件就有多少個 inode,通常在 Linux 中 inode 大小為 128 字節或 256 字節
inode 表中有許多 inode 塊,一個塊大小通常為 4kb,一個塊中有 4*1024/128=32 個 inode
查找文件 inode 的過程
當用戶或程序請求訪問一個文件時,文件系統會首先查找該文件所在的目錄
目錄本身也是一個文件,它包含了文件名和對應inode編號的映射關系(稱為目錄項)
文件系統會讀取包含目標文件名的目錄項,一旦找到與文件名匹配的目錄項,文件系統就可以從中提取出inode編號
有了inode編號后,文件系統會使用這個編號和inode表的大小來計算inode在inode表中的位置
因此,當目錄的 R 權限被取消后,由于無法讀取到目錄的文件屬性和內容,也就無法獲得對應的 inode,因此也就無法進行訪問,當目錄的 W 權限被取消后,由于無法向目錄寫入文件名和 inode 的映射關系,也就無法創建文件了
通過 inode 查找文件的過程
每一個分組都會有對應的 inode 范圍,查找文件時,首先確定在哪個分區,然后通過 inode 的編號來確定文件是在哪個分組中的,再通過分組內的 inode 表找到具體的 inode,這樣就找到了文件
目錄
目錄也是一個文件,也有自己的文件屬性和文件內容,因此也會有 inode,目錄的文件內容為文件名和 inode 編號的映射關系,目錄本質上是一個存儲文件名與文件元數據(如存儲位置、大小、權限等)映射關系的數據庫,inode 和文件名互為鍵值,彼此間能夠找到對方,如果出現同名文件,就會導致兩條相同的鍵(文件名)對應不同的值(inode 號)
可以通過目錄來知道在哪個分區下的原因
當完成分區并且創建好文件系統后,此時由于并沒有將其掛載到任何目錄,因此操作系統無法訪問,所以需要將其掛載到某一個目錄中,此時訪問該目錄也就是在訪問該分區了
進程的獲得完整的文件路徑是通過 CWD 獲取的,CWD 存放在 task_struct 中
創建一個新文件的過程
- 存儲屬性
內核先找到一個空閑的i節點(這里是263466)。內核把文件信息記錄到其中 - 存儲數據
該文件需要存儲在三個磁盤塊,內核找到了三個空閑塊:300,500,800。將內核緩沖區的第一塊數據
復制到300,下一塊復制到500,以此類推 - 記錄分配情況
文件內容按順序300,500,800存放。內核在inode上的磁盤分布區記錄了上述塊列表 - 添加文件名到目錄
當通過文件名訪問文件時,系統先通過目錄找到對應的 inode 號,再通過 inode 讀取文件數據,如果存在同名文件,就會出現不確定到達訪問哪個文件的 inode 的情況
刪除文件的過程
通過文件名找到對應的 inode,然后找到 inode 在 inode bitmap 中的位置,將這個位置標記為空,然后遍歷 inode table 中的映射關系,在 塊位圖中依次標記為空,這樣就將一個文件刪除了
軟、硬鏈接
軟鏈接
相當于生成一個快捷方式,是一個獨立的文件,因為有自己獨立的 inode,文件里面包含著目標文件所對應的路徑字符串,軟鏈接被刪除后不會影響目標文件,但是刪除目標文件后軟鏈接就會失效
硬鏈接
就是一個文件名和 inode 的映射關系,建立硬鏈接,就是在指定目錄下,添加一個新的文件名和 inode number 的映射關系
硬鏈接沒有自己獨立的 inode,用的 inode 是目標文件的
硬鏈接就是兩個文件共享同一個數據塊,可以認為是同一個文件的不同副本,但這些副本共享同一個空間,只要還存在一個硬鏈接的文件,文件內容就不會丟失
由于硬鏈接的兩個文件共享一個 inode,因此當修改任意一個文件的權限時,其他文件也會跟著被修改
硬連接數:
有多少文件名字符通過 inode 指向目標文件,硬連接數就是多少
硬鏈接的作用:
- 硬鏈接可以構建 Linux 的相對文件結構,從而能夠使用
.
和..
來進行路徑定位 - 通過硬鏈接來備份文件
當前目錄中即使沒有文件,但也會有一個 .
和 ..
,其中 .
代表當前目錄,使用的 inode 和當前目錄相同,因此目錄會有兩個硬鏈接數,當在該目錄中創建一個新的目錄時,新創建的目錄中 ..
會指向上一個目錄的 inode,因此上一個目錄的 inode 還會增加 1,變為 3
任何目錄剛新建的時候引用計數一定是 2,因此一個目錄內的目錄數量引用計數-2
Linux 中不允許給目錄建立硬鏈接,防止形成路徑環繞
一般用硬鏈接來進行文件備份,節省空間
打開的文件和內核、內存有關,沒有被打開的文件和硬盤、文件系統有關,當要修改文件時,首先會找到 inode,然后將 inode 和 task_struct 關聯起來,然后獲取文件的塊號,從指定的分區分組中拿到數據塊,將其加載到文件的內核緩沖區中,這樣通過內核的方式將文件拷貝到用戶緩沖區要修改文件時,將寫入的數據寫入語言的緩沖區,然后通過文件描述符將內容寫入文件的內核緩沖區,最終將修改的內容寫回 inode,如果內容少了,則釋放空間,否則申請空間
文本寫入和二進制寫入:
- 文本寫入:會把數據轉換為文本字符串,并且按照特定的字符編碼(像 UTF8、ASCII)來存儲,語言通過將輸入的數據轉換成字符,存放在語言的緩沖區中,最后打印出來
- 二進制寫入:直接存儲數據的原始字節,不會進行編碼轉換