Chinaunix首页 | 论坛 | 博客
  • 博客访问: 710034
  • 博文数量: 67
  • 博客积分: 994
  • 博客等级: 准尉
  • 技术积分: 1749
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-03 14:10
文章分类
文章存档

2014年(11)

2013年(14)

2012年(14)

2011年(28)

分类: LINUX

2012-05-26 21:14:49

对于文件的操作进行最多的就是文件的读写操作。因此上有必要了解文件的读写执行过程。

文件的读:

文件的读操作以页为单位进行。内核每次会传送几页(文件的预读)。用户发出read()系统调用后,内核先查看要操作的文件是否在缓存中,如果在缓存之中就给进程的用户空间拷贝一份,若所要读的文件的页不在缓冲区,则会在换中区中分配一个页框,然后把相应的页框加入到页高速缓存之中,然后从磁盘读取相应的页到缓冲区并给进程的用户空间拷贝一份。以上就是一个文件的读操作的大体流程。

接下来我们可以看看内核是如何处理文件的读操作的。其主要步骤如下:(2.6.18内核)

1、通过系统调用进入内核,然后获取相应文件的文件对象。

2、在获得文件对象之后,就要获取文件当前的偏移量。

3、调用vfs_read()函数,其主要做如下处理:

检查文件的访问权限;

检查文件对象操作是否定义了file->f_op_read()file->f_op->aio_read();

然后调用access_ok()对文件参数进行粗略验证;

调用rw_rerify_area()检查文件是否有冲突的强制锁;

如果内核定义了读函数则调用,否则调用通用读的处理函数generic_file_read()实现文件的读操作。

4、更新文件的位置

5、释放文件对象。

接下来我们主要对genneric_file_read()进行学习。

genneric_file_read()原型如下:

generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)

其中filp为文件对象的地址;

buf为文件要存放的线性区;

count为要读取的文件的字符个数;

ppos中存放读操作开始出文件偏移量。

首先函数中涉及两个结构体ioveckiocb,接着对两个结构体初始化,其中iovec中定义的两个字段:iov_base指向一个用户地址空间的缓冲区,而iov_len则定义了文件的读取长度。其原型如下:

接着kiocb用于跟踪运行的同步或异步I/O操作的完成状态。然后调用了__generic_file_aio_read(),__generic_file_aio_read()是所有文件系统实现同步和异步操作的通用例程。这个函数的读就使用到了页高速缓存。所谓页高速缓存就是一种对数据页进行操作的磁盘高速缓存,几乎所有的文件的读写都使用到了文件的高速缓存。有一种例外就是直接I/O传送(用户态地址空间中的页与磁盘之间直接传送数据)时绕过页高速缓存。对于页高速缓存来说比较重要的数据结构是address_space对象。它实现了磁盘文件与缓冲区中页的一种链接关系,且在对缓冲区进行管理时使用到了基树,基树的使用可以快速的实现数据页的查找。

上述函数主要做了如下工作:

1、对传入的数据长度进行判断

2、实现了对通用块层的操作

3、在缓冲区长度不为0的情况下,获取一个读操作描述符:read_descriptor_t,其用来存放与单个用户缓冲相关的文件读操作的当前状态。

4、接着调用了do_generic_file_read()函数

do_generic_file_read()函数的实现又调用了 do_generic_mapping_read()函数。而do_generic_mapping_read()函数的实现过程才真正使用到了缓存。

其中mmap指向“地址空间”。

_ra则是文件的预读状态

文件的预读是一种技术。它是在请求前读取普通文件或块设备文件的相邻数页。预读可以极大的提高磁盘的性能,使得在顺序读取文件时不需要等待请求的数据。但是预读对于随机访问文件来说是没有用的。

filp:则是要读取的文件

ppos:当前文件的位置

desc:读描述符

actor:读取的方法

这个函数的主要操作有通过文件的偏移量获得缓存中的索引inode。然后通过一个循环实现文件的读取。

1、判断inode是否越界

2、调用cond_resched()检查当前进程的标志。

3、如果有预读则调用page_cache_readahead()进行预读。

4、然后主要是判断缓存中是否存在要查找的页,如果不在缓存则要先进行页框分配然后再加入到页高速缓存中。

5、真正读操作的实现要调用readpage,而readpage通常不会直接编写代码实现,而是通过内核的标准函数执行。如mpage_readpage和mpage_readpages等。它可以有效的激活从物理磁盘到页高速缓存的I/O数据传输。

最后就是对相关文件的更新操作等。


具体的读操作所经过如下处理层次:

阅读(3338) | 评论(0) | 转发(0) |
0

上一篇:cache学习笔记

下一篇:内核同步

给主人留下些什么吧!~~