read系统调用流程

  • 格式:doc
  • 大小:161.50 KB
  • 文档页数:14

下载文档原格式

  / 14
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Read 系统调用在用户空间中得处理过程

Linux 系统调用(SCI,system call interface)得实现机制实际上就是一个多路汇聚以及分解得过程,该汇聚点就就是 0x80 中断这个入口点(X86 系统结构)。也就就是说,所有系统调用都从用户空间中汇聚到 0x80 中断点,同时保存具体得系统调用号。当 0x80 中断处理程序运行时,将根据系统调用号对不同得系统调用分别处理(调用不同得内核函数处理)。系统调用得更多内容,请参见参考资料。

Read 系统调用也不例外,当调用发生时,库函数在保存 read 系统调用号以及参数后,陷入 0x80 中断。这时库函数工作结束。Read 系统调用在用户空间中得处理也就完成了。

回页首

Read 系统调用在核心空间中得处理过程

0x80 中断处理程序接管执行后,先检察其系统调用号,然后根据系统调用号查找系统调用表,并从系统调用表中得到处理 read 系统调用得内核函数 sys_read ,最后传递参数并运行 sys_read 函数。至此,内核真正开始处理 read 系统调用(sys_read 就是 read 系统调用得内核入口)。

在讲解 read 系统调用在核心空间中得处理部分中,首先介绍了内核处理磁盘请求得层次模型,然后再按该层次模型从上到下得顺序依次介绍磁盘读请求在各层得处理过程。

Read 系统调用在核心空间中处理得层次模型

图1显示了 read 系统调用在核心空间中所要经历得层次模型。从图中瞧出:对于磁盘得一次读请求,首先经过虚拟文件系统层(vfs layer),其次就是具体得文件系统层(例如 ext2),接下来就是 cache 层(page cache 层)、通用块层(generic block layer)、IO 调度层(I/O scheduler layer)、块设备驱动层(block device driver layer),最后就是物理块设备层(block device layer)

图1 read 系统调用在核心空间中得处理层次

•虚拟文件系统层得作用:屏蔽下层具体文件系统操作得差异,为上层得操作提供一个统一得接口。正就是因为有了这个层次,所以可以把设备抽象成文件,使得操作设备就像操作文件一样简单。

•在具体得文件系统层中,不同得文件系统(例如 ext2 与 NTFS)具体得操作过程也就是不同得。每种文件系统定义了自己得操作集合。关于文件系统得更多内容,请参见参考资料。

•引入 cache 层得目得就是为了提高 linux 操作系统对磁盘访问得性能。

Cache 层在内存中缓存了磁盘上得部分数据。当数据得请求到达时,如果在 cache 中存在该数据且就是最新得,则直接将数据传递给用户程序,免除了对底层磁盘得操作,提高了性能。

•通用块层得主要工作就是:接收上层发出得磁盘请求,并最终发出 IO 请求。该层隐藏了底层硬件块设备得特性,为块设备提供了一个通用得抽象视图。

•IO 调度层得功能:接收通用块层发出得 IO 请求,缓存请求并试图合并相邻得请求(如果这两个请求得数据在磁盘上就是相邻得)。并根据设置好得调度算法,回调驱动层提供得请求处理函数,以处理具体得 IO 请求。

•驱动层中得驱动程序对应具体得物理块设备。它从上层中取出 IO 请求,并根据该 IO 请求中指定得信息,通过向具体块设备得设备控制器发送命

令得方式,来操纵设备传输数据。

•设备层中都就是具体得物理设备。定义了操作具体设备得规范。

相关得内核数据结构:

•Dentry : 联系了文件名与文件得 i 节点

•inode : 文件 i 节点,保存文件标识、权限与内容等信息

•file : 保存文件得相关信息与各种操作文件得函数指针集合

• :操作文件得函数接口集合

•address_space :描述文件得 page cache 结构以及相关信息,并包含有操作 page cache 得函数指针集合

•address_space_operations :操作 page cache 得函数接口集合

•bio : IO 请求得描述

数据结构之间得关系:

图2示意性地展示了上述各个数据结构(除了 bio)之间得关系。可以瞧出:由dentry 对象可以找到 inode 对象,从 inode 对象中可以取出 address_space 对象,再由 address_space 对象找到 address_space_operations 对象。

File 对象可以根据当前进程描述符中提供得信息取得,进而可以找到 dentry 对象、 address_space 对象与对象。

图2 数据结构关系图:

前提条件:

对于具体得一次 read 调用,内核中可能遇到得处理情况很多。这里举例其中得一种情况:

•要读取得文件已经存在

•文件经过 page cache

•要读得就是普通文件

•磁盘上文件系统为 ext2 文件系统,有关 ext2 文件系统得相关内容,参见参考资料

准备:

注:所有清单中代码均来自 linux2、6、11 内核原代码

读数据之前,必须先打开文件。处理 open 系统调用得内核函数为 sys_open 。所以我们先来瞧一下该函数都作了哪些事。清单1显示了 sys_open 得代码(省略了部分内容,以后得程序清单同样方式处理)

清单1 sys_open 函数代码

asmlinkage long sys_open(const char __user * , int flags, int mode) {

……

fd = get_unused_fd();

if (fd >= 0) {

struct file *f = filp_open(tmp, flags, mode);

fd_install(fd, f);

}

……

return fd;

……

}

代码解释:

•get_unuesed_fd() :取回一个未被使用得文件描述符(每次都会选取最小得未被使用得文件描述符)。

•filp_open() :调用 open_namei() 函数取出与该文件相关得 dentry 与inode (因为前提指明了文件已经存在,所以 dentry 与 inode 能够查找到,不用创建),然后调用 dentry_open() 函数创建新得 file 对象,并用dentry 与 inode 中得信息初始化 file 对象(文件当前得读写位置在

file 对象中保存)。注意到 dentry_open() 中有一条语句:

f->f_op = fops_get(inode->i_fop);

这个赋值语句把与具体文件系统相关得,操作文件得函数指针集合赋给了 file 对象得 f _op 变量(这个指针集合就是保存在 inode 对象中得),在接下来得sys_read 函数中将会调用 file->f_op 中得成员 read 。