? ? ? 虛擬文件系統(tǒng)(VFS)是linux內(nèi)核和具體I/O設(shè)備之間的封裝的一層共通訪問(wèn)接口,通過(guò)這層接口,linux內(nèi)核可以以同一的方式訪問(wèn)各種I/O設(shè)備。
虛擬文件系統(tǒng)本身是linux內(nèi)核的一部分,是純軟件的東西,并不需要任何硬件的支持。
1. 虛擬文件系統(tǒng)的作用
虛擬文件系統(tǒng)(VFS)是linux內(nèi)核和存儲(chǔ)設(shè)備之間的抽象層,主要有以下好處。
- 簡(jiǎn)化了應(yīng)用程序的開發(fā):應(yīng)用通過(guò)統(tǒng)一的系統(tǒng)調(diào)用訪問(wèn)各種存儲(chǔ)介質(zhì)
- 簡(jiǎn)化了新文件系統(tǒng)加入內(nèi)核的過(guò)程:新文件系統(tǒng)只要實(shí)現(xiàn)VFS的各個(gè)接口即可,不需要修改內(nèi)核部分
2. 虛擬文件系統(tǒng)的4個(gè)主要對(duì)象
虛擬文件中的4個(gè)主要對(duì)象,具體每個(gè)對(duì)象的含義參見(jiàn)如下的詳細(xì)介紹。
2.1 超級(jí)塊
超級(jí)塊(super_block)主要存儲(chǔ)文件系統(tǒng)相關(guān)的信息,這是個(gè)針對(duì)文件系統(tǒng)級(jí)別的概念。
它一般存儲(chǔ)在磁盤的特定扇區(qū)中,但是對(duì)于那些基于內(nèi)存的文件系統(tǒng)(比如proc,sysfs),超級(jí)塊是在使用時(shí)創(chuàng)建在內(nèi)存中的。
超級(jí)塊的定義在:
/* * 超級(jí)塊結(jié)構(gòu)中定義的字段非常多, * 這里只介紹一些重要的屬性 */struct super_block { struct list_head s_list; /* 指向所有超級(jí)塊的鏈表 */ const struct super_operations *s_op; /* 超級(jí)塊方法 */ struct dentry *s_root; /* 目錄掛載點(diǎn) */ struct mutex s_lock; /* 超級(jí)塊信號(hào)量 */ int s_count; /* 超級(jí)塊引用計(jì)數(shù) */ struct list_head s_inodes; /* inode鏈表 */ struct mtd_info *s_mtd; /* 存儲(chǔ)磁盤信息 */ fmode_t s_mode; /* 安裝權(quán)限 */};/* * 其中的 s_op 中定義了超級(jí)塊的操作方法 * 這里只介紹一些相對(duì)重要的函數(shù) */struct super_operations { struct inode *(*alloc_inode)(struct super_block *sb); /* 創(chuàng)建和初始化一個(gè)索引節(jié)點(diǎn)對(duì)象 */ void (*destroy_inode)(struct inode *); /* 釋放給定的索引節(jié)點(diǎn) */ void (*dirty_inode) (struct inode *); /* VFS在索引節(jié)點(diǎn)被修改時(shí)會(huì)調(diào)用這個(gè)函數(shù) */ int (*write_inode) (struct inode *, int); /* 將索引節(jié)點(diǎn)寫入磁盤,wait表示寫操作是否需要同步 */ void (*drop_inode) (struct inode *); /* 最后一個(gè)指向索引節(jié)點(diǎn)的引用被刪除后,VFS會(huì)調(diào)用這個(gè)函數(shù) */ void (*delete_inode) (struct inode *); /* 從磁盤上刪除指定的索引節(jié)點(diǎn) */ void (*put_super) (struct super_block *); /* 卸載文件系統(tǒng)時(shí)由VFS調(diào)用,用來(lái)釋放超級(jí)塊 */ void (*write_super) (struct super_block *); /* 用給定的超級(jí)塊更新磁盤上的超級(jí)塊 */ int (*sync_fs)(struct super_block *sb, int wait); /* 使文件系統(tǒng)中的數(shù)據(jù)與磁盤上的數(shù)據(jù)同步 */ int (*statfs) (struct dentry *, struct kstatfs *); /* VFS調(diào)用該函數(shù)獲取文件系統(tǒng)狀態(tài) */ int (*remount_fs) (struct super_block *, int *, char *); /* 指定新的安裝選項(xiàng)重新安裝文件系統(tǒng)時(shí),VFS會(huì)調(diào)用該函數(shù) */ void (*clear_inode) (struct inode *); /* VFS調(diào)用該函數(shù)釋放索引節(jié)點(diǎn),并清空包含相關(guān)數(shù)據(jù)的所有頁(yè)面 */ void (*umount_begin) (struct super_block *); /* VFS調(diào)用該函數(shù)中斷安裝操作 */};
2.2 索引節(jié)點(diǎn)
索引節(jié)點(diǎn)是VFS中的核心概念,它包含內(nèi)核在操作文件或目錄時(shí)需要的全部信息。
一個(gè)索引節(jié)點(diǎn)代表文件系統(tǒng)中的一個(gè)文件(這里的文件不僅是指我們平時(shí)所認(rèn)為的普通的文件,還包括目錄,特殊設(shè)備文件等等)。
索引節(jié)點(diǎn)和超級(jí)塊一樣是實(shí)際存儲(chǔ)在磁盤上的,當(dāng)被應(yīng)用程序訪問(wèn)到時(shí)才會(huì)在內(nèi)存中創(chuàng)建。
索引節(jié)點(diǎn)定義在:
/* * 索引節(jié)點(diǎn)結(jié)構(gòu)中定義的字段非常多, * 這里只介紹一些重要的屬性 */struct inode { struct hlist_node i_hash; /* 散列表,用于快速查找inode */ struct list_head i_list; /* 索引節(jié)點(diǎn)鏈表 */ struct list_head i_sb_list; /* 超級(jí)塊鏈表超級(jí)塊 */ struct list_head i_dentry; /* 目錄項(xiàng)鏈表 */ unsigned long i_ino; /* 節(jié)點(diǎn)號(hào) */ atomic_t i_count; /* 引用計(jì)數(shù) */ unsigned int i_nlink; /* 硬鏈接數(shù) */ uid_t i_uid; /* 使用者id */ gid_t i_gid; /* 使用組id */ struct timespec i_atime; /* 最后訪問(wèn)時(shí)間 */ struct timespec i_mtime; /* 最后修改時(shí)間 */ struct timespec i_ctime; /* 最后改變時(shí)間 */ const struct inode_operations *i_op; /* 索引節(jié)點(diǎn)操作函數(shù) */ const struct file_operations *i_fop; /* 缺省的索引節(jié)點(diǎn)操作 */ struct super_block *i_sb; /* 相關(guān)的超級(jí)塊 */ struct address_space *i_mapping; /* 相關(guān)的地址映射 */ struct address_space i_data; /* 設(shè)備地址映射 */ unsigned int i_flags; /* 文件系統(tǒng)標(biāo)志 */ void *i_private; /* fs 私有指針 */};/* * 其中的 i_op 中定義了索引節(jié)點(diǎn)的操作方法 * 這里只介紹一些相對(duì)重要的函數(shù) */struct inode_operations { /* 為dentry對(duì)象創(chuàng)造一個(gè)新的索引節(jié)點(diǎn) */ int (*create) (struct inode *,struct dentry *,int, struct nameidata *); /* 在特定文件夾中尋找索引節(jié)點(diǎn),該索引節(jié)點(diǎn)要對(duì)應(yīng)于dentry中給出的文件名 */ struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); /* 創(chuàng)建硬鏈接 */ int (*link) (struct dentry *,struct inode *,struct dentry *); /* 從一個(gè)符號(hào)鏈接查找它指向的索引節(jié)點(diǎn) */ void * (*follow_link) (struct dentry *, struct nameidata *); /* 在 follow_link調(diào)用之后,該函數(shù)由VFS調(diào)用進(jìn)行清除工作 */ void (*put_link) (struct dentry *, struct nameidata *, void *); /* 該函數(shù)由VFS調(diào)用,用于修改文件的大小 */ void (*truncate) (struct inode *);};
2.3 目錄項(xiàng)
和超級(jí)塊和索引節(jié)點(diǎn)不同,目錄項(xiàng)并不是實(shí)際存在于磁盤上的。
在使用的時(shí)候在內(nèi)存中創(chuàng)建目錄項(xiàng)對(duì)象,其實(shí)通過(guò)索引節(jié)點(diǎn)已經(jīng)可以定位到指定的文件,
但是索引節(jié)點(diǎn)對(duì)象的屬性非常多,在查找,比較文件時(shí),直接用索引節(jié)點(diǎn)效率不高,所以引入了目錄項(xiàng)的概念。
路徑中的每個(gè)部分都是一個(gè)目錄項(xiàng),比如路徑: /mnt/cdrom/foo/bar 其中包含5個(gè)目錄項(xiàng),/ mnt cdrom foo bar
每個(gè)目錄項(xiàng)對(duì)象都有3種狀態(tài):被使用,未使用和負(fù)狀態(tài)
- 被使用:對(duì)應(yīng)一個(gè)有效的索引節(jié)點(diǎn),并且該對(duì)象由一個(gè)或多個(gè)使用者
- 未使用:對(duì)應(yīng)一個(gè)有效的索引節(jié)點(diǎn),但是VFS當(dāng)前并沒(méi)有使用這個(gè)目錄項(xiàng)
- 負(fù)狀態(tài):沒(méi)有對(duì)應(yīng)的有效索引節(jié)點(diǎn)(可能索引節(jié)點(diǎn)被刪除或者路徑不存在了)
目錄項(xiàng)的目的就是提高文件查找,比較的效率,所以訪問(wèn)過(guò)的目錄項(xiàng)都會(huì)緩存在slab中。
slab中緩存的名稱一般就是 dentry,可以通過(guò)如下命令查看:
[wangyubin@localhost kernel]$ sudo cat /proc/slabinfo | grep dentrydentry 212545 212625 192 21 1 : tunables 0 0 0 : slabdata 10125 10125 0
目錄項(xiàng)定義在:
/* 目錄項(xiàng)對(duì)象結(jié)構(gòu) */struct dentry { atomic_t d_count; /* 使用計(jì)數(shù) */ unsigned int d_flags; /* 目錄項(xiàng)標(biāo)識(shí) */ spinlock_t d_lock; /* 單目錄項(xiàng)鎖 */ int d_mounted; /* 是否登錄點(diǎn)的目錄項(xiàng) */ struct inode *d_inode; /* 相關(guān)聯(lián)的索引節(jié)點(diǎn) */ struct hlist_node d_hash; /* 散列表 */ struct dentry *d_parent; /* 父目錄的目錄項(xiàng)對(duì)象 */ struct qstr d_name; /* 目錄項(xiàng)名稱 */ struct list_head d_lru; /* 未使用的鏈表 */ /* * d_child and d_rcu can share memory */ union { struct list_head d_child; /* child of parent list */ struct rcu_head d_rcu; } d_u; struct list_head d_subdirs; /* 子目錄鏈表 */ struct list_head d_alias; /* 索引節(jié)點(diǎn)別名鏈表 */ unsigned long d_time; /* 重置時(shí)間 */ const struct dentry_operations *d_op; /* 目錄項(xiàng)操作相關(guān)函數(shù) */ struct super_block *d_sb; /* 文件的超級(jí)塊 */ void *d_fsdata; /* 文件系統(tǒng)特有數(shù)據(jù) */ unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* 短文件名 */};/* 目錄項(xiàng)相關(guān)操作函數(shù) */struct dentry_operations { /* 該函數(shù)判斷目錄項(xiàng)對(duì)象是否有效。VFS準(zhǔn)備從dcache中使用一個(gè)目錄項(xiàng)時(shí)會(huì)調(diào)用這個(gè)函數(shù) */ int (*d_revalidate)(struct dentry *, struct nameidata *); /* 為目錄項(xiàng)對(duì)象生成hash值 */ int (*d_hash) (struct dentry *, struct qstr *); /* 比較 qstr 類型的2個(gè)文件名 */ int (*d_compare) (struct dentry *, struct qstr *, struct qstr *); /* 當(dāng)目錄項(xiàng)對(duì)象的 d_count 為0時(shí),VFS調(diào)用這個(gè)函數(shù) */ int (*d_delete)(struct dentry *); /* 當(dāng)目錄項(xiàng)對(duì)象將要被釋放時(shí),VFS調(diào)用該函數(shù) */ void (*d_release)(struct dentry *); /* 當(dāng)目錄項(xiàng)對(duì)象丟失其索引節(jié)點(diǎn)時(shí)(也就是磁盤索引節(jié)點(diǎn)被刪除了),VFS會(huì)調(diào)用該函數(shù) */ void (*d_iput)(struct dentry *, struct inode *); char *(*d_dname)(struct dentry *, char *, int);};
2.4 文件對(duì)象
文件對(duì)象表示進(jìn)程已打開的文件,從用戶角度來(lái)看,我們?cè)诖a中操作的就是一個(gè)文件對(duì)象。
文件對(duì)象反過(guò)來(lái)指向一個(gè)目錄項(xiàng)對(duì)象(目錄項(xiàng)反過(guò)來(lái)指向一個(gè)索引節(jié)點(diǎn))
其實(shí)只有目錄項(xiàng)對(duì)象才表示一個(gè)已打開的實(shí)際文件,雖然一個(gè)文件對(duì)應(yīng)的文件對(duì)象不是唯一的,但其對(duì)應(yīng)的索引節(jié)點(diǎn)和目錄項(xiàng)對(duì)象卻是唯一的。
文件對(duì)象的定義在:
/* * 文件對(duì)象結(jié)構(gòu)中定義的字段非常多, * 這里只介紹一些重要的屬性 */struct file { union { struct list_head fu_list; /* 文件對(duì)象鏈表 */ struct rcu_head fu_rcuhead; /* 釋放之后的RCU鏈表 */ } f_u; struct path f_path; /* 包含的目錄項(xiàng) */ const struct file_operations *f_op; /* 文件操作函數(shù) */ atomic_long_t f_count; /* 文件對(duì)象引用計(jì)數(shù) */};/* * 其中的 f_op 中定義了文件對(duì)象的操作方法 * 這里只介紹一些相對(duì)重要的函數(shù) */struct file_operations { /* 用于更新偏移量指針,由系統(tǒng)調(diào)用lleek()調(diào)用它 */ loff_t (*llseek) (struct file *, loff_t, int); /* 由系統(tǒng)調(diào)用read()調(diào)用它 */ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); /* 由系統(tǒng)調(diào)用write()調(diào)用它 */ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); /* 由系統(tǒng)調(diào)用 aio_read() 調(diào)用它 */ ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); /* 由系統(tǒng)調(diào)用 aio_write() 調(diào)用它 */ ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); /* 將給定文件映射到指定的地址空間上,由系統(tǒng)調(diào)用 mmap 調(diào)用它 */ int (*mmap) (struct file *, struct vm_area_struct *); /* 創(chuàng)建一個(gè)新的文件對(duì)象,并將它和相應(yīng)的索引節(jié)點(diǎn)對(duì)象關(guān)聯(lián)起來(lái) */ int (*open) (struct inode *, struct file *); /* 當(dāng)已打開文件的引用計(jì)數(shù)減少時(shí),VFS調(diào)用該函數(shù) */ int (*flush) (struct file *, fl_owner_t id);};
2.5 四個(gè)對(duì)象之間關(guān)系圖
上面分別介紹了4種對(duì)象分別的屬性和方法,下面用圖來(lái)展示這4個(gè)對(duì)象的和VFS之間關(guān)系以及4個(gè)對(duì)象之間的關(guān)系。
3. 文件系統(tǒng)相關(guān)的數(shù)據(jù)結(jié)構(gòu)
處理上面4個(gè)主要的對(duì)象之外,VFS中還有2個(gè)專門針對(duì)文件系統(tǒng)的2個(gè)對(duì)象,
- struct file_system_type: 用來(lái)描述文件系統(tǒng)的類型(比如ext3,ntfs等等)
- struct vfsmount??????? : 描述一個(gè)安裝文件系統(tǒng)的實(shí)例
file_system_type 結(jié)構(gòu)體位于:
struct file_system_type { const char *name; /* 文件系統(tǒng)名稱 */ int fs_flags; /* 文件系統(tǒng)類型標(biāo)志 */ /* 從磁盤中讀取超級(jí)塊,并且在文件系統(tǒng)被安裝時(shí),在內(nèi)存中組裝超級(jí)塊對(duì)象 */ int (*get_sb) (struct file_system_type *, int, const char *, void *, struct vfsmount *); /* 終止訪問(wèn)超級(jí)塊 */ void (*kill_sb) (struct super_block *); struct module *owner; /* 文件系統(tǒng)模塊 */ struct file_system_type * next; /* 鏈表中下一個(gè)文件系統(tǒng)類型 */ struct list_head fs_supers; /* 超級(jí)塊對(duì)象鏈表 */ /* 下面都是運(yùn)行時(shí)的鎖 */ struct lock_class_key s_lock_key; struct lock_class_key s_umount_key; struct lock_class_key i_lock_key; struct lock_class_key i_mutex_key; struct lock_class_key i_mutex_dir_key; struct lock_class_key i_alloc_sem_key;};
每種文件系統(tǒng),不管由多少個(gè)實(shí)例安裝到系統(tǒng)中,還是根本沒(méi)有安裝到系統(tǒng)中,都只有一個(gè) file_system_type 結(jié)構(gòu)。
當(dāng)文件系統(tǒng)被實(shí)際安裝時(shí),會(huì)在安裝點(diǎn)創(chuàng)建一個(gè) vfsmount 結(jié)構(gòu)體。
結(jié)構(gòu)體代表文件系統(tǒng)的實(shí)例,也就是文件系統(tǒng)被安裝幾次,就會(huì)創(chuàng)建幾個(gè) vfsmount
vfsmount 的定義參見(jiàn):
struct vfsmount { struct list_head mnt_hash; /* 散列表 */ struct vfsmount *mnt_parent; /* 父文件系統(tǒng),也就是要掛載到哪個(gè)文件系統(tǒng) */ struct dentry *mnt_mountpoint; /* 安裝點(diǎn)的目錄項(xiàng) */ struct dentry *mnt_root; /* 該文件系統(tǒng)的根目錄項(xiàng) */ struct super_block *mnt_sb; /* 該文件系統(tǒng)的超級(jí)塊 */ struct list_head mnt_mounts; /* 子文件系統(tǒng)鏈表 */ struct list_head mnt_child; /* 子文件系統(tǒng)鏈表 */ int mnt_flags; /* 安裝標(biāo)志 */ /* 4 bytes hole on 64bits arches */ const char *mnt_devname; /* 設(shè)備文件名 e.g. /dev/dsk/hda1 */ struct list_head mnt_list; /* 描述符鏈表 */ struct list_head mnt_expire; /* 到期鏈表的入口 */ struct list_head mnt_share; /* 共享安裝鏈表的入口 */ struct list_head mnt_slave_list;/* 從安裝鏈表 */ struct list_head mnt_slave; /* 從安裝鏈表的入口 */ struct vfsmount *mnt_master; /* 從安裝鏈表的主人 */ struct mnt_namespace *mnt_ns; /* 相關(guān)的命名空間 */ int mnt_id; /* 安裝標(biāo)識(shí)符 */ int mnt_group_id; /* 組標(biāo)識(shí)符 */ /* * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount * to let these frequently modified fields in a separate cache line * (so that reads of mnt_flags wont ping-pong on SMP machines) */ atomic_t mnt_count; /* 使用計(jì)數(shù) */ int mnt_expiry_mark; /* 如果標(biāo)記為到期,則為 True */ int mnt_pinned; /* "釘住"進(jìn)程計(jì)數(shù) */ int mnt_ghosts; /* "鏡像"引用計(jì)數(shù) */#ifdef CONFIG_SMP int *mnt_writers; /* 寫者引用計(jì)數(shù) */#else int mnt_writers; /* 寫者引用計(jì)數(shù) */#endif};
4. 進(jìn)程相關(guān)的數(shù)據(jù)結(jié)構(gòu)
以上介紹的都是在內(nèi)核角度看到的 VFS 各個(gè)結(jié)構(gòu),所以結(jié)構(gòu)體中包含的屬性非常多。
而從進(jìn)程的角度來(lái)看的話,大多數(shù)時(shí)候并不需要那么多的屬性,所有VFS通過(guò)以下3個(gè)結(jié)構(gòu)體和進(jìn)程緊密聯(lián)系在一起。
- struct files_struct? :由進(jìn)程描述符中的 files 目錄項(xiàng)指向,所有與單個(gè)進(jìn)程相關(guān)的信息(比如打開的文件和文件描述符)都包含在其中。
- struct fs_struct???? :由進(jìn)程描述符中的 fs 域指向,包含文件系統(tǒng)和進(jìn)程相關(guān)的信息。
- struct mmt_namespace :由進(jìn)程描述符中的 mmt_namespace 域指向。
struct files_struct 位于:
struct files_struct { atomic_t count; /* 使用計(jì)數(shù) */ struct fdtable *fdt; /* 指向其他fd表的指針 */ struct fdtable fdtab;/* 基 fd 表 */ spinlock_t file_lock ____cacheline_aligned_in_smp; /* 單個(gè)文件的鎖 */ int next_fd; /* 緩存下一個(gè)可用的fd */ struct embedded_fd_set close_on_exec_init; /* exec()時(shí)關(guān)閉的文件描述符鏈表 */ struct embedded_fd_set open_fds_init; /* 打開的文件描述符鏈表 */ struct file * fd_array[NR_OPEN_DEFAULT]; /* 缺省的文件對(duì)象數(shù)組 */};
struct fs_struct 位于:
struct fs_struct { int users; /* 用戶數(shù)目 */ rwlock_t lock; /* 保護(hù)結(jié)構(gòu)體的讀寫鎖 */ int umask; /* 掩碼 */ int in_exec; /* 當(dāng)前正在執(zhí)行的文件 */ struct path root, pwd; /* 根目錄路徑和當(dāng)前工作目錄路徑 */};
struct mmt_namespace 位于:
但是在2.6內(nèi)核之后似乎沒(méi)有這個(gè)結(jié)構(gòu)體了,而是用 struct nsproxy 來(lái)代替。
以下是 struct task_struct 結(jié)構(gòu)體中關(guān)于文件系統(tǒng)的3個(gè)屬性。
struct task_struct 的定義位于:
/* filesystem information */ struct fs_struct *fs;/* open file information */ struct files_struct *files;/* namespaces */ struct nsproxy *nsproxy;
?
評(píng)論
查看更多