Linux: Devices, Disks & Filesystems
Table of Contents
- Devices
- Disks and Partitions
- Filesystems
- Swap
- LVM (Logical Volume Manager)
- How the Kernel Boots
- How User Space Starts (systemd)
- Cheat Sheet
1. Devices
Device files in /dev
Most hardware is exposed to user space as device files (device nodes) in /dev. The first character of ls -l output tells you the type:
| Char | Type | Example | Notes |
|---|---|---|---|
b | Block device | /dev/sda, /dev/nvme0n1 | Fixed-size blocks, random access (disks) |
c | Character device | /dev/null, /dev/tty1 | Data streams, no fixed size |
p | Named pipe (FIFO) | — | Like a character device, but the other end is a process |
s | Socket | /dev/log | Interprocess communication |
$ ls -l /dev/sda /dev/null
brw-rw----. 1 root disk 8, 0 ... /dev/sda
crw-rw-rw-. 1 root root 1, 3 ... /dev/null
^ ^
| └─ minor number (which device)
└──── major number (which driver)
Common naming:
| Device name | Meaning |
|---|---|
/dev/sd* | SATA/SCSI/USB disks (sda, sdb, …); partitions are sda1, sda2 |
/dev/nvme* | NVMe SSDs (nvme0n1); partitions are nvme0n1p1 |
/dev/tty* | Virtual terminals / consoles |
/dev/null, /dev/zero, /dev/random | Pseudo-devices |
sysfs (/sys)
sysfs is a pseudo-filesystem that exports information (and sometimes configuration) about kernel subsystems, hardware devices and their drivers to user space as virtual files. It is mounted at /sys.
/devgives you a file to talk to a device./sysgives you a structured view of device attributes and relationships.- Similar in purpose to BSD’s
sysctl, but implemented as a filesystem.
ls /sys/block # block devices the kernel knows about
cat /sys/block/sda/size # size in 512-byte sectors
udev and udevadm
udev is the device manager. When hardware is added or removed, the kernel sends a uevent; the systemd-udevd daemon receives it, applies rules (from /usr/lib/udev/rules.d and /etc/udev/rules.d), and creates/removes nodes and symlinks in /dev (e.g. /dev/disk/by-uuid/…).
Hardware plugged in
│
▼
┌──────────────┐ uevent ┌───────────────┐ rules ┌──────────────────┐
│ Linux kernel │ ──────────► │ systemd-udevd │ ────────► │ /dev nodes and │
│ (driver) │ │ │ │ symlinks created │
└──────────────┘ └───────────────┘ └──────────────────┘
udevadm is the CLI for udev: query device info, trigger events, monitor uevents, control the daemon.
udevadm info --query=all --name=/dev/sda # everything udev knows about sda
udevadm monitor # watch kernel + udev events live
udevadm monitor --kernel # only kernel uevents
udevadm monitor --kernel --subsystem-match=scsi # only SCSI kernel events
sudo udevadm trigger # replay events (e.g. after changing rules)
Other device tools
| Command | Purpose |
|---|---|
lsblk | List block devices as a tree (name, size, type, mountpoints, RO). -l = flat list, -f = show filesystems/UUIDs |
lsscsi | List SCSI and NVMe devices (type, vendor, model, node path) |
sudo chvt N | Switch the foreground virtual terminal to /dev/ttyN |
fgconsole | Print the number of the active VT |
dd — copy raw data
dd reads from an input and writes to an output in blocks. Nicknamed “disk destroyer” because a wrong of= silently overwrites whatever it points at.
dd if=/dev/zero of=new_file bs=1024 count=1 # 1 block of 1024 zero bytes
# write an ISO to a USB stick
sudo dd if=image.iso of=/dev/sdX bs=4M status=progress conv=fsync
| Option | Meaning |
|---|---|
if= | Input file |
of= | Output file |
bs= | Block size |
count= | Number of blocks to copy |
skip= / seek= | Skip blocks in input / output |
status=progress | Show progress |
2. Disks and Partitions
Disk layout
A disk contains a partition table that describes partitions (subdivisions of the whole disk). Each partition usually holds a filesystem: filesystem data structures (metadata, inodes, directories) that point to the actual file data.
┌──────────────────────────────────────────────────────────────┐
│ Whole disk (/dev/sda) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Partition Table (MBR or GPT) │ │
│ └───────────────┬──────────────────────────────┬───────────┘ │
│ ▼ ▼ │
│ ┌──────────────────────────────┐ ┌─────────────────────────┐ │
│ │ Partition (/dev/sda1) │ │ Partition (/dev/sda2) │ │
│ │ ┌──────────────────────────┐ │ │ │ │
│ │ │ Filesystem │ │ │ (swap, another │ │
│ │ │ ┌───────────────────┐ │ │ │ filesystem, LVM PV, │ │
│ │ │ │ FS Data Structures│ │ │ │ or unused) │ │
│ │ │ └─────────┬─────────┘ │ │ │ │ │
│ │ │ ▼ │ │ │ │ │
│ │ │ ┌──────────────────────┐ │ │ │ │ │
│ │ │ │ File Data │ │ │ │ │ │
│ │ │ └──────────────────────┘ │ │ │ │ │
│ │ └──────────────────────────┘ │ │ │ │
│ └──────────────────────────────┘ └─────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
How the kernel accesses a disk
User processes normally go through the filesystem. Tools like dd, fdisk or mkfs bypass it and use raw (direct) device access via device files.
┌───────────────────────────────────────────────────────────┐
│ User Processes │
└─────────────────────────────┬─────────────────────────────┘
│
┌─────────────────────────────┼─────────────────────────────┐
│ Linux Kernel ▼ │
│ ┌──────────────┐ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │
│ │ System Calls │◄────► Raw (direct) device access │
│ └──────┬───────┘ │ ┌─────────────────────────┐ │ │
│ │ │ Device Files (nodes) │ │
│ ▼ │ └────────────┬────────────┘ │ │
│ ┌──────────────┐ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ │
│ │ Filesystem │ │ │
│ └──────┬───────┘ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Block Device Interface and Partition Mapping │ │
│ └──────────────────────────┬──────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ SCSI Subsystem and Other Drivers │ │
│ └──────────────────────────┬──────────────────────────┘ │
└─────────────────────────────┼─────────────────────────────┘
▼
┌───────────────────────────────────────────────────────────┐
│ Storage Device │
└───────────────────────────────────────────────────────────┘
(All arrows are bidirectional — data flows both ways.)
Partition tables: MBR vs GPT
| MBR (DOS) | GPT | |
|---|---|---|
| Max disk size | 2 TiB | Effectively unlimited (8 ZiB) |
| Partitions | 4 primary (or 3 + extended with logical) | 128 by default |
| Redundancy | Single copy at sector 0 | Primary + backup header at end of disk |
| Firmware | Classic BIOS | UEFI (standard) |
Partitioning tools
fdisk— traditional text-based partitioner. Modern versions support MBR, GPT and others; old versions were MBR-only.parted— supports MBR and GPT; changes are applied immediately (no “write” step!).gdisk— GPT-focused fdisk clone.
sudo parted -l # view all partition tables
sudo fdisk -l # same idea with fdisk
sudo fdisk /dev/sdd # interactively edit /dev/sdd
fdisk interactive commands (nothing is changed on disk until w):
| Key | Action |
|---|---|
m | Help |
p | Print the current table |
n | Create a new partition |
d | Delete a partition |
t | Change partition type |
g / o | Create a new empty GPT / MBR table |
w | Write changes and exit |
q | Quit without writing |
3. Filesystems
Common filesystem types
| Type | Notes |
|---|---|
| ext4 | Fourth Extended filesystem; current member of Linux’s native ext line. Mature, journaling, the safe default |
| Btrfs | B-tree filesystem; newer native Linux FS designed to scale beyond ext4. Copy-on-write, snapshots, subvolumes, checksums. Default on Fedora |
| XFS | High-performance journaling FS; default on RHEL 7+ |
FAT (msdos, vfat, exfat) | Microsoft filesystems. msdos = primitive monocase MS-DOS; vfat = long filenames; exfat = large files, common on flash media. Required for the UEFI EFI System Partition (FAT32) |
HFS+ (hfsplus) | Older Apple standard (modern macOS uses APFS) |
ISO 9660 (iso9660) | CD-ROM standard |
| tmpfs, proc, sysfs | Virtual filesystems living in memory / kernel |
Creating a filesystem
mkfs is a front end that calls mkfs.<type>.
sudo mkfs -t ext4 /dev/sdf2 # same as: mkfs.ext4 /dev/sdf2
Mounting and unmounting
Mounting attaches a filesystem on a device to a directory (the mount point) in the single directory tree.
mount # list current mounts (findmnt is nicer)
sudo mount -t type device mountpoint # general form
sudo mount -t ext4 /dev/sdf2 /mnt/data
sudo mount UUID=1234-ABCD /mnt/data # mount by UUID (stable across reboots)
sudo mount -o remount,ro /mnt/data # remount read-only
sudo umount /mnt/data # detach (use the mount point)
Useful -o options: ro, rw, noexec, nosuid, remount, loop (mount an image file).
Why UUIDs? Device names like /dev/sdb can change between boots when disks are added or detected in a different order. UUIDs belong to the filesystem and stay stable.
blkid # devices, their filesystem types and UUIDs
lsblk -f # same info as a tree
/etc/fstab — mounts at boot
# <device> <mountpoint> <type> <options> <dump> <fsck>
UUID=a1b2c3d4-... / ext4 defaults 0 1
UUID=e5f6... /home ext4 defaults,noatime 0 2
UUID=ABCD-1234 /boot/efi vfat umask=0077 0 2
UUID=9f8e... none swap sw 0 0
Last column: 1 = check first (root), 2 = check after root, 0 = never check. On systemd systems, each fstab line becomes a mount unit automatically.
Disk usage
df -h # size and usage of mounted filesystems (human-readable)
du -sh dir/ # -s = summary: grand total only
du -h --max-depth=1 / | sort -h # find the space hogs
Checking a filesystem: fsck
sudo fsck /dev/sdf2 # check and repair
sudo fsck -n /dev/sdf2 # check only, change nothing (safe first step)
Never run
fsckon a mounted filesystem. The kernel may change the disk while fsck works, causing mismatches that can crash the system and corrupt files. Only exception: the root partition mounted read-only in single-user mode.Btrfs and XFS use their own tools instead (
btrfs check,xfs_repair).
4. Swap
Swap is disk space (a partition or a file) where the kernel moves inactive memory pages when RAM runs low. The system keeps running instead of killing processes, but swapping is much slower than RAM.
free -h # RAM and swap usage
swapon --show # active swap areas
sudo mkswap /dev/sdX3 # format a partition as swap
sudo swapon /dev/sdX3 # enable it
sudo swapoff /dev/sdX3 # disable it
Swap file example:
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
(Btrfs needs special handling for swap files. Many distros, including Fedora, also use zram — compressed swap in RAM.)
5. LVM (Logical Volume Manager)
LVM adds a flexible layer between disks and filesystems: you can resize volumes, span disks and take snapshots.
Filesystems ┌──────────┐ ┌──────────┐
(ext4, xfs, …) │ / │ │ /home │
└────┬─────┘ └────┬─────┘
│ │
Logical Volumes ┌────┴─────┐ ┌────┴─────┐
(LV) │ lv_root │ │ lv_home │
└────┬─────┘ └────┬─────┘
└───────┬───────┘
Volume Group ┌────────────┴────────────┐
(VG) │ vg_main │ ← pool of storage
└─────┬─────────────┬─────┘
Physical Volumes ┌─────┴────┐ ┌────┴─────┐
(PV) │ /dev/sda2│ │ /dev/sdb1│
└──────────┘ └──────────┘
| Level | Short summary | Detailed view |
|---|---|---|
| Physical volumes | pvs | pvdisplay |
| Volume groups | vgs | vgdisplay |
| Logical volumes | lvs | lvdisplay |
vgs— compact table of VGs: number of PVs/LVs, total size, free space. Output columns are customizable (-o).vgdisplay— detailed info about a VG and its PVs/LVs: size, used and free space, extents.
LVs appear as /dev/<vg>/<lv> or /dev/mapper/<vg>-<lv>.
6. How the Kernel Boots
BIOS or UEFI?
efibootmgr # list of boot entries → UEFI; "EFI variables not supported" → BIOS
ls /sys/firmware/efi # directory exists → UEFI
Boot sequence
┌────────────────────────┐
│ 1. Firmware (BIOS/UEFI)│ power-on self-test, finds a boot loader
└───────────┬────────────┘
▼
┌────────────────────────┐
│ 2. Boot loader (GRUB, │ loads kernel image (+ initramfs) into
│ systemd-boot) │ memory, passes kernel parameters
└───────────┬────────────┘
▼
┌────────────────────────┐
│ 3. Kernel init │ initializes CPU, memory, devices, drivers
└───────────┬────────────┘
▼
┌────────────────────────┐
│ 4. Mount root FS │ (often via initramfs first)
└───────────┬────────────┘
▼
┌────────────────────────┐
│ 5. Start init (PID 1) │ ◄── USER SPACE STARTS HERE
└───────────┬────────────┘
▼
┌────────────────────────┐
│ 6. init starts the │ services, networking, …
│ rest of the system │
└───────────┬────────────┘
▼
┌────────────────────────┐
│ 7. Login prompt / GUI │ usually at or near the end of boot
└────────────────────────┘
initramfs — a small temporary root filesystem loaded by the boot loader along with the kernel. It contains drivers and tools needed to find and mount the real root (e.g. for LVM, RAID, encryption), then hands over.
Inspecting the boot
cat /proc/cmdline # kernel parameters used for this boot
dmesg | less # kernel ring buffer (boot messages)
journalctl -k # kernel messages via the journal
journalctl -b -1 # logs from the previous boot
7. How User Space Starts (systemd)
Order of user-space startup
init(systemd, PID 1)- Essential low-level services —
udevd,syslogd/journald - Network configuration
- Mid- and high-level services — cron, printing, …
- Login prompts, GUIs, high-level apps (e.g. web servers)
Unit types
systemd manages units. The most important types for boot:
| Unit type | Suffix | Purpose |
|---|---|---|
| Service | .service | Controls service daemons |
| Target | .target | Groups other units (like “runlevels”) |
| Socket | .socket | Incoming connection endpoints; can start a service on demand |
| Mount | .mount | Attachment of filesystems (generated from fstab) |
Others: .timer (cron replacement), .path, .device, .swap, .slice.
Unit dependency graph
┌──────────────────┐
│ default.target │
└────────┬─────────┘
▼
┌──────────────────┐
│multi-user.target │
└───┬─────┬─────┬──┘
┌─────────┘ │ └─────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ basic.target │ │ cron.service │ │ dbus.service │
└──────┬───────┘ └──────────────┘ └──────────────┘
▼
┌──────────────┐
│sysinit.target│
└──────────────┘
default.target is usually a symlink to multi-user.target (server/text) or graphical.target (desktop).
systemctl get-default # which target boots by default
systemd-analyze dot | dot -Tsvg > deps.svg # render the real graph (needs graphviz)
systemd-analyze blame # which units took longest to start
systemd-analyze critical-chain # the slowest dependency chain
Where unit files live
systemctl -p UnitPath show # full unit search path
pkg-config systemd --variable=systemdsystemunitdir # package units, e.g. /usr/lib/systemd/system
pkg-config systemd --variable=systemdsystemconfdir # admin units, e.g. /etc/systemd/system
/etc/systemd/system overrides /usr/lib/systemd/system. Don’t edit package files — use systemctl edit unit to create a drop-in override.
Anatomy of a unit file
Example: the D-Bus system daemon (dbus-daemon.service):
[Unit]
Description=D-Bus System Message Bus
Documentation=man:dbus-daemon(1)
Requires=dbus.socket
RefuseManualStart=yes
[Service]
ExecStart=/usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
ExecReload=/usr/bin/dbus-send --print-reply --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
[Unit]— generic info and dependencies (any unit type)[Service]— how to run the service[Install]— (not shown) whatsystemctl enablehooks the unit into, e.g.WantedBy=multi-user.target
Service Type=
| Type | systemd considers the service ready when… |
|---|---|
simple (default) | Immediately; the process doesn’t fork and stays the main process |
forking | The original process forks and exits (classic daemons) |
notify | The service sends a systemd-specific readiness notification (sd_notify) |
dbus | The service registers its name on D-Bus |
oneshot | The process finishes (for one-time setup tasks) |
systemctl show -p Type unit # check a unit's type
Dependencies
| Directive | Meaning |
|---|---|
Requires | Strict. Activating this unit activates the dependency; if the dependency fails, this unit is deactivated too |
Wants | Activation only. Dependencies are started, but their failure doesn’t matter |
Requisite | The dependency must already be active; otherwise activation of this unit fails |
Conflicts | Negative. Activating this unit stops the conflicting one; simultaneous activation fails |
Dependencies don’t define order. Use
Before=/After=for that.Requires=bwithoutAfter=bmeans both start in parallel.
Everyday systemctl / journalctl
systemctl list-units # active units
systemctl list-units --failed # failed units
systemctl list-jobs # jobs currently queued/running
systemctl status unit # state + recent log lines
systemctl start unit # start now
systemctl stop unit # stop now
systemctl restart unit
systemctl reload unit # reload config (uses ExecReload)
systemctl enable unit # start at boot (--now to also start)
systemctl disable unit
systemctl daemon-reload # re-read unit files after editing
journalctl --unit=unit_name # logs for one unit (short: -u)
journalctl -u unit_name -f # follow logs live
8. Cheat Sheet
| Task | Command |
|---|---|
| List block devices | lsblk, lsblk -f |
| List SCSI/NVMe devices | lsscsi |
| Device details from udev | udevadm info --query=all --name=/dev/sda |
| Watch device events | udevadm monitor |
| Show partition tables | sudo parted -l / sudo fdisk -l |
| Edit partitions | sudo fdisk /dev/sdX |
| Create filesystem | sudo mkfs -t ext4 /dev/sdX1 |
| Show UUIDs | blkid |
| Mount / unmount | mount -t type dev dir / umount dir |
| Free space | df -h |
| Directory size | du -sh dir |
| Check filesystem (dry run) | fsck -n /dev/sdX1 |
| Swap status | swapon --show, free -h |
| LVM overview | pvs, vgs, lvs |
| BIOS or UEFI? | efibootmgr / ls /sys/firmware/efi |
| Kernel parameters | cat /proc/cmdline |
| Boot time analysis | systemd-analyze blame |
| Service logs | journalctl -u unit |