Skip to content

Disk Usage

Disk Quotas covered limiting how much space a user or group is allowed to use. But a quota only sets a limit — it doesn't show where space is actually running out on a filesystem right now. These are two independent questions: a quota answers "who is allowed how much," while disk usage answers "how much space is actually being used right now, and where." This article is dedicated to the second question — tools for checking available space and finding the biggest consumers.

What You Will Learn

By the end of this article you will be able to:

  • explain why df -h and du -sh can give different results;
  • explain the "open but deleted file" problem and its effect on disk usage;
  • analyze a directory hierarchy step by step with du --max-depth;
  • do a quick visual analysis with the interactive ncdu tool;
  • identify inode exhaustion with df -i;
  • know how to find the largest file or directory.

df -h: the Filesystem-Level Overview

df (disk free) shows the total, used, and free space of mounted filesystems:

df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   42G  5.5G  89% /
/dev/vg_data/lv_app 20G  18G  1.1G  95% /mnt/app
tmpfs           2.0G  1.2M  2.0G   1% /run

-h (human-readable) shows bytes as GiB/MiB. df reads from filesystem metadata (the superblock), so the result appears instantly, with no delay, even on a very large filesystem.

To check one specific partition:

df -h /var

du -sh: Directory-Level Size

du (disk usage), on the other hand, calculates the actual space occupied by a specific directory or files, by counting through the actual files:

du -sh /var/log
1.2G    /var/log

-s — show only the final summed total (without listing subdirectories separately), -h — human-readable format.

du genuinely scans the filesystem, so it can take time on large directories — unlike df, the result isn't instant.

Why df and du Don't Match

Sometimes df -h / reports "95% used," but summing up du -sh /* across every directory gives a noticeably smaller number. The most common reason for this is deleted-but-open files.

On Linux, when a file is deleted with rm, if that file is still open by some process (through a file descriptor), it isn't immediately removed — it's only removed from the directory (the list of file names). The disk blocks allocated for the file aren't freed until the process closes it.

rm removes the entry from the directory
a process still holds the file open (via fd)
disk blocks stay occupied — df reports this
du doesn't "see" the file, since it's no longer in the directory

This commonly happens, for example, when a log file has been rotated, but the service writing to it still holds the old file descriptor — until the service is restarted or the file is closed, the disk space isn't freed, even though du shows no large file at all.

Warning

A situation where "df says used, but du finds nothing" is very often caused by exactly this. The fix is finding deleted-but-open files with lsof — covered in depth in Disk-Full Troubleshooting.

du --max-depth: Step-by-Step Analysis

To find exactly which subdirectory is using the most space inside a large directory, limiting the depth is convenient:

du -h --max-depth=1 /var
1.2G    /var/log
340M    /var/cache
180M    /var/lib
45M     /var/tmp
1.8G    /var

Combining this result with sort for sorting by size is recommended:

du -h --max-depth=1 /var | sort -rh

sort -rh sorts human-readable values (1.2G, 340M) correctly, in descending order.

The next step is stepping into the largest directory and repeating the same command, narrowing down the problem area step by step — a process sometimes called "disk archaeology."

ncdu: Interactive Visual Analysis

Manually descending several levels with du --max-depth can be slow and inconvenient. ncdu (NCurses Disk Usage) provides an interactive, navigable terminal interface instead:

sudo apt install ncdu
ncdu /var
--- /var -----------------------------
  1.2GiB [##########] /log
  340MiB [###       ] /cache
  180MiB [##        ] /lib
   45MiB [          ] /tmp

The arrow keys navigate into a directory, and d deletes a file or directory directly. Compared to du, ncdu scans once and then lets you navigate the whole tree quickly — no rescanning each time.

Danger

Deleting with d inside ncdu is irreversible. Before blindly deleting files on a production server, always check what a file actually is (which service it belongs to, when it was created) — an important configuration or data file could be deleted by accident.

Running Out of Inodes: df -i

Even with free disk space, it may be impossible to create a file — because inodes have run out. Every file (regardless of size) occupies one inode, and a fixed number of inodes are allocated when a filesystem is created.

df -i
Filesystem       Inodes  IUsed   IFree IUse% Mounted on
/dev/sda1       3276800 3276800      0  100% /

If IUse% is 100%, a new file can't be created even with free disk space — df -h doesn't show this at all, since it only counts bytes, not the number of files.

This situation typically shows up on systems creating millions of tiny files: session files, caches, mail spools, or a misconfigured temporary-file generator.

Finding the Largest File or Directory

Searching for files larger than a given size with find:

find / -xdev -type f -size +500M -exec ls -lh {} \;
  • -xdev — limits the search to the current filesystem, without crossing into other mounted filesystems (e.g. NFS);
  • -size +500M — files larger than 500 MiB.

Finding the top 10 largest directories, combining du and sort:

du -ah /var | sort -rh | head -10

-a (all) — counts individual files as well, not just directories.

Practical Scenario: / Is 95% Full, but the Cause Is Unclear

Situation: df -h / shows the root partition at 95% used, but which directory is responsible is unknown.

Step 1. Confirm the overall state.

df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   47G  1.2G  95% /

Step 2. Sort first-level directories.

sudo du -h --max-depth=1 / 2>/dev/null | sort -rh | head
47G     /
32G     /var
8G      /usr
4G      /home

Step 3. Go deeper into /var.

sudo du -h --max-depth=1 /var 2>/dev/null | sort -rh | head
30G     /var/log
1.5G    /var/lib

Step 4. Find the specific file inside /var/log.

sudo du -ah /var/log | sort -rh | head -5
28G    /var/log/app/debug.log

Conclusion: the culprit is a single, uncontrollably grown debug.log file, likely because log rotation stopped working. Fully resolving the issue — clearing or removing the file, then fixing log rotation — continues as the central scenario in Disk-Full Troubleshooting.

Common Mistakes

Running du on the Whole / Without -x

Without -x (or --one-file-system), running du / also descends into other mounted filesystems (NFS, an external disk), giving an incorrect, inflated result:

du -xh --max-depth=1 /

Not Looking to du for the Cause When df Says "Full"

df only says "how much is used," not "what's using it." Finding the cause always requires digging in with du or ncdu.

Forgetting About Deleted-but-Open Files

If du's result and df's result don't match, this is often not a bug — a file has already been deleted, but a process still holds it open. This situation can't be identified with du/ncdu alone.

Not Checking for Inode Exhaustion

Seeing a "there's disk space, but files can't be created" error and concluding "there's enough space" from df -h alone, without checking df -i, is a common mistake.

Exercises

  1. Compare the output of df -h and du -sh /*, determine whether there's a discrepancy, and explain why.
  2. Use du -h --max-depth=1 /var | sort -rh to find the three largest directories inside /var.
  3. Install ncdu, run it on /, and find the 5 largest directories interactively (viewing only, without deleting).
  4. Check inode usage on your system with df -i and note how it differs from df -h.

Verification criterion: given a filesystem showing 95% "used" by bytes but low inode usage, you should be able to state the next command that would find the responsible directory or file.

Summary

df -h gives a quick, filesystem-level overview, while du -sh counts the actual file sizes inside a directory — a mismatch between the two is often caused by deleted-but-open files. du --max-depth and ncdu help narrow down the culprit in a large directory hierarchy, step by step or interactively, while df -i reveals a file (inode), not byte, exhaustion problem. These tools work together with disk quotas: a quota shows who is allowed how much, while disk usage shows where space is actually going right now. The next article, Disk-Full Troubleshooting, combines both tools into a single practical procedure for resolving a real "disk is full" situation.

References