VFS中的read/write系统调用
VFS中的read/write系统调用
VFS所隐含的主要思想在于引入了一个通用的文件模型(common file model),这个模型能够表示所有支持的文件系统。VFS是所有文件系统的抽象。
linux内核对每个文件读写操作都必须使用一个指针,指向要访问的具体文件系统的适当函数。换句话说,当应用程序对read()或是write()调用引起内核调用相应的sys_read()或是sys_write()服务例程,文件在内核内存中是由一个file数据结构来表示的。这种数据结构中包含一个称为f_op的字段,该字段中包含一个指向专对某一个文件系统(如sysfs虚拟文件系统)的读写函数指针,sys_read()或是sys_write()查找到指向该函数的指针,并调用它。这样一来,应用程序的read()或是write()就被转化为相对间接的调用:
file->f_op->read() 或 file->f_op->write()
或者 file->f_op->aio_write()
剖析printf函数
下面我们以printf
函数的调用为例,说明该函数是如何一步一步最终落在内核函数上去的。
write函数内部就是调用了int
中断。一般的系统调用都是调用0x80号中断。而操作系统中一般不会的显式的写出write的实现代码,而是通过_syscall3
宏展开的实现。
_syscall3
是专门用来处理有3个参数的系统调用的函数的实现。
同理还有_syscall0
、_syscall1
和_syscall2
等,目前最大支持的参数个数为3个,这三个参数是通过ebx
, ecx
,edx
传递的。
如果有系统调用的参数超过了3个,那么可以通过一个参数结构体来进行传递。
// linux/lib/write.c
#define __LIBRARY__
#include <unistd.h>
//
_syscall3(int,write,int,fd,const char *,buf,off_t,count) //_syscall后面的数字“3”表示系统调用有三个参数
// linux/include/unistd.h
#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
type name(atype a,btype b,ctype c) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \
if (__res>=0) \
return (type) __res; \
errno=-__res; \
return -1; \
}
所以宏展开
后,write函数的实现实现为:
int write(int fd, const char *buf, off_t count)
{
long __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (__NR_write),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c)));
if (__res>=0)
return (type) __res;
errno=-__res;
return -1;
}
我们看到实际函数内部并没有做太多的事情,主要就是调用int 0x80
,将把相关的参数传递给一些通用寄存器,调用的结果通过eax
返回。其中一个很重要的调用参数是__NR_write
这个也是一个宏,就是wirte的系统调用号,在linux/include/unistd.h中被定义为4,同样还有很多其他系统调用号。因为所有的系统调用都是通过int 0x80
,那怎么知道具体需要什么功能呢,只能通过系统调用号来识别。
下面我们来看看int 0x80
是如何执行的。这是一个系统中断,操作系统对于中断处理流程一般为:
- 关中断:CPU关闭中段响应,即不再接受其它外部中断请求
- 保存断点:将发生中断处的指令地址压入堆栈,以使中断处理完后能正确地返回。
- 识别中断源:CPU识别中断的来源,确定中断类型号,从而找到相应的中断服务程序的入口地址。
- 保护现场所:将发生中断处理有关寄存器(中断服务程序中要使用的寄存器)以及标志寄存器的内存压入堆栈。
- 执行中断服务程序:转到中断服务程序入口开始执行,可在适当时刻重新开放中断,以便允许响应较高优先级的外部中断。
- 恢复现场并返回:把“保护现场”时压入堆栈的信息弹回原寄存器,然后执行中断返回指令(IRET),从而返回主程序继续运行。
前3项通常由处理中断的硬件电路完成,后3项通常由软件(中断服务程序)完成。
下一篇: HTML中关于标签的细节
推荐阅读
-
C#中调用Windows系统服务exe程序的工具类与重启服务的流程
-
把收藏夹放在U盘上让系统自动调用保存在U盘中的收藏夹内容
-
输入的word时间日期代码是从系统中调用的,在打开该Word文档时自动更新时间
-
Windows系统中C#调用WinRAR来压缩和解压缩文件的方法
-
Linux中获取某个进程的系统调用以及参数(故障排查案例)
-
Linux的系统调用open,write,read,close,及相关总结
-
文件相关系统调用接口open/write/read/close
-
open/read/write/close等文件系统调用接口说明
-
linux系统调用open、write、close、read以及stat函数详解
-
open/read/write/close等文件相关系统调用接口