df -h says the filesystem is 100% full. Applications are getting ENOSPC. vgs shows plenty of free space. Maybe you already ran lvextend and df still shows the old size. Nothing here is broken. You are looking at three layers that measure three different things, and one of them was never told to grow.
lvextend grows the logical volume. The filesystem on top keeps its old size until you explicitly resize it. The LV is a bigger container; the filesystem inside has not expanded into the new space.
The fix is one command, but the confusion causes real incidents: full filesystems, failed writes, and 3 a.m. pages that end with someone running resize2fs and going back to bed. This article covers why the layers disagree, how to confirm which state you are in, and how to extend safely on ext4 and XFS.
What this means
LVM is a storage virtualization layer between physical disks and filesystems. Capacity has three independent levels:
- VG free space (
vgs): unallocated physical extents in the volume group. Raw material for creating or extending LVs. - LV size (
lvs): how big the virtual block device is. This is whatlvextendchanges. - Filesystem size (
df): how much of that block device the filesystem actually uses. This is what applications see.
Growing the LV without growing the filesystem is like moving to a bigger warehouse but keeping all the shelving in one corner. The space exists at the block layer; nothing at the filesystem layer can use it yet.
flowchart TD VG["Volume group - vgs - free extents"] --> LV["Logical volume - lvs - block device size"] LV --> FS["Filesystem - df - usable capacity"] FS --> APP["Applications - ENOSPC when df hits 100%"] VG -.->|"lvextend allocates"| LV LV -.->|"resize2fs / xfs_growfs / lvextend -r"| FS
A filesystem can be 100% full while the VG is half empty. The layers are independent failure domains: monitoring df alone misses LVM-level problems, and monitoring vgs alone misses filesystem-level ones.
Common causes
| Cause | What it looks like | First thing to check |
|---|---|---|
lvextend run without -r, filesystem never resized | lvs shows the new larger size, df shows the old size | Compare lvs LV size against df total for the mount |
| LV never extended at all (only VG has space) | vgs shows free space, lvs and df both show the same small size | vgs -o vg_free versus lvs -o lv_size |
xfs_growfs run against the device path instead of the mount point | Error like “is not a mounted XFS filesystem” | Re-run against the mount point, e.g. xfs_growfs /var |
| Wrong LV or wrong mount (multiple LVs, similar names) | Resize “succeeds” but the full filesystem is unchanged | df -h <mount> and lsblk to map mount to LV |
--resizefs helper failure on some lvm2 builds | lvextend -r extends the LV but the filesystem resize fails or silently does not happen | Compare lvs and df after the command; resize manually if they disagree |
Quick checks
All read-only and safe during an incident.
# 1. Filesystem view: what applications see
df -h --output=source,fstype,size,used,avail,pcent,target | grep -E 'mapper|Filesystem'
# 2. LV view: the block device size
lvs -o lv_name,vg_name,lv_size,lv_attr
# 3. VG view: unallocated extents available for extension
vgs -o vg_name,vg_size,vg_free
# 4. Map the full mount point to its LV
df -h /var
lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT
# 5. Identify the filesystem type (decides resize2fs vs xfs_growfs)
findmnt -no FSTYPE /var
# or
lsblk -f /dev/mapper/<vg>-<lv>
The diagnostic is the comparison, not any single command:
dftotal ==lvssize, with VG free space available: the LV was never extended. Extend it.dftotal <lvssize: the LV was extended but the filesystem was not resized. This is the forgotten step. Resize the filesystem.- All three full: the VG itself is out of space. That is a different incident; see LVM Insufficient free extents.
How to diagnose it
Confirm the full filesystem and its backing LV. Run
df -hon the alerting mount. Note the device path (/dev/mapper/<vg>-<lv>or/dev/<vg>/<lv>).Compare against LV size. Run
lvs -o lv_name,vg_name,lv_sizeand find the LV. If the LV is larger than whatdfreports, the filesystem resize was skipped. If they match, the LV itself still needs extending.Check VG headroom. Run
vgs -o vg_name,vg_free. Confirm there are enough free extents for the extension you want. For a simple linear LV any free extents in the VG work; striped LVs need free extents distributed across the right PVs.Identify the filesystem type.
findmnt -no FSTYPE <mount>. ext4 usesresize2fswith the device path. XFS usesxfs_growfswith the mount point. XFS grows only, never shrinks, so double-check the target size before extending.Extend and resize, then verify. After the commands, re-run
df -handlvs. All three layers should now agree.
If the LV sits on a thin pool, the same filesystem resize logic applies, but pool headroom is a separate check: lvs -o lv_name,data_percent,metadata_percent on the pool. Extending a thin LV’s virtual size does not consume pool space by itself, but the writes that follow will.
Metrics and signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
Filesystem utilization per mount (df) | What applications actually hit | Above 90% on a production mount |
| LV size vs filesystem size | Catches the forgotten resize step | LV size persistently larger than df total after an extend |
| VG free space | Headroom for future extension | Below roughly 10% free |
| Thin pool data_percent (if thin) | Pool exhaustion freezes all thin LVs, independent of df | Above 85%, or LV health showing D |
LV health status (lv_attr position 9) | Surfaces failed or out-of-space states | Any value other than - |
Track VG free space, LV size, and filesystem usage as three separate capacity dimensions. df alone cannot tell you whether an extension is even possible.
Fixes
Case 1: LV already extended, filesystem not resized
The LV is bigger than the filesystem. Grow the filesystem to fill it. Both operations below are online (no unmount needed) when growing.
For ext4, pass the block device:
# Grow ext4 to fill the LV
resize2fs /dev/<vg>/<lv>
For XFS, pass the mount point, not the device path. On RHEL 8 and later, xfs_growfs no longer accepts a device path and fails with “is not a mounted XFS filesystem”:
# Grow XFS to fill the LV (argument is the mount point)
xfs_growfs /var
With no size argument, both grow the filesystem to the maximum the device supports. Verify with df -h afterward.
Case 2: LV not extended yet
Do both steps with -r (--resizefs), which extends the LV and resizes the filesystem in one command:
# Extend by 10G and grow the filesystem in one step
lvextend -r -L +10G /dev/<vg>/<lv>
# Or consume all remaining VG free space
lvextend -r -l +100%FREE /dev/<vg>/<lv>
-r is the habit worth building. It removes the entire class of “extended but not resized” incidents. A brief device-mapper suspend during the table reload is normal and typically sub-second.
Two caveats on -r:
- It calls the filesystem resize tooling internally, so the same filesystem rules apply. For XFS that still means grow-only.
- On some lvm2 builds shipped between 2023 and early 2025,
--resizefscould fail because a helper component was missing from the package, leaving the LV extended but the filesystem untouched. Iflvextend -rcompletes butdfdoes not change, fall back to runningresize2fsorxfs_growfsmanually.
If you deliberately skip -r (change windows, separate approvals for block and filesystem changes), the manual sequence is lvextend then resize2fs or xfs_growfs. Make sure the second command is in the same change ticket as the first.
Case 3: VG also has no space
If vgs shows no meaningful free extents, extension is impossible until you add capacity: pvcreate on a new device, then vgextend <vg> <device>, then the LV extension and filesystem resize above. That path is covered in LVM Insufficient free extents.
What not to do
- Do not try to shrink XFS to fix a sizing mistake. XFS cannot shrink. The only path is backup, recreate smaller, restore.
- Do not unmount to grow ext4. Online grow works; unmounting a production mount adds downtime for no reason.
- Do not assume a bigger LV fixed the application. Applications fail on ENOSPC from the filesystem. Only
dftells you whether they have room again.
Prevention
- Default to
lvextend -r. Make the atomic form the standard in runbooks, change templates, and automation. The two-step form exists for cases that need it; routine growth is not one of them. - Alert on the gap, not just the fullness. A check that compares LV size to filesystem size catches a forgotten resize within minutes instead of at the next ENOSPC page.
- Monitor all three layers. Filesystem utilization, VG free space, and (for thin) pool data and metadata percentages are independent signals. The LVM monitoring checklist lays out the full signal set and severities.
- Leave VG headroom. Free extents in the VG are what make a 2 a.m.
lvextend -rpossible at all. Plan expansion before the VG drops below roughly 10% free. - Test the resize path in staging. If you rely on
-rthrough configuration management, confirm the flag works on your exact lvm2 build and that your playbooks pass the mount point for XFS growth.
How Netdata helps
Netdata collects the signals that make this class of incident obvious instead of confusing:
- Per-mount filesystem utilization at per-second granularity, so you see the filesystem hit 100% as it happens, not on the next
dfpoll. - Block device and device-mapper metrics from the kernel, letting you correlate the LV’s block device activity with the filesystem filling on top of it.
- Disk space alerts with context, so a full-filesystem alert can be checked against VG and LV capacity instead of being triaged blind.
- Historical retention showing whether the filesystem has grown steadily for weeks (capacity planning) or spiked suddenly (runaway writer), which changes the response.
- Correlation across layers: when the filesystem says full but the block layer shows a larger device, the forgotten-resize pattern is visible in the dashboard before you open a terminal.






