为什么挂载发生在现有目录上?

Mel*_*ius 60 mount

需要一个现有目录作为挂载点

$ ls
$ sudo mount /dev/sdb2 ./datadisk
mount: mount point ./datadisk does not exist
$ mkdir datadisk
$ sudo mount /dev/sdb2 ./datadisk
$
Run Code Online (Sandbox Code Playgroud)

我觉得它很混乱,因为它覆盖了目录的现有内容。挂载点目录有​​两种可能的内容可能会意外切换(对于未执行挂载的用户)。

为什么不会mount发生在新创建的目录中?这就是图形操作系统显示可移动媒体的方式。目录是挂载(存在)还是未挂载(不存在)会很清楚。我很确定有一个很好的理由,但我还没有发现它。

pjc*_*c50 53

这是一个实现细节泄露的案例。

在 UNIX 系统中,每个目录都由映射到inode编号的名称列表组成。inode 保存元数据,它告诉系统它是文件、目录、特殊设备、命名管道等。如果它是文件或目录,它还告诉系统在磁盘上的何处找到文件或目录内容。大多数 inode 是文件或目录。将列出 inode 编号的-i选项ls

挂载文件系统需要一个目录 inode 并在内核的内存副本上设置一个标志,以说明“实际上,在查找此目录的内容时,会查看其他文件系统”(请参阅本演示文稿的幻灯片 10)。这相对容易,因为它正在更改单个数据项。

为什么它不为您创建一个指向新 inode 的目录条目?有两种方法可以实现,这两种方法都有缺点。一种是将一个新目录物理写入文件系统 - 但如果文件系统是只读的,那将失败!另一种方法是向每个目录列表过程添加一个实际上并不存在的“额外”事物列表。这很繁琐,并且可能会对每个文件操作造成很小的性能影响。

如果您想要动态创建的挂载点,automount系统可以执行此操作。特殊非磁盘文件系统也可以随意创建目录,例如procsysdevfs等等。

编辑:另请参阅“挂载”包含内容的现有文件夹时会发生什么的答案

  • @sourcejedi:绑定挂载仅绑定您实际引用的文件系统。它们不会递归绑定安装在其下的其他文件系统。这是查找被坐骑隐藏的垃圾的便捷方法。(例如,如果在`/var` 挂载失败的某个时间,某些东西最终出现在`/var/cache` 中的根FS 上。)另见[`path_resolution(7)`](http://man7.org/linux /man-pages/man7/path_resolution.7.html)。(较旧的 linux-manpages 在第 2 节中有那个手册页,如 die.net) IDK Linux 在内部的实际工作方式,以优化检查每个目录组件作为可能的安装。也许将 VFS 条目固定在缓存中? (2认同)
  • 是的,这就是我的观点......所以`fs/namei.c`(路径-> inode 查找)通过`lookup_mnt()` 调用namespace.c。dentry(目录缓存条目)上有一个标志。但这只是一个优化,也就是实现细节。它不会告诉您 *哪个 * 文件系统安装在那里;您必须查看安装表。(有关更多实现细节,请参见 m_hash()。Linux 至少避免了额外的字符串比较,同时 AFAICS 设法在例如绑定安装中重新使用 dentry,因为它是由向导编写的)。 (2认同)

Pet*_*des 20

如果mount(2) 需要创建一个新目录作为挂载点,则无法在只读文件系统下挂载任何内容。那将是愚蠢的,所以我们可以排除这种情况。

如果 mount可以选择创建一个新目录作为挂载点,那会很奇怪。这不像挂载/卸载一直发生,因此在内核中放入额外的逻辑以通过单个系统调用完成这两个步骤不会是一个重要的加速。如果需要,只需将其留给用户空间进行mkdir(2)系统调用。德米特里的回答指出,同时mount(2)做这两件事会使它成为非原子的。并且您需要一个额外的参数来mount(2)使用模式标志,例如open(2)take, for O_CREAT,O_EXCL等等。这纯粹是愚蠢的比较让用户空间做。

或者,也许您是在问让mount(8)(进行mount(2)系统调用的传统程序)这样做?这是可能的,但已经有一个非常mkdir(1)适合这项工作的,Unix 的设计就是关于可以组合的好的小工具。如果您想要一个工具可以同时执行这两个任务,那么编写一个 shell 脚本来使用两个更简单的工具构建该工具是很容易的。(或者,正如 muru 评论的那样,udisksctl已经这样做了,所以您不必编写它。)此外,mount(8)来自 util-linux 的Linux 正常支持mount -o x-mount.mkdir[=mode]将其x-语法用于用户空间的选项,而不是传递给文件系统的选项。


现在更有趣的问题是:为什么父文件系统上必须有一个目录?

就像 pjc50 的回答指出的那样(没有关系,即使他有我的首字母!),让挂载点显示在目录列表中将需要对每个readdir().

将挂载点作为目录存在于包含它们的目录中(在父 FS 上)是一个不错的技巧。 readdir()根本不必注意到它是一个挂载点。仅挂载点用作路径组件时才会发生这种情况。路径解析当然必须检查路径的每个目录组件的安装表。

  • @Izkata:将文件系统设为只读并不意味着 VFS 的整个子树都被冻结。它可能有指向读写目录的符号链接,或者当父 fs 重新挂载 `ro` 时,它下面已经有读写挂载点。有许多只读文件系统的用例,其中您的论点没有意义。 (2认同)
  • `man 8 mount`: *`x-mount.mkdir[=mode]` 允许创建目标目录(挂载点)。可选参数 mode 以八进制表示法指定用于 `mkdir(2)` 的文件系统访问模式。默认模式为 0755。此功能仅支持 root 用户。* (2认同)

Dmi*_*yev 12

挂载到现有目录mount实际上调用了原子性:它要么成功要么失败,至少从用户的角度来看。如果mount必须自己创建挂载点,则会出现两个故障点,从而无法保证完全回滚。想象以下场景:

  1. mount 成功创建挂载点
  2. mount 尝试将新文件系统挂载到该目录,但失败
  3. mount 尝试删除挂载点,但失败

系统最终会出现失败的副作用 mount

这是另一个:

  1. umount 成功卸载文件系统
  2. umount 尝试删除挂载点,但失败

现在,应该umount返回成功还是失败?

  • 我认为 OP 是在问为什么挂载点需要是一个现有目录,而不是为什么 `mount` 系统调用不创建它。虽然这可能只是我对我认为 OP 想问什么的解释/期望,或者如果我问的话我会问什么。 (8认同)
  • `mount` 有 8 种不同的错误返回码,也可以组合使用。当目录删除失败时,它可以添加另一个。http://man7.org/linux/man-pages/man8/mount.8.html#RETURN_CODES (5认同)