虚拟地址空间通常是与进程密切相关的概念,而不是文件系统。虚拟地址空间是为了提供进程对内存的抽象和隔离而设计的。
文件系统不使用页表,而是以页为单位载入文件,操作系统直接使用物理地址。
虚拟文件系统是linux内核的一个核心子系统。、
虚拟文件系统的目的:通过一个抽象层,存储设备使用不同的文件系统都可以通过相同的接口访问:open(),red(),write();
文件系统抽象层
linux能支持各种文件系统,就是因为有文件系统抽象层。
调用过程:write(fd,buf,len);
用户空间write()->虚拟文件系统sys_write()->硬件的文件系统的写方法——>物理介质
Unix文件系统
Unix使用了四种文件系统的抽象概念:文件,目录项,索引节点和安装点(mount point)。
在Unix中,目录属于普通文件,它列出包含在其中的所有文件。
inode和元数据
Unix把文件的相关信息和文件本身这两个概念加以区分,已经是说,文件的元数据(控制权限,大小,创建者。。)被存储在一个单独的数据结构中,该结构被称为索引节点(inode:index node的缩写)。
将元数据和实际数据分开存储是一种思想
Unix文件系统,在物理磁盘布局中也是按照这种思想实现的,在磁盘上,文件(目录也是文件)的元数据存储在单独的几个块中(按照索引顺序)。
控制信息被集中存储在磁盘的超级块中。
VFS对象及数据结构
VFS采用的是面向对象。使用一组数据结构来代表通用文件对象。
VFS主要有四个对象类型:
- 超级块对象,它代表一个已安装的文件系统
- 索引节点对象,它代表一个具体文件(可以是目录文件)。
- 目录项对象,目录项。
- 文件对象,有对象打开的文件。
每个数据结构其中都包含操作函数(以函数指针的形式存储在数据结构中)。
超级块对象
每个文件系统都必须实现超级块对象,存储文件系统的信息,通常对应于存放在磁盘特定扇区中的文件系统超级块。不基于磁盘的文件系统,会在使用时动态创建超级块。
struct super_block {
/* 文件系统特定的信息和操作 */
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; // 超级块标志
const char *s_id; // 文件系统的唯一标识符
unsigned int s_blocksize; // 块大小
unsigned char s_blocksize_bits; // 块大小的位数
unsigned char s_dirt; // 超级块的脏标志
int s_count; // 超级块的引用计数
atomic_t s_active; // 超级块的活跃引用计数
struct hlist_head s_inode_lru; // 超级块关联的Inode的LRU链表头
struct list_head s_list; // 全局超级块链表
struct list_head s_instances; // 文件系统实例链表
/* 与文件系统类型相关的信息 */
const struct file_system_type *s_type; // 文件系统类型
const struct fs_context_operations *s_fs_info; // 文件系统信息
struct fscrypt_info *s_cop; // 文件系统加密信息
/* 与底层存储介质相关的信息 */
struct block_device *s_bdev; // 超级块对应的块设备
struct backing_dev_info *s_bdi; // 超级块的后备设备信息
/* 文件系统挂载点的信息 */
struct mtd_info *s_mtd; // 关联的Memory Technology Device(MTD)信息
struct gendisk *s_disk; // 关联的块设备信息
struct hlist_head s_dentry_lru; // 超级块关联的Dentry的LRU链表头
/* 其他字段和操作省略... */
};
索引节点对象:存储文件的元数据
内核是根据索引节点对象的信息来操作文件的。
对于Unix风格的文件系统,这些信息可以从磁盘读入。没有索引对象信息,则需要现场创建。
struct inode {
umode_t i_mode; // 文件的权限和类型
unsigned short i_opflags; // 操作标志
kuid_t i_uid; // 文件的用户标识符
kgid_t i_gid; // 文件的组标识符
dev_t i_rdev; // 设备文件的设备号
loff_t i_size; // 文件大小
struct timespec i_atime; // 最后访问时间
struct timespec i_mtime; // 最后修改时间
struct timespec i_ctime; // 最后状态改变时间
struct super_block *i_sb; // 超级块指针
const struct inode_operations *i_op; // Inode 操作
struct file_operations *i_fop; // 文件操作
struct address_space *i_mapping; // 地址空间对象:即文件的内存中的位置信息
unsigned long i_ino; // 文件的 inode 号
atomic_t i_count; // 引用计数
unsigned int i_flags; // Inode 标志
struct list_head i_wb_list; // 写回列表
struct list_head i_lru; // LRU 列表
struct list_head i_sb_list; // 超级块链表
struct hlist_node i_hash; // Inode hash 链表
struct dquot *i_dquot[MAXQUOTAS]; // 磁盘配额
struct file_lock *i_flock; // 文件锁
unsigned long i_state; // Inode 状态
struct mutex i_mutex; // Inode 互斥锁
struct rw_semaphore i_alloc_sem; // Inode 分配信号量
// 其他字段和操作省略...
};
一个索引节点也可以代表设备或者管道这样的特殊文件。
目录项对象:在磁盘中没有对应的数据结构
目录项对象就是为了方便查找操作而引入的,真正操作文件还需要inode对象。
VFS根据字符串形式的路径名现场创建它,其没有真正保存在磁盘上,所以目录项结构体没有是否被修改的标志(不需要写回磁盘)。
文件对象
表示进程已打开的文件。进程直接处理的是文件对象。
文件是已打开的文件在内存中的表示。该对象由open()系统调用创建,由close()系统调用撤销。
文件对象只在进程层面表示已打开的文件,但其指向的对应的索引节点和目录项对象是唯一的。
struct file {
struct file_operations *f_op; // 文件操作函数指针集合
loff_t f_pos; // 文件当前位置(偏移量)
struct inode *f_inode; // 与文件关联的 inode 结构体指针
struct address_space *f_mapping; // 文件地址空间指针
unsigned int f_flags; // 文件状态和标志
struct file_ra_state f_ra; // 文件预读取状态
void *private_data; // 指向文件特定私有数据的指针
// 其他字段和操作省略...
};
其通过访问inode对象来操作文件。
和进程有关的数据结构
每一个进程都有一组自己打开的文件。有两个数据结构将VFS层和系统进程紧密联系。
进程自己打开的文件
struct files_struct {
atomic_t count; // 引用计数
struct fdtable *fdt; // 指向文件描述符表的指针
spinlock_t file_lock; // 文件表的自旋锁
unsigned int next_fd; // 下一个可用的文件描述符
unsigned long close_on_exec; // 需要在执行新程序时关闭的文件描述符标志
unsigned long open_fds; // 已打开文件描述符的位图
struct file *fd_array[0]; // 指向打开文件的指针数组
};
- fdt:指向 struct fdtable 的指针,表示文件描述符表。fdtable 包含了打开文件的数组以及相应的控制信息。
- next_fd:表示下一个可用的文件描述符。在进程打开新文件时,会从这个位置开始分配文件描述符。
- close_on_exec 和 open_fds:用于标记在执行新程序时需要关闭的文件描述符。
- fd_array:这是一个指针数组,指向打开文件的指针
进程关联的文件系统状态
struct fs_struct {
int users; // 引用计数
spinlock_t lock; // 用于保护结构的自旋锁
struct path root; // 进程的根目录
struct path pwd; // 进程的当前工作目录
struct fdtable *files; // 文件描述符表
// 其他字段和操作省略...
};
它包含了与进程关联的文件系统状态,包括当前工作目录、根目录、以及与文件描述符表相关的信息。