日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux VFS

發(fā)布時間:2023/12/20 linux 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux VFS 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文:https://blog.csdn.net/jasonchen_gbd/article/details/51511261

參考:

https://www.cnblogs.com/jimbo17/p/10107318.html

https://blog.csdn.net/u010487568/article/details/79606141

https://blog.csdn.net/u011784994/article/details/52614935

https://blog.csdn.net/u010424605/article/details/41842877

https://blog.csdn.net/mignatian/article/details/81673713

https://download.csdn.net/download/yunsongice/3326879

?

1. 通用文件模型
Linux內(nèi)核支持裝載不同的文件系統(tǒng)類型,不同的文件系統(tǒng)有各自管理文件的方式。Linux中標(biāo)準(zhǔn)的文件系統(tǒng)為Ext文件系統(tǒng)族,當(dāng)然,開發(fā)者不能為他們使用的每種文件系統(tǒng)采用不同的文件存取方式,這與操作系統(tǒng)作為一種抽象機(jī)制背道而馳。

為支持各種文件系統(tǒng),Linux內(nèi)核在用戶進(jìn)程(或C標(biāo)準(zhǔn)庫)和具體的文件系統(tǒng)之間引入了一個抽象層,該抽象層稱之為“虛擬文件系統(tǒng)(VFS)”。

VFS一方面提供一種操作文件、目錄及其他對象的統(tǒng)一方法,使用戶進(jìn)程不必知道文件系統(tǒng)的細(xì)節(jié)。另一方面,VFS提供的各種方法必須和具體文件系統(tǒng)的實(shí)現(xiàn)達(dá)成一種妥協(xié),畢竟對幾十種文件系統(tǒng)類型進(jìn)行統(tǒng)一管理并不是件容易的事。

為此,VFS中定義了一個通用文件模型,以支持文件系統(tǒng)中對象(或文件)的統(tǒng)一視圖。

Linux對Ext文件系統(tǒng)族的支持是最好的,因?yàn)閂FS抽象層的組織與Ext文件系統(tǒng)類似,這樣在處理Ext文件系統(tǒng)時可以提高性能,因?yàn)樵贓xt和VFS之間轉(zhuǎn)換幾乎不會損失時間。

內(nèi)核處理文件的關(guān)鍵是inode,每個文件(和目錄)都有且只有一個對應(yīng)的inode(struct inode實(shí)例),其中包含元數(shù)據(jù)和指向文件數(shù)據(jù)的指針,但inode并不包含文件名。系統(tǒng)中所有的inode都有一個特定的編號,用于唯一的標(biāo)識各個inode。文件名可以隨時更改,但是索引節(jié)點(diǎn)對文件是唯一的,并且隨文件的存在而存在。

?對于每個已經(jīng)掛載的文件系統(tǒng),VFS在內(nèi)核中都生成一個超級塊結(jié)構(gòu)(struct?super_block實(shí)例),超級塊代表一個已經(jīng)安裝的文件系統(tǒng),用于存儲文件系統(tǒng)的控制信息,例如文件系統(tǒng)類型、大小、所有inode對象、臟的inode鏈表等。

inode和super block在存儲介質(zhì)中都是有實(shí)際映射的,即存儲介質(zhì)中也存在超級塊和inode。但是由于不同類型的文件系統(tǒng)差異,超級塊和inode的結(jié)構(gòu)不盡相同。而VFS的作用就是通過具體的設(shè)備驅(qū)動獲得某個文件系統(tǒng)中的超級塊和inode節(jié)點(diǎn),然后將其中的信息填充到內(nèi)核中的struct super_block和struct inode中,以此來試圖對不同文件系統(tǒng)進(jìn)行統(tǒng)一管理。

由于塊設(shè)備速度較慢(于內(nèi)存而言),可能需要很長時間才能找到與一個文件名關(guān)聯(lián)的inode。Linux使用目錄項(xiàng)(dentry)緩存來快速訪問此前的查找操作結(jié)果。在VFS讀取了一個目錄或文件的數(shù)據(jù)之后,則創(chuàng)建一個dentry實(shí)例(struct dentry),以緩存找到的數(shù)據(jù)。

dentry結(jié)構(gòu)的主要用途就是建立文件名和相關(guān)的inode之間的聯(lián)系。一個文件系統(tǒng)中的dentry對象都被放在一個散列表中,同時不再使用的dentry對象被放到超級塊指向的一個LRU鏈表中,在某個時間點(diǎn)會刪除比較老的對象以釋放內(nèi)存。

另外簡單提一下兩個數(shù)據(jù)結(jié)構(gòu):

每種注冊到內(nèi)核的文件系統(tǒng)類型以struct file_system_type結(jié)構(gòu)表示,每種文件系統(tǒng)類型中都有一個鏈表,指向所有屬于該類型的文件系統(tǒng)的超級塊。

當(dāng)一個文件系統(tǒng)掛載到內(nèi)核文件系統(tǒng)的目錄樹上,會生成一個掛載點(diǎn),用來管理所掛載的文件系統(tǒng)的信息。該掛載點(diǎn)用一個struct vfsmount結(jié)構(gòu)表示,這個結(jié)構(gòu)后面會提到。

上面的這些結(jié)構(gòu)的關(guān)系大致如下:

其中紅色字體的鏈表為內(nèi)核中的全局鏈表。

2. 掛載文件系統(tǒng)
在用戶程序中,使用mount系統(tǒng)調(diào)用來掛載文件系統(tǒng),相應(yīng)的使用umount卸載文件系統(tǒng)。當(dāng)然,內(nèi)核必須支持將要掛載的文件系統(tǒng)類型,在內(nèi)核啟動時或者在安裝內(nèi)核模塊時,可以注冊特定的文件系統(tǒng)類型到內(nèi)核,注冊的函數(shù)為register_filesystem()。

mount命令最常用的方式是mount [-t fstype] something somewhere

其中something是將要被掛載的設(shè)備或目錄,somewhere指明要掛載到何處。-t選項(xiàng)指明掛載的文件系統(tǒng)類型。由于something指向的設(shè)備是一個已知設(shè)備,即其上的文件系統(tǒng)類型是確定的,所以-t選項(xiàng)必須設(shè)置正確才能掛載成功。

每個裝載的文件系統(tǒng)都對應(yīng)一個vfsmount結(jié)構(gòu)的實(shí)例。

由于裝載過程是向內(nèi)核文件系統(tǒng)目錄樹中添加裝載點(diǎn),這些裝載點(diǎn)就存在一種父子關(guān)系,這和父目錄與子目錄的關(guān)系類似。例如,我的根文件系統(tǒng)類型是squashfs,裝載到根目錄“/”,生成一個掛載點(diǎn),之后我又在/tmp目錄掛載了ramfs文件系統(tǒng),在根文件系統(tǒng)中的tmp目錄生成了一個掛載點(diǎn),這兩個掛載點(diǎn)就是父子關(guān)系。這種關(guān)系存儲在struct vfsmount結(jié)構(gòu)中。

在下圖中,根文件系統(tǒng)為squashfs,根目錄為“/”,然后創(chuàng)建/tmp目錄,并掛載為ramfs,之后又創(chuàng)建了/tmp/usbdisk/volume9和/tmp/usbdisk/volume1兩個目錄,并將/tmp/dev/sda1和/tmp/dev/sdb1兩個分區(qū)掛載到這兩個目錄上。其中/tmp/dev/sda1設(shè)備上有如下文件:

gccbacktrace/

----> gcc_backtrace.c

---->man_page.log

---->readme.txt

notes-fs.txt

smb.conf

掛載完成后,VFS中相關(guān)的數(shù)據(jù)結(jié)構(gòu)的關(guān)系如圖所示。

mount系統(tǒng)調(diào)用在內(nèi)核中的入口點(diǎn)是sys_mount函數(shù),該函數(shù)將裝載的選項(xiàng)從用戶態(tài)復(fù)制一份,然后調(diào)用do_mount()函數(shù)進(jìn)行掛載,這個函數(shù)做的事情就是通過特定文件系統(tǒng)讀取超級塊和inode信息,然后建立VFS的數(shù)據(jù)結(jié)構(gòu)并建立上圖中的關(guān)系。

在父文件系統(tǒng)中的某個目錄上掛載另一個文件系統(tǒng)后,該目錄原來的內(nèi)容就被隱藏了。例如,/tmp/samba/是非空的,然后,我將/tmp/dev/sda1掛載到/tmp/samba上,那這時/tmp/samba/目錄下就只能看到/tmp/dev/sda1設(shè)備上的文件,直到將該設(shè)備卸載,原來目錄中的文件才會顯示出來。這是通過struct vfsmount中的mnt_mountpoint和mnt_root兩個成員來實(shí)現(xiàn)的,這兩個成員分別保存了在父文件系統(tǒng)中掛載點(diǎn)的dentry和在當(dāng)前文件系統(tǒng)中掛載點(diǎn)的dentry,在卸載當(dāng)前掛載點(diǎn)之后,可以找回掛載目錄在父文件系統(tǒng)中的dentry對象。

3. 一個進(jìn)程中與文件系統(tǒng)相關(guān)的信息

struct task_struct {……/* filesystem information */struct fs_struct *fs;/* open file information */struct files_struct *files;/* namespaces */struct nsproxy *nsproxy;…… }

其中fs成員指向進(jìn)程當(dāng)前工作目錄的文件系統(tǒng)信息。files成員指向了進(jìn)程打開的文件的信息。nsproxy指向了進(jìn)程所在的命名空間,其中包含了虛擬文件系統(tǒng)命名空間。

?

從上圖可以看到,fs中包含了文件系統(tǒng)的掛載點(diǎn)和掛載點(diǎn)的dentry信息。而files指向了一系列的struct file結(jié)構(gòu),其中struct path結(jié)構(gòu)用于將struct file和vfsmount以及dentry聯(lián)系起來。struct file保存了內(nèi)核所看到的文件的特征信息,進(jìn)程打開的文件列表就存放在task_struct->files->fd_array[]數(shù)組以及fdtable中。

task_struct結(jié)構(gòu)還存放了其打開文件的文件描述符fd的信息,這是用戶進(jìn)程需要用到的,用戶進(jìn)程在通過文件名打開一個文件后,文件名就沒有用處了,之后的操作都是對文件描述符fd的,在內(nèi)核中,fget_light()函數(shù)用于通過整數(shù)fd來查找對應(yīng)的struct file對象。由于每個進(jìn)程都維護(hù)了自己的fd列表,所以不同進(jìn)程維護(hù)的fd的值可以重復(fù),例如標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯誤對應(yīng)的fd分別為0、1、2。

struct file的mapping成員指向?qū)儆谖募嚓P(guān)的inode實(shí)例的地址空間映射,通常它設(shè)置為inode->i_mapping。在讀寫一個文件時,每次都從物理設(shè)備上獲取文件的話,速度會很慢,在內(nèi)核中對每個文件分配一個地址空間,實(shí)際上是這個文件的數(shù)據(jù)緩存區(qū)域,在讀寫文件時只是操作這塊緩存,通過內(nèi)核有相應(yīng)的同步機(jī)制將臟的頁寫回物理設(shè)備。super_block中維護(hù)了一個臟的inode的鏈表。

struct file的f_op成員指向一個struct file_operations實(shí)例(圖中畫錯了,不是f_pos),該結(jié)構(gòu)保存了指向所有可能文件操作的指針,如read/write/open等。

struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); …… };

4. 打包文件系統(tǒng)
在制作好了文件系統(tǒng)的目錄之后,可通過特定于文件系統(tǒng)類型的工具對目錄進(jìn)行打包,即制作文件系統(tǒng)。例如squashfs文件系統(tǒng)的打包工具為mksquashfs。除了打包之外,打包工具還針對特定文件系統(tǒng)生成超級塊和inode節(jié)點(diǎn)信息,最終生成的文件系統(tǒng)鏡像可以被內(nèi)核解釋并掛載。

附錄 VFS相關(guān)數(shù)據(jù)結(jié)構(gòu)
inode:

struct inode {/* 全局的散列表 */struct hlist_node i_hash;/* 根據(jù)inode的狀態(tài)可能處理不同的鏈表中(inode_unused/inode_in_use/super_block->dirty) */struct list_head i_list;/* super_block->s_inodes鏈表的節(jié)點(diǎn) */struct list_head i_sb_list;/* inode對應(yīng)的dentry鏈表,可能多個dentry指向同一個文件 */struct list_head i_dentry;/* inode編號 */unsigned long i_ino;/* 訪問該inode的進(jìn)程數(shù)目 */atomic_t i_count;/* inode的硬鏈接數(shù) */unsigned int i_nlink;uid_t i_uid;gid_t i_gid;/* inode表示設(shè)備文件時的設(shè)備號 */dev_t i_rdev;u64 i_version;/* 文件的大小,以字節(jié)為單位 */loff_t i_size; #ifdef __NEED_I_SIZE_ORDEREDseqcount_t i_size_seqcount; #endif/* 最后訪問時間 */struct timespec i_atime;/* 最后修改inode數(shù)據(jù)的時間 */struct timespec i_mtime;/* 最后修改inode自身的時間 */struct timespec i_ctime;/* 以block為單位的inode的大小 */blkcnt_t i_blocks;unsigned int i_blkbits;unsigned short i_bytes;/* 文件屬性,低12位為文件訪問權(quán)限,同chmod參數(shù)含義,其余位為文件類型,如普通文件、目錄、socket、設(shè)備文件等 */umode_t i_mode;spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */struct mutex i_mutex;struct rw_semaphore i_alloc_sem;/* inode操作 */const struct inode_operations *i_op;/* file操作 */const struct file_operations *i_fop;/* inode所屬的super_block */struct super_block *i_sb;struct file_lock *i_flock;/* inode的地址空間映射 */struct address_space *i_mapping;struct address_space i_data; #ifdef CONFIG_QUOTAstruct dquot *i_dquot[MAXQUOTAS]; #endifstruct list_head i_devices; /* 若為設(shè)備文件的inode,則為設(shè)備的打開文件列表節(jié)點(diǎn) */union {struct pipe_inode_info *i_pipe;struct block_device *i_bdev; /* 若為塊設(shè)備的inode,則指向該設(shè)備實(shí)例 */struct cdev *i_cdev; /* 若為字符設(shè)備的inode,則指向該設(shè)備實(shí)例 */};__u32 i_generation;#ifdef CONFIG_FSNOTIFY__u32 i_fsnotify_mask; /* all events this inode cares about */struct hlist_head i_fsnotify_mark_entries; /* fsnotify mark entries */ #endif#ifdef CONFIG_INOTIFYstruct list_head inotify_watches; /* watches on this inode */struct mutex inotify_mutex; /* protects the watches list */ #endifunsigned long i_state;unsigned long dirtied_when; /* jiffies of first dirtying */unsigned int i_flags; /* 文件打開標(biāo)記,如noatime */atomic_t i_writecount; #ifdef CONFIG_SECURITYvoid *i_security; #endif #ifdef CONFIG_FS_POSIX_ACLstruct posix_acl *i_acl;struct posix_acl *i_default_acl; #endifvoid *i_private; /* fs or device private pointer */ };

super_block:

struct super_block {/* 全局鏈表元素 */struct list_head s_list;/* 底層文件系統(tǒng)所在的設(shè)備 */dev_t s_dev;/* 文件系統(tǒng)中每一塊的長度 */unsigned long s_blocksize;/* 文件系統(tǒng)中每一塊的長度(以2為底的對數(shù)) */unsigned char s_blocksize_bits;/* 是否需要向磁盤回寫 */unsigned char s_dirt;unsigned long long s_maxbytes; /* Max file size *//* 文件系統(tǒng)類型 */struct file_system_type *s_type;/* 超級塊操作方法 */const struct super_operations *s_op;struct dquot_operations *dq_op;struct quotactl_ops *s_qcop;const struct export_operations *s_export_op;unsigned long s_flags;unsigned long s_magic;/* 全局根目錄的dentry */struct dentry *s_root;struct rw_semaphore s_umount;struct mutex s_lock;int s_count;int s_need_sync;atomic_t s_active; #ifdef CONFIG_SECURITYvoid *s_security; #endifstruct xattr_handler **s_xattr;/* 超級塊管理的所有inode的鏈表 */struct list_head s_inodes; /* all inodes *//* 臟的inode的鏈表 */struct list_head s_dirty; /* dirty inodes */struct list_head s_io; /* parked for writeback */struct list_head s_more_io; /* parked for more writeback */struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting *//* file結(jié)構(gòu)的鏈表,該超級塊上所有打開的文件 */struct list_head s_files;/* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock *//* 不再使用的dentry的LRU鏈表 */struct list_head s_dentry_lru; /* unused dentry lru */int s_nr_dentry_unused; /* # of dentry on lru */struct block_device *s_bdev;struct mtd_info *s_mtd;/* 相同文件系統(tǒng)類型的超級塊鏈表的節(jié)點(diǎn) */struct list_head s_instances;struct quota_info s_dquot; /* Diskquota specific options */int s_frozen;wait_queue_head_t s_wait_unfrozen;char s_id[32]; /* Informational name */void *s_fs_info; /* Filesystem private info */fmode_t s_mode;/** 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 *//* Granularity of c/m/atime in ns.Cannot be worse than a second */u32 s_time_gran;/** 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 *s_options; };

dentry:

struct dentry {atomic_t d_count;unsigned int d_flags; /* protected by d_lock */spinlock_t d_lock; /* per dentry lock *//* 該dentry是否是一個裝載點(diǎn) */int d_mounted;/* 文件所屬的inode */struct inode *d_inode;/** The next three fields are touched by __d_lookup. Place them here so they all fit in a cache line.*//* 全局的dentry散列表 */struct hlist_node d_hash; /* lookup hash list *//* 父目錄的dentry */struct dentry *d_parent; /* parent directory *//* 文件的名稱,例如對/tmp/a.sh,文件名即為a.sh */struct qstr d_name;/* 臟的dentry鏈表的節(jié)點(diǎn) */struct list_head d_lru; /* LRU list *//** 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;/* 該dentry子目錄中的dentry的節(jié)點(diǎn)鏈表 */struct list_head d_subdirs; /* our children *//* 硬鏈接使用幾個不同名稱表示同一個文件時,用于連接各個dentry */struct list_head d_alias; /* inode alias list */unsigned long d_time; /* used by d_revalidate */const struct dentry_operations *d_op;/* 所屬的super_block */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 */ };

vfsmount:

struct vfsmount {/* 全局散列表 */struct list_head mnt_hash;/* 父文件系統(tǒng)的掛載點(diǎn) */struct vfsmount *mnt_parent; /* fs we are mounted on *//* 父文件系統(tǒng)中該掛載點(diǎn)的dentry */struct dentry *mnt_mountpoint; /* dentry of mountpoint *//* 當(dāng)前文件系統(tǒng)中該掛載點(diǎn)的dentry */struct dentry *mnt_root; /* root of the mounted tree *//* 指向super_block */struct super_block *mnt_sb; /* pointer to superblock *//* 該掛載點(diǎn)下面的子掛載點(diǎn)列表 */struct list_head mnt_mounts; /* list of children, anchored here *//* 父文件系統(tǒng)的子掛載點(diǎn)的列表節(jié)點(diǎn) */struct list_head mnt_child; /* and going through their mnt_child */int mnt_flags;/* 4 bytes hole on 64bits arches *//* 掛載的設(shè)備,如/dev/dsk/hda1 */const char *mnt_devname;/* 虛擬文件系統(tǒng)命名空間中的鏈表節(jié)點(diǎn) */struct list_head mnt_list;struct list_head mnt_expire; /* link in fs-specific expiry list */struct list_head mnt_share; /* circular list of shared mounts */struct list_head mnt_slave_list;/* list of slave mounts */struct list_head mnt_slave; /* slave list entry */struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list *//* 所在的虛擬文件系統(tǒng)命名空間*/struct mnt_namespace *mnt_ns; /* containing namespace */int mnt_id; /* mount identifier */int mnt_group_id; /* peer group identifier *//** 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;int mnt_expiry_mark; /* true if marked for expiry */int mnt_pinned;int mnt_ghosts; #ifdef CONFIG_SMPint *mnt_writers; #elseint mnt_writers; #endif };

總結(jié)

以上是生活随笔為你收集整理的linux VFS的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。