Block Device: Explanation & Insights
How Linux models anything you can read and write in fixed-size chunks — every disk, partition, and volume on the box.
What It Is
A block device is Linux's model for any storage you can address in fixed-size chunks called blocks — read block 7, write block 9,422, jump straight to block 1,000,000 without touching the ones in between. Spinning disks, SSDs, NVMe drives, the individual partitions carved out of them, LVM logical volumes, RAID arrays, even a humble file pretending to be a disk — Linux wraps every one of them in the same abstraction. To the kernel, and to everything built on top, they all look the same: a long, randomly-addressable array of equal-sized blocks. That uniformity is the whole point. Write code that talks to a block device and it works on a SATA drive, an NVMe stick, a network volume, or a loopback file without knowing or caring which.
If you're coming from writing application code, you've spent your career one or two layers above this. You called open(), read(), write(); the data came back; you never wondered what it was made of. The block device is the floor beneath that floor. A filesystem like ext4 or XFS takes one block device and turns its anonymous blocks into files, directories, names, and permissions. But the filesystem is a tenant — the block device is the land it's built on. Understanding that boundary is the difference between "the disk is full" being a mystery and being a diagnosis.
Here's the orientation you'll carry through the rest of the page. In Linux, block devices live under /dev with names like /dev/sda, /dev/sdb1, /dev/nvme0n1, /dev/nvme0n1p2. The first SATA/SAS/USB disk the kernel finds is /dev/sda (scsi disk a), its first partition is /dev/sda1, its second is /dev/sda2. NVMe drives follow a different scheme — /dev/nvme0n1 is namespace 1 on the first NVMe controller, and its first partition is /dev/nvme0n1p2 (note the p before the partition number, because the name already ends in a digit). You'll read about both naming systems below, but those two examples are the map most of this territory fits into.
Why It Matters
Almost everything you do to storage on a server is, underneath, an operation on a block device. You partition one. You run mkfs to lay a filesystem on one. You mount it. You stack LVM or RAID on top of several. You point a database at a raw one for the last drop of performance. Every storage emergency — a disk filling up, a filesystem going read-only, a disk that's failing — is a story told in terms of some block device misbehaving. If you can read your block-device topology, you can reason about all of it. If you can't, you're guessing.
There's also a sharper reason, and it deserves to be stated plainly: the block device is the level at which you can destroy everything in one command. A filesystem protects you with permissions, ownership, the difference between your home directory and someone else's. A raw block device offers no such courtesy. Write to the wrong /dev/sdX with dd and you have overwritten the partition table, the filesystem, and the data, all at once, with no undo and no warning. The first habit worth building — the one this whole page is quietly arguing for — is to know your topology before you touch it. Read the map first. Then act.
Block Versus Character — The Distinction That Makes /dev Click
This is the muddy thing almost every tutorial leaves you to absorb by osmosis, so let's nail it once and for all. Run ls -l in /dev and look at the very first character of each line:
ls -l /dev
brw-rw---- 1 root disk 8, 0 Jun 14 09:12 sda
brw-rw---- 1 root disk 8, 1 Jun 14 09:12 sda1
brw-rw---- 1 root disk 259, 0 Jun 14 09:12 nvme0n1
crw-rw-rw- 1 root root 1, 3 Jun 14 09:12 null
crw-rw-rw- 1 root root 1, 8 Jun 14 09:12 random
crw--w---- 1 root tty 4, 0 Jun 14 09:12 tty0
That leading letter is the device's type, and there are two that matter here. A b marks a block device. A c marks a character device. The disks are b. /dev/null, /dev/random, and the terminals are c. One letter, and it tells you the entire personality of the device.
A block device is addressable in fixed-size chunks and seekable: the kernel can jump to any block in any order, read it, write it, come back later. Because access is random and repeatable, the kernel can buffer and cache it — keep recently-read blocks in the page cache, batch writes, reorder them for efficiency. That's exactly what you want from a disk, where the same blocks get hit over and over and the order of physical access dramatically affects speed. Disks, partitions, volumes, RAID arrays, loop devices — all block.
A character device is a stream of bytes with no notion of position. You read what comes next; you can't seek back to byte 500 and re-read it, because there is no byte 500 sitting in a fixed location — the bytes flow past and are gone. Terminals, serial ports, /dev/random (an endless trickle of entropy), /dev/null (the bottomless drain) are all character devices. Access is unbuffered and immediate: a keypress should reach the program now, not after the kernel has accumulated a tidy 4 KB block of keystrokes. Caching a terminal would be absurd — there's nothing to cache, only a flow.
Note
This is "everything is a file" made concrete. A disk and a keyboard are both files under
/dev/, and you open, read, and write both with the same system calls — but theb/cflag tells the kernel which kind of file behaviour to provide underneath. The uniform interface is the genius of Unix; the type letter is the small, honest admission that storage and streams are not actually the same animal.
Once you've seen the distinction, /dev stops being an intimidating wall of cryptic names and becomes a labelled directory: here are the things you can seek around in (your disks), here are the things that only ever flow (your terminals and random sources). The reveal is worth the price of the page on its own.
Major and Minor Numbers — How the Kernel Routes a Device
Look back at that ls -l output, at the two comma-separated numbers where a regular file would show its byte size:
brw-rw---- 1 root disk 8, 0 Jun 14 09:12 sda
brw-rw---- 1 root disk 8, 1 Jun 14 09:12 sda1
brw-rw---- 1 root disk 8, 16 Jun 14 09:12 sdb
brw-rw---- 1 root disk 259, 0 Jun 14 09:12 nvme0n1
Those are the major and minor numbers, and they're how the kernel actually finds the right code to talk to the right hardware. The filename sda is for your convenience; the kernel doesn't care what a device node is called. It cares about the pair of numbers.
The major number picks the driver. Major 8 is the SCSI disk driver (which handles SATA, SAS, and USB storage too — they all speak SCSI to the kernel). Major 259 is the NVMe block driver. Major 1 is the memory devices (that's why both /dev/null and /dev/random show 1). When you open a device node, the kernel reads the major number and hands you off to whichever driver registered it.
The minor number picks the specific device that driver is responsible for. Under major 8, minor 0 is the whole disk sda, minor 1 is sda1, minor 16 is the next whole disk sdb, minor 17 would be sdb1. The SCSI disk driver reserves 16 minor numbers per disk (one for the whole device plus up to 15 partitions), which is the quiet reason behind that 16-step jump from sda to sdb.
ls -l /dev/sda*
brw-rw---- 1 root disk 8, 0 Jun 14 09:12 /dev/sda
brw-rw---- 1 root disk 8, 1 Jun 14 09:12 /dev/sda1
brw-rw---- 1 root disk 8, 2 Jun 14 09:12 /dev/sda2
brw-rw---- 1 root disk 8, 3 Jun 14 09:12 /dev/sda3
There it is in one frame: one major (8 — same driver for all of them), four minors (0 for the whole disk, then one per partition). The whole disk and its slices are the same physical drive seen through different device nodes, and the minor number is what distinguishes "the entire drive" from "partition 2 of it."
Backstory
The device node is just a tiny inode carrying a type flag and that number pair — it holds no data of its own. You can prove it:
mknod /dev/mydisk b 8 0creates a brand-new node that points at the very same disk as/dev/sda, because they share major 8, minor 0. The name was never the device. The numbers were. Modern systems letudevcreate and name these nodes automatically, but the mechanism underneath hasn't changed since the 1970s.
How the Kernel Layer Sits Underneath
It's worth a short detour into what happens between your write() and the metal, because it explains a lot of behaviour you'll otherwise find mysterious. When a filesystem (or a program writing raw) hands the kernel a block to store, the request doesn't go straight to the drive. It enters the block layer — a kernel subsystem that queues I/O requests, merges adjacent ones, and hands them to the device in a sensible order. The component that decides that order is the I/O scheduler.
On a spinning HDD, ordering was everything: the disk head physically moves, and reading blocks in roughly sequential order instead of bouncing across the platter could be the difference between fast and unusable — so schedulers worked hard to sort requests by physical position. On an SSD or NVMe drive there's no head and no seek time, so that sorting is mostly wasted effort; modern Linux ships schedulers like mq-deadline, kyber, and none, and for fast flash the right answer is often none — just get out of the way. You can see and set the active scheduler per device:
cat /sys/block/sda/queue/scheduler
[mq-deadline] kyber bfq none
The one in brackets is active. You rarely need to touch this on a normal server — the kernel's defaults are sane — but knowing the layer exists is what lets you understand why two disks with identical hardware can behave differently, and where the buffering that makes block devices fast actually happens.
Reading Your Topology With lsblk
If you remember one command from this page, make it lsblk — list block devices. It draws the entire storage tree in one glance: which physical disks exist, how each is sliced into partitions, what RAID or LVM layers sit on top, and where each piece is mounted.
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 931.5G 0 disk
├─sda1 8:1 0 512M 0 part /boot/efi
├─sda2 8:2 0 930G 0 part /
└─sda3 8:3 0 1G 0 part [SWAP]
sdb 8:16 0 1.8T 0 disk
└─sdb1 8:17 0 1.8T 0 part /data
nvme0n1 259:0 0 476.9G 0 disk
└─nvme0n1p1 259:1 0 476.9G 0 part /var/lib/mysql
Read it top to bottom. Each unindented line is a whole disk; the indented branches under it are its partitions; the TYPE column names what each is (disk, part, lvm, raid1, crypt, loop). Notice the MAJ:MIN column — the very major and minor numbers from the section above, now in context: sda is 8:0, sdb is 8:16, nvme0n1 lives under major 259. The RO column flags read-only devices, RM flags removable ones (USB sticks, SD cards). This single tree is the "know your topology before you touch it" habit made trivial.
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,SERIAL,PHY-SEC,LOG-SEC
Add -o to pick columns, and you can pull the filesystem type, the disk serial number (essential before you pull a drive — names reshuffle, serials don't), and the physical and logical block sizes, which brings us to a wrinkle worth knowing.
Logical Versus Physical Block Size — 512e and 4Kn
For decades the storage block was 512 bytes, full stop. Then drives grew so large that 512-byte sectors became wasteful — too much per-sector overhead — and manufacturers moved the physical sector size to 4096 bytes (4 KB). But mountains of software, bootloaders, and assumptions were baked around 512, so most drives quietly emulate the old size: they advertise a logical block size of 512 bytes (so everything keeps working) while their physical block size is really 4096. This is 512e — "512-byte emulation." A drive that exposes 4096 both ways, no emulation, is 4Kn — "4K native."
lsblk -o NAME,PHY-SEC,LOG-SEC
NAME PHY-SEC LOG-SEC
sda 4096 512
nvme0n1 4096 4096
Here sda is a classic 512e drive (physical 4096, logical 512); the NVMe is 4Kn (both 4096). Why care? Alignment. If a partition or a filesystem block straddles two physical 4 KB sectors, every write to it forces the drive to read both sectors, modify, and write both back — the dreaded read-modify-write penalty, and a real performance leak under database load. Modern partitioning tools (fdisk, parted, sgdisk) align partitions to 1 MiB by default precisely so this never bites you. The lesson is short: let the modern tools do the alignment, and don't hand-craft partition offsets unless you know exactly what the physical sector size is.
Loop Devices — A File That Pretends to Be a Disk
Here's the gem of the whole subject, and a genuinely useful trick the moment you learn it: you can take an ordinary file and tell Linux to treat it as a block device. The kernel wraps the file in a loop device — /dev/loop0, /dev/loop1, and so on — and from that point the file is a disk as far as the rest of the system is concerned. You can partition it, mkfs it, mount it, the lot.
# make a 1 GB empty file
fallocate -l 1G disk.img
# attach it as a block device, auto-picking a free loopN
sudo losetup -fP disk.img
# see what got attached
losetup -a
/dev/loop0: [2049]:131074 (/home/admin/disk.img)
Now /dev/loop0 behaves exactly like a small disk: sudo mkfs.ext4 /dev/loop0, sudo mount /dev/loop0 /mnt, and you have a filesystem living inside a single file. When you're done, sudo losetup -d /dev/loop0 detaches it. This is precisely how mounting an ISO image works, how disk images for VMs are built and inspected, how you experiment with a filesystem layout without sacrificing a real drive. It is "everything is a file" folding back on itself — a file presented as the device that holds files — and there's something quietly delightful about a disk you can rm.
Pro Tip
Loop devices are the safest possible sandbox for learning every other tool on this page. Want to rehearse a risky
fdisksession, test an LVM setup, or see what a corrupt filesystem does tofsck— without a single byte of real data at risk?fallocatea file,losetup -fPit, and practise on/dev/loop0. The worst case is you delete a file and start over.
There's a second family worth naming in passing: RAM disks. /dev/ram0 and the tmpfs/ramfs filesystems put block storage straight into memory — blisteringly fast, completely volatile. Useful for scratch space and caches, dangerous for anything you'd miss after a reboot.
Cheat Sheet
# --- See the whole topology (start here, always) ---
lsblk # the block-device tree
lsblk -f # add filesystem type, label, UUID, mountpoint
lsblk -o NAME,SIZE,TYPE,FSTYPE,SERIAL,PHY-SEC,LOG-SEC # serials + sector sizes
ls -l /dev/sd* /dev/nvme* # see the b flag and major:minor numbers
# --- Identify a specific device ---
blkid /dev/sda1 # filesystem type + UUID of one device
cat /sys/block/sda/queue/scheduler # active I/O scheduler for a disk
cat /sys/block/sda/size # size in 512-byte sectors
udevadm info /dev/sda # everything udev knows about the node
# --- Loop devices (a file as a disk) ---
fallocate -l 1G disk.img # create a 1 GB backing file
sudo losetup -fP disk.img # attach to first free /dev/loopN, scan partitions
losetup -a # list active loop devices
sudo losetup -d /dev/loop0 # detach
# --- Create a device node by hand (rarely needed; udev does this) ---
sudo mknod /dev/mydisk b 8 0 # b = block, major 8, minor 0 (== /dev/sda)
# --- The operations that BUILD on a block device ---
sudo fdisk /dev/sdb # partition it
sudo mkfs.ext4 /dev/sdb1 # put a filesystem on a partition
sudo mount /dev/sdb1 /data # attach that filesystem to the tree
Danger
Every command that writes to a raw
/dev/sdX—dd,mkfs,fdisk,wipefs— does so with zero regard for what's already there.dd if=image.iso of=/dev/sdawrites to your whole first disk, not the USB stick you meant. There is no trash can at this level and no confirmation prompt worth the name. Runlsblkfirst, confirm the size and serial of the target, and read the device name twice before you press Enter.ddis affectionately nicknamed "disk destroyer" for exactly one reason: it always does precisely what you typed.
Reading It by Example
A few TYPE patterns from lsblk and what they tell you at a glance:
sda(disk) →sda1,sda2(part) — a plain disk with a partition table. The ordinary case. Filesystems live directly on the partitions.sda,sdb(disk) →md0(raid1) — two disks feeding a software RAID mirror. The filesystem lives onmd0, not on the disks directly; the redundancy sits in between.sda2(part) →vg0-root(lvm) — a partition handed to LVM as a physical volume, with a logical volumevg0-rootcarved out on top. This is the device-mapper at work.sda3(part) →sda3_crypt(crypt) →vg0-root(lvm) — encryption (LUKS) layered under LVM. Each layer is its own block device stacked on the one below. This stacking is the superpower: every layer presents the same block-device interface upward, so they compose like building bricks.loop0(loop) → mounted at/snap/...— a file presented as a disk, exactly as in the section above. Snap packages mount this way.nvme0n1(disk) →nvme0n1p1(part) — an NVMe drive. Note thepbefore the partition number, because the base name ends in a digit.
History and Philosophy
The block-versus-character split is one of the oldest design decisions in Unix, dating to the early 1970s at Bell Labs, and it has aged extraordinarily well. The insight was that storage and streams are fundamentally different — one is a place you revisit, the other is a flow you consume once — but both can hide behind the same open/read/write interface if you tag each device with which behaviour it wants. That tag is the b/c flag you saw in ls -l, and it's still doing its job fifty years later on hardware its designers could not have imagined.
The major/minor scheme is from the same era and the same spirit: a device node is just a number pair in a tiny inode, the major naming a driver and the minor naming an instance. It's a phone-system metaphor — the major is the exchange, the minor is the extension — and it let Unix add wildly different hardware over the decades without ever changing the contract. The one wart history left behind is the fixed 16-minors-per-SCSI-disk limit, which is the real reason sda jumps to sdb at minor 16 and why old systems capped out at 15 partitions per disk. Modern Linux long ago grew past static major assignments — udev allocates them dynamically and conjures the /dev nodes at boot — but the model the early designers drew is still the one in front of you.
The deeper philosophy is the one this page keeps circling: a single uniform abstraction, applied ruthlessly, lets enormous complexity stack into neat layers. A filesystem doesn't know if it's sitting on a SATA disk, an NVMe drive, a RAID array, an LVM volume, an encrypted container, or a loop-mounted file — because every one of those presents the identical block-device interface. That's why you can mirror, encrypt, snapshot, and thin-provision storage in any combination: each layer is a block device to the one above and consumes block devices from the one below. Learn the interface once, and the entire storage stack opens up.
See Also
- device — the broader idea of a device node in
/dev, of which block devices are one kind - partition — the slices a disk is divided into, each its own block device
- filesystem — the structure that turns a block device's anonymous blocks into files
- LVM — logical volume management, a flexible layer stacked on raw block devices
- device-mapper — the kernel framework behind LVM, encryption, and software volumes
- RAID — redundancy built by combining several block devices into one
- disk — the physical drive a whole-disk block device represents
- NVMe — the modern flash interface and its
/dev/nvme0n1naming - SATA — the older drive interface that produces
/dev/sda-style names - kernel — the block layer and I/O schedulers live here
lsblk— the single best command for reading your block-device topologyfdisk— partition a block devicemount— attach a filesystem from a block device into the directory tree
Not sure which disk on your server is about to run out of room?
CleverUptime watches the usage on every mounted filesystem across all your block devices and warns you in plain language while there's still time to act — long before a volume fills up and your application starts throwing errors.
Want to see your own server's health right now? One command, no signup, no install.