Linux如何识别特定的文件系统以执行系统调用

19
当尝试执行read()/write()系统调用时,发生了哪些事件/步骤?内核如何知道要发出这些命令的文件系统。
假设一个进程调用了write()。 然后它会调用sys_write()。
现在可能是因为sys_write()代表当前进程执行,所以它可以访问struct task_struct,因此它可以访问包含文件系统信息的struct files_struct和struct fs_struct。
但之后我没有看到fs_struct如何帮助识别文件系统。
编辑:现在Alex已经描述了流程...我仍然怀疑读/写是如何路由到文件系统的,因为VFS不会这样做,那么它必须发生在其他地方,另外底层块设备、最终硬件协议PCI/USB是如何连接的。
一个涉及实际数据结构的简单流程图会有所帮助。
请帮忙。

1
“当我尝试执行read()/write()系统调用时”,必须先打开文件。请参见https://dev59.com/QW3Xa4cB1Zd3GeqPgp2B#14513460。 - sawdust
如果你正在寻找从read()一直到适当的文件系统/硬件驱动程序的函数调用链,那么你很可能找不到它。它们大多是函数指针和回调函数。我的一位资深同事经常使用的一个有趣技巧是在流程中最后/最深/最低的函数中故意执行空指针解引用,并从结果Linux内核oops消息中获取堆栈跟踪(最后到第一个函数调用列表)。 - TheCodeArtist
@xeonphi,你最初的问题是“VFS如何识别哪个文件系统应该处理read/write调用”。这个调用如何传播到块设备层,然后到ATA/AHCI等是另一个问题。如果你在弄清楚它方面有困难,可以发布另一个问题来询问。 - Alex D
2个回答

13

本答案基于内核版本4.0。我追踪了一些处理read系统调用的代码。建议你克隆Linux源代码库并跟随源代码。

  1. fs/read_write.c:620中的read系统调用处理程序被调用。它接收一个文件描述符(整数)作为参数,并调用fdget_pos将其转换为struct fd
  2. fdget_pos调用__fdget_pos调用__fdget调用__fget_light__fget_light使用current->files,即当前进程的文件描述符表,查找对应于传递的文件描述符号的struct file
  3. 在系统调用处理程序中,文件结构被传递给vfs_read,位于fs/read_write.c:478
  4. vfs_read调用__vfs_read,后者调用file->f_op->read。从这里开始,进入特定于文件系统的代码。

因此,VFS并不真正关心文件所在的文件系统的“标识”;它只是使用存储在其struct file中的“文件操作”函数指针表。当初始化struct file时,它将获得正确的f_op函数指针表,以实现其文件系统的所有特定于文件系统的操作。


嗨,谢谢。我已经浏览了Free electrons Linux源代码的流程...但我仍然不太理解...必须有一种机制来识别应将读取路由到哪个文件系统类型...也许不是在VFS中...那么就在其他地方...你能帮忙吗?因此,基本上,如何将读取路由到特定的FS,然后到底层块设备,最后到硬件协议,PCI、USB等。 - Haswell
1
请注意我回答中的最后一句话。每个struct file都有一个函数指针表,用于读取、写入等操作。使用的表取决于struct file所属的文件系统。如果文件在ext2文件系统上,则它将获取ext2的函数指针表。如果它在NTFS文件系统上,则它将获取NTFS的函数指针表。因此,调用file->f_op->read()将“自动”为您进入正确的文件系统所使用的read函数。 - Alex D
1
让我举个例子。看一下fs/ext2/file.c:93。(我真的建议您克隆自己的内核源码副本,而不是使用Free Electrons。请确保安装了cscope以搜索源代码。)这是ext2文件的f_op表。正如您所见,当针对ext2文件调用file->f_op->read()时,调用实际上将转到new_sync_read。这再次通过f_op表转到generic_file_read_iter,从那里转到do_generic_file_read。如果所需的页面已经缓存在内存中,则do_generic_file_read会使用它。 - Alex D
否则,它将通过在fs/ext2/inode.c:880中定义的address_space_operations表进行处理,以执行ext2_readpage。这将进入通用块读取函数mpage_readpage,该函数传递一个指向ext2_get_block的函数指针。它调用ext2_get_block来确定所需块在底层块设备上的确切位置。 - Alex D

0
每个文件系统都向VFS注册自己。当一个文件系统被挂载时,它的超级块被读取,并且VFS的超级块被填充上这些信息。此时,该文件系统的函数指针表也被填充。当发生file->f_op->read调用时,实际上是调用了文件系统中注册的函数。你可以参考http://www.science.unitn.it/~fiorella/guidelinux/tlk/node102.html中的文本。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接