1. 虚拟文件系统VFS
虚拟文件系统是Linux内核为支持各种文件系统,在用户进程和文件系统实现之间引入的一个软件抽象层——Virtual File System,仅存在于内存中。
“一切皆文件”是Unix/Linux的设计哲学之一,Linux将普通文件、目录、字符设备、块设备、套接字等都看做文件,主要是他们的操作是一套统一的接口——知乎相关问题:如何理解「In UNIX, everything is a file」?
源自:Anatomy of the Linux file system
VFS与块I/O结合,定义了所有文件系统都支持的、基本的、概念上的接口和数据结构这一抽象层。
- 使得用户使用一套标准的系统调用来操作文件而无需涉及具体的文件系统和存储介质,实现跨文件系统操作
- 引入新的文件系统只要实现VFS定义的各个接口,不需要修改内核
- 几个抽象概念:文件、目录项、索引节点、安装点(mount point,命名空间)
2. VFS中的对象类型
VFS采用面向对象的设计,主要包括超级块、索引节点、目录项、文件四个结构体对象。
超级块: 存储文件系统的控制信息。描述文件系统的状态、文件系统类型、大小、区块数、索引节点数等,存放于磁盘的特定扇区中。
索引节点: 存储文件的元数据信息。描述文件的大小、拥有者、创建时间、访问模式、磁盘mapping等。
目录: 就是一个文件,存放的数据就是目录信息,所以操作文件的接口完全可以用在目录上。
目录项: 在一个文件路径中,路径的每一部分都被称为目录项;如路径/home/source/helloworld.c中,目录 /, home, source和文件 helloworld.c都是一个目录项。
文件: 一组在逻辑上具有完整意义的信息项的系列。除了普通文件,其他诸如目录、设备、套接字等 也以文件被对待。
源自:从文件 I/O 看 Linux 的虚拟文件系统
每个对象包含一个操作对象:
- super_operations对象:针对特定文件系统能调用的方法,如write_inode()/sync_fs()
- inode_operations对象:针对特定文件所能调用的方法,如create()/link()
- dentry_operations对象:针对特定目录所能调用的方法,如d_compare()/d_delete()
file_operations对象:包括进程针对已打开文件所能调用的方法,如read()/write()
file_system_type:描述文件系统及其性能
- vfsmount:描述安装点信息
2.1 超级块super_block对象
指文件系统超级块或文件系统控制块,代表一个具体的已安装文件系统,存储着整个文件系统的信息,一般存放在磁盘特定扇区。当一个具体的文件系统安装时,内核从特定位置读取信息来填充内存中的超级块对象,一个安装实例对应一个超级块对象。
VFS超级块在各种具体文件系统在安装时建立的,并在卸载时被自动删除,所有超级块对象以双向链表链接在一起。
2.1.1 超级快的定义: 中
|
|
扩展阅读:ecryptfs加密文件系统
超级块对象的创建、管理和撤销在fs/super.c中。
2.1.2 超级块操作:linux/fs.h
|
|
在实现具体的文件系统时,可以将不需要的函数指针设置为NULL,VFS会调用通用的函数执行相应操作,一般什么也不做。
2.2 索引节点对象
索引节点包含了内核操作文件或目录需要的全部信息,在同一个文件系统内,每个索引节点号是唯一的。
2.2.1 索引节点定义:linux/fs.h
一个索引节点与文件系统中的一个文件(包括文件、目录、设备、管道)对应,和超级块一样,索引节点实际存储在磁盘上,当文件被访问时,相应的索引节点才在内存创建。
2.2.2 索引节点操作:linux/fs.h
描述VFS操作inode对象的所有方法
1234567891011121314151617181920212223242526272829 struct inode_operations {struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); /* 在特点目录中寻找索引节点,该索引节点对应dentry中给定的文件名 */const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);int (*permission) (struct inode *, int); /* 检查访问模式 */struct posix_acl * (*get_acl)(struct inode *, int);int (*readlink) (struct dentry *, char __user *,int); /* readlink()系统调用 */int (*create) (struct inode *,struct dentry *, umode_t, bool); /* create()和open()系统调用,为dentry创建新的inode */int (*link) (struct dentry *,struct inode *,struct dentry *); /*link()系统调用,创建硬链接 */int (*unlink) (struct inode *,struct dentry *); /* unlink()系统调用, 从inode对应目录中删除dentry指定的索引节点对象 */int (*symlink) (struct inode *,struct dentry *,const char *); /* symlik()系统调用,创建符号链接 */int (*mkdir) (struct inode *,struct dentry *,umode_t); /* mkdir()系统调用 */int (*rmdir) (struct inode *,struct dentry *); /* rmdir()系统调用 */int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); /* mknod()系统调用 */int (*rename) (struct inode *, struct dentry *,struct inode *, struct dentry *, unsigned int); /* VFS调用该函数来移动文件*/int (*setattr) (struct dentry *, struct iattr *); /* notify_change()调用,在修改节点后,通知发生了"改变事件" */int (*getattr) (const struct path *, struct kstat *, u32, unsigned int); /* 通知索引节点需要从磁盘更新 */ssize_t (*listxattr) (struct dentry *, char *, size_t);int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,u64 len);int (*update_time)(struct inode *, struct timespec *, int);int (*atomic_open)(struct inode *, struct dentry *,struct file *, unsigned open_flag,umode_t create_mode, int *opened);int (*tmpfile) (struct inode *, struct dentry *, umode_t);int (*set_acl)(struct inode *, struct posix_acl *, int);} ____cacheline_aligned;
2.3 目录项对象
dentry结构代表逻辑意义上的文件,是对一个文件逻辑属性的描述,目录项没有对应的磁盘数据结构,VFS根据路径名现场创建它。路径中的每个部分都是一个目录项,比如路径: /mnt/cdrom/foo 其中包含/ mnt cdrom foo 4个目录项。
直接使用inode也可以找到文件,引入目录项主要为了加快文件的查找、比较。
目录项有三个状态:
- 被使用:d_inode指向一个有效的索引节点,存在一个或多个使用者d_count>0
- 未被使用:d_inode指向一个有效的索引节点,但当前没有使用者d_count=0,需要时直接使用
- 负状态:没有对应有效的索引节点d_inode=NULL,(因为索引节点已经被删除了,或路径不再正确)
目录项缓存dcache包括:
- “被使用的”目录项链表
- “最近被使用的”双向链表
- 散列表和相应的散列函数
目录项定义在linux/dcache.h
|
|
目录项操作:linux/dcache.h
2.4 文件对象
文件对象表示进程已打开的文件,是已打开文件在内存中的表示,用户直接操作的就是文件。
文件对象反过来指向一个目录项对象(目录项反过来指向一个索引节点)。
一个文件可能对应多个文件对象(因为多个进程访问同一个文件),但是对应的索引节点和目录项是唯一的。
文件对象没有对应的磁盘数据。
文件对象定义:linux/fs.h
|
|
文件操作:
2.5 文件系统相关数据结构
file_system_type结构描述文件系统功能和行为,系统用一个全局的变量file_systems来保存所有已注册到系统中的文件系统,在mount一个文件系统时,系统遍历这个变量判断是否支持挂载的文件系统。
http://www.cnblogs.com/fengkang1008/p/4691231.html
定义:
|
|
vfsmount描述文件系统实例,代表一个安装点,文件系统被安装几次,就会创建几个vfsmount
定义:
实际的mount结构:
2.6 进程相关数据结构
系统中每个进程都有自己的一组打开文件,VFS利用file_struct、fs_struct和namespace三个数据结构与系统的进程联系起来。
file_struct:
由进程描述符中的files域指向
Open file table structure1234567891011121314151617181920struct files_struct {/** read mostly part*/atomic_t count; /* 引用计数 */bool resize_in_progress;wait_queue_head_t resize_wait;struct fdtable __rcu *fdt; /* 指向其他fd表的指针,比如进程共享描述符 */struct fdtable fdtab; /* 基fd表 *//** written part on a separate cache line in SMP*/spinlock_t file_lock ____cacheline_aligned_in_smp;unsigned int next_fd; /* 下一个可用的fd */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]; /* 缺省的文件对象数组 */};
|
|
- namespace:
由进程描述符中的 mmt_namespace域指向12345678910111213struct mnt_namespace {atomic_t count;struct ns_common ns;struct mount * root;struct list_head list;struct user_namespace *user_ns;struct ucounts *ucounts;u64 seq; /* Sequence number to prevent loops */wait_queue_head_t poll;u64 event;unsigned int mounts; /* # of mounts in the namespace */unsigned int pending_mounts;};
以上三个数据结构在task_struct中的使用
2.7 VFS所处理的系统调用
- mount、umount:挂载/卸载文件系统
- sysfs: 获取文件系统信息
- statfs、fstatfs、ustat: 获取文件系统统计信息
- chroot: 更改根目录
- chdir、fchdir、getcwd:操作当前工作目录
- mkdir、rmdir: 创建/删除目录
- getdents、readdir、link、unlink、rename: 操作目录项
- readlink、symlink: 对符号链接进行操作
- chown、fchown、lchown: 更改文件所有者
- chmod、fchmod、utime: 更改文件属性
- open、close、create、write、read等
小结
VFS作为一个抽象层,记录了安装的文件系统类型,建立设备和文件系统的联系,实现面向文件的通用操作,涉及特定文件系统的操作时映射到具体文件系统中去。
目前Linux实现的文件系统可以在fs目录下查看。