0Pricing
DevOps Bootcamp · Lesson

Disk, Filesystem, and Mount Automation

Inspect block devices, manage fstab entries, and script LVM and mount operations safely.

Disk, Filesystem, and Mount Automation is a free DevOps Bootcamp lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the DevOps Bootcamp learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Understanding Block Devices with lsblk and fdisk

Before automating disk operations, you must be able to inspect what block devices exist on the system. Two essential tools are lsblk and fdisk -l.

  • lsblk — lists block devices in a tree format showing device names, sizes, mount points, and types (disk, part, lvm)
  • fdisk -l — shows partition tables and sector details (requires root)
  • blkid — prints UUIDs and filesystem types for each block device

In scripts, you will often need to parse this output to detect available disks, check if a partition is formatted, or determine its UUID before mounting.

#!/usr/bin/env bash
# Inspect all block devices and their UUIDs
set -euo pipefail

echo '=== Block Device Tree ==='
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,UUID

echo ''
echo '=== Partition Table Details ==='
sudo fdisk -l 2>/dev/null | grep -E '^Disk |^/dev/'

echo ''
echo '=== UUID Lookup via blkid ==='
sudo blkid | awk -F: '{print $1}' | while read -r dev; do
  uuid=$(sudo blkid -s UUID -o value "$dev" 2>/dev/null || echo 'N/A')
  fstype=$(sudo blkid -s TYPE -o value "$dev" 2>/dev/null || echo 'unknown')
  printf '%-20s UUID=%-38s TYPE=%s\n' "$dev" "$uuid" "$fstype"
done

Checking Disk Space with df and du

df and du are the workhorses for reporting filesystem and directory usage. In sysadmin scripts, you use them to trigger alerts, enforce quotas, or decide when to provision more space.

  • df -h — human-readable filesystem usage across all mounted filesystems
  • df -BG — output in gigabytes for consistent numeric parsing
  • du -sh /path — summarized size of a specific directory
  • du -d 1 /var — one-level deep breakdown (useful to find which subdirectory is large)

The percent used column from df is commonly parsed to fire disk-full alerts in monitoring scripts.

#!/usr/bin/env bash
# Alert if any mounted filesystem exceeds a usage threshold
set -euo pipefail

THRESHOLD=80   # percent

echo 'Checking filesystem usage...'
df -h --output=source,pcent,target | tail -n +2 | while IFS= read -r line; do
  device=$(awk '{print $1}' <<< "$line")
  pct=$(awk '{print $2}' <<< "$line" | tr -d '%')
  mount=$(awk '{print $3}' <<< "$line")

  # Skip pseudo filesystems
  [[ "$device" == tmpfs* || "$device" == devtmpfs* ]] && continue

  if (( pct >= THRESHOLD )); then
    echo "WARNING: $device mounted at $mount is ${pct}% full" >&2
  else
    echo "OK: $device at $mount is ${pct}% used"
  fi
done

Reading and Parsing /etc/fstab

/etc/fstab is the static filesystem table — it defines which devices get mounted at boot, at what path, with which options. Each line has six fields:

  • Device — UUID=..., LABEL=..., or /dev/sdX
  • Mount point — directory path
  • Filesystem type — ext4, xfs, nfs, tmpfs, etc.
  • Options — defaults, ro, noexec, nofail, etc.
  • Dump — 0 or 1 (backup flag)
  • Pass — 0, 1, or 2 (fsck order)

Scripts that add or validate fstab entries must handle comments (lines starting with #) and blank lines gracefully. Always prefer UUID over device names to survive reboots where device ordering may change.

#!/usr/bin/env bash
# Parse /etc/fstab and display non-comment entries in a readable table
set -euo pipefail

FSTAB=/etc/fstab

printf '%-40s %-20s %-10s %s\n' 'DEVICE' 'MOUNTPOINT' 'FSTYPE' 'OPTIONS'
printf '%s\n' '-------------------------------------------------------------------------------------'

while IFS= read -r line; do
  # Skip blank lines and comments
  [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue

  read -r device mountpt fstype options _dump _pass <<< "$line"
  printf '%-40s %-20s %-10s %s\n' "$device" "$mountpt" "$fstype" "$options"
done < "$FSTAB"

Safely Adding an fstab Entry

Manually editing /etc/fstab is error-prone. A bad entry can prevent the system from booting. A safe automation script should:

  • Check if the entry already exists before appending (idempotency)
  • Back up the original file before any modification
  • Use UUID instead of device path
  • Append nofail to mount options so a missing disk does not halt boot
  • Run mount -a in dry-run or a test mount to validate before rebooting

After writing the entry, always verify with findmnt --verify (available on modern systemd distros) to catch syntax errors immediately.

#!/usr/bin/env bash
# Safely append a new entry to /etc/fstab (idempotent)
set -euo pipefail

DEVICE_PATH='/dev/sdb1'
MOUNTPOINT='/mnt/data'
FSTYPE='ext4'
OPTIONS='defaults,nofail'
FSTAB='/etc/fstab'

# Resolve UUID for stable identification
UUID=$(sudo blkid -s UUID -o value "$DEVICE_PATH")
if [[ -z "$UUID" ]]; then
  echo "ERROR: Could not resolve UUID for $DEVICE_PATH" >&2
  exit 1
fi

ENTRY="UUID=$UUID  $MOUNTPOINT  $FSTYPE  $OPTIONS  0  2"

# Idempotency: skip if UUID already referenced in fstab
if grep -qsF "UUID=$UUID" "$FSTAB"; then
  echo "INFO: fstab already contains UUID=$UUID — skipping."
  exit 0
fi

# Backup
cp -p "$FSTAB" "${FSTAB}.bak.$(date +%Y%m%d%H%M%S)"

# Create mountpoint if needed
sudo mkdir -p "$MOUNTPOINT"

# Append entry
echo "$ENTRY" | sudo tee -a "$FSTAB" > /dev/null
echo "INFO: Added: $ENTRY"

# Validate
sudo findmnt --verify --verbose || echo 'WARNING: findmnt verify reported issues'

Mounting and Unmounting Filesystems in Scripts

The mount and umount commands are straightforward, but scripts must handle edge cases:

  • A device may already be mounted — mounting again fails; check with findmnt or mountpoint
  • A mountpoint may be busy (open files) — umount fails; use lsof +D /mnt/target to find culprits
  • Use mount -o remount,ro /mnt/data to switch to read-only without unmounting
  • Use umount -l /mnt/data (lazy) as a last resort — detaches the namespace but waits for references to close

In automation, always check the exit code of mount and log failures to syslog with logger.

#!/usr/bin/env bash
# Mount a device only if not already mounted; log outcome
set -euo pipefail

DEVICE='/dev/sdb1'
MOUNTPOINT='/mnt/data'

log() { logger -t disk-mount "$*"; echo "[$(date '+%F %T')] $*"; }

# Check if already mounted
if mountpoint -q "$MOUNTPOINT"; then
  log "INFO: $MOUNTPOINT is already mounted — nothing to do."
  exit 0
fi

# Ensure mountpoint directory exists
sudo mkdir -p "$MOUNTPOINT"

# Attempt mount
if sudo mount "$DEVICE" "$MOUNTPOINT"; then
  log "OK: Mounted $DEVICE at $MOUNTPOINT"
else
  log "ERROR: Failed to mount $DEVICE at $MOUNTPOINT"
  exit 1
fi

# Show what is now mounted there
df -h "$MOUNTPOINT"

Introduction to LVM: Physical Volumes, Volume Groups, and Logical Volumes

LVM (Logical Volume Manager) adds a flexible abstraction layer between raw block devices and filesystems. The three-tier hierarchy is:

  • Physical Volume (PV) — a raw disk or partition initialized with pvcreate
  • Volume Group (VG) — one or more PVs pooled together with vgcreate
  • Logical Volume (LV) — a virtual partition carved from a VG with lvcreate; this is what you format and mount

The key advantage: you can extend an LV online without unmounting, and add new disks to a VG without reformatting. This makes LVM essential for production storage automation.

Inspection commands: pvs, vgs, lvs, and their verbose cousins pvdisplay, vgdisplay, lvdisplay.

Scripting LVM Volume Creation

Automating LVM setup follows a strict sequence: pvcreate → vgcreate → lvcreate → mkfs → mount. Each step must succeed before the next runs — use set -euo pipefail and validate each command's output.

  • Always check that the target disk has no existing partition table before calling pvcreate
  • Use -y flag to suppress interactive prompts in non-interactive scripts
  • Specify -L (fixed size) or -l 100%FREE for all remaining space
  • After mkfs, use the LV's device path: /dev/<vgname>/<lvname>
#!/usr/bin/env bash
# Automate LVM setup: PV -> VG -> LV -> mkfs -> mount
set -euo pipefail

DISK='/dev/sdc'          # raw disk, no existing partitions
VG_NAME='vg_appdata'
LV_NAME='lv_appdata'
LV_SIZE='10G'
MOUNTPOINT='/mnt/appdata'
FSTYPE='xfs'

echo "[1/6] Initializing Physical Volume on $DISK"
sudo pvcreate -y "$DISK"

echo "[2/6] Creating Volume Group: $VG_NAME"
sudo vgcreate "$VG_NAME" "$DISK"

echo "[3/6] Creating Logical Volume: $LV_NAME (${LV_SIZE})"
sudo lvcreate -y -L "$LV_SIZE" -n "$LV_NAME" "$VG_NAME"

echo "[4/6] Formatting as $FSTYPE"
sudo mkfs."$FSTYPE" "/dev/$VG_NAME/$LV_NAME"

echo "[5/6] Mounting at $MOUNTPOINT"
sudo mkdir -p "$MOUNTPOINT"
sudo mount "/dev/$VG_NAME/$LV_NAME" "$MOUNTPOINT"

echo "[6/6] Done. Disk usage:"
df -h "$MOUNTPOINT"

# Show LVM summary
vgs && lvs

Extending a Logical Volume Online

One of LVM's most powerful features is online resizing — extending a logical volume and its filesystem while it is mounted and in use. The workflow is:

  1. Extend the LV with lvextend (-r flag resizes the filesystem in the same step)
  2. If not using -r, resize the filesystem separately: resize2fs for ext4, xfs_growfs for xfs

Important constraints:

  • xfs can only grow, never shrink — plan capacity carefully
  • ext4 can shrink but only while unmounted
  • Always verify VG has free space with vgdisplay -s before extending
#!/usr/bin/env bash
# Extend an LV and its xfs filesystem online
set -euo pipefail

VG_NAME='vg_appdata'
LV_NAME='lv_appdata'
EXTEND_BY='5G'
LV_DEV="/dev/$VG_NAME/$LV_NAME"

# Confirm VG has enough free space
FREE_GB=$(vgs --noheadings --units g -o vg_free "$VG_NAME" | tr -d ' g')
echo "VG free space: ${FREE_GB}G"
if (( $(echo "$FREE_GB < 5" | bc -l) )); then
  echo 'ERROR: Not enough free space in VG' >&2
  exit 1
fi

echo "Extending LV by $EXTEND_BY..."
sudo lvextend -L "+${EXTEND_BY}" "$LV_DEV"

echo 'Growing xfs filesystem online...'
sudo xfs_growfs "$LV_DEV"

echo 'New size:'
df -h "$LV_DEV"
lvs "$LV_DEV"

Creating and Formatting Filesystems

After partitioning or LVM setup, you need to format the block device with a filesystem. Common choices in Linux administration:

  • ext4 — mature, journaled, supports shrink; default on many distros (mkfs.ext4)
  • xfs — high-performance, preferred for large files and parallel I/O; default on RHEL/CentOS (mkfs.xfs)
  • btrfs — copy-on-write, snapshots built-in (mkfs.btrfs)
  • tmpfs — RAM-backed, specified in fstab without mkfs

Always set a meaningful filesystem label (-L flag) so the device can be referenced by LABEL= in fstab as a fallback to UUID.

#!/usr/bin/env bash
# Format a partition and assign a label; print resulting UUID
set -euo pipefail

PARTITION='/dev/sdb1'
FSTYPE='ext4'
LABEL='appdata'

# Safety check: refuse to format a currently mounted device
if findmnt --source "$PARTITION" > /dev/null 2>&1; then
  echo "ERROR: $PARTITION is currently mounted. Unmount first." >&2
  exit 1
fi

echo "Formatting $PARTITION as $FSTYPE with label '$LABEL'..."
sudo mkfs."$FSTYPE" -L "$LABEL" -F "$PARTITION"

# Retrieve and display the new UUID
NEW_UUID=$(sudo blkid -s UUID -o value "$PARTITION")
echo "Formatted successfully."
echo "Label : $LABEL"
echo "UUID  : $NEW_UUID"
echo "Use this in fstab: UUID=$NEW_UUID  /mnt/$LABEL  $FSTYPE  defaults,nofail  0  2"

Automating NFS Mounts with autofs

For network filesystems, mounting at boot with fstab can cause delays or failures if the NFS server is temporarily unreachable. autofs solves this by mounting on demand and unmounting after a timeout.

  • Master map: /etc/auto.master — defines the mount-point directory and its map file
  • Direct map: /etc/auto.nfs — specifies options and the NFS server path per subdirectory
  • Reload with systemctl reload autofs after changes
  • Mounts appear automatically under the configured directory when accessed

In scripts, you can dynamically generate the map file from a list of NFS shares and reload autofs — useful for provisioning shared storage across many hosts.

#!/usr/bin/env bash
# Generate an autofs NFS map file from a share list and reload autofs
set -euo pipefail

NFS_SERVER='192.168.1.50'
AUTO_MAP='/etc/auto.nfs'
AUTO_MASTER='/etc/auto.master'
MOUNT_BASE='/nfs'

# Define shares: localname:remote_path
declare -A SHARES=(
  [homes]='/export/homes'
  [media]='/export/media'
  [backups]='/export/backups'
)

# Write map file
{
  echo '# Generated by disk-automation script'
  for localname in "${!SHARES[@]}"; do
    remote="${SHARES[$localname]}"
    echo "$localname  -rw,soft,timeo=30  ${NFS_SERVER}:${remote}"
  done
} | sudo tee "$AUTO_MAP" > /dev/null

echo "Wrote $AUTO_MAP"

# Ensure master map references this file
if ! grep -qF "$AUTO_MAP" "$AUTO_MASTER"; then
  echo "$MOUNT_BASE  $AUTO_MAP" | sudo tee -a "$AUTO_MASTER" > /dev/null
  echo "Updated $AUTO_MASTER"
fi

sudo systemctl reload autofs && echo 'autofs reloaded'

LVM Snapshot for Safe Backups

LVM snapshots provide a point-in-time copy of a logical volume, enabling consistent backups of live filesystems without unmounting them. The snapshot captures the state at creation time using copy-on-write.

  • Create: lvcreate -s -n lv_snap -L 2G /dev/vg_data/lv_data
  • Mount the snapshot read-only to back it up: mount -o ro /dev/vg_data/lv_snap /mnt/snap
  • Run rsync or tar against the snapshot mountpoint
  • Remove snapshot after backup: umount /mnt/snap && lvremove -f /dev/vg_data/lv_snap

Keep snapshot size at 10-20% of the origin LV. If the snapshot fills up, it becomes invalid — monitor with lvs -o lv_name,snap_percent.

#!/usr/bin/env bash
# Create an LVM snapshot, back up via tar, then remove snapshot
set -euo pipefail

VG='vg_appdata'
ORIGIN_LV='lv_appdata'
SNAP_LV='lv_appdata_snap'
SNAP_SIZE='2G'
SNAP_MOUNT='/mnt/snap_backup'
BACKUP_DEST='/var/backups/appdata'
DATESTAMP=$(date +%Y%m%d_%H%M%S)

trap 'sudo umount "$SNAP_MOUNT" 2>/dev/null; sudo lvremove -f "/dev/$VG/$SNAP_LV" 2>/dev/null' ERR EXIT

echo '[1] Creating snapshot...'
sudo lvcreate -s -n "$SNAP_LV" -L "$SNAP_SIZE" "/dev/$VG/$ORIGIN_LV"

echo '[2] Mounting snapshot read-only...'
sudo mkdir -p "$SNAP_MOUNT"
sudo mount -o ro "/dev/$VG/$SNAP_LV" "$SNAP_MOUNT"

echo '[3] Archiving to backup destination...'
sudo mkdir -p "$BACKUP_DEST"
sudo tar -czf "$BACKUP_DEST/appdata_${DATESTAMP}.tar.gz" -C "$SNAP_MOUNT" .

echo '[4] Cleaning up snapshot...'
sudo umount "$SNAP_MOUNT"
sudo lvremove -f "/dev/$VG/$SNAP_LV"

echo "Backup complete: $BACKUP_DEST/appdata_${DATESTAMP}.tar.gz"

Knowledge Check: Safe fstab and Mount Automation

Test your understanding of safe disk, filesystem, and mount automation practices covered in this lesson.

Lesson Recap: Disk, Filesystem, and Mount Automation

In this lesson you built a complete toolkit for safe, scriptable disk and storage management on Linux systems. Key takeaways:

  • Inspection first: lsblk, blkid, df, and du give you the information needed before any change.
  • fstab discipline: always use UUID, always include nofail, always back up before editing, and validate with findmnt --verify.
  • Mount safety: check mountpoint -q before mounting, log with logger, and handle busy-device errors with lsof.
  • LVM power: the PV → VG → LV pipeline enables online extension and snapshot-based backups without downtime.
  • Filesystem choice matters: xfs for performance (grow-only), ext4 for flexibility (can shrink offline), btrfs for snapshot-native workloads.
  • NFS on-demand: autofs avoids boot delays by mounting network shares only when accessed.
  • Snapshot backups: LVM snapshots give consistent, live backups — but always monitor snap_percent and remove snapshots promptly after backup.

Combine these patterns and you can reliably automate the entire storage lifecycle: discovery, provisioning, mounting, resizing, and backup.

Frequently asked questions

Is the “Disk, Filesystem, and Mount Automation” lesson free?

Yes — the full text of “Disk, Filesystem, and Mount Automation” is free to read here on the web, and the DevOps Bootcamp course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the DevOps Bootcamp course, upgrade to CoddyKit PRO.

What will I learn in “Disk, Filesystem, and Mount Automation”?

Inspect block devices, manage fstab entries, and script LVM and mount operations safely. You practise DevOps Bootcamp with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start DevOps Bootcamp?

No prior experience is required. DevOps Bootcamp on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Disk, Filesystem, and Mount Automation” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this DevOps Bootcamp lesson?

Yes. Every DevOps Bootcamp lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Automating User and Group Provisioning
  2. Controlling systemd Services and Writing Unit Files
  3. Disk, Filesystem, and Mount Automation
  4. Building System Health Check and Alert Scripts
← Back to DevOps Bootcamp