1. 程式人生 > 其它 >檔案系統使用的資料結構

檔案系統使用的資料結構

linux虛擬檔案系統四大物件:

1)超級塊(superblock)

2)索引節點(inode)

3)目錄項(dentry)

4)檔案物件(file)

super_block

/*超級塊代表了整個檔案系統,超級塊是檔案系統的控制塊,有整個檔案系統資訊,一個檔案系統所有的inode都要連線到超級塊上,
可以說,一個超級塊就代表了一個檔案系統
*/
struct super_block {
    struct list_head    s_list;        /* Keep this first 一個雙向迴圈連結串列,把所有的super_block連線起來,一個super_block代表一個在linux上的檔案系統,
    這個list上邊的就是所有的在linux上記錄的檔案系統。
*/ dev_t s_dev; /* search index; _not_ kdev_t 包含該具體檔案系統的塊裝置識別符號。例如,對於 /dev/hda1,其裝置識別符號為 0x301*/ unsigned char s_blocksize_bits;//上面的size大小佔用位數,例如512位元組就是9 bits unsigned long s_blocksize;//檔案系統中資料塊大小,以位元組單位 loff_t s_maxbytes; /* Max file size允許的最大的檔案大小(位元組數)
*/ struct file_system_type *s_type;//檔案系統型別 ext2還是fat32 ? “檔案系統”和“檔案系統型別”不一樣!一個檔案系統型別下可以包括很多檔案系統即很多的super_block const struct super_operations *s_op;//指向某個特定的具體檔案系統的用於超級塊操作的函式集合 const struct dquot_operations *dq_op;//指向某個特定的具體檔案系統用於限額操作的函式集合 const struct quotactl_ops *s_qcop;//用於配置磁碟限額的的方法,處理來自使用者空間的請求
const struct export_operations *s_export_op; unsigned long s_flags; unsigned long s_iflags; /* internal SB_I_* flags */ unsigned long s_magic;//區別於其他檔案系統的標識 struct dentry *s_root;//指向該具體檔案系統安裝目錄的目錄項 struct rw_semaphore s_umount;//對超級塊讀寫時進行同步 int s_count;//對超級塊的使用計數 atomic_t s_active;//引用計數 #ifdef CONFIG_SECURITY void *s_security; #endif const struct xattr_handler **s_xattr; struct hlist_bl_head s_anon; /* anonymous dentries for (nfs) exporting */ struct list_head s_mounts; /* list of mounts; _not_ for fs use */ struct block_device *s_bdev;//指向檔案系統被安裝的塊裝置 struct backing_dev_info *s_bdi; struct mtd_info *s_mtd; struct hlist_node s_instances; unsigned int s_quota_types; /* Bitmask of supported quota types */ struct quota_info s_dquot; /* Diskquota specific options磁碟限額相關選項 */ struct sb_writers s_writers; char s_id[32]; /* Informational name */ u8 s_uuid[16]; /* UUID */ void *s_fs_info; /* Filesystem private info */ unsigned int s_max_links; fmode_t s_mode; /* Granularity of c/m/atime in ns. Cannot be worse than a second */ u32 s_time_gran; /* * The next field is for VFS *only*. No filesystems have any business * even looking at it. You had been warned. */ struct mutex s_vfs_rename_mutex; /* Kludge */ /* * Filesystem subtype. If non-empty the filesystem type field * in /proc/mounts will be "type.subtype" */ char *s_subtype; /* * Saved mount options for lazy filesystems using * generic_show_options() */ char __rcu *s_options; const struct dentry_operations *s_d_op; /* default d_op for dentries */ /* * Saved pool identifier for cleancache (-1 means none) */ int cleancache_poolid; struct shrinker s_shrink; /* per-sb shrinker handle */ /* Number of inodes with nlink == 0 but still referenced */ atomic_long_t s_remove_count; /* Being remounted read-only */ int s_readonly_remount; /* AIO completions deferred from interrupt context */ struct workqueue_struct *s_dio_done_wq; struct hlist_head s_pins; /* * Context in which to interpret filesystem uids, gids, * quotas, device nodes, extended attributes and security * labels. */ struct user_namespace *s_user_ns; /* * Keep the lru lists last in the structure so they always sit on their * own individual cachelines. */ struct list_lru s_dentry_lru ____cacheline_aligned_in_smp; struct list_lru s_inode_lru ____cacheline_aligned_in_smp; struct rcu_head rcu; struct work_struct destroy_work; struct mutex s_sync_lock; /* sync serialisation lock */ /* * Indicates how deep in a filesystem stack this SB is */ int s_stack_depth; /* s_inode_list_lock protects s_inodes */ spinlock_t s_inode_list_lock ____cacheline_aligned_in_smp; struct list_head s_inodes; /* all inodes */ };

Inode:

/*
 * Keep mostly read-only and often accessed (especially for
 * the RCU path lookup and 'stat' data) fields at the beginning
 * of the 'struct inode'
     inode有兩種,一種是VFS的inode,一種是具體檔案系統的inode。前者在記憶體中,後者在磁碟中。所以每次其實是將磁碟中的inode調進填充記憶體中的inode,
 這樣才是算使用了磁碟檔案inode。
    每個inode節點的大小,一般是128位元組或256位元組。inode節點的總數,在格式化時就給定(現代OS可以動態變化),一般每2KB就設定一個inode。
 一般檔案系統中很少有檔案小於2KB的,所以預定按照2KB分,一般inode是用不完的。所以inode在檔案系統安裝的時候會有一個預設數量,
 後期會根據實際的需要發生變化
    inode號是唯一的,表示不同的檔案。其實在Linux內部的時候,訪問檔案都是通過inode號來進行的,所謂檔名僅僅是給使用者容易使用的。
 當我們開啟一個檔案的時候,首先,系統找到這個檔名對應的inode號;然後,通過inode號,得到inode資訊,最後,由inode找到檔案資料所在的block,
 現在可以處理檔案資料了。

    inode和檔案的關係:當建立一個檔案的時候,就給檔案分配了一個inode。一個inode只對應一個實際檔案,一個檔案也會只有一個inode。
 inodes最大數量就是檔案的最大數量。
 */
struct inode {
    umode_t            i_mode;//檔案的型別和訪問許可權
    unsigned short        i_opflags;
    kuid_t            i_uid;//檔案擁有者標號
    kgid_t            i_gid;//檔案所在組標號
    unsigned int        i_flags;

#ifdef CONFIG_FS_POSIX_ACL
    struct posix_acl    *i_acl;
    struct posix_acl    *i_default_acl;
#endif

    const struct inode_operations    *i_op;//索引節點操作函式集
    struct super_block    *i_sb;//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;//實際的裝置標識
    loff_t            i_size;//inode所代表的的檔案的大小,以位元組為單位
    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;//塊大小,位元組單位
    blkcnt_t        i_blocks;//檔案所佔塊數

#ifdef __NEED_I_SIZE_ORDERED
    seqcount_t        i_size_seqcount;
#endif

    /* Misc */
    unsigned long        i_state;
    struct mutex        i_mutex;

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

    struct hlist_node    i_hash;//指向hash連結串列指標,用於inode的hash表
    struct list_head    i_io_list;    /* backing dev IO list */
#ifdef CONFIG_CGROUP_WRITEBACK
    struct bdi_writeback    *i_wb;        /* the associated cgroup wb */

    /* foreign inode detection, see wbc_detach_inode() */
    int            i_wb_frn_winner;
    u16            i_wb_frn_avg_time;
    u16            i_wb_frn_history;
#endif
    struct list_head    i_lru;        /* inode LRU list */
    struct list_head    i_sb_list;
    union {
        struct hlist_head    i_dentry;//指向目錄項鍊表指標,注意一個inodes可以對應多個dentry,因為一個實際的檔案可能被連結到其他的檔案,
        //那麼就會有另一個dentry,這個連結串列就是將所有的與本inode有關的dentry都連在一起
        struct rcu_head        i_rcu;
    };
    u64            i_version;//版本號
    atomic_t        i_count;//引用計數
    atomic_t        i_dio_count;
    atomic_t        i_writecount;//記錄多少程序以刻寫模式開啟此檔案
#ifdef CONFIG_IMA
    atomic_t        i_readcount; /* struct files open RO */
#endif
    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;//連結
    };

    __u32            i_generation;

#ifdef CONFIG_FSNOTIFY
    __u32            i_fsnotify_mask; /* all events this inode cares about */
    struct hlist_head    i_fsnotify_marks;
#endif

    void            *i_private; /* fs or device private pointer */
};

dentry:

/*
    dentry則表示了不同層級之間的關係,也是連結所使用的結構體。dentry通過d_parent來和上級目錄構成連結關係,
通過d_op來儲存對應的實際檔案系統的檔案操作,如建立、刪除、開啟、讀寫等。d_sb指向實際檔案系統的超級塊,
該結構在上文已詳細介紹。d_inode指向對應的inode,d_name表示該檔案的檔名。
    一個有效的dentry結構必定有一個inode結構,這是因為一個目錄項要麼代表著一個檔案,要麼代表著一個目錄,而目錄實際上也是檔案。
所以,只要dentry結構是有效的,則其指標d_inode必定指向一個inode結構。但是inode卻可以對應多個
*/
struct dentry {
    /* RCU lookup touched fields */
    unsigned int d_flags;        /* protected by d_lock目錄項快取標識,可取 DCACHE_UNUSED    DCACHE_REFERENCED 等 */
    seqcount_t d_seq;        /* per dentry seqlock */
    struct hlist_bl_node d_hash;    /* lookup hash list 核心使用dentry_hashtable對dentry進行管理,dentry_hashtable是由list_head組成的連結串列,
    一個dentry建立之後,就通過d_hash連結進入對應的hash值的連結串列中。*/
    struct dentry *d_parent;    /*父目錄的目錄項 parent directory */
    struct qstr d_name;//目錄項名稱
    struct inode *d_inode;        /* 與該目錄項關聯的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 重新變為有效的時間!注意只要操作成功這個dentry就是有效的,否則無效*/
    void *d_fsdata;            /* fs-specific data 檔案系統私有資料 */

    struct list_head d_lru;        /*最近未使用的目錄項的連結串列   LRU list */
    struct list_head d_child;    /* child of parent list 目錄項通過這個加入到父目錄的d_subdirs中*/
    struct list_head d_subdirs;    /* our children本目錄的所有孩子目錄連結串列頭 */
    /*
     * d_alias and d_rcu can share memory
     一個有效的dentry必然與一個inode關聯,但是一個inode可以對應多個dentry,因為一個檔案可以被連結到其他檔案,
     所以,這個dentry就是通過這個欄位連結到屬於自己的inode結構中的i_dentry連結串列中的
     */
    union {
        struct hlist_node d_alias;    /* inode alias list這個dentry就是通過這個欄位連結到屬於自己的inode結構中的i_dentry連結串列中的 */
         struct rcu_head d_rcu;
    } d_u;
};

files

struct path {
    struct vfsmount *mnt;
    struct dentry *dentry;
};
struct file {
    union {
        struct llist_node    fu_llist;
        struct rcu_head     fu_rcuhead;
    } f_u;//用於通用檔案物件連結串列的指標
    struct path        f_path;//指出該檔案的已安裝的檔案系統vfsmount以及檔案相關的目錄項物件dentry
    struct inode        *f_inode;    /* cached value */
    const struct file_operations    *f_op;///*指向檔案操作表的指標    --函式指標*/

    /*
     * Protects f_ep_links, f_flags.
     * Must not be taken from IRQ context.
     */
    spinlock_t        f_lock;
    atomic_long_t        f_count;//表示開啟檔案的引用計數
    unsigned int         f_flags;//表示開啟檔案的許可權
    fmode_t            f_mode;//設定對檔案的訪問模式,例如:只讀,只寫
    struct mutex        f_pos_lock;
    loff_t            f_pos;//表示當前讀寫檔案的位置 
    struct fown_struct    f_owner;//該結構的作用是通過訊號進行I/O時間通知的資料  非同步操作;記錄一個程序ID,當某些事發送的時候傳送給該ID程序的訊號
    const struct cred    *f_cred;
    struct file_ra_state    f_ra;//檔案預讀狀態,檔案預讀演算法使用的主要資料結構,當開啟一個檔案時,f_ra中出了perv_page(預設為-1)和ra_apges(對該檔案允許的最大預讀量)這兩個欄位外,其他的所有西端都置為0

    u64            f_version;//記錄檔案的版本號,每次使用後都自動遞增
#ifdef CONFIG_SECURITY
    void            *f_security;
#endif
    /* needed for tty driver, and maybe others */
    void            *private_data;

#ifdef CONFIG_EPOLL
    /* Used by fs/eventpoll.c to link all the hooks to this file */
    struct list_head    f_ep_links;
    struct list_head    f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
    struct address_space    *f_mapping;
} __attribute__((aligned(4)));    /* lest something weird decides that 2 is OK */

files_struct:

struct fdtable {
    unsigned int max_fds;
    struct file __rcu **fd;      /* current fd array */
    unsigned long *close_on_exec;
    unsigned long *open_fds;
    unsigned long *full_fds_bits;
    struct rcu_head rcu;
};

/*
 * Open file table structure
 */
struct files_struct {
  /*
   * read mostly part
   */
    atomic_t count;/* 共享該表的程序數 */
    bool resize_in_progress;
    wait_queue_head_t resize_wait;
/*包括一個struct fdtable變數例項和一個struct fdtable型別指標;
    而struct fdtable中的成員變數close_on_exec,open_fds,fd又分別指向struct files_struct中
    的成員close_on_exec_init,open_fds_init和fd_array*/
    struct fdtable __rcu *fdt;
    struct fdtable fdtab;
  /*
   * written part on a separate cache line in SMP
   */
    spinlock_t file_lock ____cacheline_aligned_in_smp; /* 保護以下的所有域,以免在tsk->alloc_lock中的巢狀*/
    int next_fd;/*已分配的檔案描述符加1*/
    unsigned long close_on_exec_init[1];/*指向執行exec( )時需要關閉的檔案描述符*/
    unsigned long open_fds_init[1];/*指向開啟檔案描述符的指標*/
    unsigned long full_fds_bits_init[1];/*檔案描述符的初值集合*/
    struct file __rcu * fd_array[NR_OPEN_DEFAULT];;/* 檔案物件指標的初始化陣列  預設使用 不夠時動態分配*/
    /*通常,fd欄位指向files_struct結構的fd_array欄位,該欄位包括32個檔案物件指標。
    如果程序開啟的檔案數目多於32,核心就分配一個新的、更大的檔案指標陣列,
    並將其地址存放在fd欄位中,核心同時也更新max_fds欄位的值。*/
};

  linux系統中,一個程序開啟的檔案數是有初步限制的,即其檔案描述符數初始時有最大化定量,即一個程序一般只能開啟NR_OPEN_DEFAULT個檔案,該值在32位機上為32個,在64位機上為64個。上面的files_struct這種初始化正是體現了程序初步所能開啟檔案的核心結構描述。這裡需要說明的是,這不僅僅限於類似上面的靜態初始化,當init程序fork一個子程序時,也是如此(此時是files_struct是動態分配的)。

do_fork------>copy_process
        |------>dup_task_struct------>alloc_task_struct
        |------>copy_files------>dup_fd

  即先呼叫alloc_task_struct分配一個task_struct結構例項,然後使用alloc_files來分配並初始化files_struct變數例項。
上面的 files_struct初始化和上面例子中的靜態初始化並無本質差別:
語句fdt = &newf->fdtab取出newf的struct fdtable例項變數fdtab的指標,然後通過rcu_assign_pointer函式將其賦值給newf->fdt,那麼newf->fdt還是指向其自身中的struct fdtable例項變數,fdt的成員close_on_exec、open_fds和fd也是如此。

  當進行struct files_struct擴充時,會分配一個新的struct fdtable,為了敘述方便,下面該變數用指標用nfdt來表示。另外還分配了滿足擴充要求的fd陣列(即struct file陣列),以及與fd相對的bitmap描述close_on_exec,open_fds的儲存空間。
然後將新分配的close_on_exec,open_fds,fd空間指標賦值給nfdt->close_on_exec,nfdt->open_fds和nfdt->fd。注意,這裡的close_on_exec,open_fds和上面初始化時close_on_exec_init,open_fds_init的差別:
close_on_exec,open_fds的最大值按bit來說為__FDSET_LONGS,實際值為1024位,即檔案描述符的最大數為1024個。但它們也是按需分配,並和file陣列的大小一致,分配的實際值會同時賦值給nfdt->max_fds。
分配並初始化新的struct fdtable變數後,原先指向fdtab的struct files_struct指標成員fdt,會調整為指向新分配的struct fdtable變數。這時,struct files_struct例項變數中就包含兩個struct fdtable儲存區:一個是其自身的,一個新分配的,用fdt指向。
執行完上面的操作後,其關係如下圖:

  上圖中同顏色的儲存區,代表的是兩者內容是一致的。即執行完上述的操作後,還要將舊的結構儲存區的內容拷貝到新的儲存區,這包括files_struct自身所包含的close_on_exec,open_fds,fd到新分配的close_on_exec,open_fds,fd的拷貝。
執行完上述拷貝之後,就要釋放舊的struct fdtable,

http代理伺服器(3-4-7層代理)-網路事件庫公共元件、核心kernel驅動 攝像頭驅動 tcpip網路協議棧、netfilter、bridge 好像看過!!!! 但行好事 莫問前程 --身高體重180的胖子