Skip to content
ALB Wiki

Diff — Filesystem

Comparing rev 2 → rev 3

{{infobox
| title = The Filesystem
| chapter = Linux Handbook, chapter 8 — FHS, inodes, mounts, and everything is a file
| core = One rooted tree · everything a file · inodes underneath
| standard | The Filesystem Hierarchy Standard — the map of /
| skills = mount, find, links, devices, /proc + /sys
| next | The shell — the language for traversing it
}}
**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:
```sh
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.
+
The **Filesystem Hierarchy Standard** names every top-level directory — the deep table below is the working map. The headline facts first: `/` is one tree; `/etc` is all configuration; `/proc` and `/sys` are kernel-composed views, not disk; `/usr` holds the userland's bulk; `/var` holds what changes. The modern **merged-usr** layout makes `/bin`, `/sbin`, `/lib` symlinks into `/usr` — the split is historical (early `/` was a minimal rescue root; `/usr` came later with the real userland); 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:
```sh
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 b` makes 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 -s` makes 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** — `mv` rewrites a directory entry; the inode and data never move. `mv` across filesystems is copy+delete.
## The FHS map — the deep version
| Path | Holds | Notes |
| --- | --- | --- |
| `/bin` →`/usr/bin` | user binaries | ls cp mv bash — merged-usr symlink |
| `/boot` | kernel + initramfs + bootloader | its own partition often; `vmlinuz-*` `initrd` `grub/` |
| `/dev` | device nodes | devtmpfs — kernel-populated: `null zero urandom tty sda* pts/` |
| `/etc` | all configuration | fstab passwd shadow ssh/ sysconfig/ hosts resolv.conf |
| `/home` | user homes | `~alice` etc |
| `/lib` →`/usr/lib` | shared libs | `libc.so` the ld.so linker |
| `/lib64` | 64-bit libs | x86_64 split |
| `/media` | automount point | CDs, USB sticks |
| `/mnt` | manual mounts | LFS's `$LFS` |
| `/opt` | third-party | self-contained packages |
| `/proc` | kernel+process state | virtual — `cpuinfo meminfo PID/` |
| `/root` | root's home | |
| `/run` | runtime state | tmpfs — `run/user/` `run/lock` |
| `/sbin` →`/usr/sbin` | admin binaries | fdisk mkfs useradd init |
| `/srv` | site-served data | |
| `/sys` | device/driver objects | sysfs — `class/ block/ bus/` |
| `/tmp` | temp | world-writable sticky `1777`, cleared on boot |
| `/usr` | the userland bulk | `bin lib share include local src` — can be read-only |
| `/usr/local` | *your* additions | software you installed yourself |
| `/var` | variable data | `log spool cache mail lib` |
| `/var/log` | the logs | messages syslog auth.log |
| `/var/lib` | state | dpkg status, rpm db |
| `/var/spool` | queues | mail, cron, printing |
The merged-usr story: historically `/` was a minimal rescue root; `/usr` came later with the real userland — modern systems merge `/bin /sbin /lib` → `/usr/*` symlinks. The FHS exists so every Linux looks the same — a file lives where you expect.
## The special file types — the complete set
```sh
ls -l
-   regular file
d   directory
l   symlink — a path in an inode
c   character device — streams: tty, null, urandom, serial
b   block device — random-access: sda, loop
p   named pipe — FIFO — mkfifo
s   unix socket — local IPC
mkfifo myfifo; echo hi > myfifo & cat myfifo   # a file that's a queue
mknod /dev/foo b 8 32                          # a device node by hand
```
## Devices as files
`/dev` holds not programs but **device nodes** — files that open kernel drivers:
```sh
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_forward` to *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.
## /proc — the kernel's process window, deeper
```sh
cat /proc/cpuinfo          # every core's model, flags, mhz
cat /proc/meminfo          # the memory ledger — MemFree vs Buffers/Cached
cat /proc/loadavg          # load averages + running/total + last pid
cat /proc/uptime           # uptime + idle seconds
cat /proc/mounts           # the real mount table
cat /proc/filesystems      # what filesystems the kernel knows
cat /proc/partitions       # the block devices
cat /proc/version          # kernel + compiler
cat /proc/cmdline          # the boot params
cat /proc/interrupts       # irq traffic
cat /proc/net/tcp          # the sockets, raw
cat /proc/sys/kernel/hostname   # a writable kernel knob
ls /proc/self/             # YOUR reading process as files
```
Every process is `/proc/PID/` — `status`, `cmdline`, `environ`, `fd/`, `maps`, `io`, `limits`, `cwd`→real path, `exe`→the binary. `/proc/sys/` is the sysctl tree — writable knobs. `/proc` is pure kernel-composed — `cat` runs code, not disk I/O.
## /sys — the device object tree
```sh
ls /sys/class/net/              # every NIC as a directory
cat /sys/class/net/eth0/address # its MAC
ls /sys/block/                  # every block device
cat /sys/block/sda/queue/scheduler  # io scheduler — live-tunable
ls /sys/bus/usb/devices/        # the USB tree
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo performance > /sys/.../scaling_governor   # tune it
udevadm info -a /dev/sda        # the device's full sysfs record
```
`/sys` is sysfs — the kernel's devices, drivers, buses, and classes as a browsable hierarchy — the same objects udev watches for hotplug.
## Mount options — the flags that harden
```sh
mount -o ro,noexec,nosuid,nodev /dev/sda3 /mnt
# ro       read-only
# noexec   no binaries execute — /tmp, data partitions
# nosuid   setuid bits disabled
# nodev    no device files honored
# noatime  don't update access times — the performance flag
# relatime the modern atime compromise (default)
# sync     no write caching
# _netdev  wait for network
# nofail   don't fail boot if absent
# x-systemd.automount   lazy-mount on first access
# bind     mount a dir onto another path
```
`noexec`/`nosuid`/`nodev`/`ro` on `/tmp`, `/proc`, `/sys`, data mounts are the hardening layer the fstab options encode.
-
-
## The file types — the leading char decoded
-
-
```sh
-
ls -l
-
# - regular file
-
# d directory
-
# l symlink
-
# c character device — streams (tty, null)
-
# b block device — random access (disks)
-
# p named pipe — FIFO
-
# s unix socket
-
mkfifo myfifo               # a named pipe — a file that's a queue
-
```
## Practical: find and friends
```sh
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
1. `findmnt` — draw the actual mount tree of your system.
2. Create a hard link and a symlink; `stat` both; explain the inode difference.
3. `cat /proc/meminfo`, `ls /sys/class/net` — browse the kernel's mind.
4. `df -i` — could your filesystem hold a million empty files?
5. 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 / |
## See also
- [[Linux]] · [[Shell]] · [[Core utilities]] · [[Users and permissions]] · [[LFS Preparation]]
[[Category:Linux]]
[[Category:Handbook]]
[[Category:Filesystems]]