Block Devices and Partitioning
A block device is storage the kernel addresses in fixed-size blocks rather than byte by byte — a SATA SSD, an NVMe drive, a SCSI LUN, a loop file, or a RAID/LVM virtual device. The kernel exposes each one as a node under /dev (/dev/sda, /dev/nvme0n1, /dev/vda on KVM guests) and buffers reads and writes through the page cache, which is what makes block devices fast and what makes sync matter. Everything above — partitions, RAID, LVM, filesystems — is a stack of layers built on this one abstraction.
Partitioning carves a single device into independent regions, each presented as its own block device (/dev/sda1, /dev/nvme0n1p2). The operational consequence is that the partition table is the most dangerous 34 sectors on the disk: it is tiny, it is rewritten by a single command, and a wrong write or a guessed device name destroys the map to every byte of data behind it with no undo. Get the device identity and the table type right before you touch anything.
Block Device Naming and Inspection
Device names are assigned by the kernel in discovery order, so /dev/sda is not guaranteed to be the same disk across reboots once you add or remove hardware. SATA and SAS disks appear as sd* with letters for the disk and numbers for the partition; NVMe drives use nvme0n1 for the namespace and nvme0n1p1 for the partition; virtio disks on KVM guests show up as vda. For anything that must survive a reboot — /etc/fstab, boot config, RAID assembly — reference the stable identifiers under /dev/disk/by-uuid/ or /dev/disk/by-id/, never the bare sdX name.
lsblk is the first command to run: it prints the whole tree of disks, partitions, RAID, LVM, and mount points in one view. Add columns when you need them — lsblk -o NAME,SIZE,TYPE,FSTYPE,UUID,MOUNTPOINT shows what each device is and where it lands. Use blkid to read a device's UUID and filesystem type, and lsblk -d -o NAME,ROTA (where ROTA=1 means spinning rust, 0 means SSD/NVMe) to tell flash from disk.
# Map the whole storage stack at a glance lsblk -o NAME,SIZE,TYPE,FSTYPE,UUID,MOUNTPOINT NAME SIZE TYPE FSTYPE UUID MOUNTPOINT nvme0n1 476G disk ├─nvme0n1p1 1G part vfat 1234-ABCD /boot/efi ├─nvme0n1p2 2G part ext4 3f2a... /boot └─nvme0n1p3 473G part LVM2_m a9c1... └─vg0-root 473G lvm ext4 7b88... /
MBR versus GPT Partition Tables
Two partition-table formats are in use. The legacy MBR (msdos) scheme stores the table in the first 512-byte sector, caps a disk at 2 TiB because it uses 32-bit LBA sector counts, and allows only four primary partitions — you work around that with one extended partition holding logical ones. GPT (GUID Partition Table) replaces it: 128 partitions by default, sizes far beyond 2 TiB, a 128-bit GUID identifying each partition, and a backup copy of the table at the end of the disk so a corrupted primary header is recoverable.
Use GPT for anything built today. MBR survives only for compatibility with old BIOS-only systems or hardware that cannot read GPT. The two are tied to firmware: UEFI boots from GPT and needs a small FAT32 EFI System Partition (the ESP, typically 512 MiB–1 GiB mounted at /boot/efi); legacy BIOS boots MBR. Mixing them — a GPT disk on a BIOS-only board with no bios_grub partition, for instance — produces a disk that partitions fine but will not boot.
| Property | MBR (msdos) | GPT |
|---|---|---|
| Max disk size | 2 TiB | ~8 ZiB (effectively unlimited) |
| Partition count | 4 primary (extended for more) | 128 by default |
| Table redundancy | None | Backup header at end of disk |
| Partition identity | Number only | 128-bit GUID + name |
| Firmware | Legacy BIOS | UEFI (BIOS via bios_grub) |
Partitioning Tools
On Debian and Ubuntu, parted and its scriptable form drive most partitioning, while fdisk and gdisk remain the interactive standbys. Modern fdisk handles GPT too, so the old "fdisk is MBR-only" rule no longer holds; gdisk is the GPT-focused cousin with a recovery menu for damaged tables. For scripted, idempotent provisioning, sgdisk (from gdisk) and parted ... --script let you build a layout without an interactive session.
Two facts bite people. First, partitions should be aligned to 1 MiB (2048 sectors) — every current tool defaults to this, and it matters because a misaligned start forces a single logical write to straddle two physical 4 KiB sectors, adding a read-modify-write that cuts throughput. Second, the kernel does not always re-read a changed table while partitions are in use; run partprobe /dev/sdX or udevadm settle after editing, or you will format a stale view of the disk.
# Scripted GPT layout: ESP + root, 1 MiB aligned by default parted -s /dev/nvme0n1 mklabel gpt parted -s /dev/nvme0n1 mkpart ESP fat32 1MiB 513MiB parted -s /dev/nvme0n1 set 1 esp on parted -s /dev/nvme0n1 mkpart root ext4 513MiB 100% partprobe /dev/nvme0n1 # force the kernel to re-read the table
Partitions, Filesystems, and Mounting
A partition is just a labelled span of sectors — it holds no data structure of its own until you put a filesystem on it with mkfs (mkfs.ext4, mkfs.xfs) or hand it to LVM or mdadm as a physical volume. That separation is the whole point of the layered stack: the same partition can later become a RAID member or an LVM PV without re-partitioning. The chain is device → partition → (optional RAID/LVM) → filesystem → mount point.
Mounts are made permanent in /etc/fstab, and this is where the device-naming rule earns its keep: an entry keyed on /dev/sdb1 will mount the wrong disk the day discovery order shifts, so key it on UUID= (from blkid) instead. Add nofail for any non-critical disk so a missing device does not drop the boot into emergency mode, and test every change with mount -a before you reboot — a malformed fstab is the classic way to lock yourself out of a headless server.
Whole-Disk Devices and Partitionless Layouts
A partition table is not mandatory. You can put a filesystem, an LVM PV, or a RAID member directly on the whole device (/dev/sdb rather than /dev/sdb1), which is common for data disks in virtual machines and SANs where the hypervisor already presents a sized, dedicated volume. The trade-off is that some tooling and some hardware RAID controllers expect a table and behave oddly without one, and a whole-disk filesystem leaves no room for a future second partition.
Growing storage is where the layers pay off. Resize a cloud volume and the partition still ends where it did; you grow the partition with growpart /dev/sda 1, then grow the filesystem on top with resize2fs (ext4) or xfs_growfs (XFS, which only grows, never shrinks) — both online, with the filesystem mounted. Skip the growpart step and the new capacity is invisible no matter how large the underlying disk became.
- Running
mkfsorpartedagainst the wrong/dev/sdXbecause names shifted after a hardware change — there is no undo, and you have just wiped a live disk. Confirm identity withlsblkand/dev/disk/by-id/first. - Keying
/etc/fstabon/dev/sdb1instead ofUUID=— a reordered discovery mounts the wrong filesystem at a critical path, or fails the boot entirely. - Editing a partition table while the disk is in use and not running
partprobe— you then format the kernel's stale view and corrupt the real layout. - Putting a GPT disk on a legacy-BIOS board with no
bios_grubpartition, or a UEFI install with no FAT32 ESP — the disk partitions cleanly but never boots. - Resizing the underlying volume and forgetting
growpartplusresize2fs/xfs_growfs— the extra capacity stays invisible because the partition and filesystem never moved. - Choosing MBR out of habit on a disk larger than 2 TiB — everything past 2 TiB is silently unaddressable.
- Omitting
nofailon a removable or secondary disk infstab— one missing device drops a headless server into emergency mode at boot.
- Default to GPT on every new disk; reserve MBR only for genuine legacy-BIOS compatibility.
- Reference disks by
/dev/disk/by-id/orby-uuid/infstab, boot config, and RAID assembly — never by baresdX. - Run
lsblk -o NAME,SIZE,TYPE,FSTYPE,UUID,MOUNTPOINTto verify the target before any destructive command. - Let the tools handle 1 MiB alignment — start partitions at
1MiBinpartedrather than hand-picking sector offsets. - Run
partprobeorudevadm settleafter editing a table in use so the kernel reads the new layout before you format. - Add
nofailto non-rootfstabentries and validate every change withmount -abefore rebooting a remote host. - Provision layouts with
sgdiskorparted --scriptso partition tables are reproducible and reviewable, not clicked into existence interactively.
diskpart over the same MBR/GPT tables, but NTFS/ReFS volumes instead of the device → partition → LVM/RAID → filesystem stackmacOS — diskutil and the GUID/APFS container model, where container partitioning is logical rather than a classic tableFreeBSD — gpart on GEOM, GPT-native, with the same table concepts under different command namesKnowledge Check
Why should /etc/fstab entries reference UUID= rather than /dev/sdb1?
- Kernel device names are assigned in discovery order and can shift after a hardware change, so a
/dev/sdXentry may mount the wrong filesystem or fail the boot - UUIDs mount measurably faster because the kernel keeps an indexed lookup table of them in the page cache, so resolving a UUID to its device node skips the slower bus scan that a
/dev/sdXpath triggers /dev/sdXnames work only on MBR disks, so a GPT-partitioned volume can be mounted reliably only by its UUID- Referencing a UUID automatically enables
nofailbehavior, so a missing disk never blocks the boot sequence
You enlarge a cloud volume from 100 GB to 500 GB, but df still shows the old size. What is missing?
- The partition and filesystem were never grown — run
growparton the partition, thenresize2fsorxfs_growfson the filesystem - The disk must be repartitioned from scratch with
parted mklabel, since an existing partition table can never be stretched to describe the larger capacity - A reboot is mandatory before the kernel re-reads the device and the new size becomes visible to
df - The volume must be converted from MBR to GPT first, because growth past the original size needs the larger table
On a disk larger than 2 TiB, why is GPT required rather than MBR?
- MBR addresses sectors with 32-bit LBA, capping a disk at 2 TiB; capacity beyond that is unaddressable, while GPT has no practical size limit
- MBR allows only four primary partitions, and a disk past 2 TiB always needs more than four to lay out, so the partition count is what forces the switch to GPT
- GPT writes data faster on large disks because its backup header at the disk end shortens seek distance
- MBR cannot be read by UEFI firmware, and UEFI is the only mode that can boot a disk above 2 TiB
After editing a partition table on a disk that is still in use, why run partprobe?
- The kernel may still hold the old table while partitions are in use; without re-reading it you risk formatting a stale view and corrupting the layout
partproberealigns the new partitions to 1 MiB boundaries automatically so writes stay sector-optimal- It flushes the page cache so that every pending dirty write reaches the platter before the partition-table change takes effect, preventing a half-written layout
- It is required to convert the in-memory table from MBR to GPT so the larger layout is recognized
You got correct