Linux VFS与Read/Write系统调用

一、引言

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;
}

如有错误请指正

猜你喜欢

转载自blog.csdn.net/baidu_34045013/article/details/80229859