一、通用文件系统接口
Linux通过虚拟文件系统,使得用户可以直接使用open()、read()、write()访问文件系统,这种协作性和泛型存取成为可能。
不管文件系统是什么,也不管文件系统位于何种介质,采用策略是统一的。
二、文件系统抽象层
为了支持多文件系统,VFS提供了一个通用文件系统模型, 囊括了任何文件系统的常用功能集和行为。
用户空间的write()将调用VFS的sys_write(),然后调用文件系统中文件系统的写方法,最后写进物理介质中去。
三、Unix文件系统
Unix使用了四种和文件系统相关的传统抽象概念:文件、目录项、索引节点、安装点。
从本质上讲文件系统是特殊的数据分层存储结构,它包括文件、目录和相关的控制信息。
文件系统的通用操作包含创建、删除和安装等。多有已安装的文件系统都作为根文件系统树的枝叶出现在系统中。
文件其实可以做一个有序字节串,字节串抵押给字节是文件的头,最后一个字节是文件的尾。
文件通过目录组织起来,文件目录好比一个文件夹,用来容纳相关文件。目录可以包含子目录,层层嵌套,形成文件路径。
Unix系统将文件的相关信息和文件本身这两个概念加以区分,例如访问控制权限、大小、拥有者、创建按时间等信息。
而文件相关的信息被存储在单独的结构中,被称作索引节点。
四、VFS对象及其数据结构
VFS有四个主要对象类型,分别是:
- 超级块对象:代表一个具体的已安装文件系统。
- 索引节点对象:代表一个具体文件
- 目录项对象:代表一个目录项,是路径的要给组成部分
- 文件对象:代表由进程打开的文件
每个对象都有对应的操作对象:
super_operations对象:其中包括内核针对特定文件系统所能调用的方法
inode_operations对象:其中包括内核针对特定文件所能调用的方法
dentry_operations对象:其中包括内核针对特定目录所能调用的方法
file_operations对象:其中包括进程对已打开文件所能调用的方法
如果通用函数提供的基本功能无法满足需求,那么就必须使用实际文件系统的独有方法填充这些函数指针,使其指向文件系统实例。这里的对象是结构体指针,不是类。
五、超级块对象
定义在文件<linux/fs.h>中,创建、管理撤销超级块对象的代码位于文件fs/super.c中。
struct super_block { struct list_head s_list; /* 指向所有超级块的链表 */ dev_t s_dev; /* 设备标识符 */ unsigned long s_blocksize; /* 以字节为单位的块大小 */ unsigned char s_blocksize_bits; /* 以位为单位的块大小 */ unsigned char s_dirt; /* 修改(脏)标志 */ unsigned long long s_maxbytes; /* 文件大小上限 */ struct file_system_type s_type; /* 文件按系统类型 */ struct super_operations s_op; /* 超级块方法 */ struct quotactl_operations *dp_op; /* 磁盘限额方法 */ struct export_operations *s_export_op; /* 导出方法 */ unsigned long s_flags; /* 挂载文件标志 */ struct dentry *s_root; /* 目录挂载点 */ struct rw_semaphore s_umount; /* 卸载信号量 */ struct semaphore s_lock; /* 超级块信号量 */ int s_count; /* 超级块引用计数 */ int s_need_sync; /* 尚未同步标志 */ atomic_t s_active; /* 活动引用计数 */ void *s_security; /* 安全模块 */ struct xattr_handler **s_xattr; /* 扩展的属性操作 */ struct list_head s_inodes; /* inodes链表 */ struct list_head s_dirty; /* 脏数据链表 */ struct list_head s_io; /* 回写链表 */ struct list_head s_more_io; /* 更多回写的链表 */ struct hlist_head s_anon; /* 匿名目录项 */ struct list_head s_files; /* 被分配文件链表 */ struct list_head s_dentry_lru; /* 未被使用目录项链表 */ int s_nr_dentry_unused; /* 链表中目录项的数目 */ struct block_device *s_bdev; /* 相关的块设备 */ struct mtd_info *s_mtd; /* 存储磁盘信息 */ struct list_head s_instances; /* 该类型文件系统 */ struct quota_info s_dquot; /* 限额相关选项 */ int s_frozen; /* frozen标志位 */ wait_queue_head_t s_wait_unfrozen; /* 冻结的等待队列 */ char s_id[32]; /* 文本名字 */ void *s_fs_info; /* 文件系统特殊信息 */ fmode_t s_mode; /* 安装权限 */ struct semaphore s_vfs_rename_sem; /* 重命名信号量 */ u32 s_time_gran; /* 时间戳粒度 */ char *s_subtype; /* 子类型名称 */ char *s_options; /* 已存安装选项 */ };
六、超级块操作
超级块最重要的一个域是s_op,指向超级块的操作函数表。super_operations结构体表示,定义文件<linux/fs.h>:
struct super_operations { struct inode *(*alloc_inode)(struct super_block *sb); void (*destroy_inode)(struct inode *); void (*dirty_inode)(struct inode *); int (*write_inode)(struct inode *, int); void (*drop_inode)(struct inode *); void (*delete_inode)(struct inode *); void (*put_super)(struct super_block *); void (*write_super)(struct super_block *); int (*sync_fs)(struct super_block *sb, int wait); int (*freeze_fs)(struct super_block *); int (*unfreeze_fs)(struct super_block *); int (*statfs)(struct dentry *, struct kstatfs *); int (*remount_fs)(struct super_block *, int *, char *); void (*clear_inode)(struct inode *); void (*umount_begin)(struct super_block *); int (*show_options)(struct seq_file *, struct vfsmount *); int (*show_stats)(struct seq_file *, struct vfsmount *); ssize_t (*quota_read)(struct super_block *, int , char *, size_t, loff_t); ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); int (*bdev_try_to_free_page)(struct super_block *, struct page*, gfp_t); };
当文件需要对其超级块执行操作时,首先要寻找需要的操作方法:
struct inode *alloc_inode(struct super_block *sb) 在给定超级块下创建和初始化一个新的索引节点 void destroy_inode(struct inode *inode) VFS在索引节点脏时会调用此函数。日志文件系统执行该函数更新日志 void write_inode(struct inode *inode, int wait) 用于将给定的索引节点写入磁盘,wait参数指明写操作是否需要同步 void drop_inode(struct inode *inode) 在最后一个指向索引节点的引用被释放后,VFS会调用该函数。 void delete_inode(struct inode *inode) 用于从磁盘上删除给定的索引节点 void put_super(struct super_block *sb) 在卸载文件系统时由VFS调用,用来释放超级块。必须一直持有s_lock锁 void write_super(struct super_block *sb) 用给定的超级块更新磁盘上的超级块。 int sync_fs(struct super_block *sb, int wait) 使文件系统的数据元与磁盘上的文件系统同步。 void write_super_lockfs(struct super_block *sb) 首先禁止对文件系统做该表,再使用给定的超级块更新磁盘上的超级块 void unlockfs(struct super_block *sb) 对文件系统解除锁定,write_super_lockfs()逆操作 int statfs(struct super_block *sb, struct statfs *statfs) VFS通过调用该函数获取文件系统状态。 int remount_fs(struct super_block *sb, int *flags, char *data) 当指定新的安装选项重新安装我呢见系统时,VFS会调用该函数。 void clear_inode(struct inode *inode) VFS调用该函数释放索引节点,并清空包含相关数据的所有页面 void umount_begin(struct super_block *sb) VFS调用该函数中断安装操作。
七、索引节点对象
struct inode { struct hlist_node i_hash; /* 散列表 */ struct list_head i_list; /* 索引节点链表 */ struct list_head i_sb_list; /* 超级块链表 */ struct list_head i_dentry; /* 目录项链表 */ unsigned long i_ino; /* 节点号 */ atomic_t i_count; /* 引用计数 */ unsigned int i_nlink; /* 硬链接数 */ uid_t i_uid; /* 使用者的id */ gid_t i_gid; /* 使用组的id */ kdev_t i_rdev; /* 实际设备标识符 */ u64 i_version; /* 版本号 */ loff_t i_size; /* 以字节为单位的文件大小 */ seqcount_t i_size_seqcount; /* 对i_size进行串行计数 */ struct timespec i_atime; /* 最后访问时间 */ struct timespec i_mtime; /* 最后修改时间 */ struct timespec i_ctime; /* 最后改变时间 */ unsigned int i_blkbits; /* 以位为单位的块大小 */ blkcnt_t i_blocks; /* 文件的块数 */ unsgined short i_bytes; /* 使用的字节数 */ umode_t i_mode; /* 访问权限 */ spinlock_t i_lock; /* 自旋锁 */ struct rw_semaphore i_alloc_sem; /* 嵌入i_sem内部 */ struct semaphore i_sem; /* 索引节点信号量 */ struct inode_operations *i_op; /* 索引节点操作表 */ struct file_operations *i_fop; /* 缺省的索引节点操作 */ struct super_block *i_sb; /* 相关的超级块 */ struct file_lock *i_flock; /* 文件锁链表 */ struct address_space *i_mapping; /* 相关的地址映射 */ struct address_space i_data; /* 设备地址映射 */ struct dquot *i_dquot[MAXQUOTAS]; /* 索引节点的磁盘限额 */ struct list_head i_devices; /* 块设备链表 */ union { struct pipe_inode_info *i_pipe; /* 管道信息 */ struct block_device *i_bdev; /* 块设备驱动 */ struct cdev *i_cdev; /* 字符设备驱动 */ }; unsigned long i_dnotify_mask; /* 目录通知掩码 */ struct dnotify_struct *i_dnotify; /* 目录通知 */ struct list_head inotify_watched; /* 索引节点通知监测链表*/ struct mutex inotify_mutex; /* 保护inotify_watches */ unsigned long i_state; /* 状态标志 */ unsigned long dirtied_when; /* 第一次弄脏数据的时间 */ unsigned int i_flags; /* 文件系统标志 */ atomic_t i_writecount; /* 写者计数 */ void *i_security; /* 安全模块 */ void *i_private; /* fs私有指针 */ };
一个索引节点代表文件系统中的一个文件,它也可以是设备或管道这样的特殊文件。
八、索引节点操作
九、目录项对象
十、目录项操作
十一、文件对象
十二、文件操作
十三、文件系统相关的数据结构
十四、和进程相关的数据结构