理解linux文件系統---VFS主要數據結構及之間的關系


1 VFS文件系統
 
計算機體系由三個部分組成:計算,存儲,網絡,體現了物體流轉的三個方面。
 
生產酒也是這樣的一個過程,首先是收割小麥,將小麥發酵蒸餾形成了酒(處理),然后裝在瓶子里,運送到倉庫。(傳輸),最后將所有的酒存在倉庫里。(存儲)
 
物理設備比如磁盤可以看作是土地,有了土地之后並不能使用,它還無法存儲酒。需要在土地上建立倉庫,並給每一個倉庫通電,編號。這個過程可以理解為建立
文件系統的過程。文件系統建立以后就可以往里面存酒了。什么樣的酒存在哪個倉庫需要有管理人員記錄在本子上。當然倉庫在存儲的時候不一定存的都是酒,也
可能存一些箱子,或者是小麥。
 
虛擬文件系統可以理解為建造倉庫的標准。建造倉庫的時候我們會告訴施工隊,我要實現的功能有哪些,比如我希望倉庫可以存儲5噸的貨物,倉庫要有一個自動門,汽車來到驗證車牌就可以放行,倉庫內部的溫度要保存在5度左右。只要滿足這幾個要求和標准即可。至於施工隊用什么樣的材料建造房屋。用的是鐵門還是合金門,都不是使用倉庫的人要考慮的。
 
而在VFS則定義了虛擬文件系統,這個東西類似於建造倉庫的標准。有了標准之后,所有的文件系統都需要按照這種標准來構建文件系統。
 

 

從上圖可以看到,虛擬機文件系統介於具體的文件系統和C語言標准庫之間,有了VFS之后,所有按照VFS接口開發的文件系統都可以接入linux,標准的接口提供了標准

的操作,接口的設計理念一致貫穿於整個編程科學的發展。面向對象的設計理念又深化了這個理念。

 

 2 VFS關鍵數據結構及關系 

 

上面是虛擬文件系統的一個概覽,虛擬文件系統定義了通用接口,所有具體的文件系統都必須實現這樣的結構。task_struct是進程描述符,里面記錄了進程的相關信息。一個進程可能操作某個文件,因此,task_struck成員內部有一個files,filtes對應files_struct里面記錄了所有打開的file,file於file之間通過雙向鏈表組織起來。
file內部包含了d_dentry,也就是目錄項,通過目錄項可以找到對應的inode,inode記錄了文件的權限和屬性。進程在操作文件的時候需要用到權限和屬性,比如判斷某個進程對某個文件是不是有寫權限。inode里面有一個成員i_mapping,對應address_space。其中的 i_mapping域指向一個address_space結構。這樣,一個文件就對應一個address_space結構, 一個 address_space與一個偏移量能夠確定一個page cache 或swap cache中的一個頁面。至於什么是page cache和swap cache可以
查閱相關知識。以上就是VFS組件相互之間的關系,下面看看每一個具體的組件。
 
super_block
 
是文件系統的心臟,它存儲了文件系統的全局信息,如硬盤已用空間,數據塊可用空間。
文件系統所有的inode信息都鏈接到超級塊上, 如下所示是超級塊的數據結構,下面節選某些關鍵信息。
struct super_block {
   struct list_head   s_list;       /* Keep this first */
   dev_t        s_dev;    /* search index; _not_ kdev_t */
   unsigned char     s_blocksize_bits;
   unsigned long     s_blocksize;
   loff_t       s_maxbytes;    /* Max file size */
   struct file_system_type    *s_type;
   ………..
   unsigned int      s_quota_types; /* Bitmask of supported quota types */
   struct quota_info  s_dquot;   /* Diskquota specific options */

   struct sb_writers  s_writers;
   void         *s_fs_info;    /* Filesystem private info */

   /* Granularity of c/m/atime in ns (cannot be worse than a second) */
   u32          s_time_gran;
#ifdef CONFIG_FSNOTIFY
   __u32        s_fsnotify_mask;
   struct fsnotify_mark_connector __rcu   *s_fsnotify_marks;
#endif

   char         s_id[32];  /* Informational name */
   uuid_t       s_uuid;       /* UUID */

   unsigned int      s_max_links;
   fmode_t          s_mode;
   struct mutex s_vfs_rename_mutex;   /* Kludge */
   char *s_subtype;

   const struct dentry_operations *s_d_op; /* default d_op for dentries */
   struct user_namespace *s_user_ns;
   struct list_head   s_inodes;  /* all inodes */

   spinlock_t    s_inode_wblist_lock;
   struct list_head   s_inodes_wb;   /* writeback inodes */
}
  • s_blocksize 代表文件系統的大小。
  • s_inodes     代表了所有的inode。
  • s_type   代表文件系統的類型。
Inode

代表一個具體的文件, 包含文件的大小,創建時間,文件的塊大小等數據,以及對文件的讀寫函數,文件的讀寫緩存信息等。看一下inode的數據結構,這里只保留一些關鍵的數據信息,其他一些都去掉了。
struct inode {
    umode_t i_mode;
    unsigned short        i_opflags;
    kuid_t            i_uid;
    kgid_t            i_gid;
    unsigned int        i_flags;
    const struct inode_operations    *i_op; struct super_block    *i_sb; struct address_space    *i_mapping;
    unsigned long        i_ino;
   {
        const unsigned int i_nlink;
        unsigned int __i_nlink;
    };

    /* Misc */
    unsigned long        i_state;
    struct rw_semaphore    i_rwsem;

    unsigned long        dirtied_when;    /* jiffies of first dirtying */
    unsigned long        dirtied_time_when;

    struct hlist_node    i_hash;
    struct list_head    i_io_list;    /* backing dev IO list */
    struct list_head    i_lru;        /* inode LRU list */
    struct list_head    i_sb_list;
    struct list_head    i_wb_list;    /* backing dev writeback list */
    const struct file_operations    *i_fop;    /* former ->i_op->default_file_ops */
    struct file_lock_context    *i_flctx;
    struct address_space    i_data;
    struct list_head    i_devices;
    union {
        struct pipe_inode_info    *i_pipe;
        struct block_device    *i_bdev;
        struct cdev        *i_cdev;
        char            *i_link;
        unsigned        i_dir_seq;
    };

    __u32            i_generation;

    void            *i_private; /* fs or device private pointer */
。。。。。。。
}
鏈表其實是linux中組織數據非常常用的數據結構,這個結構里面有三個鏈表頭。
  • i_mapping是非常重要的一個結構,描述了文件地址。
  • block_device描述對應的塊設備(塊設備可以被看作一個文件系統來處理)。
  • inode_operations,該結構體定義了對文件的操作(如下代碼所示),可以看到有獲取屬性,設置屬性,重新命名等操作
  • i_mode,主要作用是用來區分文件類型,比如塊設備,字符設備,目錄, socket等。
  • super_block,指向超級塊,也就是表示文件系統基本信息的數據結構。
struct inode_operations {
   struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
   const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
   int (*permission) (struct inode *, int);
   struct posix_acl * (*get_acl)(struct inode *, int);

   int (*readlink) (struct dentry *, char __user *,int);

   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 *, unsigned int);
   int (*setattr) (struct dentry *, struct iattr *);
   int (*getattr) (const struct path *, struct kstat *, u32, unsigned int);
   ssize_t (*listxattr) (struct dentry *, char *, size_t);
   int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
            u64 len);
   int (*update_time)(struct inode *, struct timespec64 *, int);
   int (*atomic_open)(struct inode *, struct dentry *,
            struct file *, unsigned open_flag,
            umode_t create_mode);
   int (*tmpfile) (struct inode *, struct dentry *, umode_t);
   int (*set_acl)(struct inode *, struct posix_acl *, int);
}

dentry 

目錄項對象,代表一個目錄項。目錄項反應了文件系統的樹狀結構,目前主流的操作系統基本都是用樹狀結構來組織文件的。linux也不例外。dentry表示一個目錄項,目錄項下面又有子目錄。
struct dentry {
   /* RCU lookup touched fields */
   unsigned int d_flags;     /* protected by d_lock */
   seqcount_t d_seq;     /* per dentry seqlock */
   struct hlist_bl_node d_hash;   /* lookup hash list */
   struct dentry *d_parent;   /* parent directory */
   struct qstr d_name;
   struct inode *d_inode;    /* Where the name belongs to - NULL is
                * negative */
   unsigned char d_iname[DNAME_INLINE_LEN];   /* small names */

   /* Ref lookup also touches following */
   struct lockref d_lockref;  /* per-dentry lock and refcount */
   const struct dentry_operations *d_op;
   struct super_block *d_sb;  /* The root of the dentry tree */
   unsigned long d_time;     /* used by d_revalidate */
   void *d_fsdata;          /* fs-specific data */

   union {
      struct list_head d_lru;       /* LRU list */
      wait_queue_head_t *d_wait; /* in-lookup ones only */
   };
   struct list_head d_child;  /* child of parent list */
   struct list_head d_subdirs;    /* our children */
   /*
    * d_alias and d_rcu can share memory
    */
   union {
      struct hlist_node d_alias; /* inode alias list */
      struct hlist_bl_node d_in_lookup_hash; /* only for in-lookup ones */
      struct rcu_head d_rcu;
   } d_u;
}
  • d_inode 這個成員志向inode,
  • super_block 指向對應的超級塊。
  • dentry_operations 這個成員指向dentry對應的操作,如下所示
struct dentry_operations {
   int (*d_revalidate)(struct dentry *, unsigned int);
   int (*d_weak_revalidate)(struct dentry *, unsigned int);
   int (*d_hash)(const struct dentry *, struct qstr *);
   int (*d_compare)(const struct dentry *,
         unsigned int, const char *, const struct qstr *);
   int (*d_delete)(const struct dentry *);
   int (*d_init)(struct dentry *);
   void (*d_release)(struct dentry *);
   void (*d_prune)(struct dentry *);
   void (*d_iput)(struct dentry *, struct inode *);
   char *(*d_dname)(struct dentry *, char *, int);
   struct vfsmount *(*d_automount)(struct path *);
   int (*d_manage)(const struct path *, bool);
   struct dentry *(*d_real)(struct dentry *, const struct inode *);
}
File
 
文件對象,代表進程打開的文件,描述的是進程和文件之間的關系。一個文件,在不同的進程中有不同的文件對象,如下圖是文件的數據結構

 從文件操作的角度來看文件系統不同結構體之間的關系。

 

文件系統的主要目的是解決用戶對文件的操作,包括創建,刪除,修改,存放。操作文件需要在內核中創建相對應的進程,有了進程之后,需要知道進程操作的文件是什么。那么反應進程和文件之間關系的就是file。file是實際發生操作時創建出來的對象,存儲在內存里。file內部保存着文件的dentry,也就是目錄項,除此之外還保存着file_operation,也就是對文件的讀寫,打開等操作。通過dentry還可以找到inode,那么就可以對inode執行mkdir等操作。super_block代表了一個文件系統,以及文件了解一個文件系統所需的基本數據。

 

參考資料:

   文件系統詳解

《鳥哥的linux私房菜》

《深入linux內核架構》

《linux內核探秘》

 

 

 

 

 


免責聲明!

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



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