文件系统
文件系统是一套实现了数据的存储、分级组织、存取和获取等操作的抽象数据类型 。
文件系统是一种用于向用户提供底层数据存取的机制。它将设备中的空间划分为特定大小的块,一般每块512字节。数据存储在这些块中,大小被修正为占用整数个块。由文件系统软件来负责将这些块组织为文件和目录,并记录哪些块被分配给了哪个文件,以及哪些块没有被使用。
文件系统并不一定只在特定存储设备上出现,它是数据的组织者和提供者,至于它的底层可以是磁盘,也可以是其他动态生成数据的设备。
类型
-
磁盘文件系统:
磁盘文件系统是一种设计用来利用数据存储设备来保存计算机文件的文件系统,最常用的数据存储设备是磁盘驱动器,可以直接或间接地连接到计算机上。例如:ext2/3、FAT、XFS、NTFS等。
-
虚拟文件系统:
虚拟文件系统在内核中生成,是一种使用户应用程序与用户通信的方法。最典型的proc文件系统,它不需要在任何种类的硬件设备上分配存储空间。相反,内核建立了一个层次化的文件结构,其中的项包含了与系统特定部分相关的信息。
-
网络文件系统:
网络文件系统允许访问另一台计算机上的数据,该计算机通过网络连接到本地计算机。在这种情况下数据实际存储在一个不同系统的硬件设备上。
虚拟文件系统(VFS)
我们知道,文件系统有很多种,例如:ext2、ext3、xfs和/proc等等。不同的文件系统的操作和数据结构肯定是不同的,为了使用户使用统一的接口,在用户进程和文件系统中间抽象出VFS,用户和VFS进行交互,然后VFS根据用户操作的文件来进行对应文件系统的操作。
VFS向上对应用层提供了一个标准的文件操作接口,向下对文件系统提供了一个标准的接口,可以方便其他操作系统的文件系统的移植。
VFS有四大对象:
-
超级块(super block)
-
索引节点(inode)
-
目录项(dentry)
-
文件对象(file)
-
super block
一个super block对应一个文件系统,例如ext2有一个super block,xfs对应一个super block。super block保存文件系统的类型、大小和状态等等。
struct super_block
结构部分:struct super_block { struct list_head s_list; //super block链表的指针 unsigned long s_blocksize; //数据块大小,以字节单位 struct file_system_type *s_type; //文件系统类型,ext2/ext3 struct list_head s_files; //所有的已经打开文件的链表 ... };
-
inode
inode保存文件实际数据的一些信息,也就是元数据,例如文件大小,文件模式,扩展属性和指向存储文件数据的磁盘区块指针等等。
inode有两种,一种是VFS的inode,一种是文件系统的inode,前者存在在内存中,后者在磁盘中。系统开启后将磁盘中的inode填充到内存中的inode。
inode号是唯一的,和实际文件一一对应。在linux内部,通过inode号来访问文件,文件名是提供给用户容易使用的。当打开一个文件时,系统找到这个文件名对应的inode号,然后通过inode号得到inode信息,最后,由inode找到文件数据所在的block,从而处理文件数据。
struct inode
结构部分:struct inode { struct list_head i_list; //inode链表指针 struct list_head i_dentry; //dentry链表指针,与此inode有关的dentry连在一起 unsigned long i_ino; //inode号 atomic_t i_count; //引用计数 umode_t i_mode; //文件类型和访问权限 loff_t i_size; //文件大小 time_t i_atime; //文件最后一次访问时间 time_t i_mtime; //文件最后一次修改时间 time_t i_ctime; //inode最后一次修改时间 unsigned int i_blkbits; //块大小,字节单位 unsigned long i_blksize; //块大小,bit单位 unsigned long i_blocks; //文件所占块数 struct inode_operations *i_op; //索引节点操作 struct file_operations *i_fop; //文件操作 struct super_block *i_sb; //inode所属文件系统的超级块指针 ... };
-
dentry
dentry是描述文件的逻辑属性,只存在在内存中,磁盘上没有实际对应的描述。存在于内存的dentry缓存,是为了提高查找性能。不管是文件还是文件夹,都属于dentry,所有的dentry一起构成一棵目录树。
打开一个文件时,例如打开/home/vrv/test.txt,/、home、vrv、test.txt都是一个dentry,VFS在查找文件的时候,根据一层一层的dentry找到对应每个dentry的inode,沿着dentry就可以找到文件。
struct dentry
结构部分:struct dentry{ atomic_t d_count; //引用计数 struct inode * d_inode; //与该dentry关联的inode struct dentry * d_parent; //父目录的dentry struct dentry_operations *d_op; //目录项操作 struct super_block * d_sb; //dentry所属的文件系统的超级块 ... };
一个有效的dentry必定有一个inode,所以其
d_inode
必定指向一个inode。 -
file
文件对象描述的是进程已经打开的文件。由于一个文件可以被多个进程打开,所以一个文件可以存在多个文件对象。但是由于文件时唯一的,对应的inode就是唯一的,dentry也是唯一的。
进程通过文件描述符来操作文件。 每个文件都有一个32位的数字来表示下一个读写的字节位置,这个数字叫做文件位置。
struct file
结构部分:struct file{ struct list_head f_list; //所有的打开的文件形成的链表,链接到super_block中的s_files链表 struct dentry *f_dentry; //该文件的dentry struct vfsmount *f_vfsmnt; //该文件在这个文件系统中的装载点 struct file_operations *f_op; //文件操作,当进程打开文件时,这个文件的inode中的i_fop会初始化这个字段 atomic_t f_count; //引用计数,当关闭一个fd时,并不是真正的关闭文件,仅仅是将f_count减一,当f_count等于零时才真正关闭文件 unsigned int f_flags; //打开文件时候指定的标识 mode_t f_mode; //文件的访问模式 loff_t f_pos; //目前文件的偏移 struct fown_struct f_owner; //记录一个进程ID unsigned int f_uid, f_gid; //用户ID和组ID ... };