Your thin pool hit 100% data usage, writes to every thin LV in the pool started failing, and the auto-extend you thought was protecting you never fired. Or you are reading this before that happens, auditing a pool that has been “protected” for months without anyone ever confirming the mechanism works.

The most common root cause is a one-line surprise in /etc/lvm/lvm.conf: the default value of thin_pool_autoextend_threshold is 100, and a threshold of 100 does not mean “extend when the pool is full”. It means auto-extend is disabled. The commented-out line # thin_pool_autoextend_threshold = 100 in the shipped config looks like a sensible default. It is the off switch.

Even with the threshold set correctly, auto-extend still fails silently if dmeventd is not running, if the pool is not registered for monitoring, or if the volume group has no free extents to extend into. No error is surfaced to applications in any of these cases. The first symptom is the pool filling up.

What this means

Thin pool auto-extend is not a kernel feature. It is a userspace policy executed by dmeventd (the device-mapper event daemon, usually managed as lvm2-monitor.service). The chain that has to work end to end is:

  1. thin_pool_autoextend_threshold in /etc/lvm/lvm.conf must be below 100 (values below 50 are treated as 50).
  2. thin_pool_autoextend_percent must be greater than 0 (it controls how much the pool grows per event, as a percentage of current size).
  3. dmeventd must be running.
  4. The thin pool must be registered for monitoring with dmeventd (seg_monitor state).
  5. The VG must have free extents when the event fires.

If any link breaks, nothing happens. dmeventd does not page you. A failed extend is retried internally with increasing delays (up to roughly 42 minutes between attempts), but if the VG is full it will simply never succeed.

flowchart TD
    A[Pool data usage crosses threshold] --> B{threshold < 100 in lvm.conf?}
    B -- "No: default is 100" --> X1[Auto-extend disabled. Nothing fires.]
    B -- Yes --> C{dmeventd running?}
    C -- No --> X2[No event handling. Silent.]
    C -- Yes --> D{Pool monitored? seg_monitor}
    D -- No --> X3[dmeventd not watching this pool. Silent.]
    D -- Yes --> E{VG has free extents?}
    E -- No --> X4[Extend attempted, fails, retried. Silent.]
    E -- Yes --> F[Pool extended by autoextend_percent]

Common causes

CauseWhat it looks likeFirst thing to check
Threshold still at default 100Pool fills to 100% with no extend ever attemptedlvmconfig activation/thin_pool_autoextend_threshold
dmeventd not runningThreshold is correct, still no extend eventssystemctl is-active lvm2-monitor.service
Pool not monitoreddmeventd runs but ignores this poollvs -o+seg_monitor vg/pool
thin_pool_autoextend_percent is 0Threshold crossing logged, pool size never changeslvmconfig activation/thin_pool_autoextend_percent
VG out of free extentsExtend events fire and fail, pool keeps fillingvgs -o vg_name,vg_free
Config edited but service never restartedNew values in file, old behavior in productionRestart lvm2-monitor and verify with a forced event
Containerized LVM (e.g. lvm-localpv)Auto-extend never works inside the containerdmeventd in the container cannot manage host pools

Quick checks

All read-only and safe to run during an incident.

# 1. Effective auto-extend configuration (what LVM is actually using)
lvmconfig activation/thin_pool_autoextend_threshold activation/thin_pool_autoextend_percent

# 2. Is dmeventd running?
systemctl is-active lvm2-monitor.service
pgrep -x dmeventd

# 3. Is the pool registered for monitoring?
#    Look for "monitored" in the output. "not monitored" means dmeventd ignores it.
lvs -o lv_name,vg_name,seg_monitor vg/thinpool

# 4. Current pool usage, data and metadata
lvs -o lv_name,vg_name,data_percent,metadata_percent,lv_size vg/thinpool

# 5. Does the VG have room to extend into?
vgs -o vg_name,vg_size,vg_free

# 6. Pool health flag (position 9 of lv_attr: D = out of data space, F = failed)
lvs -o lv_name,vg_name,lv_attr vg/thinpool

# 7. Raw pool status from kernel memory (works even if lvs hangs on a sick pool)
dmsetup status vg-thinpool-tpool 2>/dev/null || dmsetup status --target thin-pool

Two notes. First, prefer lvmconfig over grep on lvm.conf: it shows the merged effective value, which is what matters when a commented default is in play. Second, check 7 exists because lvs takes LVM metadata locks and performs I/O. If the pool is already full and the system is sick, lvs can hang while dmsetup status still answers, since it reads from kernel memory.

How to diagnose it

  1. Confirm the symptom precisely. Is the pool actually full (data_percent at or near 100, health flag D), or is auto-extend merely suspected broken? lvs -o lv_name,data_percent,lv_attr vg/thinpool answers this.

  2. Read the effective threshold. lvmconfig activation/thin_pool_autoextend_threshold. If it prints 100, you have found it: auto-extend was never enabled. This is the most frequent cause, because every major distribution (RHEL 7 through 9, Ubuntu, Debian, Arch) ships 100 as the default. Since lvm2-2.02.152, LVM prints a warning when you create thin LVs with auto-extend disabled, but pools created before that, or via tooling that suppresses output, never surfaced it.

  3. Check dmeventd. If the threshold is sane, verify lvm2-monitor.service is active. A pool with a correct threshold and no dmeventd behaves identically to threshold 100: nothing happens. The service state at boot is what matters; if it was started late or failed once, the pool may never have been registered.

  4. Check the monitoring registration. lvs -o+seg_monitor vg/thinpool. dmeventd only acts on pools it is monitoring. A pool that reports “not monitored” needs lvchange --monitor y vg/thinpool.

  5. Check VG headroom. vgs -o vg_free. Auto-extend consumes VG extents at each event, roughly current_pool_size * autoextend_percent / 100 per cycle. If the VG has been full for weeks, every event has been failing silently in the background.

  6. Prove it end to end. Do not close the incident on a config edit. Either wait for organic growth to cross the threshold, or temporarily lower the threshold below current usage and watch lvs -o lv_size and the journal for dmeventd activity until the pool extends. Restore the production threshold afterwards.

Metrics and signals to monitor

SignalWhy it mattersWarning sign
Thin pool data_percentThe countdown to write failure across all thin LVs in the poolAbove 85%
Thin pool metadata_percentSeparate exhaustion domain, can corrupt the pool at 100%Above 75%
seg_monitor stateTells you whether dmeventd is watching the pool at all“not monitored” on a production pool
dmeventd process / lvm2-monitor.serviceNo daemon, no auto-extend, regardless of configService inactive on any host with thin pools
Effective threshold and percent (config audit)Threshold 100 reads as configured but means disabledAny pool on a host with threshold >= 100
VG free spaceAuto-extend’s fuel; zero free extents means events fire and failBelow what two extend cycles would consume
Pool size over timeThe only proof auto-extend has ever actually workedThreshold crossed repeatedly with no size change

Fixes

Fix the disabled default

Edit /etc/lvm/lvm.conf:

activation {
    thin_pool_autoextend_threshold = 80
    thin_pool_autoextend_percent = 20
}

A threshold of 70-80 leaves room for write bursts between the event and the extend completing. The percent controls growth per event; the default is 20, but it must be greater than 0 and large enough that one event buys meaningful runway. Beware: an over-aggressive percent on a nearly-full VG can let one extend consume the last of your VG headroom.

Restore dmeventd

# Enable and start the event daemon
systemctl enable --now lvm2-monitor.service

# Register an existing pool for monitoring if seg_monitor says otherwise
lvchange --monitor y vg/thinpool

After changing lvm.conf, restart the service so dmeventd picks up the new thresholds. On RHEL-family systems the unit is lvm2-monitor.service; other distributions may wire dmeventd differently, so verify with pgrep -x dmeventd rather than assuming.

Feed the VG

If VG free space is the blocker, no LVM config change fixes auto-extend. You need new capacity (pvcreate + vgextend on a new device) or you need to free space inside the pool: delete stale thin snapshots, and run fstrim on thin LV filesystems so discarded blocks return to the pool. Without discard, deleted data never frees pool space. See the related guide on extending LVs when the VG is full.

Emergency: pool already at 100%

If the pool is full right now, extend it manually. This is safe online:

# Manual extend of the pool itself (not the individual thin LVs)
lvextend -L +20G vg/thinpool

If the VG is also full, adding a PV comes first. Check the pool’s error policy: by default LVM uses error_if_no_space, so writes fail immediately when the pool is full. If the pool was created or changed to queue_if_no_space, writes instead queue until the no-space timeout (60 seconds by default) and then error, which looks like a hung system. In either state, lvs can become unresponsive; use dmsetup status --target thin-pool for diagnosis.

Containerized LVM

If your LVM is managed from inside a container (for example OpenEBS lvm-localpv), dmeventd inside the container cannot act on the host’s device-mapper events, and auto-extend will not work from there. Run monitoring and dmeventd on the host, or handle extension from your platform layer.

Prevention

  • Audit the threshold everywhere. Add “effective thin_pool_autoextend_threshold < 100 and thin_pool_autoextend_percent > 0” to your configuration management as an enforced assertion, not a documentation line. Treat threshold 100 on a host with thin pools as a finding.
  • Monitor dmeventd as a first-class service. It is the safety net for thin pools, RAID event handling, and snapshot overflow. Alert when it is not running on any host with thin provisioning.
  • Alert on “threshold crossed, size unchanged”. Track pool size alongside data_percent. Data crossing 80% with no subsequent size increase is the auto-extend failure signature, and it is detectable long before 100%.
  • Keep VG headroom for at least two extend cycles. Auto-extend is only as good as the free extents behind it. Track VG free as a separate capacity dimension from both filesystem usage and pool usage.
  • Prove the mechanism once per pool. After any change, force or observe one real extend event. Most teams first test auto-extend during the incident it was supposed to prevent.
  • Do not rely on df. A thin LV’s filesystem can show 50% used while the pool underneath is at 98%. These are independent failure domains and need independent alerts.

How Netdata helps

  • Per-second disk and device-mapper metrics let you see pool-adjacent I/O behavior (latency climbing as the pool approaches full from reclaim overhead) before writes start failing, rather than after.
  • Correlating block-device saturation with LVM layer state shortens the “is it the pool or the disk” question that opens every thin pool incident.
  • Service and process monitoring catches the dmeventd gap directly: lvm2-monitor.service going inactive on a host with thin pools is itself an alertable event, days before the pool fills.
  • Filesystem usage vs. block device trends side by side makes the classic thin-provisioning blind spot visible: flat df numbers against a steadily filling backing device.
  • Historical trend retention is what LVM itself lacks. LVM commands report current state only; runway estimation for data_percent and VG free requires a time series, and that trend is also how you prove an extend event actually fired.
  • ML anomaly detection on I/O latency flags the subtle pre-failure degradation (allocator strain near pool capacity) that static thresholds on utilization alone miss.