1. 程式人生 > >核心中inode結構體

核心中inode結構體

在介紹inode結構體之前先做一個連結檔案的實驗:
1.建立一個普通的檔案test.txt,並寫入內容檢視,如下
這裡寫圖片描述
2.建立test.txt的硬連結檔案,並測試如下:
這裡寫圖片描述
3.建立test.txt的軟連線檔案並測試,如下:
這裡寫圖片描述
4.ls命令檢視檔案相關資訊,如下:
這裡寫圖片描述
根據現象可以發現,test.txt檔案的硬連結檔案test_hardlink的inode號和原檔案一樣,而它的軟連結檔案tesrt_softlink的inode號就和原檔案不一樣,根據瞭解我們知道硬連結檔案是原來檔案的副本只是檔名不一樣而已,軟連線檔案是一個新的檔案(實際上硬連結檔案在磁碟上和原檔案使用的是同一個inode節點,軟連線檔案使用不同的inode節點來管理檔案)。
那麼inode究竟是什麼,它在核心中處於什麼的地位?
下面我們來介紹下核心中的inode結構(大部分做了註釋):

struct inode {
    umode_t         i_mode;//檔案的訪問許可權(eg:rwxrwxrwx)
    unsigned short      i_opflags;
    kuid_t          i_uid;//inode擁有者id
    kgid_t          i_gid;//inode擁有者組id
    unsigned int        i_flags;//inode標誌,可以是S_SYNC,S_NOATIME,S_DIRSYNC等

#ifdef CONFIG_FS_POSIX_ACL
    struct posix_acl    *i_acl;
    struct
posix_acl *i_default_acl; #endif const struct inode_operations *i_op;//inode操作 struct super_block *i_sb;//所屬的超級快 /* address_space並不代表某個地址空間,而是用於描述頁快取記憶體中的頁面的一個檔案對應一個address_space,一個address_space與一個偏移量能夠確定一個一個也快取記憶體中的頁面。i_mapping通常指向i_data,不過兩者是有區別的,i_mapping表示應該向誰請求頁面,i_data表示被改inode讀寫的頁面。 */
struct address_space *i_mapping; #ifdef CONFIG_SECURITY void *i_security; #endif /* Stat data, not accessed from path walking */ unsigned long i_ino;//inode號 /* * Filesystems may only read i_nlink directly. They shall use the * following functions for modification: * * (set|clear|inc|drop)_nlink * inode_(inc|dec)_link_count */ union { const unsigned int i_nlink;//硬連結個數 unsigned int __i_nlink; }; dev_t i_rdev;//如果inode代表裝置,i_rdev表示該裝置的裝置號 loff_t i_size;//檔案大小 struct timespec i_atime;//最近一次訪問檔案的時間 struct timespec i_mtime;//最近一次修改檔案的時間 struct timespec i_ctime;//最近一次修改inode的時間 spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ unsigned short i_bytes;//檔案中位於最後一個塊的位元組數 unsigned int i_blkbits;//以bit為單位的塊的大小 blkcnt_t i_blocks;//檔案使用塊的數目 #ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount;//對i_size進行序列計數 #endif /* Misc */ unsigned long i_state;//inode狀態,可以是I_NEW,I_LOCK,I_FREEING等 struct mutex i_mutex;//保護inode的互斥鎖 //inode第一次為髒的時間 以jiffies為單位 unsigned long dirtied_when; /* jiffies of first dirtying */ struct hlist_node i_hash;//散列表 struct list_head i_wb_list; /* backing dev IO list */ struct list_head i_lru; /* inode LRU list */ struct list_head i_sb_list;//超級塊連結串列 union { struct hlist_head i_dentry;//所有引用該inode的目錄項形成的連結串列 struct rcu_head i_rcu; }; u64 i_version;//版本號 inode每次修改後遞增 atomic_t i_count;//引用計數 atomic_t i_dio_count; atomic_t i_writecount;//記錄有多少個程序以可寫的方式開啟此檔案 const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ struct file_lock *i_flock;//檔案鎖鏈表 struct address_space i_data; #ifdef CONFIG_QUOTA struct dquot *i_dquot[MAXQUOTAS];//inode磁碟限額 #endif /* 公用同一個驅動的裝置形成連結串列,比如字元裝置,在open時,會根據i_rdev欄位查詢相應的驅動程式,並使i_cdev欄位指向找到的cdev,然後inode新增到struct cdev中的list欄位形成的連結串列中 */ struct list_head i_devices;, union { struct pipe_inode_info *i_pipe;//如果檔案是一個管道則使用i_pipe struct block_device *i_bdev;//如果檔案是一個塊裝置則使用i_bdev struct cdev *i_cdev;//如果檔案是一個字元裝置這使用i_cdev }; __u32 i_generation; #ifdef CONFIG_FSNOTIFY //目錄通知事件掩碼 __u32 i_fsnotify_mask; /* all events this inode cares about */ struct hlist_head i_fsnotify_marks; #endif #ifdef CONFIG_IMA atomic_t i_readcount; /* struct files open RO */ #endif //儲存檔案系統或者裝置的私有資訊 void *i_private; /* fs or device private pointer */ };

實際上,inode是VFS使用的一個物件,用於存放核心在操作檔案或目錄時所需要的全部資訊。索引節點有兩種,一種是這裡所說的VFS索引節點,存在記憶體中;另一種是具體檔案系統的索引節點,存在於磁碟上,使用時將其讀入記憶體填充VFS的索引節點,之後對VFS索引節點的任何修改都將寫回磁碟更新磁碟的索引節點。
對於inod需要知道:
1)對於Unix風格的檔案系統來說,這些資訊可以從磁碟索引節點直接讀入。如果一個檔案 系統沒有索引節點,那麼不管這些相關資訊在磁碟上市怎麼存放的,檔案系統都必須從中提取這些資訊。沒有索引的檔案系統通常將檔案的描述資訊作為檔案的一部分來存放。這些檔案系統與Unix風格的檔案系統不同,沒有將資料與控制資訊分開存放。而有些現代的檔案系統使用資料庫來儲存檔案的資料。但是不管哪種情況、採用哪種方式,索引節點物件必須在記憶體中建立,以便檔案系統來使用。
2)一個索引節點代表了檔案系統的一個檔案,在檔案建立時建立檔案刪除時銷燬,但是索引節點僅在當檔案被訪問時,才在記憶體中建立,且無論有多少個副本訪問這個檔案,inode只存在一份。
3)inode只是用於描述檔案的元資料資訊,並不是檔案的資料,檔案的資料會根據inode的資訊存放在一個數據塊中(例如:test.txt檔案ls -l看到的資訊就是它的屬性元資訊,“hello”資料存放在另一個數據塊中)。
4)可以簡單理解為ls -l 看到的就是此檔案的inode資訊。
5)inode可以描述像普通檔案、目錄這樣的磁碟檔案,他也可以描述裝置或者管道這樣的檔案,不過這些特殊的檔案一般只存在inode塊不分配資料塊(因為索引節點中有一些特殊檔案相關的項,比如i_pipe項就指向一個代表有名管道的資料結構,i_bdev塊裝置結構體,i_cdev指向字元裝置結構體。這三個指標被放在一個共用體中,因為一個給定的索引節點每次只能表示三者之一(或者均不))。
6)有時,某些檔案系統可能並不能完整地包含索引節點結構體所要求的所有資訊。例如,有的檔案系統可能並不記錄檔案的訪問時間,這時,該檔案系統可以在實現中選擇合適的辦法來解決和這個問題。它可以在i_atime中儲存0,或者讓i_atime等於i_mtime,或者只在記憶體中更新i_atime而不將其寫回磁碟,或者由檔案系統 的實現者來決定。

介紹完了inode,接下來看看inode的操作i_op:

struct inode_operations {
    struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
    void * (*follow_link) (struct dentry *, struct nameidata *);
    int (*permission) (struct inode *, int);
    struct posix_acl * (*get_acl)(struct inode *, int);

    int (*readlink) (struct dentry *, char __user *,int);
    void (*put_link) (struct dentry *, struct nameidata *, void *);

    int (*create) (struct inode *,struct dentry *, umode_t, bool);
    int (*link) (struct dentry *,struct inode *,struct dentry *);
    int (*unlink) (struct inode *,struct dentry *);
    int (*symlink) (struct inode *,struct dentry *,const char *);
    int (*mkdir) (struct inode *,struct dentry *,umode_t);
    int (*rmdir) (struct inode *,struct dentry *);
    int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
    int (*rename) (struct inode *, struct dentry *,
            struct inode *, struct dentry *);
    int (*setattr) (struct dentry *, struct iattr *);
    int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
    int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
    ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
    ssize_t (*listxattr) (struct dentry *, char *, size_t);
    int (*removexattr) (struct dentry *, const char *);
    int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
              u64 len);
    int (*update_time)(struct inode *, struct timespec *, int);
    int (*atomic_open)(struct inode *, struct dentry *,
               struct file *, unsigned open_flag,
               umode_t create_mode, int *opened);
    int (*tmpfile) (struct inode *, struct dentry *, umode_t);
    int (*set_acl)(struct inode *, struct posix_acl *, int);
} ____cacheline_aligned;

下面介紹常用的各種藉口函式:在給定的節點上,可能是由VFS執行這些函式,也可能由具體的檔案系統執行:
struct dentry * (*lookup) (struct inode *dir,struct dentry *dentry , unsigned int )
該函式在在特定目錄中尋找索引節點,改索引節點要對應於dentry中給出的檔名。

int (*create) (struct inode *dir,struct dentry *dentry , umode_t mode, bool )
VFS通過系統呼叫create()和open()來呼叫改函式,從而為dentry物件建立一個新的索引節點。在建立時使用mode指定初始模式

int (link) (struct dentry *old_denrty,struct inode dir,struct dentry *dentry);
該函式被系統呼叫link()呼叫,用來建立硬連結。硬連結名稱由dentry指定,連線物件是dir目錄中old_denrty目錄項所代表的檔案。

int (unlink) (struct inode *dir,struct dentry dentry);
該函式被系統呼叫ulink()呼叫,從目錄dir中刪除由目錄項dentry指定的索引節點物件。

int (*symlink) (struct inode *dir,struct dentry *dentry ,const char *symname);
該函式被系統呼叫symlink()呼叫,建立符號連結。改符號連結的名稱由symname指定,連線物件是dir目錄中的dentry目錄項。

int (*mkdir) (struct inode *dir,struct dentry *dentry ,umode_t mode);
該函式被系統呼叫mkdir()呼叫,建立一個新的目錄。建立時使用mode指定初始模式。

int (*rmdir) (struct inode *dir,struct dentry *dentry );
該函式被系統呼叫rmdir()呼叫,刪除dir目錄中的dentry 目錄項代表的檔案。

int (*mknod) (struct inode *dir,struct dentry *dentry ,umode_t mode,dev_t rdev);
該函式被系統呼叫mknod()呼叫,建立特殊檔案(裝置檔案、命名管道或套接字)。要建立的檔案在dir目錄中,其目錄項為dentry,關聯的裝置為rdev,初始許可權有mode指定。

int (*rename) (struct inode *old_dir, struct dentry *old_dentry ,struct inode *new_dir ,struct dentry *new_dentry );
VFS呼叫該函式來移動檔案。檔案路徑在old_dir目錄中,原始檔由old_dentry目錄項指定,目標路徑在new_dir中,目標檔案由new_dentry指定。