Linux Disk & Storage Management — From fdisk to LVM
Server says disk full but you see 50% free — here's what's actually happening. Disk management is one of those skills you don't think about until a production server runs out of space at 2 AM. Let's make sure you're ready when that happens.
Understanding Disk Usage — df and du
Before fixing anything, you need to see what's going on. These two commands are your first response tools.
# Show disk usage for all mounted filesystems (human-readable)
df -h
# Show inode usage — you can run out of inodes before disk space!
df -i
# Find the top 10 largest directories under /var
du -h --max-depth=1 /var | sort -rh | head -10
# Find files larger than 100MB anywhere on the system
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null
Here's the secret that catches people: you can have 50% disk space free but still get "No space left on device" errors. That happens when you run out of inodes — one inode is consumed per file. A directory with millions of tiny files (like a session cache) can exhaust inodes while barely touching disk space.
| Command | What It Shows | When to Use |
|---|---|---|
df -h | Filesystem disk space | First check — overall capacity |
df -i | Inode usage | "No space" errors with free disk |
du -sh * | Directory sizes | Finding what's eating space |
lsblk | Block devices and partitions | Seeing all disks and mounts |
blkid | Filesystem UUIDs and types | Configuring fstab entries |
Listing and Identifying Disks
Before you partition anything, know what you're working with.
# List all block devices with size, type, and mount points
lsblk
# Show detailed partition table for a specific disk
sudo fdisk -l /dev/sda
# Get UUID and filesystem type for all partitions
sudo blkid
# Show SCSI devices (useful for identifying new disks in cloud VMs)
lsscsi
In cloud environments like AWS, new EBS volumes typically appear as /dev/xvdf or /dev/nvme1n1. Always double-check with lsblk before doing anything destructive.
Partitioning with fdisk and parted
fdisk handles MBR partitions (disks up to 2TB). For anything larger or for GPT partition tables, use parted.
# Interactive partitioning with fdisk
sudo fdisk /dev/sdb
# Inside fdisk:
# n → new partition
# p → primary
# 1 → partition number
# (accept defaults for full disk)
# w → write changes and exit
# Non-interactive partitioning with parted (GPT, full disk)
sudo parted /dev/sdb --script mklabel gpt
sudo parted /dev/sdb --script mkpart primary ext4 0% 100%
# Create a filesystem on the new partition
sudo mkfs.ext4 /dev/sdb1
| Tool | Partition Table | Max Disk Size | Best For |
|---|---|---|---|
fdisk | MBR | 2 TB | Legacy systems, small disks |
parted | GPT or MBR | 18 EB | Modern systems, large disks |
gdisk | GPT | 18 EB | GPT-specific operations |
Mounting and fstab
Creating a partition is useless until you mount it.
# Create a mount point and mount the partition
sudo mkdir -p /data
sudo mount /dev/sdb1 /data
# Verify it's mounted
df -h /data
# Get the UUID for fstab (never use device names in fstab — they can change!)
sudo blkid /dev/sdb1
Add a persistent mount to /etc/fstab so it survives reboots:
# Add to /etc/fstab (use UUID, not /dev/sdb1)
echo "UUID=your-uuid-here /data ext4 defaults,noatime 0 2" | sudo tee -a /etc/fstab
# Test your fstab entry without rebooting
sudo mount -a
# If mount -a succeeds with no errors, your fstab is correct
Pro tip: Always run mount -a after editing fstab. A typo in fstab can make your server unbootable.
LVM — The Real Power Tool
LVM (Logical Volume Manager) adds a flexible layer between physical disks and filesystems. You can resize volumes on the fly, span multiple disks, and take snapshots — all without downtime.
The LVM stack has three layers:
| Layer | Abbreviation | What It Is |
|---|---|---|
| Physical Volume | PV | A disk or partition prepared for LVM |
| Volume Group | VG | A pool of storage from one or more PVs |
| Logical Volume | LV | A "virtual partition" carved from a VG |
# Step 1: Create Physical Volume from a disk
sudo pvcreate /dev/sdc
# Step 2: Create a Volume Group (pool of storage)
sudo vgcreate data-vg /dev/sdc
# Step 3: Create a Logical Volume (use 80% of the VG)
sudo lvcreate -l 80%VG -n app-data data-vg
# Step 4: Create filesystem and mount
sudo mkfs.ext4 /dev/data-vg/app-data
sudo mkdir -p /app/data
sudo mount /dev/data-vg/app-data /app/data
Extending LVM Volumes — The Killer Feature
This is why LVM exists. Your /app/data is full? Add more space without unmounting.
# Scenario: Add a new disk to an existing volume group
sudo pvcreate /dev/sdd
sudo vgextend data-vg /dev/sdd
# Check available space in the volume group
sudo vgdisplay data-vg | grep "Free"
# Extend the logical volume by 50GB
sudo lvextend -L +50G /dev/data-vg/app-data
# Resize the filesystem to use the new space
# For ext4:
sudo resize2fs /dev/data-vg/app-data
# For XFS (cannot shrink, only grow):
sudo xfs_growfs /app/data
You can even do this in one command:
# Extend LV and resize filesystem in one shot
sudo lvextend -L +50G --resizefs /dev/data-vg/app-data
Managing Swap Space
Swap acts as overflow memory. Here's how to add it when your server is running low on RAM.
# Check current swap
swapon --show
free -h
# Create a 4GB swap file
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# Make it permanent
echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstab
# Verify
free -h
To adjust how aggressively the kernel uses swap:
# Check current swappiness (default is 60)
cat /proc/sys/vm/swappiness
# Set to 10 for servers (prefer RAM, use swap only when necessary)
sudo sysctl vm.swappiness=10
# Make permanent
echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf
Emergency: Disk Full Recovery
When a production disk is 100% full, you need a quick fix before you can even log in properly.
# Find and delete large log files (careful!)
sudo find /var/log -name "*.log" -size +500M -exec ls -lh {} \;
# Truncate a huge log file without deleting it (keeps the file handle valid)
sudo truncate -s 0 /var/log/large-application.log
# Find deleted files still held open by processes (this is the hidden space eater!)
sudo lsof | grep deleted | sort -k7 -rn | head -10
# Restart the process holding the deleted file to reclaim space
sudo systemctl restart the-guilty-service
# Clean package manager cache
sudo apt clean # Debian/Ubuntu
sudo yum clean all # RHEL/CentOS
The lsof | grep deleted trick is the one most people miss. A process can hold a file handle to a deleted file, and the space won't be reclaimed until that process releases it. This is often why df shows full but du shows less usage.
Next up in our Linux series: Systemd Deep Dive — learn how to create services that restart automatically, replace cron with systemd timers, and understand the Linux boot process.
