Server LVM: Flexible Storage and Online Resize
You will build a flexible LVM storage stack on a server and grow a live filesystem without unmounting it. By the end you will expand capacity with zero downtime, the way production systems add space.
Learning Objectives
- Assemble physical volumes into a volume group.
- Carve a logical volume and put a filesystem on it.
- Extend the volume and filesystem online.
- Time: ~3 hours · Difficulty: Advanced · Prereqs: a server with two spare disks.
Architecture Overview
Environment Setup
You will need: a Linux server with LVM2 and two empty disks (/dev/sdb, /dev/sdc).
Before you begin: verify the disks are empty with lsblk.
Prerequisites
- Linux with lvm2 installed and two spare block devices (or loop files).
- Root or sudo access for all storage operations.
- The disk management lab for partitioning context (optional but helpful).
- A filesystem choice: ext4 for this lab (resize2fs shown).
Step-by-Step Execution
This labels the disks for LVM and pools them into one resizable group.
sudo pvcreate /dev/sdb /dev/sdc && sudo vgcreate data /dev/sdb /dev/sdcExpected output:
Physical volume "/dev/sdb" successfully created.
Physical volume "/dev/sdc" successfully created.
Volume group "data" successfully created
What this teaches: pvcreate stamps disks as LVM-managed; vgcreate pools their extents into one resizable volume group named data. Check free space with sudo vgs before carving volumes; the default physical extent size is 4 MiB (adjust with vgcreate -s if you plan many small LVs).
The LV behaves like a partition but can grow across both disks.
sudo lvcreate -L 10G -n srv data && sudo mkfs.ext4 /dev/data/srv
Expected output:
Logical volume "srv" created.
Creating filesystem with 2621440 4k blocks: done
What this teaches: lvcreate carves a 10G logical volume from the pool; mkfs.ext4 formats the resulting /dev/data/srv device like any partition.
sudo mkdir -p /srv/store && sudo mount /dev/data/srv /srv/store
Expected output:
(no output on success; verify with: df -h /srv/store)
What this teaches: The LV is a normal block device: mkdir the mountpoint and mount it. From here applications cannot tell it is not a partition.
Extend the LV, then grow the filesystem, all while it stays mounted and in use.
Expected output:
What this teaches: lvextend grows the device and resize2fs grows the filesystem, both online. This two-phase growth is the core LVM superpower. Shortcut: lvextend -r (or --resizefs) runs the filesystem grow for you; the manual two steps are shown here so you see both layers. For XFS the second step is xfs_growfs /srv/store instead of resize2fs.
How It Works
LVM decouples logical storage from physical disks through extents: PVs donate fixed-size chunks to the VG pool, and LVs are allocated from the pool regardless of which disk backs them. An LV can therefore span disks, and growing it is an allocation decision, not a repartitioning.
The device-mapper layer in the kernel presents each LV as /dev/VG/LV, translating I/O to the underlying extents. Because this mapping is dynamic, operations like extension, snapshotting, and even migration (pvmove) happen while the filesystem stays mounted and serving.
For servers this means capacity planning becomes reversible: grow volumes as data arrives, add PVs to the VG when the pool runs low, and snapshot before risky changes. Plain partitions offer none of this without downtime.
Progress So Far
Testing & Validation
df -h /srv/store && sudo vgs && sudo lvs && lsblk -f /dev/data/srvYou should see the larger size while the mount stayed active, and lsblk -f confirms the ext4 label on the LV. If so, you grew storage with zero downtime.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| lvextend succeeded but df unchanged | Filesystem not grown after the device | Run resize2fs for ext4 or xfs_growfs for XFS on the mounted LV |
| No free extents in VG | Pool exhausted | vgextend the VG with another PV, then retry |
| pvcreate: device has existing signatures | Old partition table or filesystem remains | Confirm the disk is expendable, then wipefs -a before pvcreate |
| LV path missing under /dev/data/ | Device-mapper did not activate the LV | Run vgchange -ay data and check lvscan |
| Cannot deactivate VG: LVs in use | Volumes still mounted or open | Unmount all LVs, deactivate snapshots first, then vgchange -an |
| Filesystem check needed after shrink | Shrinking requires offline fsck first | Plan shrinks in maintenance windows; ext4 only, XFS cannot shrink |
| resize2fs: Bad magic number on the LV | Targeted the wrong device (for example the raw disk instead of the LV) | Always grow /dev/VG/LV, never /dev/sdX; verify with sudo lvs first |
Troubleshooting
- Filesystem size unchanged: run resize2fs (ext4) or xfs_growfs (xfs) after lvextend.
- VG out of space: add a disk with pvcreate + vgextend before lvextend.
- Cannot create PV: the disk has an existing signature; wipe with
wipefsafter confirming it is empty.
Extension Ideas
- Add LVM snapshots for consistent backups in Backup & Recovery.
- Compare with the fundamentals view in Linux Fundamentals: LVM.
- Experiment with thin provisioning for over-commit scenarios.
Key Results
- Grew a mounted filesystem from 10GB to 15GB with zero downtime.
- Pooled two disks into one flexible volume group.
- Decoupled filesystem size from physical disk limits.
- Verified capacity changes with df, vgs, and lvs.
Key Takeaways
- PVs pool extents into a VG; LVs allocate from the pool.
- LVs appear as normal block devices under /dev/VG/LV.
- Online growth is two steps: lvextend, then filesystem grow.
- vgextend adds capacity without touching existing LVs.
- Snapshots (see fundamentals LVM lab) ride on the same layering.
Practice Challenges
Challenge 1: Pool expansion
Goal: fill the VG to 95%, add a third PV with vgextend, then grow the LV into the new space online.
Hint: vgs shows free extents before and after.
Challenge 2: Migrate off a disk
Goal: use pvmove to evacuate all extents from /dev/sdb onto /dev/sdc while the LV stays mounted, then vgreduce sdb out.
Hint: pvmove is online and shows progress.