48

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 ?

3
  • 9
    I should warn against rm -r on a mount --bind. With a ln, it removes the link, whereas for a --bind, it has the same effect as running the rm -r on the target. Not good, as I found shortly before rebuilding one of my servers... – Mark K Cowan Dec 8 '14 at 12:18
  • @MarkKCowan that's true unless you created a hard link. – JohnnyQ Jul 15 '16 at 4:31
  • @JohnnyQ Can't hardlink directories – Mark K Cowan Jul 15 '16 at 8:56
45

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.

2
  • I can't get the point of your second case. I guess the second case describes the characteristic of symbolic link, am I correct? and if I have a mount point /mnt which mounts a partition, and I make a symbolic link somewhere else pointing to /mnt, of course the the link should show the disk content. I can't get the meaning of the last sentence. "The link will show the contents of mount target (B) instead of the original (A)". Can you elaborate a little more? or add some examples in the answer for people like me? – Chan Kim Jun 17 at 14:50
  • @ChanKim "of course the the link should show the disk content" yes, true. Yes, that's pretty much it. Whether it's an "of course" or not depends on how much the person asking the question knows about symlinks and mount points. – muru Jun 17 at 15:25
22

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.

1
  • 1
    I haven't used mount --bind, but I doubt it can replicate the behavior of a symlink like ln -s ../../myfile .. If you move that to another directory, it will point somewhere else because it's a relative link. This can be useful if you need to backup a sub-tree and still have the links work in the backup. – Joe Dec 17 '14 at 4:41
16

Additionally, ln -s would survive a reboot; whereas mount --bind would not, unless you edit /etc/fstab to make it persistent.

2

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:

OpenSSH refused .ssh directory with a symbolic link

2

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 directory
    

    As 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

1
  • What system did you test this on? Your tab completion results look like you have set -P set in bash, and I can't reproduce the ll ln/../ result on Ubuntu 20.04 or 18.04 or Arch Linux. – muru May 12 at 12:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.