Phase 1: Filesystem & Inode Mastery
Phase 1: Filesystem & Inode Mastery
Target: Weeks 2-4 (Apr 28 - May 18, 2026)
Man Pages to Master
| Reference | What It Teaches |
|---|---|
|
Inode structure, timestamps (atime/mtime/ctime), permission bits, link count |
|
The |
|
|
|
TESTS section: |
|
Hard links vs symbolic, behavior on deletion |
|
Filesystem-level space reporting — |
|
Directory-level space reporting — |
|
Open files, |
|
The |
|
Mount tree — filesystem types, mount options, source devices |
|
Block device tree — partitions, sizes, mount points, filesystem types |
|
Filesystem check — when and why, inode recovery |
|
ext4 debugging — inode inspection, undelete, superblock recovery |
Concepts to Internalize
The Inode Model
Directory entry (name) → inode number → inode structure → data blocks Inode stores: - File type (regular, directory, symlink, device, pipe, socket) - Permissions (rwx) + special bits (SUID, SGID, sticky) - Owner UID, Group GID - Size in bytes - Timestamps: atime (access), mtime (modify), ctime (change metadata) - Link count (how many directory entries point here) - Block pointers (direct, indirect, double-indirect, triple-indirect) Inode does NOT store: the filename. Names live in directory entries.
Hard Link vs Symbolic Link
Hard link: - Another directory entry pointing to the SAME inode - Same inode number, link count increments - Deleting original: hard link still works (data exists until link count = 0) - Cannot cross filesystem boundaries - Cannot link to directories (prevent cycles) Symbolic link: - A new file whose DATA is a path string - Different inode number, own permissions - Deleting original: symlink breaks (dangling) - Can cross filesystems - Can link to directories
stat Format Strings
man stat → FORMAT SEQUENCESstat -c '%n' file # filename
stat -c '%i' file # inode number
stat -c '%h' file # hard link count
stat -c '%s' file # size in bytes
stat -c '%b' file # blocks allocated (512-byte units)
stat -c '%a' file # permissions (octal)
stat -c '%A' file # permissions (human: -rwxr-xr-x)
stat -c '%U' file # owner name
stat -c '%G' file # group name
stat -c '%x' file # atime (last access)
stat -c '%y' file # mtime (last modify)
stat -c '%z' file # ctime (last status change)
stat -c '%F' file # file type (regular file, directory, symbolic link)
stat -c '%t %T' file # major/minor device number (for device files)
# Combined — the competition dump:
stat -c 'inode=%i links=%h perm=%a owner=%U:%G size=%s type=%F' file
The df vs du Mismatch (Competition Favorite)
Scenario: df shows 90% full. du shows only 60% used. Where's the missing space? Answer: Deleted files still held open by a process. Diagnosis: lsof +L1 # files with link count < 1 (deleted but open) The file's directory entry is removed (du can't see it). The inode still exists because a process has an open file descriptor. df counts at the filesystem level (sees the blocks as used). du counts by walking directory entries (can't see the deleted name). Fix: identify the process, close or restart it. Space reclaimed.
/proc Filesystem
/proc is not on disk. It's a virtual filesystem — the kernel exposes runtime state as files. /proc/self/ → your current process /proc/<pid>/ → any process by PID /proc/<pid>/fd/ → open file descriptors (symlinks to actual files) /proc/<pid>/status → name, state, memory, UIDs, threads /proc/<pid>/cmdline → command that started this process (null-separated) /proc/<pid>/environ → environment variables (null-separated) /proc/<pid>/maps → memory map (shared libs, heap, stack) /proc/<pid>/cwd → symlink to current working directory /proc/<pid>/exe → symlink to the executable binary /proc/<pid>/root → symlink to the filesystem root (may differ in chroot) /proc/mounts → current mounts (equivalent to findmnt) /proc/filesystems → supported filesystem types /proc/cpuinfo → CPU details /proc/meminfo → memory stats /proc/loadavg → load averages /proc/uptime → system uptime in seconds /proc/sys/ → tunable kernel parameters (sysctl)
Drills
# Create a file. Inspect its inode completely.
echo "arena drill" > /tmp/drill-1-1
stat /tmp/drill-1-1
# Extract just the inode number:
stat -c '%i' /tmp/drill-1-1
# Find all files on this filesystem with 2+ hard links:
find / -xdev -type f -links +1 2>/dev/null | head -10
# man find → -links, -xdev (don't cross filesystem boundaries)
# Predict the link count at each step. Then verify with stat -c '%h'.
echo "test" > /tmp/drill-1-2 # link count = ?
ln /tmp/drill-1-2 /tmp/drill-1-2-hard # link count = ?
ln /tmp/drill-1-2 /tmp/drill-1-2-h2 # link count = ?
rm /tmp/drill-1-2 # link count on remaining files = ?
rm /tmp/drill-1-2-hard # link count on last file = ?
cat /tmp/drill-1-2-h2 # works? data intact?
rm /tmp/drill-1-2-h2 # inode freed (link count = 0, no open FDs)
# Open a file, delete it, recover from /proc
echo "critical data" > /tmp/drill-1-3
tail -f /tmp/drill-1-3 &
PID=$!
rm /tmp/drill-1-3
# File is deleted but PID holds it open
ls -la /proc/$PID/fd/ | grep deleted
# Recover:
cp /proc/$PID/fd/3 /tmp/drill-1-3-recovered
cat /tmp/drill-1-3-recovered
kill $PID
# Simulate: create a large file, open it, delete it
dd if=/dev/zero of=/tmp/drill-1-4 bs=1M count=100
tail -f /tmp/drill-1-4 &
PID=$!
rm /tmp/drill-1-4
# du won't see it:
du -sh /tmp/ | grep drill # nothing
# lsof will:
lsof +L1 | grep drill-1-4 # shows the deleted-but-open file
kill $PID
# Space reclaimed after process exits
# Check inode usage:
df -i
# A filesystem can be out of inodes but have free space:
# Many tiny files = many inodes, little data
# man df → -i (show inode information instead of block usage)