Filesystems and inodes
A filename is a directory entry pointing at an inode. The inode is the file's identity; metadata, blocks, links, all hang off it.
The model
A Unix filesystem is two trees:
- The directory tree you navigate. Each directory is a special file mapping names to inode numbers.
- The inode table holding metadata for every file: size, permissions, owner, timestamps, and pointers to the actual data blocks.
A filename like /etc/passwd is resolved by walking directories, looking up "etc" in /'s dir, then "passwd" in /etc's dir. The final lookup gives you an inode number. The inode tells you everything else.
A filename is a directory entry (dentry); an inode is the file itself. Multiple filenames can point to the same inode (hard links). When all links are gone AND no process has it open, the inode is freed and its blocks reclaimed.
What's in an inode
- Mode (file type + permissions)
- Owner uid, group gid
- Size in bytes
- Block count
- Atime, mtime, ctime, crtime (depending on fs)
- Link count (number of hardlinks to this inode)
- Direct block pointers, indirect, double-indirect pointers (ext4) or extent tree (most modern fs)
No filename. The filename is only in the directory entry. Run stat foo to see all of this.
Hard links vs symlinks
- Hard link: another directory entry pointing to the same inode. Indistinguishable from the original. Both must be on the same filesystem.
- Symbolic link: a tiny file whose contents are a path string. Resolved at use time. Can point across filesystems, can dangle if the target is deleted.
ln a b makes a hardlink. ln -s a b makes a symlink. ls -li shows inode numbers.
Common filesystems
| FS | Used for | Notes |
|---|---|---|
| ext4 | Linux default for years | Solid, journaled, no checksums on data |
| xfs | RHEL/CentOS default | Better for large files, parallel allocation |
| btrfs | Snapshots, COW | Compression, RAID, snapshots; some perf trade-offs |
| zfs | Storage servers | COW, snapshots, checksums, native RAID; not in mainline kernel |
| APFS | macOS | COW, snapshots, encryption |
| NTFS | Windows | Journaled, ACLs, alternate data streams |
| tmpfs | /tmp, /dev/shm | Lives in RAM (with swap backing) |
| procfs | /proc | Kernel data exposed as files, no actual storage |
The "deleted but open" gotcha
# fill disk
dd if=/dev/zero of=/var/log/huge bs=1M count=1000
# delete
rm /var/log/huge
# df still shows huge as used because some daemon has it open!
df -h /var/log
# find the culprit
lsof | grep deletedThe inode lives until link count is 0 AND no open file descriptors reference it. Restart the holding process or truncate the file via > /proc/PID/fd/N.
The interview answer
"A filename is a directory entry pointing to an inode number. The inode holds size, permissions, owner, timestamps, and block pointers; the data lives in blocks on disk. Multiple names can hardlink to the same inode. A file isn't freed until all names are gone AND no process holds it open, which is why df can disagree with du after a delete."
Learn more
- Docs
- ArticleJulia Evans: inodesJulia Evans