要厘清这个概念,我们首先要建立一个合理的名称空间。我们从用户态建立这个名称空间,和内核中的概念不直接对应。
我们把存在磁盘上那个文件叫做inode,inode里面是文件真正的内容。
把用来访问这个文件的那个路径,叫做一个dentry。比如/tmp/foo。
目录是一个保存目录中dentry的inode,这个inode也有自己的dentry。
软链接(soft_link)是一个独立的inode,它的内容是被链接的dentry。
硬链接(hard_link)不是一个inode,它是一个dentry,指向链接对象inode的另一个dentry。
bind_mount是在dentry之上覆盖了一层dentry(是的,bind_mount可以同时作用在目录和普通文件身上),也就是你通过这个dentry访问inode的时候,你再也访问不到原来的inode了,它指向了被你bind_mount的对象的inode。比如你原来有两个dentry:/tmp/a和/tmp/b,你做mount --bind /tmp/a /tmp/b后,你访问/tmp/b,修改的是原来/tmp/a的inode的内容,你umount后,/tmp/b中原来的内容不会改变,改变的是/tmp/a中的内容
有趣的是,当你用mount(或者mount --bind)查看你建立的bind mount链接的时候,它不会显示被你链接的对象文件,而是现实那个文件所在的mount point,比如你mount --bind a b然后你看mount的结果,它可能显示的是:
/dev/sda1 on /home/rancher/test2/b type ext4 (rw,relatime,data=ordered)
这是mount这个构架的原始设计导致的,它仅仅记录每个真正的mountpoint,而不是bind的时候的文件,要知道实际的binding是什么,可以查看这个文件:/proc/self/mountinfo。这个特性在2.6.28版本中由Alexey Dobriyan合入。
所以,ln -s和mount --bind是不同的。前者要求应用程序“知道”这是个链接,后者应用程序会“以为”这个文件是个真正的普通文件。
bind可以起到很多ln不能实现的效果(当然,前提是你有root权限)。比如你要修改一个只读文件系统的内容,比如你的/etc/hostname是只读的,你想临时修改,可以在/tmp目录下写一个/tmp/hostname,然后做mount --bind /etc/hostname /tmp/hostname,然后修改后者,就可以了。