read()/write()的生命旅程-系列

http://blog.sina.com.cn/s/blog_a558c25a0102v7nj.html
read()/write()是libc最常用的库函数,那么在application调用了read()/write()之后,发生了哪些事情,数据经过了怎样的流程才从media上读出到用户的buffer里,或是从用户buffer被写到media上的呢?本文将通过以下章节详细阐述整个过程。
第一章:文件系统基础
  1. 整个文件系统Overview
  2. 从libc到SYSCALL
  3. VFS的分发
  4. 重要概念:file, inode, page cache, file mapping, address space
第二章:read()
  1. read():从file operation到page cache
  2. read():从page cache到bio
  3. 重要概念:page cache, buffer head和bio
第三章:write()
  1. write():从file operation到page cache
  2. write():从page cache到writeback queue
第四章:writeback:
  1. writeback的init, register
  2. 从writeback queue到bio
第五章:从bio到media
  1. block layer的核心:request queue
  2. bio进入request queue
  3. ioscheduler
  4. request的接力
第一章:文件系统基础
1. 整个文件系统Overview
下图显示了Linux中文件系统涉及的所有模块,我们会在之后的章节了一个一个描述他们的职责和关系。

2. 从libc到SYSCALL
这一部分比较简单,libc调用了Kernel的SYSCALL read()/write():
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count)。
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE;

return do_sys_open(AT_FDCWD, filename, flags, mode);
}
本文之后的read()/write()均是指kernel的SYSCALL read()/write。

3. VFS的分发
VFS的全称是 Virtual File System,即虚拟文件系统。他是位于各种实际的文件系统如ext2, ext3, nfs和用户层之间的接口,他的存在意义是:
  • 对用户层而言:VFS屏蔽了各种实际文件系统的差异点,为用户层提供了一套统一的接口来进行文件操作,用户不必关心实际的文件系统是什么。这套统一接口就是文件操作相关的一系列SYSCALL,如open(), read(), write(), seek()等。
  • 对于各种实际文件系统而言:VFS提供了一套统一接口,只要实现了这套接口,就能为用户提供这种文件系统的支持。实际的文件系统不需要关心用户会进行怎样的操作。这套接口就是各种文件系统注册到VFS的file_operations结构。下面是ext2的file_operations:
const struct file_operations ext2_file_operations = {
  .llseek     = generic_file_llseek,
  .read       = do_sync_read,
  .write      = do_sync_write,
  .aio_read   = generic_file_aio_read,
  .aio_write  = generic_file_aio_write,
  unlocked_ioctl = ext2_ioctl,
#ifdef CONFIG_COMPAT
  .compat_ioctl   = ext2_compat_ioctl,
#endif
  .mmap       = generic_file_mmap,
  .open       = dquot_file_open,
  .release    = ext2_release_file,
  .fsync      = ext2_fsync,
  .splice_read    = generic_file_splice_read,
  .splice_write   = generic_file_splice_write,
};
在 发生SYSCALL read()/write()后,VFS会根据fd来判断该文件是哪种文件系统的文件,并调用相应的file_operations.read()来处理 。fd属于什么文件系统的对应关系是在read()/write()之前的open()时就已经建立的。下图表明了VFS的作用(假设APP要read/write的文件在ext2文件系统上)。

4. 重要概念:file, inode, page cache, address space
在讲解read()/write()的详细流程前,必须先理解文件系统的几个重要概念,否则后面的都是天书。

file:  是进程里一个打开的文件,它的有效范围就是打开它的进程。 如通过open()获得一个fd,这个fd只在这个进程里代表这个文件,对于其他进程这个fd无意义 。文件系统中的一个文件abc.txt,如果在process 1中fd1=open()一次,在proces 2中也fd2=open()一次,fd1和fd2是完全独立的,虽然他们打开的是media上的同一个文件。
inode: inode是kernel为每一个文件(目录也是文件)建立的数据结构。inode和media上实际的文件一一对应。前面提到的fd1和fd2打开的是同一个文件,所以他们指向一个inode。也就是说一个文件在许多进程中被打开,每个进程有自己的file, 但是这些file都指向同一个inode。这种指向是通过file->f_mapping->host来实现的。
page cache: 为了加快文件读写的速度,kernel会把最近访问的inode(也就是文件)的数据缓存在内存里,我们知道linux的内存管理的是以页为单位的,这些inode数据的缓存就叫做page cache。 注意是inode的数据不是inode本身。inode->i_mapping->page_tree指向了一个inode的被kernel缓存的所有page cache的tree。
file mapping:  文件被load到page cache里之后page还是物理地址,通过mmap2()或kmap()可以将page map到虚拟地址上,这样用户或kernel就可以读写page cache里的内容了。这个过程叫做file mapping。mmap2()是系统调用,将文件load到page cache并map到user space。kmap()是kernel里的函数,将page映射到kernel space。
address space:  这是一个比较难理解的概念。抽象的说 struct address_space是用来描述kernel里某一实体的物理缓存page ,以及这些page对应的虚拟地址映射的关系的。在文件系统这个实体就是inode,所以address_space->host != NULL,必须指向一个inode。在其他一个场合address_space->host可以为NULL。inode->i_mapping指向它的address space。每个进程里的file也有一个file->f_mapping,其实file->f_mapping在open()的时候就已经file->f_mapping=inode->i_mapping了。所以,所有同一个inode的file会共享address space。
一个inode的所有已经被缓存的page都在inode->i_mapping->page_tree里。这些page被map到所有进程的虚拟地址空间的描述即很多个vm_area_struct都在inode->mapping->i_mmap和inode->mapping->nonlinear里。注意:一个inode的page可以被不同的进程map,如Preocess 1和Process 2都map了file这个文件的page,因为每个进程的虚拟地址是独立的,所以在inode->mapping->i_mmap里有2个vm_area_struct分别描述在Process 1和Process 2里的map关系。
struct address_space里还有一个重要的成员struct address_space_operations *a_ops。address_space_operations定义了page cache的一系列操作,如.readpage(), .writepage()等。对于像linux这样支持page cache的文件系统,page cache的操作至关重要。 因为所有的文件读写都要通过page cache ,对文件的读写最后都要转化为page cache的读写。address_space_operations里的这些函数指针是每个特定的文件系统,如ext2, ext3等必须要实现的。在后面我们将详细阐述。
下面这张图显示了file, inode, page cache, file mapping,address space之间的关系。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值