系统调用Open()函数的内核追踪(上篇)
来源:互联网 发布:vb.net key value 编辑:程序博客网 时间:2024/05/17 02:33
From: http://blog.chinaunix.net/uid-24585858-id-2125500.html
open函数相信大家都用过,这里就不多说它的使用方法等事项,现直接进入正题...
用户态程序调用open函数时,会产生一个中断号为5的中断请求,其值以该宏__NR__open进行标示.而后该进程上下文(processcontext)将会被切换到内核空间。待内核中的相关操作完成后,就会从内核返回,此时还需要一次进程上下文切换(processcontext switch)。
待进程执行流进入内核后,会通过一系列转换(这里我们不关心),最终进入SYSCALL_DEFINE3(open,...)函数中。看起来该函数定义比较特殊,其实SYSCALL_DRFINE3是一个宏,它被定义成如下形式:
#define SYSCALL_DEFINE3(name,...) SYSCALL_DEFINEx(3, _##name,__VA_ARGS__)
而 SYSCALL_DEFINEx宏具有如下形式:
#ifdef CONFIG_FTRACE_SYSCALLS
#define SYSCALL_DEFINEx(x, sname,...) \
static constchar *types_##sname[]= { \
__SC_STR_TDECL##x(__VA_ARGS__) \
}; \
static constchar *args_##sname[]= { \
__SC_STR_ADECL##x(__VA_ARGS__) \
}; \
SYSCALL_METADATA(sname, x); \
__SYSCALL_DEFINEx(x, sname,__VA_ARGS__)
#else
#define SYSCALL_DEFINEx(x, sname,...) \
__SYSCALL_DEFINEx(x, sname,__VA_ARGS__)
#endif
可以看到,不论是何种形式的宏定义,最终都会进入__SYSCALL_DEFINEx中,而__SYSCALL_DEFINEx的定义如下:
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
#define SYSCALL_DEFINE(name)static inlinelong SYSC_##name
#define __SYSCALL_DEFINEx(x, name,...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)); \
static inlinelong SYSC##name(__SC_DECL##x(__VA_ARGS__)); \
asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__)) \
{ \
__SC_TEST##x(__VA_ARGS__); \
return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__)); \
} \
SYSCALL_ALIAS(sys##name, SyS##name); \
static inlinelong SYSC##name(__SC_DECL##x(__VA_ARGS__))
#else /* CONFIG_HAVE_SYSCALL_WRAPPERS */
#define SYSCALL_DEFINE(name) asmlinkagelong sys_##name
#define __SYSCALL_DEFINEx(x, name,...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
#endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */
经过该宏的替换作用以后,最终我们就会得到sys_open或SYS_open所对应的函数原型。如下:
asmlinkage long sys_open(const char __user filename,int flags, int mode);
这也就是我们最常见到的open函数所对应的在内核中的实现部份。其实,对于linux下所有的系统调用函数,采用上述方法均可找到与其对应的内核函数sys_xxx().
接下来我们来看sys_open()函数。其实现如下:
SYSCALL_DEFINE3(open, const char __user*, filename,int, flags,int, mode)
{
long ret;
if (force_o_largefile())
flags |= O_LARGEFILE;
ret = do_sys_open(AT_FDCWD, filename, flags, mode);
/* avoid REGPARM breakage on x86:*/
asmlinkage_protect(3,ret, filename, flags, mode);
return ret;
}
在函数中首先调用force_o_largefile()宏进行LARGEFILE?确认。若是LARGEFILE则将其在flags中置位。随后调用主处理函数do_sys_open进行后续处理。其实,open的工作也就是在该函数中进行的。该函数原型如下:
long do_sys_open(int dfd,const char __user*filename, int flags, int mode);
在该函数中,如果通过getname()得到filename变量中文件名的指针没有错误的话,接下来就会掉用get_unused_fd_flags()函数获得一个没被使用的文件描述符fd。注意,对于文件描述符fd来讲,它只对本进程有效,也即它只在该进程中可见而在其它进程中代表着完全不同的文件。在32位系统中,一个进程最多打开32个文件,而在64位系统中可以打开64个文件。该函数就是用来获得一个未被使用的文件描述符fd.至于它的获取过程是很复杂的,这里不进行讲述。有兴趣的话,可以到www.kernel.org下载最新的内核源码进行研究。
在获得了有效的fd之后,我们通过do_filp_open()函数打开或者创建相应的文件,并且返回与之对应的文件结构structfile*f。如果函数返回的结构地址有效的话,那么就会调用fsnotify_open()函数(参数为f)将该文件加入到文件监控的系统中。该系统是用来监控文件被打开,创建,读写,关闭,修改等操作的,具体工作原理见后面文章。本文中不做讲述。随后调用fd_install()函数将structfile*f加入到fd索引位置处的数组中。如果后续过程中,有对该文件描述符的操作的话,就会通过查找该数组得到对应的文件结构,而后在进行相关操作。完成这些工作之后,open函数就返回了。返回值也就是刚才得到的fd.
那么,在do_filp_open()函数中有具体做了哪些工作呢?文件是如何被创建的呢?以及文件若存在的话,又是怎样被找到,而后被打开的呢?在中篇中我们将会回答这些问题。
- 系统调用Open()函数的内核追踪(上篇)
- 系统调用Open()函数的内核追踪(下篇)
- Open()函数的内核追踪
- linux下的系统调用函数到内核函数的追踪
- 转载_linux下的系统调用函数到内核函数的追踪
- linux下的系统调用函数到内核函数的追踪
- linux下的系统调用函数到内核函数的追踪
- linux下的系统调用函数到内核函数的追踪
- linux下的系统调用函数到内核函数的追踪
- linux下的系统调用函数到内核函数的追踪
- linux下的系统调用函数到内核函数的追踪
- linux下的系统调用函数到内核函数的追踪
- 系统调用open函数
- 彻底的系统调用---open函数
- 彻底的系统调用---open函数
- 系统调用1--open函数的使用
- linux内核文件IO的系统调用实现分析(open)
- unix系统调用 open 函数
- PHP如何获取二个日期的相差天数?
- 《程序开发心理学》作者:Gerald M Weinberg
- Google 报亭应用 ActionBar 动画效果 实现
- 动态集合中两个最接近的数的差值
- 推荐5个提高Java开发效率的工具
- 系统调用Open()函数的内核追踪(上篇)
- 学习笔记--实现类似酷狗音乐歌词的效果
- git初级教程
- maven 技巧
- PHP保留2位小数 格式化小数、浮点数
- 大家好啊
- Python已成美国顶尖高校中最受欢迎的入门编程语言
- Android 不自动锁屏 4.0以后横竖屏切换不重新启动
- Linux makefile 教程 非常详细,且易懂