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"
doneChecking 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 filesystemsdf -BG— output in gigabytes for consistent numeric parsingdu -sh /path— summarized size of a specific directorydu -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
doneReading 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
nofailto mount options so a missing disk does not halt boot - Run
mount -ain 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
findmntormountpoint - A mountpoint may be busy (open files) —
umountfails; uselsof +D /mnt/targetto find culprits - Use
mount -o remount,ro /mnt/datato 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
-yflag to suppress interactive prompts in non-interactive scripts - Specify
-L(fixed size) or-l 100%FREEfor 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 && lvsExtending 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:
- Extend the LV with
lvextend(-rflag resizes the filesystem in the same step) - If not using
-r, resize the filesystem separately:resize2fsfor ext4,xfs_growfsfor 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 -sbefore 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 autofsafter 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
rsyncortaragainst 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, anddugive you the information needed before any change. - fstab discipline: always use UUID, always include
nofail, always back up before editing, and validate withfindmnt --verify. - Mount safety: check
mountpoint -qbefore mounting, log withlogger, and handle busy-device errors withlsof. - 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_percentand 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
- Automating User and Group Provisioning
- Controlling systemd Services and Writing Unit Files
- Disk, Filesystem, and Mount Automation
- Building System Health Check and Alert Scripts