Use when you have a written implementation plan to execute in a separate session with review checkpoints
npx skills add netsapiensis/claude-code-skills --skill "rocky-storage"
Install specific skill from multi-skill repository
# Description
Rocky Linux 8/9 storage management including LVM lifecycle (PV/VG/LV), XFS and ext4 filesystem operations, fstab configuration, disk partitioning, and mount management. Use when managing disks, partitions, logical volumes, filesystems, or mount points.
# SKILL.md
name: rocky-storage
description: Rocky Linux 8/9 storage management including LVM lifecycle (PV/VG/LV), XFS and ext4 filesystem operations, fstab configuration, disk partitioning, and mount management. Use when managing disks, partitions, logical volumes, filesystems, or mount points.
Rocky Linux Storage Management
LVM, filesystems, partitioning, fstab, and mount management for Rocky Linux 8/9.
Prerequisite: See rocky-foundation for OS detection and safety tier definitions.
Disk and Partition Inspection
# List block devices # [READ-ONLY]
lsblk
lsblk -f # Show filesystem info
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,UUID
# Disk usage # [READ-ONLY]
df -h
df -hT # Include filesystem type
df -i # Inode usage
# Partition tables # [READ-ONLY]
fdisk -l /dev/sda
gdisk -l /dev/sda # GPT disks
parted /dev/sda print
# Disk health (SMART) # [READ-ONLY]
smartctl -a /dev/sda
smartctl -H /dev/sda # Quick health check
Partitioning
GPT Partitioning (Recommended)
# Create GPT partition table and partition # [DESTRUCTIVE]
parted /dev/sdb mklabel gpt
parted /dev/sdb mkpart primary xfs 0% 100%
# Or interactive:
parted /dev/sdb # [DESTRUCTIVE]
# (parted) mklabel gpt
# (parted) mkpart primary xfs 0% 100%
# (parted) quit
MBR Partitioning (Legacy)
# Create MBR partition # [DESTRUCTIVE]
fdisk /dev/sdb
# n (new) -> p (primary) -> 1 -> defaults -> w (write)
WRONG -- partitioning a mounted/in-use disk:
# WRONG: Modifying partitions on a disk with mounted filesystems
fdisk /dev/sda # sda has mounted partitions!
# CORRECT: Only partition unused disks or unmounted partitions
lsblk /dev/sdb # Verify nothing is mounted # [READ-ONLY]
fdisk /dev/sdb # Safe if no mounts # [DESTRUCTIVE]
LVM (Logical Volume Management)
LVM Concepts
Physical Volumes (PV) -> Volume Groups (VG) -> Logical Volumes (LV) -> Filesystem
/dev/sdb1 vg_data lv_app /opt/app
/dev/sdc1 lv_logs /var/log/app
Inspection
# Physical volumes # [READ-ONLY]
pvs
pvdisplay
pvdisplay /dev/sdb1
# Volume groups # [READ-ONLY]
vgs
vgdisplay
vgdisplay vg_data
# Logical volumes # [READ-ONLY]
lvs
lvdisplay
lvdisplay /dev/vg_data/lv_app
Create LVM Stack
# 1. Create physical volume # [CONFIRM]
pvcreate /dev/sdb1
# 2. Create volume group # [CONFIRM]
vgcreate vg_data /dev/sdb1
# 3. Create logical volume # [CONFIRM]
lvcreate -L 50G -n lv_app vg_data
# Or use percentage of free space:
lvcreate -l 80%FREE -n lv_app vg_data
# 4. Create filesystem # [DESTRUCTIVE]
mkfs.xfs /dev/vg_data/lv_app
# 5. Mount # [CONFIRM]
mkdir -p /opt/app
mount /dev/vg_data/lv_app /opt/app
Extend LVM (Online)
The most common LVM operation -- growing a volume:
# Check available space in VG # [READ-ONLY]
vgs
# Extend logical volume + filesystem in one command # [CONFIRM]
lvextend -r -L +10G /dev/vg_data/lv_app # -r resizes filesystem too
# Or extend to a specific size # [CONFIRM]
lvextend -r -L 100G /dev/vg_data/lv_app
# Or use all remaining space # [CONFIRM]
lvextend -r -l +100%FREE /dev/vg_data/lv_app
WRONG -- extending LV without -r and forgetting filesystem resize:
# WRONG: LV is bigger but filesystem still sees old size
lvextend -L +10G /dev/vg_data/lv_app
# df still shows old size!
# CORRECT: Use -r to auto-resize filesystem
lvextend -r -L +10G /dev/vg_data/lv_app
# Or manually resize after:
# XFS: xfs_growfs /opt/app
# ext4: resize2fs /dev/vg_data/lv_app
Add Disk to Existing VG
# 1. Create PV on new disk # [CONFIRM]
pvcreate /dev/sdc1
# 2. Extend volume group # [CONFIRM]
vgextend vg_data /dev/sdc1
# 3. Now extend LVs as needed # [CONFIRM]
lvextend -r -L +50G /dev/vg_data/lv_app
Shrink LVM (ext4 Only)
XFS cannot be shrunk. ext4 can:
# ext4 shrink -- MUST unmount first # [DESTRUCTIVE]
umount /opt/app
e2fsck -f /dev/vg_data/lv_app # Required before shrink
resize2fs /dev/vg_data/lv_app 30G # Shrink filesystem first
lvreduce -L 30G /dev/vg_data/lv_app # Then shrink LV
mount /dev/vg_data/lv_app /opt/app
WRONG -- shrinking LV before filesystem:
# WRONG: Shrinking LV first destroys data
lvreduce -L 30G /dev/vg_data/lv_app # DATA LOSS -- filesystem extends beyond LV!
# CORRECT: Always shrink filesystem first, then LV
resize2fs /dev/vg_data/lv_app 30G
lvreduce -L 30G /dev/vg_data/lv_app
Remove LVM Components
# Remove logical volume # [DESTRUCTIVE]
umount /opt/app # Unmount first
lvremove /dev/vg_data/lv_app # Confirm when prompted
# Remove volume group (all LVs must be removed first) # [DESTRUCTIVE]
vgremove vg_data
# Remove physical volume # [DESTRUCTIVE]
pvremove /dev/sdb1
LVM Snapshots
# Create snapshot # [CONFIRM]
lvcreate -L 5G -s -n lv_app_snap /dev/vg_data/lv_app
# Mount snapshot (read-only) # [CONFIRM]
mkdir -p /mnt/snap
mount -o ro /dev/vg_data/lv_app_snap /mnt/snap
# Remove snapshot # [CONFIRM]
umount /mnt/snap
lvremove /dev/vg_data/lv_app_snap
LVM Thin Provisioning
# Create thin pool # [CONFIRM]
lvcreate -L 100G --thinpool thin_pool vg_data
# Create thin volume # [CONFIRM]
lvcreate -V 50G --thin -n thin_vol vg_data/thin_pool
# Check thin pool usage # [READ-ONLY]
lvs -a -o +lv_layout,pool_lv,data_percent vg_data
Filesystems
XFS (Default on Rocky Linux)
# Create XFS filesystem # [DESTRUCTIVE]
mkfs.xfs /dev/vg_data/lv_app
# Create with label # [DESTRUCTIVE]
mkfs.xfs -L appdata /dev/vg_data/lv_app
# Grow XFS (online, mount point required) # [CONFIRM]
xfs_growfs /opt/app # Grows to fill the LV
# XFS info # [READ-ONLY]
xfs_info /opt/app
# XFS repair (unmount first) # [CONFIRM]
umount /opt/app
xfs_repair /dev/vg_data/lv_app
mount /opt/app
# XFS freeze/thaw (for consistent snapshots) # [CONFIRM]
xfs_freeze -f /opt/app # Freeze
# Take snapshot here
xfs_freeze -u /opt/app # Thaw
Key XFS limitation: XFS can only grow, never shrink. Plan accordingly.
Cloud image note: Rocky 9 GenericCloud images use a single XFS root partition. Since XFS cannot shrink, you cannot repartition the root disk for LVM after deployment. Instead, add a second virtio disk for LVM volumes (see rocky-virtualization -- LVM on Cloud Image VMs).
ext4
# Create ext4 filesystem # [DESTRUCTIVE]
mkfs.ext4 /dev/vg_data/lv_app
# Create with label # [DESTRUCTIVE]
mkfs.ext4 -L appdata /dev/vg_data/lv_app
# Grow ext4 (online) # [CONFIRM]
resize2fs /dev/vg_data/lv_app # Grows to fill the LV
resize2fs /dev/vg_data/lv_app 50G # Or to specific size
# Shrink ext4 (offline only) # [DESTRUCTIVE]
umount /opt/app
e2fsck -f /dev/vg_data/lv_app
resize2fs /dev/vg_data/lv_app 30G
mount /opt/app
# ext4 info # [READ-ONLY]
tune2fs -l /dev/vg_data/lv_app
dumpe2fs /dev/vg_data/lv_app | head -50
# Filesystem check (unmount first) # [CONFIRM]
umount /opt/app
e2fsck -f /dev/vg_data/lv_app
mount /opt/app
XFS vs ext4 Comparison
| Feature | XFS | ext4 |
|---|---|---|
| Default on Rocky | Yes | No |
| Online grow | Yes | Yes |
| Online shrink | No | No |
| Offline shrink | No (never) | Yes |
| Max file size | 8 EiB | 16 TiB |
| Max volume size | 8 EiB | 1 EiB |
| Fragmentation | Better for large files | Better for small files |
| Journal | Metadata only | Metadata + optional data |
| Best for | Large files, databases | General purpose |
fstab Configuration
Rules for fstab
- Always use UUID, never device paths (
/dev/sdXcan change between boots) - Always run
findmnt --verifyafter editing - Keep a backup of fstab before editing
Find UUIDs
# Find UUID of a filesystem # [READ-ONLY]
blkid
blkid /dev/vg_data/lv_app
lsblk -f
fstab Entry Format
# <device> <mountpoint> <type> <options> <dump> <pass>
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /opt/app xfs defaults 0 2
UUID=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy /var/log/app ext4 defaults 0 2
/dev/vg_data/lv_app /opt/app xfs defaults 0 2
For LVM volumes, using the /dev/mapper/ or /dev/vg/lv path is acceptable since LVM names are stable:
/dev/mapper/vg_data-lv_app /opt/app xfs defaults 0 2
Adding fstab Entry
# 1. Back up fstab # [CONFIRM]
cp /etc/fstab /etc/fstab.bak.$(date +%Y%m%d%H%M%S)
# 2. Get UUID # [READ-ONLY]
blkid /dev/vg_data/lv_app
# 3. Add entry to /etc/fstab # [CONFIRM]
echo 'UUID=<uuid-here> /opt/app xfs defaults 0 2' >> /etc/fstab
# 4. Verify fstab syntax # [READ-ONLY]
findmnt --verify
# 5. Test mount # [CONFIRM]
mount -a
# 6. Verify mount # [READ-ONLY]
findmnt /opt/app
df -h /opt/app
WRONG -- skipping verification:
# WRONG: Edit fstab and reboot without testing
echo '/dev/sdb1 /data xfs defaults 0 2' >> /etc/fstab
reboot # May fail to boot if fstab entry is wrong!
# CORRECT: Always verify before reboot
findmnt --verify # Check for errors
mount -a # Test all entries
# Only reboot if both commands succeed
Common Mount Options
| Option | Purpose |
|---|---|
defaults |
rw, suid, dev, exec, auto, nouser, async |
noexec |
Prevent execution of binaries |
nosuid |
Ignore SUID/SGID bits |
nodev |
Ignore device files |
noatime |
Don't update access times (performance) |
nofail |
Don't fail boot if device missing |
ro |
Read-only |
Security-hardened mount for /tmp:
UUID=xxx /tmp xfs defaults,noexec,nosuid,nodev 0 2
Swap Management
# Check current swap # [READ-ONLY]
swapon --show
free -h
# Create swap file # [CONFIRM]
dd if=/dev/zero of=/swapfile bs=1M count=2048
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
# Add to fstab # [CONFIRM]
echo '/swapfile none swap sw 0 0' >> /etc/fstab
# Create swap on LVM # [CONFIRM]
lvcreate -L 4G -n lv_swap vg_data
mkswap /dev/vg_data/lv_swap
swapon /dev/vg_data/lv_swap
# Add to fstab:
# /dev/mapper/vg_data-lv_swap none swap sw 0 0
Monitoring Disk Usage
# Filesystem usage # [READ-ONLY]
df -h
df -hT
# Directory sizes # [READ-ONLY]
du -sh /var/log/*
du -sh /home/* | sort -rh | head -10
# Find large files # [READ-ONLY]
find / -xdev -type f -size +100M -exec ls -lh {} \; 2>/dev/null
# Inode usage (out of inodes = can't create files even with space) # [READ-ONLY]
df -i
# Monitor IO # [READ-ONLY]
iostat -x 1 5
iotop -b -n 3
Checklist: Adding New Storage
- [ ] Identify the disk (
lsblk,fdisk -l) - [ ] Partition if needed (
partedorfdisk) - [ ] Create PV (
pvcreate) - [ ] Create or extend VG (
vgcreateorvgextend) - [ ] Create LV (
lvcreate) - [ ] Create filesystem (
mkfs.xfsormkfs.ext4) - [ ] Create mount point (
mkdir -p) - [ ] Add to fstab with UUID
- [ ] Run
findmnt --verify - [ ] Test with
mount -a - [ ] Set SELinux context if needed (
semanage fcontext+restorecon) - [ ] Verify with
df -handls -Z
When to Use This Skill
- Adding new disks or partitions
- Extending logical volumes (the most common LVM task)
- Creating or resizing filesystems
- Editing /etc/fstab
- Troubleshooting disk space issues
- Setting up swap
- LVM snapshot management
Related Skills
- rocky-foundation -- OS detection, safety tiers
- rocky-selinux -- Setting file contexts on new mount points
- rocky-core-system -- systemd mount units (alternative to fstab)
- rocky-borg-backup -- Backup before destructive storage operations
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.