linux内核分析:read过程分析

读数据时,进行read函数调用,进入陷阱门调用到函数:

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) // (/fs/read_write.c) 
    --> ret = __vfs_read(file, buf, count, pos);
        -->if (file->f_op->read)
                return file->f_op->read(file, buf, count, pos);
            else if (file->f_op->read_iter)
                return new_sync_read(file, buf, count, pos);

在linux3.16后文件系统的file_operations操作一般已经不使用操作read函数操作了,可以进入到源码/fs下面的文件系统的file.c里面看下。

分析new_sync_read –>
三个数据结构:

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

//存放用户空间传入的数据和长度

struct kiocb kiocb;
// kiocb --> kernel i/o control block

struct iov_iter iter;   
// struct iovec 的迭代器

迭代器原理 : https://lwn.net/Articles/625077/

内核空间和用户空间之间的数据传输,需要解除隔离操作
get_fs()和set_fs()解析 :
http://blog.chinaunix.net/uid-24237502-id-35023.html

ret = filp->f_op->read_iter(&kiocb, &iter);
   -->generic_file_read_iter

分为DIRECT 和 使用缓存
ps: DIRECT,使用方式为open时使用O_DIRECT, 他与使用缓存的区别就是他不使用内核提供的缓存模式,绕过缓存模式,直接进行磁盘的读写操作。有特殊需要的可以使用这种模式进行操作。

分析缓存方式:

do_generic_file_read(file, &iocb->ki_pos, iter, retval)

ps :struct file_ra_state *_ra,预读参数,预读窗口大小,命中计数器,控制标志等参数

页高速缓存是linux内核实现的一种主要磁盘缓存,它主要用来减少对磁盘的IO操作,具体地讲,是通过把磁盘中的数据缓存到物理内存中,把对磁盘的访问变为对物理内存的访问,从而加快读写速度。

每个inode都有一个address_space对象,由该address_space来维护该inode所拥有的所有页缓存,即每个inode都需要一个address_space对象,每个inode维护一个基树。
如果假设系统维护一个大的基树,然后每个inode的基树都挂在上面,会有锁竞争,查找耗时等问题。
基数树分析:
http://blog.csdn.net/lonewolfxw/article/details/7953805

当我们读取一个文件的时间,首先会检查数据是否已经缓存,如果没有就会预读取,将数据加载入缓存页。

do_generic_file_read
    --> page = find_get_page(mapping, index);

查找不到情况下:

page = __page_cache_alloc(gfp_mask);
        add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_RECLAIM_MASK)

这里写代码片最近最少使用(LRU)块高速缓存
(LRU的使用牵涉到缓存的回收处理)
LRU原理分析:http://flychao88.iteye.com/blog/1977653
LRU程序分析:http://blog.csdn.net/yunsongice/article/details/5850807

缓存页预读取
page_cache_sync_readahead

预读取过程代码分析:http://blog.csdn.net/vah101/article/details/7709820
最后调用
mapping->a_ops->readpages
或者
mapping->a_ops->readpage
进行读取操作

回到do_generic_file_read里下面调用copy_page_to_iter
从缓存页中拷贝数据到iter里

大概的画了一点流程图:
read过程流程

总结:读取文件过程的时候,先通过基数树去检查数据是否已经缓存到缓存页中了,如果没有则执行预读取过程将数据进行缓存处理,缓存完成后直接在缓存页中数据读取,如果有则直接读取。

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值