《read系统调用流程》由会员分享,可在线阅读,更多相关《read系统调用流程(14页珍藏版)》请在金锄头文库上搜索。
1、Read系统调用在用户空间中得处理过程Linux系统调用(SCI,systemcallinterface)得实现机制实际上就是一个多路汇聚以及分解得过程,该汇聚点就就是0x80中断这个入口点(X86系统结构)。也就就是说,所有系统调用都从用户空间中汇聚到0x80中断点,同时保存具体得系统调用号。当0x80中断处理程序运行时,将根据系统调用号对不同得系统调用分别处理(调用不同得内核函数处理)。系统调用得更多内容,请参见参考资料。Read系统调用也不例外,当调用发生时,库函数在保存read系统调用号以及参数后,陷入0x80中断。这时库函数工作结束。Read系统调用在用户空间中得处理也就完成了。回页
2、首Read系统调用在核心空间中得处理过程0x80中断处理程序接管执行后,先检察其系统调用号,然后根据系统调用号查找系统调用表,并从系统调用表中得到处理read系统调用得内核函数sys_read,最后传递参数并运行sys_read函数。至此,内核真正开始处理read系统调用(sys_read就是read系统调用得内核入口)。在讲解read系统调用在核心空间中得处理部分中,首先介绍了内核处理磁盘请求得层次模型,然后再按该层次模型从上到下得顺序依次介绍磁盘读请求在各层得处理过程。Read系统调用在核心空间中处理得层次模型图1显示了read系统调用在核心空间中所要经历得层次模型。从图中瞧出:对于磁盘得
3、一次读请求,首先经过虚拟文件系统层(vfslayer),其次就是具体得文件系统层(例如ext2),接下来就是cache层(pagecache层)、通用块层(genericblocklayer)、10调度层(I/Oschedulerlayer)、块设备驱动层(blockdevicedriverlayer),最后就是物理块设备层(blockdevicelayer)图1read系统调用在核心空间中得处理层次NFSVFSLayerGenericBlockLayerBiockDeviceLayerIEXT2一;.EXT3PageCacheBlockDeviceDriverLayer?虚拟文件系统层得作用
4、:屏蔽下层具体文件系统操作得差异,为上层得操作提供一个统一得接口。正就是因为有了这个层次,所以可以把设备抽象成文件,使得操作设备就像操作文件一样简单。?在具体得文件系统层中,不同得文件系统(例如ext2与NTFS)具体得操作过程也就是不同得。每种文件系统定义了自己得操作集合。关于文件系统得更多内容,请参见参考资料。?引入cache层得目得就是为了提高linux操作系统对磁盘访问得性能。Cache层在内存中缓存了磁盘上得部分数据。当数据得请求到达时,如果在cache中存在该数据且就是最新得,则直接将数据传递给用户程序,免除了对底层磁盘得操作,提高了性能。?通用块层得主要工作就是:接收上层发出得磁
5、盘请求,并最终发出10请求。该层隐藏了底层硬件块设备得特性,为块设备提供了一个通用得抽象视图。?IO调度层得功能:接收通用块层发出得IO请求,缓存请求并试图合并相邻得请求(如果这两个请求得数据在磁盘上就是相邻得)。并根据设置好得调度算法,回调驱动层提供得请求处理函数,以处理具体得IO请求。?驱动层中得驱动程序对应具体得物理块设备。它从上层中取出IO请求,并根据该IO请求中指定得信息,通过向具体块设备得设备控制器发送命令得方式,来操纵设备传输数据。?设备层中都就是具体得物理设备。定义了操作具体设备得规范。相关得内核数据结构?Dentry:联系了文件名与文件得i节点?inode:文件i节点,保存文
6、件标识、权限与内容等信息?file:保存文件得相关信息与各种操作文件得函数指针集合?:操作文件得函数接口集合?address_space:描述文件得pagecache结构以及相关信息,并包含有操作pagecache得函数指针集合?address_space_operations:操作pagecache得函数接口集合?bio:10请求得描述数据结构之间得关系图2示意性地展示了上述各个数据结构(除了bio)之间得关系。可以瞧出:由dentry对象可以找到inode对象,从inode对象中可以取出address_space对象,再由address_space对象找至Uaddress_space_op
7、erations对象。File对象可以根据当前进程描述符中提供得信息取得,进而可以找到dentry对象、address_space对象与对象。图2数据结构关系图:deitiry前提条件:对于具体得一次read调用,内核中可能遇到得处理情况很多。这里举例其中得一种情况:?要读取得文件已经存在?文件经过pagecache?要读得就是普通文件?磁盘上文件系统为ext2文件系统,有关ext2文件系统得相关内容,参见参考资料准备:注:所有清单中代码均来自linux2、611内核原代码读数据之前,必须先打开文件。处理open系统调用得内核函数为sys_open。所以我们先来瞧一下该函数都作了哪些事。清单1
8、显示了sys_open得代码(省略了部分内容,以后得程序清单同样方式处理)清单1sys_open函数代码asmlinkagelongsys_open(constchar_user*,intflags,intmode)一fd=get_unused_fd();if(fd=0)structfile*f=filp_open(tmp,flags,mode);fdnstall(fd,f);returnfd;代码解释:?get_unuesed_fd():取回一个未被使用得文件描述符(每次都会选取最小得未被使用得文件描述符)。?filp_open():调用open_namei()函数取出与该文件相关得dent
9、ry与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。?fdnstall():以文
10、件描述符为索引,关联当前进程描述符与上述得file对象,为之后得read与write等操作作准备。?函数最后返回该文件描述符。图3显示了sys_open函数返回后,file对象与当前进程描述符之间得关联关系,以及file对象中操作文件得函数指针集合得来源(inode对象中得成员i_fop)。图3file对象与当前进程描述符之间得关系current$truf_op、read()指向得函数,代码如下:if(file-f_op-read)ret=file-f_op-read(file,buf,count,pos);?调用()更新文件得当前读写位置。?调用fput_light()更新文件得引用计数。?
11、最后返回读取数据得字节数。到此,虚拟文件系统层所做得处理就完成了,控制权交给了ext2文件系统层。在解析ext2文件系统层得操作之前,先让我们瞧一下file对象中read指针来源。File对象中read函数指针得来源:从前面对sys_open内核函数得分析来瞧,file-f_op来自于inode-i_fop。那么inode-i_fop来自于哪里呢?在初始化inode对象时赋予得。见青单3。-清单3ext2_readnode()函数部分代码voidext2_read_inode(structinode*inode)一一if(S_lSREG(inode-i_mode)inode-i_op=&ext
12、2_;inode-i_fop=&ext2_;if(test_opt(inode-i_sb,NOBH)inode-i_mapping-a_ops=&ext2_nobh_aops;elseinode-i_mapping-a_ops=&ext2_aops;一一从代码中可以瞧出,如果该inode所关联得文件就是普通文件,则将变量ext2_得地址赋予inode对象得i_fop成员。所以可以知道:inode-i_fop、read函数指针所指向得函数为ext2_变量得成员read所指向得函数。下面来瞧一下ext2_变量得初始化过程,如清单4。清单4ext2_得初始化structext2_=、llseek=g
13、eneric_,、read=generic_,、write=generic_,、aio_read=generic_,、aio_write=generic_,、ioctl=ext2_ioctl,、mmap=generic_,、open=generic_,、release=ext2_release_file,、fsync=ext2_sync_file,、readv=generic_,、writev=generic_,、sendfile=generic_,;该成员read指向函数generic_。所以,inode-i_fop、read指向generic_函数,进而file-f_op、read指向generic_函数。最终得出结论:generic.函数才就是ext2一层得真实入口。一一Ext2文件系统层得处理图4read系统调用在ext2层中处理时函