Disk 'Full' But df Shows Free Space (Inode Exhaustion)

Storage has two limits: bytes and inode counts. When a partition runs out of inodes, writes fail even with terabytes free — usually a mail spool or session directory with millions of tiny files.

What you'll see

Root causes

Inode exhaustion

df -i shows IUse% at 100%. Some workload creates millions of tiny files — mail queues, PHP sessions, cache dirs.

Deleted-but-open files

A process holds a deleted log open; the space frees only when the process restarts. lsof shows them.

Fix it

  1. Check inodes, not bytes
    df -i | awk 'NR==1 || $5+0 > 80'
  2. Find the directory hoarding the files
    du --inodes -x /var | sort -rn | head
  3. Delete the small-file pile (mail queues and old sessions first)
    find /var/lib/php/sessions -type f -mtime +7 -delete
  4. For deleted-but-open space, restart the holder
    lsof +L1 | grep -i deleted

Field note

This is why 'rm the big log' sometimes frees nothing: if a daemon still has it open, the kernel keeps the blocks until the fd closes. Restart the daemon, then re-check df.

Common questions

Why does du find less than df reports?

Deleted-but-open files: a process holds a large file's descriptor, the space stays allocated until the process closes it. lsof +L1 lists the culprits; restarting the holding process frees the space immediately.

Where else does space hide besides deleted files?

Mount points shadowing full directories (a mount over a directory hides its contents), sparse-looking-but-dense filesystems, and reserved blocks (tune2fs -l shows the 5% root reserve df counts as 'used').

Ship it right the first time

Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.

Browse the template store →

One-time. Yours to modify. Instant download from the NinjaOps template store.