磁盘被访问了多少次?

磁盘被访问了多少次?

这是关于通用UFS

据我了解,当给出绝对路径(例如:)时,/home/userU/file.txt每个目录和文件都会访问磁盘。因此在这种情况下磁盘被访问了 4 次

1 个/, 1 个home/, 1 个/userU, 1 个file.txt

我的问题是

  1. 如果给出硬链接/hL,指向上述文件的inode,那么磁盘访问的顺序是什么?
  2. 如果给出一个软链接/sL,指向上面的文件,那么磁盘访问的顺序是什么?

假设在所有三种情况下最初都没有缓存任何 inode 或任何其他数据。

答案1

背景

假设我们有以下目录设置:

$ ll
total 0
-rw-r--r-- 2 root root 0 Jul 29 23:36 afile.txt
-rw-r--r-- 2 root root 0 Jul 29 23:36 hL
lrwxrwxrwx 1 root root 9 Jul 30 01:22 sL -> afile.txt

现在我们来看看你的 2 个问题。


问题

  1. 如果给出一个硬链接/hL,指向上述文件的inode,那么磁盘访问的顺序是什么?

通过硬链接,它们拥有与它们指向的原始文件/目录相同的索引节点引用。因此没有额外的 HDD 访问权限来读取它们。

例如:

$ stat hL | head -3
  File: ‘hL’
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 667668      Links: 2

$ stat afile.txt | head -3
  File: ‘afile.txt’
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 667668      Links: 2

这两个之间的唯一区别是名称。因此,任一路径都会产生相同数量的 HDD 访问。

  1. 如果给出软链接/sL,指向上面的文件,那么磁盘访问的顺序是什么?

然而,通过软链接,可以进行额外的 HDD 访问。这种额外的访问将针对文件所在目录的元数据sL。然后,这将返回详细信息,说明该文件实际上是符号链接,并且它指向另一个文件/目录。

例如:

$ stat sL | head -3
  File: ‘sL’ -> ‘afile.txt’
  Size: 9           Blocks: 0          IO Block: 4096   symbolic link
Device: fd00h/64768d    Inode: 681295      Links: 1

在这里我们可以看到它的类型是“符号链接”并且它指向afile.txt.还要注意它有一个不同的 inode(681295 与 667668),进一步证明它将花费额外的读取费用。

那么读取顺序是什么呢?

如果您使用strace针对这些文件/目录运行命令的 Bash shell 本身,您可以了解事情是如何工作的。

[pid 18098] stat("/tmp/adir/hL", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
[pid 18098] open("/tmp/adir/hL", O_RDONLY) = 3
[pid 18098] fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0

这是命令的输出more /tmp/adir/hL

为了/tmp/adir/hL

  • 统计/打开 (/) → 统计/打开 (tmp) → 统计/打开 (adir) → 统计/打开 (hL)

为了/tmp/adir/sL

  • 统计/打开 (/) → 统计/打开 (tmp) → 统计/打开 (adir) → 统计/打开 (sL) → 统计/打开 (afile.txt)

更多细节

符号链接的维基百科页面也回避了这一切:

虽然将链接值存储在 inode 内可以节省磁盘块和磁盘读取,但操作系统仍然需要解析链接中的路径名,这总是需要读取额外的 inode,并且通常需要读取其他(可能是许多)目录、处理文件列表和每个文件的索引节点,直到找到与链接的路径组件匹配的内容。仅当链接指向同一目录中的文件时,“快速符号链接”才提供比其他符号链接明显更好的性能。

参考

答案2

这两个问题其实都是一个问题:“如何path_resolution运作?”,所以就从这个角度来看整个过程。

路径分辨率(7)我们读:

文件名(或路径名)的解析如下。

然后我们看到第一步对于硬链接和符号链接都是通用的(系统决定路径解析的起点:根目录/、chrooted 目录或当前目录)。

如果路径名以“/”字符开头,则起始查找目录是调用进程的根目录。 (进程从其父进程继承根目录。通常这将是文件层次结构的根目录。进程可以通过使用 chroot(2) 系统调用获得不同的根目录。进程可以获得完全私有的挂载命名空间,以防它(或其祖先之一)是通过调用设置了 CLONE_NEWNS 标志的 Clone(2) 系统调用启动的。)这处理路径名的“/”部分。

如果路径名不以“/”字符开头,则解析进程的起始查找目录是该进程的当前工作目录。 (这也是从父级继承的。它可以通过使用 chdir(2) 系统调用来更改。)

以“/”字符开头的路径名称为绝对路径名。不以“/”开头的路径名称为相对路径名。

正如我们所看到的,硬链接和符号链接之间的起点没有区别。但是,当开始行走路径时,下一步确实会出现差异:

将当前查找目录设置为起始查找目录。现在,对于路径名的每个非最终组件(其中组件是由“/”字符分隔的子字符串),将在当前查找目录中查找该组件。

如果进程没有当前查找目录的搜索权限,则会返回 EACCES 错误(“权限被拒绝”)。

如果未找到该组件,则返回 ENOENT 错误(“没有此类文件或目录”)。如果找到该组件,但既不是目录也不是符号链接,则返回 ENOTDIR 错误(“不是目录”)。

如果找到该组件并且是一个目录,我们将当前查找目录设置为该目录,然后转到下一个组件。

正如描述所示,文件和硬链接的路径解析没有区别 - 过程是相同的。那么符号链接呢?我们进一步阅读:

如果找到该组件并且是符号链接(symlink),我们首先解析这个符号链接(以当前查找目录作为起始查找目录)。发生错误时,将返回该错误。如果结果不是目录,则返回 ENOTDIR 错误。如果符号链接解析成功并返回一个目录,我们将当前查找目录设置为该目录,然后转到下一个组件。请注意,如果路径名的前缀(“dirname”)组件包含一个文件名,该文件名是解析为目录的符号链接(其中该目录的前缀组件可能包含符号链接,因此,这里的解析过程可能涉及递归)在)。为了保护内核免受堆栈溢出的影响,并防止拒绝服务,对最大递归深度和遵循的最大符号链接数有限制。当超过最大值时,会返回 ELOOP 错误(“符号链接级别过多”)。

如上所述,符号链接解析需要额外的磁盘访问操作,因此回答这两个问题:

如果给出一个硬链接/hL,指向上述文件的inode,那么磁盘访问的顺序是什么?

如果给出软链接/sL,指向上面的文件,那么磁盘访问的顺序是什么?

我们可以得出结论,硬链接访问与普通文件访问没有区别,但符号链接解析需要额外的磁盘访问操作,即符号链接解析

补充阅读:

相关内容