| | {{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 — 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. |
| | |
| | ## 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]] |
| + | [[Category:Linux Handbook]] |
| | |