【Linux】Linux根据文件路径查找索引节点

根据文件路径查找索引节点

操作系统的文件管理系统的主要作用就是,当用户需要访问一个文件时,系统可以通过用户给出的文件路径找到文件的索引节点,从而找到文件,并以文件对象的实例交付给用户进程。下面就以系统调用open()为例来说明文件的查找过程,以加深对文件系统的理解和认识。

系统调用open()的内核函数为sys_open(),下图描述了用户进程调用系统调用open()的整个流程:

sys_open()系统调用打开或创建一个文件,成功后,返回该文件的文件描述符。下图是sys_open()实现代码中主要的函数调用关系图:

sys_open()

从sys_open()的函数调用关系图可以看出,sys_open()在做了一些简单的参数检验后,就接着调用do_sys_open(),在该函数中:

  • get_unused_fd()得到一个可用的文件描述符。通过该函数,可知文件描述符实质上是进程打开文件列表中对应某个文件对象的索引值;
  • do_filp_open()打开文件,返回一个file对象,代表由该进程打开的一个文件。进程通过这样的一个数据结构对物理文件进行读写操作;
  • fd_install()建立文件描述符与file对象的联系,以后进程对文件的读写都是通过操作该文件描述符而进行的。

do_filp_open()

do_filp_open()用于打开文件,返回一个file对象;而打开之前需要先找到该文件。

open_namei()用于根据文件路径名查找文件,借助一个持有路径信息的数据结构nameidata而进行;

查找结束后,将填充有路径信息的nameidata返回给接下来的函数nameidata_to_filp(),从而得到最终的file对象。当达到目的后,nameidata这个数据结构会马上被释放。

open_namei()

open_namei()用于查找一个文件。

path_lookup_open()实现文件的查找工作。要打开的文件若不存在,还需要一个新建的过程,则调用path_lookup_create(),后者和前者封装的是同一个实际的路径查找函数,只是参数不一样,使它们在处理细节上有所偏差;

当以创建文件的方式打开文件时,即设置了O_CREAT标识时,需要创建一个新的索引节点,代表创建一个文件。由vfs_create()里面的一句核心语句:

dir->i_op->create(dir, dentry, mode, nd);

它调用了具体的文件系统所提供的创建索引节点的方法。注意,这里的索引节点的概念,还只是位于内存中。只有把它写入磁盘才是一个物理文件的真正创建;

path_to_nameidata()填充nameidata数据结构;

may_open()检查是否可以打开该文件。

__path_lookup_intent_open()

不管是path_lookup_open()还是path_lookup_create(),最终都是调用__path_lookup_intent_open()来实现查找文件的功能。

查找时,会遍历路径的过程中,会逐层地将各个路径组成部分解析成目录项对象。如果此目录项对象在目录项缓存中,则直接从缓存中获取;如果该目录项在缓存中不存在,则进行一次实际的读盘操作,从磁盘中读取该目录项所对应的索引节点。得到索引节点之后,则建立索引节点与该目录项的联系。如此循环,直到找到目标文件对于的目录项,也就找到了索引节点,而由索引节点找到对应的超级块对象,就可知道该文件所在的文件系统的类型。

知道了文件系统的类型,VFS就能调用这个文件系统相对应的索引节点操作函数集来进行操作。

从磁盘中读取该目录项对应的索引节点;将引发VFS和实际的文件系统的一次交互。

进程创建时文件的复制与共享

之前讲到:当一个进程系统调用fork()创建一个子进程时,fork()将调用内核函数do_fork()对父进程的进程控制块进行复制,并将这个副本作为子进程的控制块。如果父进程有已经打开的文件,那么子进程理所当然的按某种方式来继承这些文件。为此,do_fork()中有以下这样的一段决定子进程在文件方面的继承方式:

if(copy files(clone_flags, p))
        goto bad_fork_clcanup;
if(copy fs(clone_flags, p))
        goto bad_fork_clcanup_files;

其中,copy files()就是用来处理父进程已打开文件的函数。该函数根据参数clone_flags的设置位来决定子进程以何种方式来继承父进程的打开文件。

  • 当clone_flags中的CLONE_FILES标志为0时,函数copy files()将复制父进程控制块中已打开文件的整个控制结构。这是虽然父子进程使用同一组被打开文件,但各自在自己的文件上下文中工作;
  • 当clone_flags中的CLONE_FILES标志非0时,函数copy files()只是简单地把父进程控制块中的files指针复制到子进程控制块,同时将file_struct结构中的共享计数成员加1,以表明文件又多了一个使用者,即子进程只是通过指针与父进程共享同一组打开文件。

函数copy fs()只是用来处理fs_struct结构的,类似的,这个结构也是根据其参数clone_flags决定子进程是以复制还是共享方式继承父进程的fs_struct结构的。

猜你喜欢

转载自blog.csdn.net/qq_38410730/article/details/81416195