linux ----Inode的結構圖


 http://www.ruanyifeng.com/blog/2011/12/inode.html

先看看Inode的結構圖
 
 
 
 
 
 
inode table sample

 

再來了解一下文件系統如何存取文件的

1、根據文件名,通過Directory里的對應關系,找到文件對應的Inode number
2、再根據Inode number讀取到文件的Inode table
3、再根據Inode table中的Pointer讀取到相應的Blocks

這里有一個重要的內容,就是Directory,他不是我們通常說的目錄,而是一個列表,記錄了一個文件/目錄名稱對應的Inode number。如下圖
 
 
 
 
 

Directory:
A directory is a mapping between the human name for the file and the computer's inode number.
所以說,這個Directory不是文件,我們可以看作是文件系統中的一個屬性,只是用來關鍵文件名與Inode number。這個一定要理解好,否則后面關於硬鏈接的內容,就不容易理解了。

我在一天一點學習Linux之文件與目錄權限的基本概念中講到
第二欄表示的是有多少文件連接到inode
如果是一個文件,此時這一字段表示這個文件所具有的硬鏈接數, 
如果是一個目錄,則此字段表示該目錄所含子目錄的個數。

現在是不是容易理解了?如果你還不是很明白,那么下面我們就再通過實例讓大家明白。

我們以RHEL6系統為例

在根目錄下創建一個test目錄,我們進入此目錄,進行操作。
[root@yufei test]# pwd
/test
[root@yufei test]# touch testfile
[root@yufei test]# mkdir testdir
創建實驗文件和目錄
[root@yufei test]# ls -li
total 4
977 drwxr-xr-x. 2 root root 4096 Apr  5 16:48 testdir
976 -rw-r--r--. 1 root root    0 Apr  5 16:47 testfile
查看到文件與目錄的Inode和inode count分別為
977 <-----> 2 <-----> testdir
976 <-----> 1 <-----> testfile
現在目錄的鏈接數為2,文件的鏈接數為1。為什么會這樣呢?其實很好理解。對於目錄而言,每個目錄里面肯定會有兩個特殊目錄,那就是.和..這兩個目錄,我們前面的課程中也講到,.表示當前的目錄,而..則是表示上層目錄。我們也知道,在Linux系統中,是從根來開始查找的,要想找到某個目錄,必需要先找到他的上層目錄,所以說,空目錄(嚴格的來說,不能叫空目錄)是有兩個鏈接到相應的Inode number的。作為文件很明顯,他只有一個鏈接到相應的Inode number。也不用多說,

下面我們就來看看這個鏈接數是如何改變的。
繼續上面的操作
[root@yufei test]# ln testfile testfile.hard
[root@yufei test]# ln -s testfile testfile.soft
對testfile建立一個硬鏈接和一個軟鏈接
[root@yufei test]# ls -il
total 4
977 drwxr-xr-x. 2 root root 4096 Apr  5 16:48 testdir
976 -rw-r--r--. 2 root root    0 Apr  5 16:47 testfile
976 -rw-r--r--. 2 root root    0 Apr  5 16:47 testfile.hard
978 lrwxrwxrwx. 1 root root    8 Apr  5 17:03 testfile.soft -> testfile
再查看文件和目錄的屬性,我們就發現:創建一個硬鏈接后,testfile的inode count增加了一個。而且testfile和testfile.hard這兩個的Inode number是一樣的。這個硬鏈接就是重新創建了一個文件名對應到原文件的Inode。實質就是在Directory中增加了一個新的對應關系。通過這個例子,你是不是更清楚了,這個Inode count的含義了。他就是指,一個Inode對應了多少個文件名。

下面我們再來看看硬鏈接的其他特點

[root@yufei ~]# watch -n 1 "df -i;df"
Every 1.0s: df -i;df                            Tue Apr  5 21:52:53 2011

Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/sda1             960992  105415  855577   11% /
tmpfs                  63946       1   63945    1% /dev/shm
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             15118728   2747612  11603116  20% /
tmpfs                   255784         0    255784   0% /dev/shm
用上面的命令可以實時查看系統中所剩的block和inode的變化數量。
建議大家不要用deumpe2fs和tune2fs這兩個命令,如果使用他們來查看的話,將會很郁悶——你會發現,你無論怎么創建文件或對文件寫入內容,Inode和block的值都不會變,除非你每操作一次,重新啟動一次系統,而用了上面的命令,就是第秒鍾監視他們的變化情況。關於df的命令使用,大家可以自行查看幫助進行學習。當然還有du這個命令,他們都和文件系統有關。

我們再來創建一個硬鏈接
[root@yufei test]# ls -li
total 4
977 drwxr-xr-x. 2 root root 4096 Apr  5 16:48 testdir
976 -rw-r--r--. 2 root root    0 Apr  5 16:47 testfile
976 -rw-r--r--. 2 root root    0 Apr  5 16:47 testfile.hard
978 lrwxrwxrwx. 1 root root    8 Apr  5 17:03 testfile.soft -> testfile
[root@yufei test]# ln testfile testfile.hard1
[root@yufei test]# ls -li
total 4
977 drwxr-xr-x. 2 root root 4096 Apr  5 16:48 testdir
976 -rw-r--r--. 3 root root    0 Apr  5 16:47 testfile
976 -rw-r--r--. 3 root root    0 Apr  5 16:47 testfile.hard
976 -rw-r--r--. 3 root root    0 Apr  5 16:47 testfile.hard1
978 lrwxrwxrwx. 1 root root    8 Apr  5 17:03 testfile.soft -> testfile
可以再觀察一下Inode count和Inode number的對應關系。
下面再看看inodes和blocks的變化
[root@yufei ~]# watch -n 1 "df -i;df"
Every 1.0s: df -i;df                            Tue Apr  5 21:53:38 2011

Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/sda1             960992  105415  855577   11% /
tmpfs                  63946       1   63945    1% /dev/shm
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             15118728   2747612  11603116  20% /
tmpfs                   255784         0    255784   0% /dev/shm
我們發現,inodes和blocks是沒有減少的,所以說,硬鏈接是不會占用磁盤的空間的。
如果說刪除硬鏈接的話,就會改變Inode count的數量。硬鏈接還有其他的兩個特性:不能跨Filesystem也不能link目錄。

下面再來看看這個軟鏈接

[root@yufei test]# ls -il testfile.soft testfile
976 -rw-r--r--. 3 root root 0 Apr  5 21:50 testfile
978 lrwxrwxrwx. 1 root root 8 Apr  5 21:52 testfile.soft -> testfile
他的Inode number和原文件不一樣。而且大小也發生了變化。可見,這個軟鏈接是重新建立了一個文件,而文件是指向到原文件,而不是指向原Inode。當然他會占用掉 inode 與 block。當我們刪除了源文件后,鏈接文件不能獨立存在,雖然仍保留文件名,但我們卻不能查看軟鏈接文件的內容了。但軟鏈接是可以跨文件系統,而且是可以鏈接目錄。他就相當於windows系統下的快捷方式一樣。通過這個特性,我們可以通過軟鏈接解決某個分區inode conut不足的問題(軟鏈接到另一個inode count足夠多的分區)。

接下來,我們再來分析一下復制文件、移動文件和刪除文件對inode的影響

[root@yufei ~]# watch -n 1 "df -i;df"
Every 1.0s: df -i;df                            Tue Apr  5 21:57:38 2011

Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/sda1             960992  105415  855577   11% /
tmpfs                  63946       1   63945    1% /dev/shm
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             15118728   2747612  11603116  20% /
tmpfs                   255784         0    255784   0% /dev/shm

[root@yufei test]# ls -li
total 4
977 drwxr-xr-x. 2 root root 4096 Apr  5 16:48 testdir
976 -rw-r--r--. 3 root root    0 Apr  5 18:54 testfile
976 -rw-r--r--. 3 root root    0 Apr  5 18:54 testfile.hard
976 -rw-r--r--. 3 root root    0 Apr  5 18:54 testfile.hard1
978 lrwxrwxrwx. 1 root root    8 Apr  5 17:03 testfile.soft -> testfile
我們先記錄以上的信息

先看復制文件的情況
[root@yufei test]# cp testfile testfile.cp
[root@yufei test]# ls -li
976 -rw-r--r--. 3 root root    0 Apr  5 21:50 testfile
979 -rw-r--r--. 1 root root    0 Apr  5 21:58 testfile.cp
我們只對比這兩個文件,發現Inode number不一樣,我們再來看看inodes和blocks的剩余情況
Every 1.0s: df -i;df                            Tue Apr  5 22:02:49 2011

Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/sda1             960992  105416  855576   11% /
tmpfs                  63946       1   63945    1% /dev/shm
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             15118728   2747620  11603108  20% /
tmpfs                   255784         0    255784   0% /dev/shm
發現inodes減少了一個,而blocks也少了,這就說明,復制文件是創建文件,並占Inode和Block的。
文件創建過程是:先查找一個空的Inode,寫入新的Inode table,創建Directory,對應文件名,向block中寫入文件內容

關於移動文件和刪除文件的實驗,大家可以自己動手來實踐吧。我直接給出相應的說明。
移動文件,他分兩種情況:
在同一個文件系統中移動文件時
創建一個新的文件名和Inode的對應關系(也就是在Directory中寫入信息),然后在Directory中刪除舊的信息,更新CTIME,其他的信息如Inode等等均無任何影響

在不同文件系統移動文件時
先查找一個空的Inode,寫入新的Inode table,創建Directory中的對應關系,向block中寫入文件內容,同時還會更改CTIME。

刪除文件
他實質上就是減少link count,當link count為0時,就表示這個Inode可以使用,並把Block標記為可以寫,但並沒有清除Block里面數據,除非是有新的數據需要用到這個block。

最后我們來做個總結:

1、一個Inode對應一個文件,而一個文件根據其大小,會占用多塊blocks。
2、更為准確的來說,一個文件只對應一個Inode。因為硬鏈接其實不是創建新文件,只是在Directory中寫入了新的對應關系而已。
3、當我們刪除文件的時候,只是把Inode標記為可用,文件在block中的內容是沒有被清除的,只有在有新的文件需要占用block的時候,才會被覆蓋。
 
 
附錄:kernel部分inode數據結構列表

                、*
*索引節點對象由inode結構體表示,定義文件在linux/fs.h中
*/
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;
};
/*
*索引節點的操作inode_operations定義在linux/fs.h中 
*/
struct inode_operations {
        int (*create) (struct inode *, struct dentry *,int);
        /*VFS通過系統調用create()和open()來調用該函數,從而為dentry對象創建一個新的索引節點。在創建時使用mode制定初始模式*/
        struct dentry * (*lookup) (struct inode *, struct dentry *);
        /*該韓式在特定目錄中尋找索引節點,該索引節點要對應於dentry中給出的文件名*/
        int (*link) (struct dentry *, struct inode *, struct dentry *);
        /*該函數被系統調用link()電泳,用來創建硬連接。硬鏈接名稱由dentry參數指定,連接對象是dir目錄中ld_dentry目錄想所代表的文件*/
        int (*unlink) (struct inode *, struct dentry *);
        /*該函數被系統調用unlink()調用,從目錄dir中刪除由目錄項dentry制動的索引節點對象*/
        int (*symlink) (struct inode *, struct dentry *, const char *);
        /*該函數被系統電泳symlik()調用,創建符號連接,該符號連接名稱由symname指定,連接對象是dir目錄中的dentry目錄項*/
        int (*mkdir) (struct inode *, struct dentry *, int);
        /*該函數被mkdir()調用,創建一個新魯姆。創建時使用mode制定的初始模式*/
        int (*rmdir) (struct inode *, struct dentry *);
        /*該函數被系統調用rmdir()調用,刪除dir目錄中的dentry目錄項代表的文件*/
        int (*mknod) (struct inode *, struct dentry *, int, dev_t);
        /*該函數被系統調用mknod()調用,創建特殊文件(設備文件、命名管道或套接字)。要創建的文件放在dir目錄中,其目錄項問dentry,關聯的設備為rdev,初始權限由mode指定*/
        int (*rename) (struct inode *, struct dentry *,
                       struct inode *, struct dentry *);
        /*VFS調用該函數來移動文件。文件源路徑在old_dir目錄中,源文件由old_dentry目錄項所指定,目標路徑在new_dir目錄中,目標文件由new_dentry指定*/
        int (*readlink) (struct dentry *, char *, int);
        /*該函數被系統調用readlink()調用,拷貝數據到特定的緩沖buffer中。拷貝的數據來自dentry指定的符號鏈接,最大拷貝大小可達到buflen字節*/
        int (*follow_link) (struct dentry *, struct nameidata *);
        /*該函數由VFS調用,從一個符號連接查找他指向的索引節點,由dentry指向的連接被解析*/
        int (*put_link) (struct dentry *, struct nameidata *);
        /*在follow_link()調用之后,該函數由vfs調用進行清楚工作*/
        void (*truncate) (struct inode *);
        /*該函數由VFS調用,修改文件的大小,在調用之前,索引節點的i_size項必須被設置成預期的大小*/
        int (*permission) (struct inode *, int);
        /*該函數用來檢查給低昂的inode所代表的文件是否允許特定的訪問模式,如果允許特定的訪問模式,返回0,否則返回負值的錯誤碼。多數文件系統都將此區域設置為null,使用VFS提供的通用方法進行檢查,這種檢查操作僅僅比較索引及誒但對象中的訪問模式位是否和mask一致,比較復雜的系統,比如支持訪問控制鏈(ACL)的文件系統,需要使用特殊的permission()方法*/
        int (*setattr) (struct dentry *, struct iattr *);
        /*該函數被notify_change調用,在修改索引節點之后,通知發生了改變事件*/
        int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
        /*在通知索引節點需要從磁盤中更新時,VFS會調用該函數*/
        int (*setxattr) (struct dentry *, const char *,
                         const void *, size_t, int);
        /*該函數由VFS調用,向dentry指定的文件設置擴展屬性,屬性名為name,值為value*/
        ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
        /*該函數被VFS調用,向value中拷貝給定文件的擴展屬性name對應的數值*/
        ssize_t (*listxattr) (struct dentry *, char *, size_t);
        /*該函數將特定文件所有屬性別表拷貝到一個緩沖列表中*/
        int (*removexattr) (struct dentry *, const char *);
        /*該函數從給定文件中刪除指定的屬性*/
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM