Linux Tutorial / Mount File Systems and Diagnose Storage Usage

Mounting makes a file system accessible through a directory in the Linux namespace. Verify the target and mount point first, then inspect the actual source, path, and options with findmnt; diagnose space shortages using both byte and inode usage.

Before choosing a format target, review disks, partitions, and file systems. The exercise below uses only a new temporary image file.

System configuration exercises use a conventional Ubuntu 26.04 LTS or Rocky Linux 9 VM as the reference environment. Containers, WSL, and other releases can differ in service and package configuration. Prepare console recovery and record your versions using the virtual machine setup lesson.

Understand what a mount point hides

Mounting over a nonempty directory hides the original entries while the mount is present; it does not delete them. They reappear after unmounting. Use an empty practice mount point and query the exact path with findmnt -T to identify the storage that currently backs it.

findmnt -T "$HOME"
df -hT "$HOME"
df -i "$HOME"

These commands show the mount containing your home, its space usage, and inode usage. Inodes represent file objects and associated metadata; many tiny files can exhaust them even when byte capacity remains. Reporting details and limits depend on the file system.

Mount, write to, and unmount a fresh image

Run this standalone example in a disposable VM with sudo and ext4 tools. A restricted container may not allow mounting. It does not depend on a previous lesson’s shell variables and formats only a newly created image file.

Save the complete code below as mount-lab.sh with LF line endings and run bash mount-lab.sh. It needs Bash, util-linux, e2fsprogs, and sudo access. Prepare tools with sudo apt install util-linux e2fsprogs on Ubuntu or sudo dnf install util-linux e2fsprogs on Rocky. It allocates a loop device explicitly and writes only after the exact mount point reports that device as its source. Preparation failures stop before writing.

#!/usr/bin/env bash
set -u
set -o pipefail
for tool in mktemp truncate mkfs.ext4 losetup mount umount findmnt sudo tee; do
  command -v "$tool" >/dev/null || { printf 'Missing tool: %s\n' "$tool" >&2; exit 1; }
done
sudo -v || exit 1
lab=$(mktemp -d "$HOME/linux-mount-lab.XXXXXX") || exit 1
img=$lab/disk.img
mnt=$lab/mnt
loop=''
cleanup() {
  result=$?
  trap - EXIT
  if [[ -n "$loop" ]]; then
    source=$(findmnt -rn --mountpoint "$mnt" -o SOURCE)
    lookup=$?
    if (( lookup == 0 )) && [[ "$source" == "$loop" ]]; then
      sudo umount -- "$mnt" || result=1
    elif (( lookup != 1 )); then
      printf 'Inspect mount before cleanup: %s\n' "$mnt" >&2
      result=1
    fi
    if findmnt -rn --source "$loop" >/dev/null; then
      printf 'Still mounted; keeping loop device: %s\n' "$loop" >&2
      result=1
    else
      lookup=$?
      if (( lookup == 1 )); then
        sudo losetup --detach "$loop" || result=1
      else
        printf 'Cannot verify loop usage; keeping: %s\n' "$loop" >&2
        result=1
      fi
    fi
  fi
  printf 'Lab retained for inspection: %s\n' "$lab"
  exit "$result"
}
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
truncate -s 128M "$img" || exit 1
mkfs.ext4 -F "$img" || exit 1
mkdir "$mnt" || exit 1
loop=$(sudo losetup --find --show "$img") || exit 1
[[ "$loop" == /dev/loop* ]] || { printf 'Unexpected loop device\n' >&2; exit 1; }
sudo mount -t ext4 -o nodev,nosuid "$loop" "$mnt" || exit 1
source=$(findmnt -rn --mountpoint "$mnt" -o SOURCE) || exit 1
[[ "$source" == "$loop" ]] || { printf 'Mount source mismatch; no write\n' >&2; exit 1; }
printf 'mounted storage\n' | sudo tee "$mnt/note.txt" >/dev/null || exit 1
cat "$mnt/note.txt" || exit 1
sudo umount -- "$mnt" || exit 1
if findmnt -rn --mountpoint "$mnt"; then
  printf 'Mount still present\n' >&2
  exit 1
else
  lookup=$?
  (( lookup == 1 )) || exit 1
fi
printf 'Unmount verified\n'

On success, expect mounted storage and Unmount verified. Exit cleanup unmounts only the verified device at this mount point, then detaches that loop device only if no mount still uses it. Failed unmounts or lookup errors retain the device and return failure. The lab directory and image are always preserved and their path is printed; a rerun creates a fresh directory.

This assumes a personal practice VM without another administrator changing mounts concurrently. It does not eliminate a race between source verification and writing. After failure, inspect the printed path with findmnt --mountpoint and the device with sudo losetup --list; do not remove files while a mount remains.

Handle a busy mount without forcing removal

A shell whose working directory is inside the mount, an open file, or a running service can prevent unmounting. Move terminals outside the mount and stop the relevant program cleanly. If available, use fuser -vm MOUNT_PATH or lsof to investigate. Do not make forceful termination or lazy unmounting the default response.

Treat persistent mounts as a verified configuration change

/etc/fstab records source, mount point, type, options, dump flag, and fsck order. Device names can change, so use a stable identifier such as a UUID where appropriate. The following is an illustrative entry for a secondary ext4 file system, not a line to paste unchanged or use for the temporary lab image.

UUID=REPLACE_WITH_ACTUAL_UUID /srv/data ext4 defaults,nodev,nosuid 0 2

Back up fstab and run sudo findmnt --verify --verbose to check syntax and accessible targets. On systemd systems, reload generated unit configuration with sudo systemctl daemon-reload, then deliberately test the specific mount. Verification cannot guarantee every future boot condition, so retain console recovery access.

nofail can allow boot to continue without an optional device, but it does not prevent an application from writing into the underlying empty directory. For required storage, design mount dependencies and service start conditions. Choose read-only, nodev, nosuid, and noexec options according to the workload rather than treating them as universal security fixes.

Explain df/du differences before deleting data

df -hT
df -i
du -xhd1 "$HOME" 2>/dev/null | sort -h

df measures allocation at file-system level; du walks accessible files. Deleted but open files, unreadable paths, reserved blocks, and metadata can cause differences. du -x avoids crossing file-system boundaries, but a large traversal still causes I/O. Suppressed permission errors mean the total may be incomplete.

Identify a large file’s owner and retention requirements before removing it. Use log rotation or application-supported cache cleanup where appropriate. Remove lab images only after confirming they are unmounted; restore and verify any fstab entry changed during practice.

Official references