第 8 章 虚拟文件系统(7)

目录

8.5 标准函数

8.5.1 通用读取例程

8.5.2 失效机制

8.5.3 权限检查

8.6 小结


本专栏文章将有70篇左右,欢迎+关注,查看后续文章。

8.5 标准函数

大多数文件系统中 file_operations 的 read,write 分别为:

        do_sync_read,do_sync_write。

如:

const   struct file_operations    ext4_file_operations   =   {

        .read    =    do_sync_read,

        .write    =    do_sync_write,

        ...

}

inode 是文件属性,而不是数据本身,数据存在块设备中。

内存保存块设备数据的方式:

        1. mmap映射:

                即映射到用户虚拟地址空间。

                特点:适用大文件,不预加载,访问时加载,不浪费内存。

        2. 页缓存:

                缓存到内核内存中。

                特点:

                        预加载,加速读写,进程通过标准文件读写操作。

                        适用小文件,不立即写回块设备。

所以读写文件时,需先查询数据是否缓存在内存?

        若在缓存,则读写页缓存,否则向块设备发出读请求。

拓展

fd   =   open("myfile",    O_RDWR | O_CREAT | O_SYNC | O_DIRECT,    S_IRUSR | S_IWUSR);

        O_DIRECT:不使用内核缓冲区,直接读写磁盘文件。

        O_SYNC:以同步IO方式,打开文件。

O_DIRECT:

        含义:

                用户空间直接读磁盘文件,绕过页高速缓存。也称裸IO(RAW IO)。

        应用场景:

                性能要求极高的场景,如数据库系统(需快速访问大量数据)。

        注意:

                1. 一个进程以O_DIRECT访问文件,而另一进程以页缓存打开同一文件,两个进程读写数据可能不一致。

                2. 某些文件系统可能不支持O_DIRECT。如某些网络文件系统。

                3. 通常结合O_SYNC或O_DSYNC,以确保数据的完整性和一致性。

O_SYNC:

        含义:

                写操作后,数据不仅写到内核缓冲区,还要同步刷新到磁盘。

        好处:

                实现数据同步。

O_SYNC 和 O_DSYNC 区别:

        O_DSYNC 不要求元数据的同步。

        O_SYNC 要求数据和元数据都要同步。

8.5.1 通用读取例程

struct   file_operations    ext4_file_operations    =    {

        .read    =    do_sync_read,

                // 同步读,将阻塞调用进程。

        .aio_read    =    generic_file_aio_read,

                // 异步读,提交请求后,立即返回,不必等待数据读取完成。

};

ssize_t    do_sync_read(struct file    *filp,    char __user   *buf,    size_t   len,    loff_t   *ppos)

{

        struct iovec    iov   =   { .iov_base  =   buf,    .iov_len   =   len };

        struct kiocb    kiocb;

        init_sync_kiocb( &kiocb,    filp );

        kiocb.ki_pos    =    *ppos;

        kiocb.ki_left    =    len;

        kiocb.ki_nbytes    =    len;

        ret    =    filp->f_op->aio_read(&kiocb,    &iov,    1,    kiocb.ki_pos);

                //aio_read 指向 generic_file_aio_read()

        if (-EIOCBQUEUED    ==    ret) 若读请求正在排队

                ret    =    wait_on_sync_kiocb(&kiocb); //阻塞,等待读完成。

        *ppos    =    kiocb.ki_pos;

        return    ret;

}

1. 异步读取

内核异步读函数如下:

2. 从映射中读取

do_generic_mapping_read():已被淘汰。

原理如下:

操作流程:

         1. 检查文件内容是否在页缓存中。

                struct page    *find_get_page(struct address_space    *mapping,    pgoff_t    offset)

                使用方法:

                        page    =    find_get_page(filp->i_mapping,    index);

                作用:

                        检查某文件的指定偏移是否被缓存到内存页上。

        2. 若没有缓存,则预读并缓存。

                page_cache_sync_readahead()

        3. 用 Page_Uptodate 检查,页缓存数据是否是最新的。

                若不是最新,调用mapping->a_ops_readpage:从块设备读数据到页。

        4. 若页是最新,调用 mark_page_accessed。

                void    mark_page_accessed(struct page    *page);

                作用:

                        更新页访问的时间戳,选择换出的页时使用该标记。

                注意:

                        匿名页不需要更新访问时间戳。

        5. 将页映射到用户地址空间

                即actor函数指针。

        PageAnon():

                作用:检查页面是否是匿名页面。

        PageReferenced()

                作用:检查是否已被访问过。

预读机制:

8.5.2 失效机制

filemap_fault:

        作用:

                读取未保存在缓存中的页。

        最终也调用:

                struct   address_space   mapping -> a_ops -> readpage();

8.5.3 权限检查

int    inode_permission(struct   inode    *inode,    int   mask)

        作用:

                检查是否允许以指定权限访问inode。

        使用场景:

                chdir/chroot系统调用。

int    inode_permission(struct inode  *inode,    int   mask)

{

        sb_permission(inode->i_sb,    inode,    mask);

        __inode_permission(inode,    mask);

}

mask:

        即检查是否可以访问的权限。

        如MAY_READ,MAY_WRITE,MAY_EXEC。

1. sb_permission:

                若mask = MAY_WRITE,根据 sb->s_flags 确认不是只读文件系统。

2. __inode_permission:

        通常调用:generic_permission(inode,   mask);

                包括 check_acl()

struct   inode_operations    sysfs_inode_operations    =    {

        .permission    =    sysfs_permission,

                //也调用 generic_permission(inode,    mask);

};

sysfs_permission  ->  generic_permission  ->  check_acl

检查用户,组,other的 inode 权限。

8.6 小结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山下小童

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值