理解inode
inode 是一個重要概念,是理解 Unix/Linux 文件系統和硬盤儲存的基礎。
我覺得,理解 inode,不僅有助于提高系統操作水平,還有助于體會 Unix 設計哲學,即如何把底層的復雜性抽象成一個簡單概念,從而大大簡化用戶接口。
下面就是我的 inode 學習筆記,盡量保持簡單。
===================================
理解 inode
作者:阮一峰
一、inode 是什么?
理解 inode,要從文件儲存說起。
文件儲存在硬盤上,硬盤的最小存儲單位叫做"扇區"(Sector)。每個扇區儲存 512 字節(相當于0.5KB)。
操作系統讀取硬盤的時候,不會一個個扇區地讀取,這樣效率太低,而是一次性連續讀取多個扇區,即一次性讀取一個"塊"(block)。這種由多 個扇區組成的"塊",是文件存取的最小單位。"塊"的大小,最常見的是 4KB,即連續八個 sector 組成一個 block。
文件數據都儲存在"塊"中,那么很顯然,我們還必須找到一個地方儲存文件的元信息,比如文件的創建者、文件的創建日期、文件的大小等等。這種儲存文件元信息的區域就叫做 inode,中文譯名為"索引節點"。
每一個文件對應一個 inode,硬盤上有多少文件,就有多少個 inode。
二、inode 的內容
inode 包含文件的元信息,具體來說有以下內容:
* 文件的字節數
* 文件擁有者的 User ID
* 文件的 Group ID
* 文件的讀、寫、執行權限
* 文件的時間戳,共有三個:ctime 指 inode 上一次變動的時間,mtime 指文件內容上一次變動的時間,atime 指文件上一次打開的時間。
* 鏈接數,即有多少文件名指向這個 inode
* 文件數據 block 的位置
可以用 stat 命令,查看某個文件的 inode 信息:
stat example.txt
總之,除了文件名以外的所有文件信息,都存在 inode 之中。至于為什么沒有文件名,下文會有詳細解釋。
三、inode 的大小
inode 也會消耗硬盤空間,所以硬盤格式化的時候,操作系統自動將硬盤分成兩個區域。一個是數據區,存放文件數據;另一個是 inode 區(inode table),存放 inode 所包含的信息。
每個 inode 節點的大小,一般是 128 字節或 256 字節。inode 節點的總數,在格式化時就給定,一般是每 1KB 或每 2KB 就設置一個 inode。假定在一塊 1GB 的硬盤中,每個 inode 節點的大小為 128 字節,每 1KB 就設置一個 inode,那么 inode table 的大小就會達到 128MB,占整塊硬盤的 12.8%。
查看每個硬盤分區的 inode 總數和已經使用的數量,可以使用 df 命令。
df -i
查看每個 inode 節點的大小,可以用如下命令:
sudo dumpe2fs -h /dev/hda grep "Inode size"
由于每個文件都必須有一個 inode,因此有可能發生 inode 已經用光,但是硬盤還未存滿的情況。這時,就無法在硬盤上創建新文件。
四、inode 號碼
每個 inode 都有一個號碼,操作系統用 inode 號碼來識別不同的文件。
這里值得重復一遍,Unix/Linux 系統內部不使用文件名,而使用 inode 號碼來識別文件。對于系統來說,文件名只是 inode 號碼便于識別的別稱或者綽號。
表面上,用戶通過文件名,打開文件。實際上,系統內部這個過程分成三步:首先,系統找到這個文件名對應的 inode 號碼;其次,通過 inode 號碼,獲取 inode 信息;最后,根據 inode 信息,找到文件數據所在的 block,讀出數據。
使用 ls -i命令,可以看到文件名對應的 inode 號碼:
ls -i example.txt
五、目錄文件
Unix/Linux 系統中,目錄(directory)也是一種文件。打開目錄,實際上就是打開目錄文件。
目錄文件的結構非常簡單,就是一系列目錄項(dirent)的列表。每個目錄項,由兩部分組成:所包含文件的文件名,以及該文件名對應的 inode 號碼。
ls 命令只列出目錄文件中的所有文件名:
ls /etc
ls -i命令列出整個目錄文件,即文件名和 inode 號碼:
ls -i /etc
如果要查看文件的詳細信息,就必須根據 inode 號碼,訪問 inode 節點,讀取信息。ls -l命令列出文件的詳細信息。
ls -l /etc
六、硬鏈接
一般情況下,文件名和 inode 號碼是"一一對應"關系,每個 inode 號碼對應一個文件名。但是,Unix/Linux 系統允許,多個文件名指向同一個 inode 號碼。
這意味著,可以用不同的文件名訪問同樣的內容;對文件內容進行修改,會影響到所有文件名;但是,刪除一個文件名,不影響另一個文件名的訪問。這種情況就被稱為"硬鏈接"(hard link)。
ln 命令可以創建硬鏈接:
ln 源文件目標文件
運行上面這條命令以后,源文件與目標文件的 inode 號碼相同,都指向同一個 inode。inode 信息中有一項叫做"鏈接數",記錄指向該 inode 的文件名總數,這時就會增加1。
反過來,刪除一個文件名,就會使得 inode 節點中的"鏈接數"減1。當這個值減到0,表明沒有文件名指向這個 inode,系統就會回收這個 inode 號碼,以及其所對應 block 區域。
這里順便說一下目錄文件的"鏈接數"。創建目錄時,默認會生成兩個目錄項:"."和".."。前者的 inode 號碼就是當前目錄的 inode 號碼,等同于當前目錄的"硬鏈接";后者的 inode 號碼就是當前目錄的父目錄的 inode 號碼,等同于父目錄的"硬鏈接"。所以,任何一個目錄的"硬鏈接"總數,總是等于 2 加上它的子目錄總數(含隱藏目錄)。
七、軟鏈接
除了硬鏈接以外,還有一種特殊情況。
文件A和文件B的 inode 號碼雖然不一樣,但是文件A的內容是文件B的路徑。讀取文件A時,系統會自動將訪問者導向文件B。因此,無論打開哪一個文件,最終讀取的都是文件B。這 時,文件A就稱為文件B的"軟鏈接"(soft link)或者"符號鏈接(symbolic link)。
這意味著,文件A依賴于文件B而存在,如果刪除了文件B,打開文件A就會報錯:"No such file or directory"。這是軟鏈接與硬鏈接最大的不同:文件A指向文件B的文件名,而不是文件B的 inode 號碼,文件B的 inode"鏈接數"不會因此發生變化。
ln -s命令可以創建軟鏈接。
ln -s 源文文件或目錄目標文件或目錄
八、inode 的特殊作用
由于 inode 號碼與文件名分離,這種機制導致了一些 Unix/Linux 系統特有的現象。
1. 有時,文件名包含特殊字符,無法正常刪除。這時,直接刪除 inode 節點,就能起到刪除文件的作用。
2. 移動文件或重命名文件,只是改變文件名,不影響 inode 號碼。
3. 打開一個文件以后,系統就以 inode 號碼來識別這個文件,不再考慮文件名。因此,通常來說,系統無法從 inode 號碼得知文件名。
第 3 點使得軟件更新變得簡單,可以在不關閉軟件的情況下進行更新,不需要重啟。因為系統通過 inode 號碼,識別運行中的文件,不通過文件名。更新的時候,新版文件以同樣的文件名,生成一個新的 inode,不會影響到運行中的文件。等到下一次運行這個軟件的時候,文件名就自動指向新版文件,舊版文件的 inode 則被回收。