1.基本说明
当link_path_walk()进行完毕之后,也就意味着文件路径的查找位于最后一个目录项中,这个目录项是否存在目前还不明确,因为还需要配合用户使用open()时所传递的参数,有可能是打开已存在文件,有可能是创建新文件。
2.函数分析
2.1.do_last()
在path_openat()中,经过link_path_walk()对open路径的查找,将进入do_last()对路径中最后一个目录项做处理。最后一个目录项可能是各种类型,比如“.”或者“..”,也可能是符号链接文件或者是“/”,在此将对普通目录项(LAST_NORM)所进行的处理进行说明。
对于open系统调用来说,flags参数通过取不同的值可以进行不同的操作,下面将针对open最常用的两种操作进行说明,即打开文件和创建文件。
2.1.1.打开文件
如果使用open系统调用的作用仅仅是打开文件,那么flags中必然不会存在O_CREAT标志,基本步骤如下:
1.通过walk_component()对最后一个目录项进行查找。walk_component()首先在rcu模式下对目录项进行查找,如果查找失败则进行ref模式下的目录项查找。如果两种方式均查找失败,则返回值小于0;如果当前目录项为符号链接文件,则返回1,该函数将直接返回到path_openat()中,进而通过follow_link()进行处理;如果查找成功,则跳至ok标号处;
2.完成最后一个目录项的查找工作,即将进行真正的打开操作。不过,在这之前还需要通过may_open()对当前inode的权限和标志位进行检查;
3.如果一切顺利,则通过nameidata_to_filp()执行打开操作;
4.返回file结构。
2.1.2.创建文件
如果创建一个文件,那么flags必然设置标志O_CREAT。基本步骤如下:
1.首先会检查最后一个目录项是否以“/”结尾,如果是,则直接错误返回。否则,继续进行;
2.通过lookup_hash()对最后一个目录项进行查找,这个查找函数将返回一个dentry。如果最后一个目录项确实存在,那么dentry->d_inode不为空,那么说明要创建的这个文件事先是存在的。此时先进行标志位的判断,比如如果用户设置了O_EXCL标志,那么此时就不必继续进行直接错误返回。如果标志检查一切成功,则进行步骤4;否则,dentry->d_inode将为空,继续进行;
3.当最后一个目录项inode为空时,那么需要通过vfs_create()调用具体文件系统的create钩子函数创建这个文件;
4.通过may_open()检查inode标志位和权限的合法性;
5.通过nameidate_to_flip()调用具体文件系统的open钩子函数进行文件的打开工作;
6.返回file。
3.总结
通过前面的系列文章,说明了open()在Linux内核实现。事实上,这仅仅反映的是它在在虚拟文件系统的实现过程,主要涉及的内容为对路径的查找。最终,文件的打开操作必须经过具体文件系统的实现,虽然每个文件系统具体实现不同,但是他们的输入输出都将受到虚拟文件系统的限制保持一致。
参考资料:
1.Linux源码3.2.69;
2.Linux系统调用open七日游:http://blog.chinaunix.net/uid-20522771-id-4419666.html
3.深入理解Linux内核:http://book.douban.com/subject/2287506/;
4.深入Linux内核架构:http://book.douban.com/subject/4843567/;
5.Linux内核探秘:http://book.douban.com/subject/25817503/;