open()在Linux内核的实现(3)-“.”和“..”的处理

2015年2月17日 由 edsionte 留言 »

1.基本说明

open()在内核的实现过程中,有一大部分工作都是路径查找。路径查找即对用户态传入的文件路径以目录项为单位进行依次遍历。目录项包含五种类型,当目录项为”.”(LAST_DOT)或者“..”(LAST_DOTDOT),那么walk_component()将通过handle_dots()对其进行处理。

实际上,如果当前目录项为“.”,那么该函数什么也不做直接返回(返回到link_path_walk中)即可。也就是说,如果当前目录项为”.”,那么walk_component()此时的作用就是“越过”这些当前目录,而nd信息不做改变,因为所有“.”之前的普通目录项已经更新了nd。比如/home/edsionte/./././doc,目录项edsionte之后的“.”对应的nd与edsionte目录项相同,因此walk_component()在遇到“.”时直接越过他们,进而处理doc目录项。

如果当前目录项为“..”,即当前要walk的目录项为上一次已经walk的目录项的父目录,也就是需要向上获取当前目录的父目录。

2.函数实现

2.1.handle_dots()

该函数的实现比较简单,内部根据当前的walk类型做了函数分发。

static inline int handle_dots(struct nameidata *nd, int type);

如果当前搜索路径的模式位rcu,则进入follow_dotdot_rcu()的流程;否则进入follow_dotdot()的流程。

2.2.follow_dotdot_rcu()

该函数的声明如下:

static int follow_dotdot_rcu(struct nameidata *nd);

该函数是在rcu模式下获取父目录项信息,如果搜索成功,则返回0;否则,返回ECHILD,也就是说需要切换到ref-walk方式下进行搜索路径。该函数的主要处理过程如下:

1.如果有需要的话,首先通过set_root_rcu()设置当前路径的根目录信息。可以在path_init()中获知,只有搜索路径是绝对路径,nd中的root才会在一开始就被设置;否则,比如是相对路径,那么这里就必须对根目录进行设置了。因为此处是向上搜索,可能会一直找到根目录处。

2.进入循环体,向上获取当前目录项的父目录项。通过情况下,这个循环体只会被执行一次即退出,只有当父目录项为一个挂载点时才有可能不断进行循环。

3.如果退出循环体,至此已经获取到了当前目录项的上一级目录项(即“..”所代表的父目录项)。

4.如果这个父目录项是一个挂载点,那么还需做一些特殊检查。因为在特殊情况下,当前这个父目录项又被挂载了其他的文件系统,那么返回上级目录这个操作获取的应该是最新文件系统的内容而不是之前那个文件系统的内容。通过__lookup_mnt()检查父目录下挂载的文件系统是否为最新的文件系统,如果是则检查结束;否则,将继续检查;

5.更新nd中的inode,并返回;

在循环体中,可能会出现三种情况:

a.如果当前目录项恰好为根目录目录项,则直接跳出循环;比如在根目录下执行“cd ../../../”;

b.如果当前目录项既不是根目录,也不是一个挂载点,则属于最普通的情况,即直接获取当前目录项的父目录项。方法很简单,直接用当前目录项的parent(nd->path.dentry->d_parent)覆盖当前的nd结构中的path.dentry即可;

c.如果当前目录项代表的是当前文件系统的根目录,则不能通过简单的获取当前目录项parent这种方法,因为获取的parent为“/”(当然指的是当前文件系统的根目录)。此时需要通过follow_up_rcu()对nd->path进行填充。如果follow_up_rcu()返回1,则循环继续;返回0,则结束循环;

2.3.follow_up_rcu()

如果“..”所代表的目录项正好是一个挂载点时,那么需要将当前的遍历从当前的文件系统向上(follow up)切换到父文件系统。该函数的声明如下:

static int follow_up_rcu(struct path *path);

既然是向上跨越到父文件系统,那么首先将父文件系统的挂载点对应的dentry(nd->path->mnt->mnt_mountpoint)赋值给当前nd中对应的dentry(nd->path->dentry)。因为这个挂载点也就是“..”对应的目录项,挂载点本质也就是个目录。

其次,将父文件系统的vfsmount结构(nd->path->mnt->mnt_parent)复制给当前nd中对应的mnt项(nd->path->mnt)。

通过以上两个步骤,即将当前的walk位置向上移动到父文件系统中的一个目录上。

下面通过举例说明上述过程。假设存在路径/home/edsionte/work,其中fs1文件系统下有目录/home/edsionte/work,文件系统fs2挂载在work目录下,即fs2的挂载点为work。假设work下有文件w1和file,在/home/edsionte/work/file目录下,用户访问的路径为“../w1”,则“..”对应的dentry即为fs2文件系统根目录,则需要跨越到fs1文件系统中。“跨越”操作首先是将当前dentry指向work,也就是下次将要在work目录下寻找w1文件;其次,需要改变当前文件系统状态,即通过替换vfsmount来体现。

完成以上操作,将返回1。也就是说,必须再进行一次follow_dotdot_rcu()中的循环过程,因为follow_up_rcu()完成的只是文件系统的跨越,跨越完毕后必须进行follow_dotdot_rcu()中的循环体工作。

更特殊的是,跨越文件系统之后的这个目录项很可能又是一个挂载点,那么又必须进入follow_up_rcu()中执行上述操作。只有当当前文件系统的挂载点就是自己的时候,即跨越到根文件系统的时候,该函数返回0,那么返回到上级函数follow_dotdot_rcu()中的循环体时,也将结束整个循环过程。

下面再通过举例说明follow_dotdot_rcu()中循环体反复执行的例子。假设fs1文件系统存在路径/home/edsionte/work,首先将fs2文件系统挂载于work下,再将fs3挂载在work下,那么此时fs3对应的父vfsmount为fs2对应的结构;再将fs4文件系统挂载在wrok下,那么fs4指向fs3。此刻,/home/edsionte/work可以访问fs4的内容,而其他之前挂载在这里的文件系统将被隐藏。假设用户在wrok目录下执行“cd ../”,用户想得到的结果是fs1文件系统下edsionte/下的内容。而此刻work位于fs4中,那么他必须向上逐步跨越文件系统,即fs4通过follow_up_rcu()跨越到父文件系统fs3,fs3再跨越到fs2,fs2再跨越到fs1。

2.4.follow_dotdot()

follow_dotdot()和follow_dotdot_rcu()的实现方式几乎一致,只不过该函数在内部实现上使用了读写锁。具体的,主要体现在follow_up()和follow_mount()两个函数的内部,它们的实现过程中均使用了读写锁,这在rcu-walk中是不允许的。

3.总结

本文针对open()在内核中的路径查找过程进行简单说明,并集中关注了“..”这个特殊的目录项。LAST_DOTDOT类型的目录项之所以特殊是由于它向上(follow up)的查找过程与当前所位于的路径查找过程(向下,follow down)相反,同时还会涉及到文件系统挂载点。如果您想了解其他类型目录项的查找过程,可以阅读本系列其他文章。

参考资料:

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/;

广告位

发表回复

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key