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 what lvextend changes.
  • 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

CauseWhat it looks likeFirst thing to check
lvextend run without -r, filesystem never resizedlvs shows the new larger size, df shows the old sizeCompare 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 sizevgs -o vg_free versus lvs -o lv_size
xfs_growfs run against the device path instead of the mount pointError 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 unchangeddf -h <mount> and lsblk to map mount to LV
--resizefs helper failure on some lvm2 buildslvextend -r extends the LV but the filesystem resize fails or silently does not happenCompare 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:

  • df total == lvs size, with VG free space available: the LV was never extended. Extend it.
  • df total < lvs size: 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

  1. Confirm the full filesystem and its backing LV. Run df -h on the alerting mount. Note the device path (/dev/mapper/<vg>-<lv> or /dev/<vg>/<lv>).

  2. Compare against LV size. Run lvs -o lv_name,vg_name,lv_size and find the LV. If the LV is larger than what df reports, the filesystem resize was skipped. If they match, the LV itself still needs extending.

  3. 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.

  4. Identify the filesystem type. findmnt -no FSTYPE <mount>. ext4 uses resize2fs with the device path. XFS uses xfs_growfs with the mount point. XFS grows only, never shrinks, so double-check the target size before extending.

  5. Extend and resize, then verify. After the commands, re-run df -h and lvs. 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

SignalWhy it mattersWarning sign
Filesystem utilization per mount (df)What applications actually hitAbove 90% on a production mount
LV size vs filesystem sizeCatches the forgotten resize stepLV size persistently larger than df total after an extend
VG free spaceHeadroom for future extensionBelow roughly 10% free
Thin pool data_percent (if thin)Pool exhaustion freezes all thin LVs, independent of dfAbove 85%, or LV health showing D
LV health status (lv_attr position 9)Surfaces failed or out-of-space statesAny 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, --resizefs could fail because a helper component was missing from the package, leaving the LV extended but the filesystem untouched. If lvextend -r completes but df does not change, fall back to running resize2fs or xfs_growfs manually.

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 df tells 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 -r possible at all. Plan expansion before the VG drops below roughly 10% free.
  • Test the resize path in staging. If you rely on -r through 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 df poll.
  • 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.