深入理解Linux文件系统之VFS

1. VFS介绍

        “一切皆文件”,文件系统是linux系统的基础,Linux内核通过虚拟文件系统(Virtual File System, VFS)管理文件系统 ,VFS为所有的文件系统提供了统一的接口,对每个具体文件系统的访问要通过VFS定义的接口来实现,VFS既是向下的接口(所有文件系统都必须实现该接口),同时也是向上的接口(用户进程通过系统调用最终能够访问文件系统功能)。

        文件系统官方的定义为操作系统中负责管理和存储文件信息的软件机构,文件本身和文件的内容可以分开理解,就像容器和它存放的液体一样。

        操作文件本身:比如磁盘中的普通文件,如果需要操作它(删除或者更改属性等),因为程序是在内存中,不会直接操作磁盘,而文件又在磁盘中,所以需要一个抽象作为它的代表,这个代表会把操作最终传递至文件。

        同样地,如果需要操作文件的内容(read/write),首先应该找到它或者它的代表,获取操作内容的方法和数据,然后对它的内容进行读写等。

        以上提供了几个概念:文件系统、文件本身、文件的代表和文件内容,它们在内核中都有对应的数据结构,弄清楚了这几个概念,文件系统的整个框架就了然于心了。

文件系统和结构体关系表
概念                数据结构
文件系统super_block
文件本身       inode
文件的代表dentry
文件的内容file

2. 数据结构

2.1 超级块 super_block

        super_block结构体代表了整个文件系统本身,超级块的内容需要读取具体文件系统在硬盘上的超级块结构获得,所以超级块是具体文件系统超级块的内存抽象。

        结构体定义源码路径:include/linux/fs.h

super_block结构体部分字段
字段类型描述
s_listlist_head将super_block链接到super_blocks变量指向的链表中
s_blocksizeunsigned long系统中文件的最小块大小
s_maxbytesloff_t文件系统中最大文件的尺寸
s_typefile_system_type*提供文件系统的mount、kell_sb等回调函数
s_magicunsigned long魔术数字,每个文件系统都有的
s_opsuper_operations*提供alloc_inode、destroy_inode等回调函数
s_rootdentry*        指向文件系统根dentry的指针        
s_inodeslist_head文件系统的inode组成的的链表头
s_instanceshlist_node将它链接到同一种文件系统组成的链表
s_mountslist_head

挂载它的mount对象组成的链表头

s_bdevstruct block_device*        指向文件系统存在的块设备指针

 2.2 dentry 目录项

        文件和目录一般按树状结构保存,在VFS里,目录本身也是一个文件,每个文件都有一个dentry(可能不止一个),这个dentry链接到上级目录的dentry。根目录有一个dentry结构,而根目录里的文件和目录都链接到这个根dentry,二级目录里的文件和目录,同样通过dentry链接到二级目录。这样一层层链接,就形成了一颗dentry树。从树顶可以遍历整个文件系统的所有目录和文件。

        结构体定义源码路径:include/linux/dcache.h

dentry结构体部分字段
字段类型描述
d_parent;struct dentry *指向父dentry结构
d_namestruct qstr名字和哈希值信息
d_inodestruct inode *指向一个inode结构。这个inode和dentry共同描述了一个普通文件或者目录文件。
d_opstruct dentry_operations dentry相关操作
d_hashstruct hlist_bl_node将dentry链接到hash链表中
d_subdirsstruct list_headd_subdirs是子项(子项可能是目录,也可能是文件)的链表头,所有的子项都要链接到这个链表
d_childstruct list_headd_child是dentry自身的链表头,需要链接到父dentry的d_subdirs成员,当移动文件的时候,需要把一个dentry结构从旧的父dentry的链表上脱离,然后链接到新的父dentry的d_subdirs成员
du.d_aliasstruct hlist_node将dentry链接到文件的硬链接链表中

2.3 inode 索引节点

        inode代表一个文件。inode保存了文件的大小、创建时间、文件的块大小等参数,以及对文件的读写函数、文件的读写缓存等信息。一个真实的文件可以有多个dentry,因为指向文件的路径可以有多个(考虑文件的链接),而inode只有一个。

        结构体定义源码路径:include/linux/fs.h

inode 结构体部分字段
字段类型描述
i_modeumode_t  文件的类型
i_uid; i_gidkuid_t 文件的属性
i_opinode_operations*inode操作函数,create/link/unlink/mkdir
i_sbsuper_block*指向inode所属的super_block
i_inounsigned long  成员i_ino是inode的号
i_countatomic_ti_count是inode的引用计数
i_sizeloff_t     字节为单位的文件长度

i_atime

i_mtime

i_ctime

timespecaccess/mdify/change time
i_fopfile_operations*文件的读写函数和异步io函数都在这个结构中提供
i_hashhlist_node将inode链接到hash链表中
i_sb_listlist_head将inode链接到super_block链表中
i_dentryhlist_head文件的硬链接的dentry组成的链表头
i_nlinkunsigned int 文件的链接数目
i_linkchar*链接的目标文件路径
i_mappingaddress_space*        这个结构目的是缓存文件的内容,对文件的读写操作首先要在i_mapping包含的缓存里寻找文件的内容。如果有缓存,对文件的读就可以直接从缓存中获得,而不用再去物理硬盘读取,从而大大加速了文件的读操作。写操作也要首先访问缓存,写入到文件的缓存。然后等待合适的机会,再从缓存写入硬盘
i_bdevblock_device*指向块设备的指针。这个块设备就是文件所在的文件系统所绑定的块设备。

2.4 file 文件

        文件对象的作用是描述进程和文件交互的关系,file结构体对应文件的内容,并不是说它包含了文件的内容,而是说它记录了文件的访问方法和访问状态。

struct file {
	   union {
		   struct  llist_node	fu_llist;      /*单链表成员*/
		   struct  rcu_head 	fu_rcuhead;
	   } f_u;
	   struct path	 f_path;            /*文件路径信息*/
	   struct inode	*f_inode;	       /*指向内核文件inode实例*/
	   const struct file_operations	*f_op;  
/*文件操作结构指针,通常在打开文件时设为inode->i_fop*/
	   spinlock_t		f_lock;
	   atomic_long_t		f_count;
	   unsigned int 		f_flags;    /*open()系统调用传递的flags标记参数*/
	   fmode_t			f_mode;    /*标记进程以何种模式打开文件*/
	   struct mutex		f_pos_lock;
	   loff_t			    f_pos;      /*文件当前读写位置,相对于文件开头处的字节偏移量*/
	   struct fown_struct	f_owner;
	   const struct cred	*f_cred;
	   struct file_ra_state	f_ra;   
	   u64		f_version;
    #ifdef  CONFIG_SECURITY
	   void		*f_security;
    #endif
	   void		*private_data;  /*文件私有数据指针,例如设备文件指向驱动程序定义的数据结构*/

    #ifdef CONFIG_EPOLL
	   struct list_head	  f_ep_links;
	   struct list_head   f_tfile_llink;
#endif        
   struct address_space	*f_mapping;     /*文件地址空间指针,用于具有外部存储介质的文件*/
} __attribute__((aligned(4)));

2.5 file_system_type

        在使用file_system_type前需要先调用register_filesystem,将其注册到系统中,后者将它链接到file_systems变量指向的单向链表中,使用时将它的名字作为参数调用get_fs_type即可获取。

        所有可用的file_system_type组成一个链表,同一种文件系统(super_block)链接到file_system_type的fs_supers字段表示的链表中。

        

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值