I am trying to understand difference between using ln -s and mount --bind. In basic scenario I can use both to access one directory from somewhere else. In what scenarios those two will behave differently ?
5 Answers
They will behave differently in at least two cases:
- In a chroot, if the link target is outside the chroot, the link will be dead. A bind mount will still be accessible.
- Several programs can distinguish between symbolic links and actual directories or files. Few (if any) can distinguish between a directory or file and the one mounted on it. This also extends to symbolic links to something (
A) which have something else (B) mounted on them. The link will show the contents of mount target (B) instead of the original (A).
Also, you can bind mount a directory or file on an existing directory or file, masking the original contents (rendering the original contents inaccessible unless the original was bind mounted elsewhere). A symbolic link requires that the original be moved or deleted.
- 207,228
Well, ln -s creates a symbolic link, whereas mount --bind creates a mount.
A symbolic link is a special type of file. If you do ln -s /var/target /var/link, then /var/link will be a file containing the path "/var/target" in it. The only difference between a symbolic link and an ordinary file is that when a program tries to perform an operation on a symbolic link, the operation is usually performed on the target instead of the file. So now if you do ls /var/link, the ls program will try to get a directory listing for /var/link, but will actually get a directory listing for /var/target instead.
Symbolic links are still just files, though. They can be renamed and deleted and all that jazz. Note that you can't create a symbolic link (or an ordinary file, for that matter) called /var/link if there's already a file called /var/link; you'd need to get rid of it first.
A mount isn't a file; it's a record that the kernel keeps in memory. If you do mount --bind /var/target /var/mount, the kernel will record the fact that /var/mount is now a new name for /var/target. (I don't know the details; in particular, I don't know if mounting something in a subdirectory of /var/target will make it show up in /var/mount as well, or why or why not. Edits to this answer would be appreciated.) So now if you do ls /var/mount, the same thing will happen as if you did ls /var/target, because /var/mount and /var/target are the same directory.
Mounts aren't files. I don't know what would happen if you tried to rename or delete /var/mount. Note that you can't mount anything at /var/mount unless there's already a directory at /var/mount.
- 401
Additionally, ln -s would survive a reboot; whereas mount --bind would not, unless you edit /etc/fstab to make it persistent.
- 2,610
Besides the conceptual differences between the 2 (well explained by the currently existing answers), here's a functional thing that might create a bit of confusion, as one doesn't behave as one would first expect (that was my case). It involves directories.
Setup
Create a symlink and a mount point to the same dir:
[cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> uname -a Linux cfati-5510-0 4.19.128-microsoft-standard #1 SMP Tue Jun 23 12:58:10 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> cat /etc/lsb-release | grep LTS DISTRIB_DESCRIPTION="Ubuntu 20.04.2 LTS" [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> echo $- himBHs [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll total 0 drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ./ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ../ [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ln -s /mnt/e/Work/Dev/Utils/cup-vm/test0 ln [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> mkdir mnt [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> sudo mount --bind /mnt/e/Work/Dev/Utils/cup-vm/test0 mnt [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> # Check the 2 [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll total 0 drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ./ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ../ lrwxrwxrwx 1 cfati cfati 34 Feb 26 2021 ln -> /mnt/e/Work/Dev/Utils/cup-vm/test0/ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 mnt/ [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll ln lrwxrwxrwx 1 cfati cfati 34 Feb 26 2021 ln -> /mnt/e/Work/Dev/Utils/cup-vm/test0/ [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll ln/ total 0 drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ./ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ../ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 dir0/ -rwxrwxrwx 1 cfati cfati 0 Feb 26 2021 file0.txt* [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll mnt total 0 drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ./ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ../ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 dir0/ -rwxrwxrwx 1 cfati cfati 0 Feb 26 2021 file0.txt* [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]>
Test
Everything went as expected. Here's the behavior for the 2, when going up one level in the tree:
Mount point:
[cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll mnt/.. total 0 drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ./ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ../ lrwxrwxrwx 1 cfati cfati 34 Feb 26 2021 ln -> /mnt/e/Work/Dev/Utils/cup-vm/test0/ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 mnt/ [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll mnt/../ ln/ mnt/ [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll mnt/../mnt/ # With TAB completion (previous line) total 0 drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ./ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ../ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 dir0/ -rwxrwxrwx 1 cfati cfati 0 Feb 26 2021 file0.txt*symlink:
[cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll ln/.. total 0 drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 ./ drwxrwxrwx 1 cfati cfati 4096 Feb 14 03:37 ../ drwxrwxrwx 1 cfati cfati 4096 Feb 26 2021 test0/ drwxrwxrwx 1 cfati cfati 4096 Dec 24 2019 windows/ [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll ln/../ ln/ mnt/ [cfati@cfati-5510-0:~/Work/Dev/AskUbuntu/q000557733]> ll ln/../ln # With TAB completion (previous line) ls: cannot access 'ln/../ln': No such file or directoryAs seen, the parent dir is computed relative to the target. This might have unexpected (and undesirable) results when working with relative paths that are not contained in the symlinked dir
- 121
- 1
- 5
In addition to the other answers. The system does not allow hard link to directory:
# ln mydir mpoint
ln: `mydir': hard link not allowed for directory
The mount let you make hard link-like ie two or more names for same one inode:
# mount -B mydir/ mpoint/
# ls -d -i *
807175 mpoint/ 807175 mydir/
(One can find it helps for snapshot-backup with old version of rsync.)
Also, note that this mount is not complete:
# mount -B -oro mydir/ mpoint/
mount: warning: mpoint/ seems to be mounted read-write.
# mount | grep mpoint
/root/learn/mydir on /root/learn/mpoint type none (rw,bind)
So, the mount is still read and write even if I asked for the option ro (read only).
Additional Usage:
In case the OS dose not allow you to change permissions of directory or an application dose not respect the permissions, see the following solution regarding SSH:
- 51