open atlas
↑ Back to track
Linux, the operating system LIN · 06 · 03

Mounting

Mounting grafts a filesystem into the single Linux directory tree at a chosen path. Mount options like ro, noexec, and nosuid add security constraints. Bind mounts expose an existing directory at a second path. findmnt and /proc/mounts show what is mounted.

LIN Middle ◷ 22 min
Level
FoundationsJuniorMiddleSenior

Windows assigns each disk a drive letter: C:, D:, E:. You always know which physical disk you are on. Linux does the opposite: there are no drive letters. Every filesystem — whether it lives on an NVMe drive, a USB stick, a network share, or a RAM disk — is grafted into a single unified directory tree at a path you choose. /data, /mnt/usb, /home — these are all just directories where additional filesystems have been attached.

This design means you can move filesystems around (change where /home lives) without changing a single application that reads from /home. It also means there is exactly one operation to learn: mount.

Goal

After this lesson you can mount and unmount a filesystem manually, use mount options to apply security constraints (ro, noexec, nosuid, relatime), create a bind mount, inspect all active mounts with findmnt and /proc/mounts, and diagnose the “device is busy” error on umount.

1

mount grafts a filesystem into the directory tree at a mount point. The mount point is any existing directory. After mounting, that directory’s contents appear to be the root of the mounted filesystem. The directory’s previous contents are hidden (not deleted) while the mount is active.

# Basic mount: attach /dev/sdb1 at /mnt/data
sudo mount /dev/sdb1 /mnt/data

# The mount point must exist first
sudo mkdir -p /mnt/data

# Verify the mount
mount | grep sdb1
# /dev/sdb1 on /mnt/data type ext4 (rw,relatime)

# Or more readably:
findmnt /mnt/data
# TARGET    SOURCE    FSTYPE OPTIONS
# /mnt/data /dev/sdb1 ext4   rw,relatime

# See all mounts in a tree view
findmnt
# TARGET                                SOURCE     FSTYPE     OPTIONS
# /                                     /dev/sda3  ext4       rw,relatime
# ├─/sys                                sysfs      sysfs      rw,nosuid,nodev,noexec
# ├─/proc                               proc       proc       rw,nosuid,nodev,noexec
# ├─/dev                                devtmpfs   devtmpfs   rw,nosuid
# ├─/boot                               /dev/sda2  ext4       rw,relatime
# ├─/boot/efi                           /dev/sda1  vfat       rw,relatime
# └─/mnt/data                           /dev/sdb1  ext4       rw,relatime

The kernel keeps the active mount table in /proc/mounts (and its alias /etc/mtab on modern systems is a symlink to it). Every mount syscall adds a row; every umount removes one.

2

Mount options control how the filesystem behaves. Pass them with -o. Multiple options are comma-separated.

# Mount read-only (cannot write even as root)
sudo mount -o ro /dev/sdb1 /mnt/data

# Mount with noexec (binaries on this filesystem cannot be executed)
sudo mount -o noexec,nosuid /mnt/uploads /mnt/uploads
# noexec: prevents executing binaries from this filesystem
# nosuid: ignores setuid/setgid bits on files (privilege escalation prevention)

# Remount with different options (without unmounting)
sudo mount -o remount,rw /mnt/data
sudo mount -o remount,ro /mnt/data

# relatime vs noatime vs strictatime
# relatime: update atime only if atime < mtime (the default since Linux 2.6.30)
# noatime:  never update atime (best performance, common for SSDs and databases)
# strictatime: always update atime on read (POSIX-correct but slow)
sudo mount -o noatime /dev/sdb1 /mnt/data

# Common secure options for untrusted data (e.g. a shared upload directory):
sudo mount -o nosuid,nodev,noexec /dev/sdc1 /mnt/untrusted
# nodev: prevents device files (character/block) from working on this filesystem

The options listed in findmnt or /proc/mounts are exactly what the kernel is enforcing. If /mnt/uploads is mounted noexec and someone uploads a shell script and runs it, the kernel returns EACCES. This is a meaningful security boundary — not just a convention.

# See all options for a specific mount
cat /proc/mounts | grep '/mnt/data'
# /dev/sdb1 /mnt/data ext4 rw,relatime 0 0
# Fields: device, mountpoint, fstype, options, dump, pass
3

umount detaches a filesystem from the tree. The filesystem must not be in use.

# Unmount by mount point
sudo umount /mnt/data

# Unmount by device
sudo umount /dev/sdb1

# The classic failure: "target is busy"
sudo umount /mnt/data
# umount: /mnt/data: target is busy.

# Find out who is using it
sudo lsof /mnt/data
# COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
# bash     4821 alice  cwd    DIR    8,17     4096    2 /mnt/data
# tail     5102 root    3r   REG    8,17   102400  983 /mnt/data/app.log

# The shell process 4821 has /mnt/data as its current working directory
# tail process 5102 has a file open

# Also useful:
sudo fuser -m /mnt/data
# /mnt/data:            4821  5102

# Fix: move out of the directory and kill or wait for processes
cd /
sudo kill 5102   # if safe to terminate

# Lazy unmount (detaches immediately but cleans up when last reference drops)
sudo umount -l /mnt/data   # use with care: new opens will fail, existing fds still work

The “device is busy” error is almost always a process that has the mount point as its current working directory (cd /mnt/data && ...) or has an open file descriptor inside the tree. lsof and fuser reveal the culprit.

4

Bind mounts expose an existing directory at a second path in the tree. The same inode tree appears under two paths simultaneously. Writes through either path affect the same underlying data.

# Bind mount /var/app/uploads to /srv/uploads (two paths, one directory)
sudo mount --bind /var/app/uploads /srv/uploads

# Both paths now show the same content
ls /var/app/uploads
# report.pdf  data.csv

ls /srv/uploads
# report.pdf  data.csv   <- identical

# Bind mounts are useful for:
# 1. Exposing a path inside a chroot without duplicating data
# 2. Making a specific directory available at a path expected by an application
# 3. Re-mounting with different options (e.g. read-only view of a read-write dir)

# Read-only bind mount: expose /var/app/uploads read-only at /srv/ro-uploads
sudo mount --bind /var/app/uploads /srv/ro-uploads
sudo mount -o remount,ro,bind /srv/ro-uploads
# Now /srv/ro-uploads is read-only even though /var/app/uploads is read-write

# Bind mounts appear in /proc/mounts
cat /proc/mounts | grep bind
# /var/app/uploads /srv/uploads ext4 rw,relatime,bind 0 0

Container runtimes (Docker, podman) use bind mounts extensively — when you do docker run -v /host/path:/container/path, that is a bind mount of the host directory into the container’s filesystem namespace.

5

findmnt is more useful than parsing mount output or /proc/mounts manually. It understands the mount tree structure and supports filtering.

# Show mounts for a specific filesystem type
findmnt -t ext4
# TARGET   SOURCE    FSTYPE OPTIONS
# /        /dev/sda3 ext4   rw,relatime
# /boot    /dev/sda2 ext4   rw,relatime
# /mnt/data /dev/sdb1 ext4  rw,relatime

# Show a specific mount and all its children (submounts)
findmnt /

# Output as JSON (useful in scripts)
findmnt -J /mnt/data

# Check if a path is a mount point (exit 0 = yes, exit 1 = no)
findmnt /mnt/data > /dev/null && echo "mounted" || echo "not mounted"

# Show mount options in detail
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS /mnt/data
# TARGET    SOURCE    FSTYPE OPTIONS
# /mnt/data /dev/sdb1 ext4   rw,relatime

# In scripts, this is how you check before mounting
if ! findmnt /mnt/data > /dev/null 2>&1; then
    sudo mount /dev/sdb1 /mnt/data
fi
Worked example

Setting up a secure upload directory: noexec, nosuid, nodev mounted at /srv/uploads.

# Context: a web server receives user file uploads to /srv/uploads.
# Risk: an attacker uploads a setuid binary or a device file.
# Mitigation: mount the upload partition with nosuid,nodev,noexec.

# Step 1: dedicated partition /dev/sdc1 for uploads (already formatted ext4)
sudo mkdir -p /srv/uploads

# Step 2: mount with security options
sudo mount -o nosuid,nodev,noexec /dev/sdc1 /srv/uploads

# Step 3: verify the options are applied
findmnt /srv/uploads
# TARGET       SOURCE    FSTYPE OPTIONS
# /srv/uploads /dev/sdc1 ext4   rw,nosuid,nodev,noexec,relatime

# Step 4: test that exec is actually blocked
cp /bin/ls /srv/uploads/test-exec
/srv/uploads/test-exec
# -bash: /srv/uploads/test-exec: Permission denied  <- kernel blocks it

# Step 5: test that setuid is stripped
cp /usr/bin/passwd /srv/uploads/
ls -l /srv/uploads/passwd
# -rwsr-xr-x 1 root root ...   <- setuid bit is visible
sudo -u nobody /srv/uploads/passwd
# The process runs as nobody's UID, not root — nosuid suppressed the setuid effect

# Step 6: make it permanent in /etc/fstab (next lesson)
# /dev/sdc1 /srv/uploads ext4 nosuid,nodev,noexec,relatime 0 2

This pattern — dedicated partition with nosuid,nodev,noexec — is standard hardening for any directory that accepts untrusted data. It does not prevent an attacker from storing malicious files, but it does prevent those files from being directly executed or from exploiting setuid tricks on the upload server itself.

Why this works

On macOS, the filesystem model is similar (single unified tree, mount points) but the experience differs significantly. macOS auto-mounts external volumes under /Volumes/DiskName when you plug them in. There is no /dev/sda — disks are /dev/disk0, /dev/disk1. The mount and umount commands exist but are rarely used directly; diskutil mount and diskutil unmount are the macOS-native equivalents. macOS uses APFS for SSDs (with built-in snapshot support) and HFS+ for spinning disks. The noexec and nosuid mount options are supported but less commonly needed because Gatekeeper and SIP (System Integrity Protection) provide overlapping controls.

Common mistake

A subtle trap: if you cd /mnt/data in a terminal and then run umount /mnt/data from that same terminal, the umount fails with “target is busy” because your shell process has the mount point as its current working directory — even if you have no files open. The fix is always cd / (or any path outside the mount) before umounting. Another trap: forgetting that umount takes either the mount point OR the device, but not both — umount /dev/sdb1 /mnt/data is an error.

Check yourself
Quiz

You run 'sudo umount /mnt/data' and get 'target is busy'. Which command shows you which processes are keeping the mount busy?

Recap

Linux uses a single unified directory tree — no drive letters. mount grafts a filesystem into this tree at any existing directory (the mount point). Mount options (ro, noexec, nosuid, nodev, noatime) are security and performance constraints enforced by the kernel. Bind mounts (mount --bind) expose an existing directory at a second path, with optional different options. umount detaches a filesystem; it fails with “target is busy” if any process has an open file or cwd inside the mount — use lsof or fuser -m to find the culprit. findmnt gives a tree view of all active mounts with their options and is more useful than parsing /proc/mounts manually. Active mounts live in the kernel and are visible via /proc/mounts; they survive until reboot unless persisted in /etc/fstab.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 4 done

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.