首頁 > 軟體

Linux目錄與inode 深入理解

2020-06-16 17:15:03

1. 關於Linux目錄,檔案,資料塊
對於使用計算機的人而言,經常有一種 錯誤的認知:目錄(或者說,資料夾)裡面存放著檔案。實際上,目錄裡面並不存放檔案,以及檔案資料。
實際上,目錄是一個特殊的檔案,針對這個特殊的檔案也存在一些特殊的規則,比如利用命令cp /dev/null <your directory>並不能夠銷毀這個特殊的檔案,因為目錄的一些特殊的位元位保證了這一安全性,降低了人工操作帶來的風險。在一些老版本的Unix系統裡面,使用者可以利用cat命令開啟目錄,檢視裡面的資訊,在一些衍生於Debian系統的發行版Linux裡面,也可以利用vi工具開啟目錄,檢視一些資訊。
在Linux裡面,一個檔案的資訊被存放於兩個位置:

  1. 資料塊(data block)當中
  2. inode當中

硬碟的最小儲存單位叫做“磁區”(Sector)。每個磁區儲存512位元組(相當於0.5KB)。作業系統讀取磁碟的時候,不會一個個磁區“挨個讀取”,而是一次讀取多個磁區,即一次讀取一個“塊”(block),這種由多個磁區組成的”塊”,是檔案存取的最小單位。”塊”的大小,最常見的是4KB,即連續八個 sector組成一個 block。data block當中存放了檔案的真實內容,而檔案的後設資料資訊,被存放到了inode當中。data block和inode被檔案系統有效地組織到了一起。
當檔案系統被建立之後,inode的數量以及data block的數量也被固定下來。我們不能夠修改inode的數量,也不能夠修改data block的數量。
當我們建立一個檔案的時候,inode編號將作為該檔案的唯一id,即,一個檔案在同一時刻僅擁有一個inode編號。當我們向一個檔案寫入內容的時候,資料被存放到了data block當中。而該檔案的檔名,被存放到了該檔案所在的目錄檔案當中。
對於目錄這種“特殊的檔案”,可以簡單地理解為是一張表,這張表裡面存放了隸屬於該目錄的檔案的檔名,以及所匹配的inode編號。
因此,在linux裡面,檔案被“拆分”到了3個地方,索引存於inode,檔名存於目錄,資料存於data block。

2. 關於硬連結以及複製
基於上述內容對於目錄的描述,可以比較容易解釋linux裡面的另外一個重要的概念: hard link(硬連結)。
對於檔案而言,真正的ID是inode編號,而並非檔名。回憶一下目錄檔案: 一張含有檔名和inode編號的表。在這張表裡面,我們暫定用一個如下結構表示一個檔案: [directory : (filename, inode_number)],這裡以/etc/passwd檔案舉例,假設其inode編號為123456(確實有點兒假……),則可以寫為[/etc/ : (passwd, 123456)],假設我們在終端上面鍵入了如下命令:
[root@CentOS7-front1 ~]# ln /etc/passwd /root/hard_link_passwd則會在/root目錄下面出現一個新的檔名,叫做hard_link_passwd。如果用上述結構表示這個檔案,則為[/root/ : (hard_link_passwd, 123456)],因此,這種目錄或檔名不同,但是inode編號相同的檔案,稱為硬連結。由於硬連結inode編號相同,而且對於同一個inode結構體,便會擁有相同的地址對映以及相同的塊裝置連結串列。因此,對於使用者空間而言,修改/etc/passwd,就相當於修改了/root/hard_link_passwd,反之亦然。
同樣基於上述內容對於目錄的描述,針對i_device相同的mv操作,僅僅是刪除了原目錄裡面對應的[directory : (filename, inode_number)],並且在目標目錄新建了另一個[directory : (filename, inode_number)],由於並沒有對於data block的任何操作,因此速度很快。

3. 初步檢視inode
利用ls -i命令可以檢視到當前目錄下面的所有檔案的inode編號,注意inode編號僅僅是inode結構體裡面的一項,並不代表inode全部,下面擷取/etc/目錄下的前5個檔案:
[root@centos7-front1 etc]# ls -i | head -n 5
  768684 abrt
 34370879 adjtime
 33554592 aliases
 35506331 aliases.db
100705463 alternatives

利用stat命令可以檢視一個檔案更加詳細的inode資訊,包括inode編號,佔用的塊數量,塊大小,硬連結個數,atime, mtime, ctime, ……下面用stat命令檢視/etc目錄(如上文所說,目錄也是一種特殊的檔案)
[root@centos7-front1 /]# stat /etc
  File: ‘/etc’
  Size: 8192            Blocks: 24        IO Block: 4096  directory
Device: 803h/2051d      Inode: 33554561    Links: 85
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)  Gid: (    0/    root)
Access: 2017-03-28 17:13:00.510221799 -0400
Modify: 2017-03-28 12:37:32.150999451 -0400
Change: 2017-03-28 12:37:32.150999451 -0400
 Birth: -

從上述結果中,我們可以看出,針對/etc目錄而言,其大小為8192kb,為該目錄下的檔案所分配的塊數量為24個,型別為directory,裝置名稱為803h/2051d,其Inode編號為33554561,其硬連結個數為85個,許可權為0755,Uid和Gid均為0,還有atime, mtime, ctime這些資訊。
當然,利用stat命令查到的某個檔案的inode資訊並不是全部的inode結構體裡面的資訊。核心使用的inode結構體如下所示:
struct inode {
        struct hlist_node      i_hash;      // 雜湊表 */
        struct list_head        i_list;        // 索引節點連結串列 */
        struct list_head        i_dentry;    // 目錄項連結串列 */
        unsigned long          i_ino;      // 節點號 */
        atomic_t                i_count;      // 參照記數 */
        umode_t                i_mode;        // 存取許可權控制 */
        unsigned int            i_nlink;            // 硬連結數 */
        uid_t                  i_uid;              // 使用者id */
        gid_t                  i_gid;              // 使用者id組 */
        kdev_t                  i_rdev;              // 實裝置識別符號 */
        loff_t                  i_size;              // 以位元組為單位的檔案大小 */
        struct timespec        i_atime;            // 最後存取時間 */
        struct timespec        i_mtime;            // 最後修改(modify)時間 */
        struct timespec        i_ctime;            // 最後改變(change)時間 */
        unsigned int            i_blkbits;          // 以位為單位的塊大小 */
        unsigned long          i_blksize;          // 以位元組為單位的塊大小 */
        unsigned long          i_version;          // 版本號 */
        unsigned long          i_blocks;            // 檔案的塊數 */
        unsigned short          i_bytes;            // 使用的位元組數 */
        spinlock_t              i_lock;              // 自旋鎖 */
        struct rw_semaphore    i_alloc_sem;        // 索引節點號誌 */
        struct inode_operations *i_op;              // 索引節點操作表 */
        struct file_operations  *i_fop;              // 預設的索引節點操作 */
        struct super_block      *i_sb;              // 相關的超級塊 */
        struct file_lock        *i_flock;            // 檔案鎖連結串列 */
        struct address_space    *i_mapping;          // 相關的地址對映 */
        struct address_space    i_data;              // 裝置地址對映 */
        struct dquot            *i_dquot[MAXQUOTAS]; // 節點的磁碟限額 */
        struct list_head        i_devices;          // 塊裝置連結串列 */
        struct pipe_inode_info  *i_pipe;            // 管道資訊 */
        struct block_device    *i_bdev;            // 塊裝置驅動 */
        unsigned long          i_dnotify_mask;      // 目錄通知掩碼 */
        struct dnotify_struct  *i_dnotify;          // 目錄通知 */
        unsigned long          i_state;            // 狀態標誌 */
        unsigned long          dirtied_when;        // 首次修改時間 */
        unsigned int            i_flags;            // 檔案系統標誌 */
        unsigned char          i_sock;              // 可能是個通訊端吧 */
        atomic_t                i_writecount;        // 寫???記數 */
        void                    *i_security;        // 安全模組 */
        __u32                  i_generation;        // 索引節點版本號 */
        union {
                void            *generic_ip;        // 檔案特殊資訊 */
        } u;
};

4. 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命令。
[root@centos7-front1 ~]# df -i
Filesystem      Inodes IUsed    IFree IUse% Mounted on
/dev/sda3      23860224 59694 23800530    1% /
devtmpfs        122809  367  122442    1% /dev
tmpfs            125170    1  125169    1% /dev/shm
tmpfs            125170  433  124737    1% /run
tmpfs            125170    13  125157    1% /sys/fs/cgroup
/dev/sda1        256000  329  255671    1% /boot
tmpfs            125170    1  125169    1% /run/user/0

檢視某個分割區的檔案系統所分配的單個inode節點的大小,在ext檔案系統下,可以使用dumpe2fs命令,例如CentOS6系統上,針對/dev/sda3分割區:
[root@maCentos6 ~]# dumpe2fs -h /dev/sda3 | grep -i "inode size"
dumpe2fs 1.41.12 (17-May-2010)
Inode size:              256

在xfs檔案系統下,可以使用xfs_info命令,例如CentOS7系統上,針對/dev/sda3分割區:
[root@centos7-front1 ~]# xfs_info /dev/sda1
meta-data=/dev/sda1              isize=256    agcount=4, agsize=16000 blks
        =                      sectsz=512  attr=2, projid32bit=1
        =                      crc=0        finobt=0
data    =                      bsize=4096  blocks=64000, imaxpct=25
        =                      sunit=0      swidth=0 blks
naming  =version 2              bsize=4096  ascii-ci=0 ftype=0
log      =internal              bsize=4096  blocks=853, version=2
        =                      sectsz=512  sunit=0 blks, lazy-count=1
realtime =none                  extsz=4096  blocks=0, rtextents=0

本文永久更新連結地址http://www.linuxidc.com/Linux/2017-05/143786.htm


IT145.com E-mail:sddin#qq.com