一、引言
VFS(虚拟文件系统,Virtual File System)是物理文件系统与服务之间的接口层,向下对文件系统提供标准接口,方便其他文件系统移植,向上对应用层提供标准文件操作接口,使open()、read()、write()等系统调用可以跨越各种文件系统和不同介质执行。
二、VFS对象及数据结构
超级块对象super_block,对应已装载的文件系统
索引节点对象inode,对应介质上的一个文件
目录项对象dentry,对应一个目录项
文件对象file,对应由进程打开的文件
(在linux/fs.h中定义)
1、超级块对象
- 超级块用来描述整个文件系统的信息
- 每个具体的文件系统都有自己的超级块
- 所有超级块对象以双向循环链表的形式连接
- 超级块对象在文件系统装载时创建,保存在内存中,在文件系统卸载时自动删除
2、索引节点对象
- 索引节点对象包含了内核在操作文件或目录时需要的全部信息
3、目录项对象
- 目录项对象没有对应的磁盘数据结构
- 三种状态:被使用、未使用、负状态
4、文件对象
- 文件对象表示进程已打开的文件
- 由open()系统调用创建,由close()系统调用撤销
- 多个进程同时打开和操作同一对象,存在多个对应的文件对象
- 类似于目录项对象,文件对象没有对应的磁盘数据,通多dentry指针指向相关的目录项对象,目录项会指向相关的索引节点,索引节点会记录文件是否是脏的
三、read、write
read和write系统调用在内核中的入口函数为sys_read和sys_write,定义在fs/read_write.c中,sys_read和sys_write调用fget_light通过fd得到对应的file结构,然后调用vfs_read和vfs_write,调用特定文件系统的读写操作(包括权限及文件锁检查、同步异步读写、块IO等操作),最后调用fput_light释放file对象,sys_read和sys_write返回,read和write系统调用结束。
sys_read:
asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
{
struct file *file;
ssize_t ret = -EBADF;
int fput_needed;
file = fget_light(fd, &fput_needed); //通过fd从current进程文件对象table里找出file对象
if (file) {
ret = vfs_read(file, buf, count, &file->f_pos); //调用vfs_read,这里会调用特定文件系统的file_operations->read做读动作
fput_light(file, fput_needed); //释放file对象
}
return ret;
}
sys_write:
asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
{
struct file *file;
ssize_t ret = -EBADF;
int fput_needed;
file = fget_light(fd, &fput_needed); //通过fd从current进程文件对象table里找出file对象
if (file) {
ret = vfs_write(file, buf, count, &file->f_pos); //调用vfs_write,这里会调用特定文件系统的file_operations->write做写动作
fput_light(file, fput_needed); //释放file对象
}
return ret;
}
vfs_read:
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
struct inode *inode = file->f_dentry->d_inode;
ssize_t ret;
if (!(file->f_mode & FMODE_READ))
return -EBADF;
if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
return -EINVAL;
ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count);
if (!ret) {
ret = security_file_permission (file, MAY_READ);
if (!ret) {
if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);
else
ret = do_sync_read(file, buf, count, pos);
if (ret > 0)
dnotify_parent(file->f_dentry, DN_ACCESS);
}
}
return ret;
}
vfs_write:
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
struct inode *inode = file->f_dentry->d_inode;
ssize_t ret;
if (!(file->f_mode & FMODE_WRITE))
return -EBADF;
if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
return -EINVAL;
ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count);
if (!ret) {
ret = security_file_permission (file, MAY_WRITE);
if (!ret) {
if (file->f_op->write)
ret = file->f_op->write(file, buf, count, pos);
else
ret = do_sync_write(file, buf, count, pos);
if (ret > 0)
dnotify_parent(file->f_dentry, DN_MODIFY);
}
}
return ret;
}
如有错误请指正