筆者在前文《Linux EXT2 檔案系統中》中介紹了 EXT2 檔案系統中的基本概念,本文繼續以 EXT2 檔案系統為例介紹檔案系統是如何管理檔案儲存的。
inode
在前文介紹檔案系統時我們提到了 inode 和 data block。在 EXT2 檔案系統中,inode 用來存放檔案的元資訊,data block 用來存放檔案的內容。inode 包含的檔案元資訊有:
- 該檔案的讀寫許可權(rwx)
- 該檔案的擁有者和所屬組(owner/group)
- 該檔案的大小
- 該檔案的 ctime(建立時間)
- 該檔案的 atime(最近一次的讀取時間)
- 該檔案的 mtime(最近修改的時間)
- 該檔案的特殊標識,比如 SetUID 等
- 該檔案真正內容的指向(檔案 data block 的位置)
總之,除了檔名之外的所有檔案資訊都存在 inode 中。我們可以使用 stat 命令來檢視檔案的 inode 資訊:
$ stat test.txt
inode 的大小
inode 本身是會消耗磁碟空間的,我們可以透過下面的方式檢視 inode 的大小:
$ sudo dumpe2fs -h /dev/sdd1 | grep "Inode size"
在筆者的機器上,輸出的結果如下:
dumpe2fs 1.42.13 (17-May-2015) Inode size: 256
也就是說一個 inode 佔用 256 個位元組的磁碟空間。
inode 耗盡問題
因為每個檔案需要佔用一個 inode,所以生產中會碰到 inode 耗盡導致無法建立新檔案的問題。我們可以透過 df 命令 的 -i 選項檢視檔案系統中 inode 的使用情況:
$ df -i
檔案
每個檔案都會佔用一個 inode,inode 內則有檔案資料放置的 block 號碼。當我們在 Linux 下的 ext2 檔案系統中建立一個一般檔案時,ext2 檔案系統會分配一個 inode 與相對於該檔案大小的 data block(一個或多個) 給該檔案。inode 記錄該檔案的許可權與屬性,並記錄分配到的 data block 號碼。例如:假設一個 data block 的大小為 4 KBytes,而要建立一個 100 Kbytes 的檔案,linux 就會分配一個 inode 與 25 個data block 來儲存該檔案!
單個檔案,inode 和 data block 的示意圖(可以簡單的理解為下圖的樣子):
這種資料存取的方法我們稱為索引式檔案系統(indexed allocation)。
雖然從實現的層面上來看,可以直接從 inode 找到其對應的 data block,但是我們卻不能透過 inode 直接訪問檔案,因為這會破壞透過許可權進行的訪問控制。例如,如果沒有遍歷目錄的許可權,那麼無論檔案上的許可權是什麼,都不能訪問該目錄中的任何檔案。如果可以透過inode訪問檔案,就可以繞過目錄許可權。
目錄
注意,inode 本身並不記錄檔名,檔名的記錄是在目錄的 data block 當中。
目錄本質上也是一個檔案,所以當我們在 ext2 檔案系統中建立一個目錄時,檔案系統會分配一個 inode 和至少一塊 data block 給這個目錄。其中,inode 記錄該目錄相關的許可權與屬性,並記錄分配到的 data block 號碼。而 data block 中則記錄著在這個目錄下的檔名(目錄也是檔案)與該檔名的 inode 號碼。也就是說目錄所佔用的 data block 的內容記錄著類似下面的資訊:
目錄項
檔名及其對應的 inode 被稱為目錄項。其實,目錄項是記憶體中的資料結構,所以實際情況是檔名對應的是指向 inode 的指標。我們可以透過下面的示意圖來理解 inode、目錄、檔案以及目錄項之間的關係:
從磁碟讀取一個檔案的過程
由於目錄樹是由根目錄開始讀起,因此透過檔案系統的掛載資訊可以找到掛載點的 inode 號,此時就能夠得到根目錄的 inode 內容,並透過這個 inode 讀取根目錄的 data block 中的檔名稱,再一層一層的往下查詢,直到讀到正確的檔名。下面讓我們透過讀取 /etc/passwd 檔案來理解檔案的讀取過程。
上面的 ls 命令使用 i 選項輸出了 /、 /etc、 /etc/passwd 的 inode 分別為 2、4325377、4329700。
我們透過當前使用者 nick 讀取 /etc/passwd 檔案的內容,其過程如下:
- / 的 inode 號為 2,許可權資訊允許我們讀取 data block 中的內容(有 r 與 x)
- / 的 data block 中記錄的 etc/ 目錄的 inode 號為 4325377
- etc/ 的 inode 中許可權資訊包含 rx,因此使用者 nick 可以讀取 etc/ data block 的內容
- etc/ 的 data block 中記錄的 passwd 檔案的 inode 號為 4329700
- 檔案 passwd 的 inode 中許可權資訊包含 r,因此使用者 nick 可以讀取 passwd data block 的內容
- passwd 的 data block 中的內容被讀取出來
參考:
鳥哥的私房菜
理解inode
Linux inode 詳解
關於 inode
目錄項物件