Filesystem
Linux's filesystem is one tree — a single root / from which every disk, every device, every process, every kernel interface hangs. There are no drive letters; a second disk doesn't become D: — it mounts into the tree at any point you choose. And beneath the tree: inodes — the kernel's real file objects, which filenames merely point at. Learn the tree and the inodes and you've learned the filesystem; everything else is elaboration.
The one-tree rule
A disk, a CD-ROM, a USB stick, a network share, a directory of the kernel's internals — all appear as paths under /. The filesystem namespace is unified even though the storage behind it is scattered across devices:
df -hT # which device backs which path — the tree's true plumbing
mount # every currently-mounted filesystem
findmnt # the mount tree, visualized
This is what mount actually does — graft a device onto a path. Unmount it and the path is empty again; the tree is the interface, the mounts are the plumbing.
The FHS map
The Filesystem Hierarchy Standard names every top-level directory:
| Path | Holds | Notes |
|---|---|---|
/bin | essential user binaries | → /usr/bin (merged-usr on modern systems) |
/boot | kernel, initramfs, bootloader | often its own partition |
/dev | device files | devtmpfs — populated by the kernel itself |
/etc | system configuration | all text, all yours |
/home | user homes | |
/lib | essential shared libraries | → /usr/lib |
/media | auto-mount point for removable media | |
/mnt | manual temporary mounts | LFS's staging ground |
/opt | third-party software | |
/proc | process + kernel state | virtual — kernel-composed, not on disk |
/root | root's home | |
/run | runtime state | tmpfs — dies on boot |
/sbin | system binaries | → /usr/sbin |
/srv | site-served data | |
/sys | devices/drivers/kernel objects | sysfs — virtual |
/tmp | temporary files | usually tmpfs; world-writable + sticky |
/usr | the userland's bulk | bin, lib, share — read-only-able |
/var | variable data | logs, spool, caches |
The modern merged-usr layout makes /bin, /sbin, /lib symlinks into /usr — the split is historical (early / was a rescue root; /usr came later); modern systems unify them.
Inodes — what a file actually is
A filename is not a file — it's a directory entry pointing at an inode. The inode holds everything: size, owner, permissions, timestamps, and the block pointers to the data. The name is just one of possibly several links to it:
ls -i file # the inode number
stat file # the inode's full record: times, links, blocks
df -i # inode exhaustion — a full FS can have blocks free
This architecture explains three Unix truths:
- Hard links —
ln a bmakes a second name for the same inode; no "original" exists, only a refcount. Delete one name and the file persists until the last name goes. - Symlinks —
ln -smakes a new inode whose contents are a path — a pointer by name, not by number; it dangles if the target dies. - Moving within a filesystem is free —
mvrewrites a directory entry; the inode and data never move.mvacross filesystems is copy+delete.
Devices as files
/dev holds not programs but device nodes — files that open kernel drivers:
ls -l /dev | head
# crw-rw-rw- 1 root root 1, 3 null <- c = character, 1,3 = major,minor
# brw-rw---- 1 root disk 8, 0 sda <- b = block device
echo hi > /dev/null # a write to the kernel's void
cat /dev/urandom | head -c16 | xxd # reading entropy as a file
Major number = which driver; minor = which instance. /dev/null, /dev/zero, /dev/urandom, /dev/full, tty devices, disks — all files, all opened with the same open() syscall. This is "everything is a file" made literal.
Virtual filesystems — the kernel exposes itself
Three pseudo-filesystems are kernel interfaces wearing file costumes:
/proc— every process as a directory; kernel state as files:cat /proc/cpuinfo,cat /proc/meminfo,ls /proc/self,echo 1 > /proc/sys/net/ipv4/ip_forwardto configure the kernel by writing a file./sys(sysfs) — devices, drivers, buses as a browsable object tree./dev(devtmpfs) — populated automatically as hardware is detected.
None of it lives on disk — the kernel composes it on read. It's the purest "everything is a file" — including the kernel's own mind.
Filesystem types
| FS | Purpose |
|---|---|
| ext4 | The boring correct default — journaled, everywhere |
| xfs | Large files, large filesystems |
| btrfs | CoW, snapshots, checksums |
| tmpfs | RAM-backed — /run, /tmp |
| vfat | The ESP, USB sticks, interop |
| iso9660 | CD images |
| nfs, cifs | Network filesystems |
| proc, sysfs, devtmpfs, cgroup2 | The kernel interfaces |
Permissions on the tree
Every inode carries owner, group, and mode — the rwxrwxrwx triad ×3 (detailed in Users and permissions). On filesystems: mount options like noexec, nosuid, nodev, ro constrain what inodes permit — /proc and /sys mount nosuid,nodev,noexec for good reason.
Practical: find and friends
find /etc -name '*.conf' # name match
find / -type f -size +100M 2>/dev/null # the space hogs
find . -mtime -7 # changed this week
find / -xdev -name target # stay on one filesystem
find . -type l -xtype l # broken symlinks
du -sh /var/* | sort -rh | head # where the space went
Exercises
findmnt— draw the actual mount tree of your system.- Create a hard link and a symlink;
statboth; explain the inode difference. cat /proc/meminfo,ls /sys/class/net— browse the kernel's mind.df -i— could your filesystem hold a million empty files?- Mount a USB stick manually —
mount /dev/sdX1 /mnt— and unmount.
Timeline
| Concept | What it is |
|---|---|
| One tree | Every device grafts into / |
| Inodes | The real files; names are links |
| /dev | Devices as files |
| /proc, /sys | The kernel exposing itself |
| FHS | The standard map of / |