read系统调用流程
简介几种系统调用函数:write、read、open、close、ioctl

简介⼏种系统调⽤函数:write、read、open、close、ioctl 在 Linux 中,⼀切(或⼏乎⼀切)都是⽂件,因此,⽂件操作在 Linux 中是⼗分重要的,为此,Linux 系统直接提供了⼀些函数⽤于对⽂件和设备进⾏访问和控制,这些函数被称为系统调⽤(syscall),它们也是通向操作系统本⾝的接⼝。
⼀、系统调⽤ 系统调⽤就是 Linux 内核提供的⼀组⽤户进程与内核进⾏交互的接⼝。
这些接⼝让应⽤程序受限的访问硬件设备,提供了创建新进程并与已有进程进⾏通信的机制,也提供了申请操作系统其他资源的能⼒。
系统调⽤⼯作在内核态,实际上,系统调⽤是⽤户空间访问内核空间的唯⼀⼿段(除异常和陷⼊外,它们是内核唯⼀的合法⼊⼝)。
系统调⽤的主要作⽤如下:1)系统调⽤为⽤户空间提供了⼀种硬件的抽象接⼝,这样,当需要读写⽂件时,应⽤程序就可以不⽤管磁盘类型和介质,甚⾄不⽤去管⽂件所在的⽂件系统到底是哪种类型;2)系统调⽤保证了系统的稳定和安全。
作为硬件设备和应⽤程序之间的中间⼈,内核可以基于权限、⽤户类型和其他⼀些规则对需要进⾏的访问进⾏判断;3)系统调⽤是实现多任务和虚拟内存的前提。
要访问系统调⽤,通常通过 C 库中定义的函数调⽤来进⾏。
它们通常都需要定义零个、⼀个或⼏个参数(输⼊),⽽且可能产⽣⼀些副作⽤(会使系统的状态发⽣某种变化)。
系统调⽤还会通过⼀个 long 类型的返回值来表⽰成功或者错误。
通常,⽤⼀个负的值来表明错误,0表⽰成功。
系统调⽤出现错误时,C 库会把错误码写⼊ errno 全局变量,通过调⽤ perror() 库函数,可以把该变量翻译成⽤户可理解的错误字符串。
⼆、⼏种常⽤的系统调⽤函数2.1 write 系统调⽤ 系统调⽤ write 的作⽤是把缓冲区 buf 的前 nbytes 个字节写⼊与⽂件描述符 fildes 关联的⽂件中。
它返回实际写⼊的字节数。
如果⽂件描述符有错或者底层的设备驱动程序对数据块长度⽐较敏感,该返回值可能会⼩于 nbytes。
简述系统调用的执行过程

简述系统调用的执行过程
系统调用是指用户程序通过操作系统提供的接口来请求操作系统完成某些特殊操作的过程。
这些特殊操作通常是硬件相关的,例如读取磁盘文件、发送数据包、申请内存等。
系统调用的执行过程可以分为以下几个步骤:
1. 用户程序向操作系统发起系统调用请求。
这个请求通常是通过函数调用的形式发起的,例如C语言中的read()、write()等函数。
2. 操作系统接收到用户程序的请求后,会进行权限检查,以确保用户程序有权限执行该系统调用。
3. 如果权限检查通过,操作系统会将用户程序的上下文切换到内核模式,这是因为只有在内核模式下,操作系统才能访问硬件资源。
4. 操作系统会执行所请求的系统调用,并将执行结果返回给用户程序。
在执行系统调用期间,操作系统会对相关的硬件资源进行访问和管理。
5. 当系统调用执行完毕后,操作系统会将用户程序的上下文切换回用户模式,并将执行结果返回给用户程序。
需要注意的是,系统调用的执行过程比普通函数调用复杂得多。
这是因为系统调用需要在用户态与内核态之间切换,而且系统调用的执行涉及到一些硬件资源的访问和管理,因此系统调用的效率比普通函数调用低。
因此,应该尽量减少系统调用的使用,以提升程序的性能。
系统调用read函数

系统调用read函数**系统调用read函数**在编程中,`read`函数是一种系统调用,它通常用于从文件或其他输入流中读取数据。
`read`函数读取指定数量的字节,并将其存储到提供的缓冲区中。
在本文中,我们将探讨`read`函数的使用方法以及它在文件读取方面的一些重要特性。
## `read`函数的语法`read`函数的基本语法如下:```c#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);```这里的参数含义如下:- `fd`:文件描述符,它指定了要读取的文件或输入流。
- `buf`:指向存储读取数据的缓冲区。
- `count`:要读取的最大字节数。
`read`函数返回读取的字节数,如果出现错误,则返回-1。
需要注意的是,`read`函数是一个阻塞的调用,意味着它会一直等待,直到读取到足够数量的数据或者发生了错误。
## 示例代码下面是一个简单的示例,展示了如何使用 `read`函数从文件中读取数据并打印出来:#include <unistd.h>#include <string.h>#include <stdio.h>#include <fcntl.h>#define BUFFER_SIZE 1024int main() {int file_descriptor = open("example.txt", O_RDONLY); // 打开文件,获得文件描述符if (file_descriptor == -1) {perror("Open file failed");return 1;}char buffer[BUFFER_SIZE];ssize_t bytes_read;while ((bytes_read = read(file_descriptor, buffer, sizeof(buffer))) > 0) { // 循环读取文件内容// 处理读取到的数据// ...// 在标准输出中打印读取到的数据write(STDOUT_FILENO, buffer, bytes_read);close(file_descriptor); // 关闭文件return 0;}```在这个示例中,我们首先使用`open`函数打开一个文件,并获得文件描述符。
q1完open、read、write、lseek、close系统调用1

inux上面对文件的操作可以分为两种:1.Linux系统提供的API; 2.C标准的文件操作函数。
前者依赖于Linux系统,后者是标准的C文件操作函数与操作系统无关。
文件操作方式主要是打开,读写和关闭这三种。
在LinuxAPI之中主要是使用open函数,write,read,close。
open有两个原形:int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);这三个参数比较容易看出它们的含义,pathname是文件路径,flags打开文件的标志,mode 是打开的模式,返回值应该是打开文件的句柄。
flags标志有下面的定义:O_RDONLY 以只读的方式打开文件O_WRONLY 以只写的方式打开文件O_RDWR 以读写的方式打开文件O_APPEND 以追加的方式打开文件O_CREAT 创建一个文件O_EXEC 如果使用了O_CREAT而且文件已经存在,就会发生一个错误O_NOBLOCK 以非阻塞的方式打开一个文件O_TRUNC 如果文件已经存在,则删除文件的内容O_RDONLY、O_WRONLY、O_RDWR三个标志只能使用任意的一个。
如果flags中使用了O_CREAT标志,则调用open函数的时候需要加上打开文件的模式,设置文件的用户权限int open(const char *pathname, int flags, mode_t mode);下面是mode可取的一些值,下面都是八进制的值,使用这些值的时候需要包含头文件:sys/types.h,sys/stat.hS_IRWXU 00700 用户可以读S_IRUSR 00400 用户可以写S_IWUSR 00200 用户可以执行S_IXUSR 00100 用户可以读、写、S_IRWXG 00070 组可以读S_IRGRP 00040 组可以写S_IWGRP 00020 组可以执行S_IXGRP 00010 组可以读写执行S_IRWXO 00007 其他人可以读S_IROTH 00004 其他人可以写S_IWOTH 00002 其他人可以执行S_IXOTH 00001 其他人可以读、写S_ISUID 04000 设置用户执行IDS_ISGID 02000 设置组的执行ID呵呵,这个跟chmod命令中的后面的值差不多,个人比较喜欢用数值来代替,用八进制数据表示为0777等,其中4:读权限,2:写权限,1:可执行权限,0:无权限,每一位的值可以取其中的一位或是它们的组合从最低位开始分别对应的权限是:其它用户权限,组权限,当前用户权限。
read 系统调用剖析共10页word资料

read 系统调用剖析级别:初级赵健博(zhaojianbo@ncic.ac),硕士,中国科学院计算技术研究所2019年3月13日大部分程序员可能会有这样的疑问:当在程序中调用库函数read时,这个请求是经过哪些处理最终到达磁盘的呢,数据又是怎么被拷贝到用户缓存区的呢?本文介绍了从read系统调用发出到结束处理的全过程。
该过程包括两个部分:用户空间的处理、核心空间的处理。
用户空间处理部分是系统调用从用户态切到核心态的过程。
核心空间处理部分则是read系统调用在linux内核中处理的整个过程。
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系统调用在核心空间中所要经历的层次模型。
系统调用的11个步骤

为了使系统调用机制更清晰,让我们简要地考察read系统调用。
如上所述,它有三个参数:第一个参数指定文件,第二个指向缓冲区,第三个说明要读出的字节数。
几乎与所有的系统调用一样,它的调用由C程序完成,方法是调用一个与该系统调用名称相同的库过程:read。
由C程序进行的调用可有如下形式:1.count = read(fd, buffer, nbytes);系统调用(以及库过程)在count中返回实际读出的字节数。
这个值通常和nbytes相同,但也可能更小,例如,如果在读过程中遇到了文件尾的情形就是如此。
如果系统调用不能执行,不论是因为无效的参数还是磁盘错误,count都会被置为-1,而在全局变量errno中放入错误号。
程序应该经常检查系统调用的结果,以了解是否出错。
系统调用是通过一系列的步骤实现的。
为了更清楚地说明这个概念,考察上面的read调用。
在准备调用这个实际用来进行read系统调用的read库过程时,调用程序首先把参数压进堆栈,如图1-17中步骤1~步骤3所示。
由于历史的原因,C以及C++编译器使用逆序(必须把第一个参数赋给printf(格式字串),放在堆栈的顶部)。
第一个和第三个参数是值调用,但是第二个参数通过引用传递,即传递的是缓冲区的地址(由&指示),而不是缓冲区的内容。
接着是对库过程的实际调用(第4步)。
这个指令是用来调用所有过程的正常过程调用指令。
在可能是由汇编语言写成的库过程中,一般把系统调用的编号放在操作系统所期望的地方,如寄存器中(第5步)。
然后执行一个TRAP指令,将用户态切换到内核态,并在内核中的一个固定地址开始执行(第6步)。
TRAP指令实际上与过程调用指令相当类似,它们后面都跟随一个来自远地位置的指令,以及供以后使用的一个保存在栈中的返回地址。
然而,TRAP指令与过程指令存在两个方面的差别。
首先,它的副作用是,切换到内核态。
而过程调用指令并不改变模式。
其次,不像给定过程所在的相对或绝对地址那样,TRAP指令不能跳转到任意地址上。
2012年408真题及答案解析

2012年408真题及答案解析2012年全国硕⼠研究⽣⼊学统⼀考试计算机科学与技术学科联考计算机学科专业基础综合试题⼀、单项选择题:第1~40⼩题,每⼩题2分,共80分。
下列每题给出的四个选项中,只有⼀个选项最符合试题要求。
1.求整数n(n≥0)阶乘的算法如下,其时间复杂度是。
int fact(int n){if (n<=1) return 1;return n*fact(n-1);}A. O(log2n)B. O(n)C. O(nlog2n)D. O(n2)2.已知操作符包括…+?、…-?、…*?、…/?、…(?和…)?。
将中缀表达式a+b-a*((c+d)/e-f)+g转换为等价的后缀表达式ab+acd+e/f-*-g+时,⽤栈来存放暂时还不能确定运算次序的操作符,若栈初始时为空,则转换过程中同时保存在栈中的操作符的最⼤个数是。
A.5 B.7 C.8 D.113.若⼀棵⼆叉树的前序遍历序列为a, e, b, d, c,后序遍历序列为b, c, d, e, a,则根结点的孩⼦结点。
A. 只有eB. 有e、bC. 有e、cD. ⽆法确定4.若平衡⼆叉树的⾼度为6,且所有⾮叶结点的平衡因⼦均为1,则该平衡⼆叉树的结点总数为。
A. 10B. 20C. 32D. 335.对有n个结点、e条边且使⽤邻接表存储的有向图进⾏⼴度优先遍历,其算法时间复杂度是。
A.O(n) B.O(e) C.O(n+e) D.O(n*e)6.若⽤邻接矩阵存储有向图,矩阵中主对⾓线以下的元素均为零,则关于该图拓扑序列的结论是。
A.存在,且唯⼀B.存在,且不唯⼀C.存在,可能不唯⼀D.⽆法确定是否存在7.对如下有向带权图,若采⽤迪杰斯特拉(Dijkstra)算法求从源点a到其他各顶点的最短路径,则得到的第⼀条最短路径的⽬标顶点是b,第⼆条最短路径的⽬标顶点是c,后续得到的其余各最短路径的⽬标顶点依次是。
A.d,e,f B.e,d,f C.f,d,e D.f,e,d8.下列关于最⼩⽣成树的叙述中,正确的是。
2022年东北林业大学数据科学与大数据技术专业《操作系统》科目期末试卷A(有答案)

2022年东北林业大学数据科学与大数据技术专业《操作系统》科目期末试卷A(有答案)一、选择题1、某时刻进程的资源使用情况见表。
此时的安全序列是()A.P1、P2、P3、P4B. P1、P3、P2、P4C. P1、P4、P3、P2D.不存在2、下面说法错误的有()。
I分时系统中,时间片越短越好。
II.银行家算法是防止死锁发生的方法之。
III若无进程处于运行状态,则就绪和等待队列均为空。
A. I和IIB. II和IIIC. I和IIID. I、II和II3、为多道程序提供的共享资源不足时,可能会产生死锁。
但是,不当的()也可能产生死锁。
A.进程调度顺序B.进程的优先级C.时间片大小D.进程推进顺序4、与单道程序相比,多道程序系统的优点是()I.CPU 利用率高II.系统开销小III.系统吞吐量大IV. I/O设备利用率高A.仅I、IIIB.仅I、IVC. 仅II、IIID.仅I、III,IV5、既考虑作业等待时间,又考虑作业执行时间的调度算法是()A.高响应比优先调度算法B.短作业优先调度算法C.优先级调度算法D.先来先服务调度算法6、下列关于SPOOLing技术的叙述中,错误的是()A.需要外存的文持B.需要多道程序设计技术的支持C.可以让多个作业共享一台独占设备D.由用户作业控制设备与输入/输出之间的数据传送7、下列关于设备驱动程序的叙述中,正确的是()。
I.与设备相关的中断处理过程是由设备驱动程序完成的II.由于驱动程序与I/O设备(硬件)紧密相关,故必须全部用汇编语言书写III.磁盘的调度程序是在设备驱动程序中运行的IV.一个计算机系统配置了2台同类绘图机和3台同类打印机,为了正确驱动这些设备,系统应该提供5个设备驱动程序A. 仅I、IIIB. 仅II、IIIC.仅I、III,IVD. I、II、III、IV8、用户在删除某文件的过程中,操作系统不可能执行的操作是A.删除此文件所在的目录B.删除与此文件关联的目录项C.删除与此文件对应的文件控制块D.释放与此文件关联的内存缓冲区9、下面关于文件的叙述中,错误的是()。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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 。
•fd_install() :以文件描述符为索引,关联当前进程描述符与上述得file 对象,为之后得 read 与 write 等操作作准备。
•函数最后返回该文件描述符。
图3显示了 sys_open 函数返回后, file 对象与当前进程描述符之间得关联关系,以及 file 对象中操作文件得函数指针集合得来源(inode 对象中得成员i_fop)。
图3 file 对象与当前进程描述符之间得关系到此为止,所有得准备工作已经全部结束了,下面开始介绍 read 系统调用在图1所示得各个层次中得处理过程。
虚拟文件系统层得处理:内核函数 sys_read() 就是 read 系统调用在该层得入口点,清单2显示了该函数得代码。
清单2 sys_read 函数得代码asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count){struct file *file;ssize_t ret = -EBADF;int fput_needed;file = fget_light(fd, &fput_needed);if (file) {loff_t pos = (file);ret = vfs_read(file, buf, count, &pos);(file, pos);fput_light(file, fput_needed);}return ret;}代码解析:•fget_light() :根据 fd 指定得索引,从当前进程描述符中取出相应得file 对象(见图3)。
•如果没找到指定得 file 对象,则返回错误•如果找到了指定得 file 对象:•调用 () 函数取出此次读写文件得当前位置。
•调用 vfs_read() 执行文件读取操作,而这个函数最终调用 file->f_op、read() 指向得函数,代码如下:if (file->f_op->read)ret = file->f_op->read(file, buf, count, pos);•调用 () 更新文件得当前读写位置。
•调用 fput_light() 更新文件得引用计数。
•最后返回读取数据得字节数。
到此,虚拟文件系统层所做得处理就完成了,控制权交给了 ext2 文件系统层。
在解析 ext2 文件系统层得操作之前,先让我们瞧一下 file 对象中 read 指针来源。
File 对象中 read 函数指针得来源:从前面对 sys_open 内核函数得分析来瞧, file->f_op 来自于inode->i_fop 。
那么 inode->i_fop 来自于哪里呢?在初始化 inode 对象时赋予得。
见清单3。
清单3 ext2_read_inode() 函数部分代码void ext2_read_inode (struct inode * inode){……if (S_ISREG(inode->i_mode)) {inode->i_op = &ext2_;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 所指向得函数。