当您“挂载”包含内容的现有文件夹时会发生什么?

use*_*ser 106 mount tmp

现在里面/tmp有一些临时文件。当我将硬盘驱动器 ( /dev/sdc1)安装在 之上时/tmp,我可以看到硬盘驱动器上的文件。/tmp当我的硬盘被挂载时,实际内容会发生什么变化?是否可以在/tmp安装硬盘驱动器时对实际内容执行 r/w 操作?

python@lanix / $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       286G   43G  229G  16% /
none            4.0K     0  4.0K   0% /sys/fs/cgroup
udev            3.8G  4.0K  3.8G   1% /dev
tmpfs           766M  1.4M  765M   1% /run
none            5.0M     0  5.0M   0% /run/lock
none            3.8G   38M  3.8G   1% /run/shm
none            100M   24K  100M   1% /run/user
/dev/sdb1       7.5G  2.7G  4.9G  35% /mnt
/dev/sdc1       932G  242G  691G  26% /tmp
Run Code Online (Sandbox Code Playgroud)

Mat*_*Mat 152

挂载硬盘时 /tmp 的实际内容会发生什么变化?

几乎没有。它们只是隐藏在视图之外,无法通过正常的文件系统遍历访问。

是否可以在挂载硬盘时对 /tmp 的实际内容执行 r/w 操作?

是的。在“原始”中具有打开文件句柄的进程/tmp将继续能够使用它们。您还可以通过在其他地方绑定安装来使“重新出现”/在其他地方。

# mount -o bind / /somewhere/else
# ls /somewhere/else/tmp  
Run Code Online (Sandbox Code Playgroud)

这是一个小实验,您可以运行它来更好地(我希望)了解正在发生的事情。

注意:这不是试图完全正确或对实际发生的事情的详尽描述。不过,应该足够准确,以便为您提供大局。

me在我的机器上创建了一个用户,并在他的家中创建了一个随机目录,其中包含一个文件:

me@home $ pwd
/home/me/tmp
me@home $ echo hello > some_file
me@home $ ls  
some_file
me@home $ cat some_file 
hello
Run Code Online (Sandbox Code Playgroud)

在这一点上,没有什么不寻常的 - 它只是一个带有普通文件的普通目录。我让该会话保持打开状态,并cwd在该测试目录中。

作为 root,我创建了一个小文件系统并将它挂载到/home/me/tmp.

root@home # dd if=/dev/zero of=./fs bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 0.00467318 s, 2.2 GB/s

root@home # mkfs -t ext2 ./fs 
mke2fs 1.42.12 (29-Aug-2014)
[... snip ...]
Writing superblocks and filesystem accounting information: done

root@home # mount ./fs /home/me/tmp
Run Code Online (Sandbox Code Playgroud)

然后我打开一个新终端me,并环顾四周:

me@home #2 $ cd tmp
me@home #2 $ ls
lost+found
me@home #2 $ cat some_file
cat: some_file: No such file or directory
me@home #2 $ echo bye bye > some_file
-su: some_file: Permission denied
Run Code Online (Sandbox Code Playgroud)

所以,我们创建的那个文件显然不存在。该lost+found目录表示 ext 文件系统的根目录。而且我失去了写权限,所以它显然不是原始目录。

回到第一节me,我们来看看它是如何看世界的:

me@home $ echo something else > other_file
Run Code Online (Sandbox Code Playgroud)

写作没问题。

me@home $ cat some_file other_file 
hello
something else
Run Code Online (Sandbox Code Playgroud)

原始文件仍然存在,创建的新文件没有问题。

嗯?这是怎么回事?

第一个会话在它被 root 挂载另一个文件系统覆盖之前进入目录。该挂载操作根本不会影响原始文件系统。shell 进程对原始文件系统中的目录具有完全有效的句柄,并且可以继续与其交互。它有点像在地毯安装点下方跑来跑去。

第二个会话在安装后进入目录。所以它会看到新的空文件系统。系统管理员取消了权限,因此它无法使用请求的空间......让我们解决这个问题。

root@home # chown me:users /home/me/tmp
Run Code Online (Sandbox Code Playgroud)
me@home #2 $ echo bye bye > some_file
me@home #2 $ ls 
lost+found  some_file
me@home #2 $ cat some_file 
bye bye
Run Code Online (Sandbox Code Playgroud)

会话 1 可以从地毯下逃脱吗?(开始发霉了。)

当然!如果会话 1 将文件系统树移回挂载之外,它将失去内部的句柄,并将像其他人一样跟随挂载。

me@home $ cd
me@home $ pwd
/home/me
me@home $ cd tmp
me@home $ cat some_file other_file
bye bye
cat: other_file: No such file or directory
Run Code Online (Sandbox Code Playgroud)

与会话#2 相同的视图,我们恢复正常。

但是你怎么知道文件没有消失呢?没人再找了!

这是绑定坐骑变得方便的时刻之一。他们让你在其他地方挂载一个已经挂载的文件系统。

me@home $ mkdir ~/bind
Run Code Online (Sandbox Code Playgroud)
root@home # mount -o bind /home/me /home/me/bind
Run Code Online (Sandbox Code Playgroud)

(是的,您可以在“内部”绑定挂载文件系统。很酷的技巧,嗯?)

me@home $ ls bind/tmp
other_file  some_file
me@home $ cat bind/tmp/*
something else
hello
Run Code Online (Sandbox Code Playgroud)

所以他们确实在那里,准备好采取行动。只是它们在原始位置不可见/不可访问,挂载将它们隐藏在正常的目录遍历中。


我鼓励你玩这个,一旦你理解了正在玩的“技巧”,它真的并不复杂。一旦你有了它™,看看联合文件系统以获得更多的地毯拉:-)

但有一个注意事项:一旦启动过程完成,挂载/tmp/var(或任何核心操作系统目录)确实不是一个好主意。许多应用程序将状态留在这些目录中,如果您在它们周围玩安装游戏,可能会感到严重困惑。

  • 这是一种非常常见的神秘丢失磁盘空间的方法。如果在启动脚本中由于任何原因挂载失败,数据可以写入根文件系统上的目录。如果然后尝试重新启动,挂载可能会成功,并且可能没有人会注意到(例如,如果文件系统包含 tmp 文件或日志),除非它会占用空间,可能会占用很多空间。 (16认同)
  • 这是一个很好的答案——你已经超越了我对你的要求。绑定挂载的想法也很酷!感谢您的详细回答。干杯。 (7认同)
  • @DanSheppard 这就是我喜欢我的挂载点设置 chmod 000 的原因之一。也是为什么如果关键挂载失败 systemd 启动失败的原因。 (4认同)