咱們在進程中要怎樣去描述一個文件呢?咱們用目錄項(dentry)和索引節點(inode)。它們的定義以下:html
struct dentry {
struct inode *d_inode; /* Where the name belongs to - NULL is
struct dentry *d_parent; /* parent directory */
struct list_head d_child; /* child of parent list */
struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
void *d_fsdata; /* fs-specific data */
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
......
};
struct inode {
unsigned long i_ino;
atomic_t i_count;
umode_t i_mode;
unsigned int i_nlink;
uid_t i_uid;
gid_t i_gid;
dev_t i_rdev;
loff_t i_size;
struct timespec i_atime;
unsigned long i_blocks;
unsigned short i_bytes;
unsigned char _sock;
12
struct inode_operations *i_op;
struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct super_block *i_sb;
......
}; node
所謂"文件", 就是按必定的形式存儲在介質上的信息,因此一個文件其實包含了兩方面的信息,一是存儲的數據自己,二是有關該文件的組織和管理的信息。在內存中, 每一個文件都有一個dentry(目錄項)和inode(索引節點)結構,dentry記錄着文件名,上級目錄等信息,正是它造成了咱們所看到的樹狀結構;而有關該文件的組織和管理的信息主要存放inode裏面,它記錄着文件在存儲介質上的位置與分佈。同時dentry->d_inode指向相應的inode結構。dentry與inode是多對一的關係,由於有可能一個文件有好幾個文件名(硬連接, hard link, 能夠參考這個網頁http://www.ugrad.cs.ubc.ca/~cs219/CourseNotes/Unix/commands-links.html)。數組
全部的dentry用d_parent和d_child鏈接起來,就造成了咱們熟悉的樹狀結構。數據結構
inode表明的是物理意義上的文件,經過inode能夠獲得一個數組,這個數組記錄了文件內容的位置,如該文件位於硬盤的第3,8,10塊,那麼這個數組的內容就是3,8,10。其索引節點號inode->i_ino,在同一個文件系統中是惟一的,內核只要根據i_ino,就能夠計算出它對應的inode在介質上的位置。就硬盤來講,根據i_ino就能夠計算出它對應的inode屬於哪一個塊(block),從而找到相應的inode結構。但僅僅用inode仍是沒法描述出全部的文件系統,對於某一種特定的文件系統而言,好比ext3,在內存中用ext3_inode_info描述。他是一個包含inode的"容器"。函數
struct ext3_inode_info {
__le32 i_data[15];
......
struct inode vfs_inode;
};佈局
le32 i data[15]這個數組就是上一段中所提到的那個數組。ui
注意,在遙遠的2.4的古代,不一樣文件系統索引節點的內存映像(ext3_inode_info,reiserfs_inode_info,msdos_inode_info ...)都是用一個union內嵌在inode數據結構中的. 但inode做爲一種很是基本的數據結構而言,這樣搞太大了,不利於快速的分配和回收。可是後來發明了container_of(...)這種方法後,就把union移到了外部,咱們能夠用相似container of(inode, struct ext3_inode_info, vfs_inode),從inode出發,獲得其的"容器"。atom
dentry和inode終究都是在內存中的,它們的原始信息必需要有一個載體。不然斷電以後豈不是玩完了?且聽我慢慢道來。spa
文件能夠分爲磁盤文件,設備文件,和特殊文件三種。設備文件暫且不表。orm
磁盤文件
就磁盤文件而言,dentry和inode的載體在存儲介質(磁盤)上。對於像ext3這樣的磁盤文件來講,存儲介質中的目錄項和索引節點載體以下,
struct ext3_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Creation time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
......
__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
......
}
struct ext3_dir_entry_2 {
__u32 inode; /* Inode number */
__u16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT3_NAME_LEN]; /* File name */
};
le32 i block[EXT2 N BLOCKS];/* Pointers to blocks */
i_block數組指示了文件的內容所存放的地點(在硬盤上的位置)。
ext3_inode是放在索引節點區,而ext3_dir_entry_2是以文件內容的形式存放在數據區。咱們只要知道了ino,因爲ext3_inode大小已知,咱們就能夠計算出ext3_inode在索引節點區的位置( ino * sizeof(ext3_inode) ),而獲得了ext3_inode,咱們根據i_block就能夠知道這個文件的數據存放的地點。將磁盤上ext3_inode的內容讀入到ext3_inode_info中的函數是ext3_read_inode()。以一個有100 block的硬盤爲例,一個文件系統的組織布局大體以下圖。位圖區中的每一位表示每個相應的對象有沒有被使用。
特殊文件
特殊文件在內存中有inode和dentry數據結構,可是不必定在存儲介質上有"索引節點",它斷電以後的確就玩完了,因此不須要什麼載體。當從一個特殊文件讀時,所讀出的數據是由系統內部按必定的規則臨時生成的,或從內存中收集,加工出來的。sysfs裏面就是典型的特殊文件。它存儲的信息都是由系統動態的生成的,它動態的包含了整個機器的硬件資源狀況。從sysfs讀寫就至關於向kobject層次結構提取數據。
還請注意, 咱們談到目錄項和索引節點時,有兩種含義。一種是在存儲介質(硬盤)中的(如ext3_inode),一種是在內存中的,後者是根據在前者生成的。內存中的表示就是dentry和inode,它是VFS中的一層,無論什麼樣的文件系統,最後在內存中描述它的都是dentry和inode結構。咱們使用不一樣的文件系統,就是將它們各自的文件信息都抽象到dentry和inode中去。這樣對於高層來講,咱們就能夠不關心底層的實現,咱們使用的都是一系列標準的函數調用。這就是VFS的精髓,實際上就是面向對象。
咱們在進程中打開一個文件F,實際上就是要在內存中創建F的dentry,和inode結構,並讓它們與進程結構聯繫來,把VFS中定義的接口給接起來。咱們來看一看這個經典的圖。這張圖之於文件系統,就像天天愛你多一些之於張學友,番茄炒蛋之於復旦南區食堂,刻骨銘心。