LinuxIII · Filesystems and FilesInodes
Inodes, dentries, and the VFS — how Linux tracks files
What you'll learn
- Explain what an inode is and what it stores
- Read inode numbers from `ls -i` and `stat`
- Identify the inode exhaustion failure mode before it happens
- Understand why `df` and `du` can disagree on the same filesystem
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09
The filesystem path is for humans. The kernel does not look up files by path — it looks them up by inode number, an integer that uniquely identifies a file on a particular filesystem.
What an inode stores
Each file on disk has an inode. The inode holds everything the kernel needs to access the file except its name and its contents:
| Field | What it stores |
|---|---|
| File kind | Regular, directory, symlink, device, socket, pipe |
| Permissions | Mode bits (rwx for owner/group/other) |
| Ownership | UID, GID |
| Size | Logical size in bytes |
| Timestamps | atime, mtime, ctime (and on modern filesystems, btime) |
| Link count | Number of hard links pointing at this inode |
| Block pointers | Locations of the data blocks on disk |
| Extended attributes | xattrs, capability bits, ACLs |
The path is not in the inode. The kernel maintains a separate structure (the dentry cache) that maps paths to inodes in memory.
Inspecting inodes
$ ls -li /etc/passwd /etc/shadow /etc/group12345 -rw-r--r-- 1 root root 3010 Aug 9 11:11 /etc/passwd
12346 -rw-r----- 1 root shadow 1840 Aug 9 11:11 /etc/shadow
12347 -rw-r--r-- 1 root root 1024 Aug 9 11:11 /etc/groupIllustrative output
The inode number is unique within a filesystem. The same inode number can appear on different filesystems and refer to different files.
Inode exhaustion
Every filesystem is created with a fixed number of inodes. A small file uses one inode; a large file uses one inode. The filesystem has a fixed pool regardless of file size.
This matters in production:
$ df -i /varFilesystem Inodes IUsed IFree IUse% Mounted on
/dev/sdc1 6553600 6549870 3730 100% /varIllustrative output
Why df and du disagree
The classic production question: df says the filesystem is full,
but du on every directory adds up to half the size. What is
missing?
| Tool | What it measures |
|---|---|
df | Total blocks allocated to the filesystem’s free-space bitmap, including blocks held by open-but-deleted files |
du | Bytes accounted for by walking the directory tree from a starting point |
The gap is almost always deleted-but-open files. A process holds
a file descriptor open after the file has been unlinked; the file’s
inode is preserved (because the link count never hit zero) and its
blocks are not freed; but the file no longer appears in any directory,
so du does not see it.
$ lsof +L1 | headCOMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
mysqld 1234 mysql 42u REG 253,1 5242880000 0 67890 /var/lib/mysql/ibdata1 (deleted)
logrotat 5678 root 4w REG 253,1 104857600 0 34567 /var/log/nginx/access.log (deleted)Illustrative output
The remediation: restart or signal the holding process (often after
rotating logs without copytruncate), or use fuser / lsof to
identify the process holding the file and decide whether the
file-descriptor leak is real.
Knowledge check
Knowledge check · 3 questions
Q1. Which piece of file metadata does an inode store?
Q2. A write can fail with ENOSPC while df -h still shows the filesystem is nearly empty.
Q3. Which of the following would cause `df` to report the filesystem as more full than `du` suggests? Select all that apply.
Passing score: 75%. Answers are checked in this browser.