61

An existing directory is needed as a mount point.

$ ls
$ sudo mount /dev/sdb2 ./datadisk
mount: mount point ./datadisk does not exist
$ mkdir datadisk
$ sudo mount /dev/sdb2 ./datadisk
$

I find it confusing since it overlays existing contents of the directory. There are two possible contents of the mount point directory which may get switched unexpectedly (for a user who is not performing the mount).

Why doesn’t mount happen into a newly created directory? This is the way how graphical operating systems display removable media. It would be clear if the directory is mounted (exists) or not mounted (does not exist). I am pretty sure there is a good reason but I haven’t been able to discover it yet.

5
  • 1
    If you want that behaviour, use udisksctl. Why use mount?
    – muru
    Commented Dec 23, 2015 at 8:29
  • 2
    Because it is the way of Unix. Because this way it is more flexible, and you can mount then anywhere. Because mounting them anywhere allows you to extend your servers as you need, for instance, getting a new disk for the database partition, moving the data in the DB partition to the new disk, and mount it in the right place to allow the DB data to grow more. Commented Dec 23, 2015 at 9:03
  • 10
    As a historical note, before Windows and LInux essentially crushed all other OSes, there was a company called Apollo. They wrote a unix-alike (better design than Unix!) operating system. It created the directories on which NFS exports got mounted automatically. In fact, you couldn't mount on a pre-existing directory. HP bought Apollo, threw away the operating system, and used Apollo's 64-bit CPU as HP-PA. Apollo's system of remote procedure calls became OSF's DCE, which apparently lives on inside of Windows. Knowing is half the battle!
    – user732
    Commented Dec 23, 2015 at 14:24
  • somehow this happens on my ubuntu 14.04,3 system. i have not investigated, yet. when my SD card gets mounted, it ends up at a path which has nothing underneath. if i umount it and try to manually mount it back, the error i get is there is no directory at the mount point.
    – Skaperen
    Commented Dec 24, 2015 at 11:25
  • 2
    @BruceEdiger better design than Unix! [citation needed]
    – Ruslan
    Commented Dec 26, 2015 at 9:34

5 Answers 5

55

This is a case of an implementation detail that has leaked.

In a UNIX system, every directory consists of a list of names mapped to inode numbers. An inode holds metadata which tells the system whether it is a file, directory, special device, named pipe, etc. If it is a file or directory it also tells the system where to find the file or directory contents on disk. Most inodes are files or directories. The -i option to ls will list inode numbers.

Mounting a filesystem takes a directory inode and sets a flag on the kernel's in-memory copy to say "actually, when looking for the contents of this directory look at this other filesystem instead" (see slide 10 of this presentation). This is relatively easy as it's changing a single data item.

Why doesn't it create a directory entry for you pointing at the new inode instead? There are two ways you could implement that, both of which have disadvantages. One is to physically write a new directory into the filesystem - but that fails if the filesystem is readonly! The other is to add to every directory listing process a list of "extra" things that aren't really there. This is fiddly and potentially incurs a small performance hit on every file operation.

If you want dynamically-created mount points, the automount system can do this. Special non-disk filesystems can also create directories at will, e.g. proc, sys, devfs and so on.

Edit: see also the answer to What happens when you 'mount over' an existing folder with contents?

7
  • Except it doesn't set a flag on the inode. sudo mount --bind / /mnt ; ls /mnt/proc -> empty. I wonder how it does work.
    – sourcejedi
    Commented Dec 23, 2015 at 15:11
  • The exact operation is in fs/namespace.c, I think; I'm not familiar with the source and didn't want to spend too long on drilling to the detail. The "flag on the inode" I got from the linked presentation.
    – pjc50
    Commented Dec 23, 2015 at 17:03
  • 2
    @sourcejedi: bind mounts only bind the filesystem you actually refer to. They don't recursively bind other filesystems mounted under it. This is a handy way to find junk hidden by mounts. (e.g. if some stuff ended up on the root FS in /var/cache some time when /var failed to mount.) See also path_resolution(7). (Older linux-manpages had that man page in section 2, like die.net) IDK how Linux actually works internally, to optimize checking every directory component as a possible mount. Maybe pin that VFS entry in cache? Commented Dec 24, 2015 at 17:58
  • 2
    Right, that's my point... So fs/namei.c (path -> inode lookup) calls into namespace.c though lookup_mnt(). There is a flag on the dentry (directory cache entry). But that's just an optimization a.k.a. implementation detail. It doesn't tell you which filesystem is mounted there; you have to look in the mount table. (See m_hash(), for more implementation details. Linux, at least, avoids additional string comparisons, and AFAICS at the same time manages to re-use dentry's across e.g. bind mounts, because it's written by wizards).
    – sourcejedi
    Commented Dec 25, 2015 at 9:26
  • 1
    @PeterCordes: man 8 mount: mount --bind foo foo. The bind mount call attaches only (part of) a single filesystem, not possible submounts. The entire file hierarchy including sub‐mounts is attached a second place by using: mount --rbind olddir newdir
    – mikeserv
    Commented Dec 26, 2015 at 1:16
20

If mount(2) required the creation of a new directory to be the mount point, you couldn't mount anything under a read-only filesystem. That would be dumb, so we can rule that out.

If mount optionally created a new directory to be the mountpoint, that would be weird. It's not like mount/unmount happen all the time, so putting extra logic in the kernel to do these two steps with a single system call would not be an important speedup. Just leave it up to user-space to make a mkdir(2) system call if it wants one. Dmitry's answer points out that having mount(2) do both things would make it non-atomic. And you'd want an extra argument to mount(2) with mode flags like open(2) takes, for O_CREAT, O_EXCL, etc. It would just be silly compared to letting user-space do it.

Or maybe you were asking about having mount(8) (the traditional program that makes mount(2) system calls) do this? That would be possible, but there's already a perfectly good mkdir(1) for the job, and Unix's design is all about good small tools that can be combined. If you want a tool that does both, it's easy to write a shell script to build that tool out of two simpler tools. (Or, as muru commented, udisksctl already does this, so you don't have to write it.) Also, Linux's normal mount(8) from util-linux supports mount -o x-mount.mkdir[=mode] using it's x- syntax for options for userspace, rather than options to be passed to the filesystem.


Now the more interesting question: why does there have to be a directory on the parent filesystem at all?

Like pjc50's answer points out (no relation, even though he has my initials!) , having mount points show up in directory listings would then require an extra check on every readdir().

Having mount points exist as directories in the directory containing them (on the parent FS) is a nice trick. readdir() doesn't have to notice that it is a mount point at all. That only happens if the mount point is used as a path component. Path resolution of course does have to check the mount table for every directory component of a path.

9
  • 1
    If mount(2) required the creation of a new directory to be the mount point, you couldn't mount anything under a read-only filesystem. That would be dumb - I'd argue it smarter: From the user's perspective, a read-only filesystem shouldn't change, but allowing mounts means it can
    – Izkata
    Commented Dec 23, 2015 at 19:36
  • 2
    @Izkata: Making a filesystem read-only doesn't mean that whole subtree of the VFS is frozen. It could have symlinks pointing to read-write directories, or already have read-write mount points under it when the parent fs was remounted ro. There are many use cases for read-only filesystems where your argument doesn't make sense. Commented Dec 23, 2015 at 23:12
  • 2
    man 8 mount: x-mount.mkdir[=mode] Allow to make a target directory (mountpoint). The optional argument mode specifies the filesystem access mode used for mkdir(2) in octal notation. The default mode is 0755. This functionality is supported only for root users.
    – mikeserv
    Commented Dec 25, 2015 at 3:12
  • I don't see any important use cases of read-only filesystems with mounted read-write filesystems, especially not in the early Unix. @PeterCordes
    – kubanczyk
    Commented Dec 25, 2015 at 20:17
  • @kubanczyk: read-only root filesystem, with a read-write /tmp and /home. Or read-only NFS-mounted /usr with a local /usr/local mounted on it. Or more generally, any shared read-only image with a modifiable part mounted over it. (local mods to a read-only image can also be done on a per-file basis with custom filesystems like overlayfs or other union filesystems for Linux, used on LiveCD bootable images.) I was initially thinking of the root FS initially mounted RO at boot, but making it rw can happen before other mounts. Commented Dec 25, 2015 at 20:36
12

Mounting to existing directory makes a call to mount practically atomic: it either succeeds or fails, at least from user's perspective. If mount had to create the mountpoint itself, it would have two points of failure, making it impossible to guarantee a clean roll back. Imagine the following scenario:

  1. mount successfully creates the mountpoint
  2. mount tries to mount a new file system to that directory, but fails
  3. mount tries to remove the mountpoint, but fails

The system ends up with a side effect of a failed mount.

Here's another one:

  1. umount successfully unmounts a file system
  2. umount tries to remove the mountpoint, but fails

Now, should umount return success or failure?

2
  • 5
    mount has 8 different return codes for errors which can also be combined. It could just add another one when the directory remove fails. man7.org/linux/man-pages/man8/mount.8.html#RETURN_CODES
    – chaos
    Commented Dec 23, 2015 at 9:11
  • 8
    I think the OP is asking why the mountpoint needs to be an existing directory at all, not why doesn't the mount system call create it. Although maybe that was just my interpretation / expectation of what I thought the OP meant to ask, or what I would have asked if I was asking. Commented Dec 23, 2015 at 12:06
3

Another case that can occur:

When you boot, a basic read only image is load on root directory. So you would like to override it when you would like to mound real root. So you can imagine that mount syscall just swap the ro mountpoint to rw.

Here, lets imagine you have a filesystem issue on root mountpoint, you would like to be able to try to repair it. With mount overlap, you can unmount filesystem and use fsck provided into basic image to solve it.

This feature can also be useful in systems that need strong security to be make track of change between a ro partition and a rw one.

4
  • 1
    I'm not sure how this answers the question. Are you pointing out that if mount required creating a new directory at the location of the mountpoint that you couldn't mount anything on top of a read-only filesystem? The opening paragraph is confusing: that's not how Linux initrd works. It uses the pivot_root system call to change the root fs, not just mount more stuff over it. That made it hard to follow your logic in the next paragraphs, because I thought you were talking about pivot_root(2). Commented Dec 23, 2015 at 12:14
  • 2
    @PeterCordes - linux hasn't used an initrd for many years: When switching another root device, initrd would pivot_root and then umount the ramdisk. But initramfs is rootfs: you can neither pivot_root rootfs, nor unmount it. Instead delete everything out of rootfs to free up the space (find -xdev / -exec rm {} \;), overmount rootfs with the new root (cd /newmount; mount --move . /; chroot .), attach stdin/stdout/stderr to the new /dev/console, and exec the new init
    – mikeserv
    Commented Dec 26, 2015 at 1:11
  • @mikeserv: Neat! I hadn't realized that the basic mechanism for switching roots changed when we started using initramfs instead of initrd. From a "make sure the right kernel modules end up in it" admin perspective, they're identical >.<. I still think this doesn't really answer the question very well. It seems to assume the "mount under a rofs is impossible" interpretation, and gives a very specific problem case (which seems unlikely because initramfs isn't mounted read-only at boot. And even if it is, it can simply be remounted read-write without affecting the cpio.gz image.) Commented Dec 26, 2015 at 7:59
  • @PeterCordes - i dont really understand this answer. i just saw your comment - the initramfs is a file system - it cant really ever be read-only - its fs cache incarnate.
    – mikeserv
    Commented Dec 26, 2015 at 8:30
2

I've always wondered that too.

A simple wrapper such as:

#!/bin/sh
eval "mkdir -p \"\$$#\"" 
/bin/mount "$@"  

saved as an executable script named mount in a directory overriding /bin in your PATH should take care of this if it bothers you too much

(Before running the actual mount binary, it creates a directory named after the last argument to mount, if such directory doesn't exist already.)


Alternatively, if you don't want failed invocations of the mount wrapper to create directories, you can do:

#!/bin/sh
set -e
eval "lastArg=\"\$$#\""
test -d "$lastArg" || { mkdir "$lastArg"; madeDir=1; }
/bin/mount "$@"  ||  {  test -z "$madeDir" || rmdir "$lastArg"; }
5
  • Shouldn't the mount command then use the directory thus created?
    – muru
    Commented Dec 23, 2015 at 13:08
  • 1
    @muru That's what the last line does. Commented Dec 23, 2015 at 13:10
  • Oh, so you mean it should be used thus: mount /dev/foo /some/path? I assumed it would work like udisksctl does, so you would run mount /dev/foo.
    – muru
    Commented Dec 23, 2015 at 13:13
  • 4
    You can get the last cmdline arg without eval to expand $#, using "${@:-1}". I tested this with DASH, since I think it doesn't support anything beyond what POSIX sh is required to support. /bin/dash -c 'echo ${@:-1}' foo bar prints bar. Commented Dec 23, 2015 at 13:14
  • 1
    you can use man -o x-mount.mkdir...
    – mikeserv
    Commented Dec 25, 2015 at 3:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .