Skip to content

Disks and Block Devices

Managing any server starts with disks: how many are attached, what they're named, which name maps to which physical device, and how large each one is. This storage module begins with exactly that question — how Linux sees disks and how it names them. Later articles build on this foundation to partition a disk, make it more flexible with RAID and LVM, create a filesystem on it, and mount it — but all of that rests on what's covered here.

What You Will Learn

By the end of this article you will be able to:

  • explain what a block device is and how it differs from a character device;
  • distinguish the /dev/sd*, /dev/nvme*, and /dev/vd* naming conventions;
  • inspect the disks attached to a system with lsblk, blkid, fdisk -l, and lsscsi;
  • explain why major/minor numbers exist;
  • find kernel-level information about a disk through /sys/block;
  • explain the difference between logical and physical sector size.

What a Block Device Is

Linux exposes every device as a file under /dev. These files fall into two categories:

  • Character device — data is transferred as a byte stream, one byte at a time. Examples: /dev/tty, /dev/random.
  • Block device — data is transferred in fixed-size blocks (typically 512 or 4096 bytes) and supports random access to any position. Hard disks, SSDs, and USB flash drives are all block devices.
ls -l /dev/sda
brw-rw---- 1 root disk 8, 0 Jul 25 10:00 /dev/sda

The b at the start of the line marks this as a block device (it would be c for a character device). 8, 0 is the major and minor number pair.

Major and Minor Numbers

The kernel identifies every device file with two numbers:

  • Major number — identifies the driver that manages the device (for example, 8 is the SCSI/SATA disk driver).
  • Minor number — identifies the specific device or partition within that driver (0 is the whole disk, 1 is the first partition, and so on).
ls -l /dev/sd*
brw-rw---- 1 root disk 8,  0 Jul 25 10:00 /dev/sda
brw-rw---- 1 root disk 8,  1 Jul 25 10:00 /dev/sda1
brw-rw---- 1 root disk 8,  2 Jul 25 10:00 /dev/sda2
brw-rw---- 1 root disk 8, 16 Jul 25 10:00 /dev/sdb

/dev/sda and /dev/sda1 share the same major number (8), since the same driver handles both; the minor number identifies exactly which partition it is.

Disk Naming Conventions

The device name depends on which driver or interface is in use:

Name pattern Device type Partition naming
/dev/sda, /dev/sdb, ... SATA/SAS/USB disk (SCSI subsystem) /dev/sda1, /dev/sda2
/dev/nvme0n1, /dev/nvme1n1, ... NVMe SSD (attached via PCIe) /dev/nvme0n1p1, /dev/nvme0n1p2
/dev/vda, /dev/vdb, ... Virtio virtual disk (KVM/QEMU virtual machines) /dev/vda1, /dev/vda2
/dev/xvda, /dev/xvdb, ... Xen virtual disk (some cloud providers) /dev/xvda1

sd* naming follows alphabetical order: a, b, c, ... z, then aa, ab, and so on. This order isn't guaranteed to stay the same across reboots — disk detection order can change, which is why production systems should rely on a UUID rather than a name like /dev/sda (covered in depth in fstab).

The NVMe naming format is different: nvme0n1 — controller number 0, n1 — namespace 1 under that controller, p1 — partition 1 within that namespace. The p is needed as a separator because nvme0n1 already ends in a digit.

Info

NVMe disks connect directly over PCIe rather than through the SCSI subsystem, and are handled by the nvme driver — which is why they use a different naming convention.

Commands for Inspecting Disks

lsblk — the Block Device Tree

lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda           8:0    0    40G  0 disk
├─sda1        8:1    0     1G  0 part /boot
└─sda2        8:2    0    39G  0 part /
sdb           8:16   0   100G  0 disk
nvme0n1     259:0    0   500G  0 disk
└─nvme0n1p1 259:1    0   500G  0 part /data

Useful flags:

lsblk -f      # filesystem type, UUID, and label
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
lsblk -d      # disks only, no partitions

blkid — UUID and Filesystem Type

sudo blkid
/dev/sda1: UUID="1a2b3c4d-5e6f-7890-abcd-ef1234567890" TYPE="ext4" PARTUUID="..."
/dev/sda2: UUID="9f8e7d6c-5b4a-3210-fedc-ba0987654321" TYPE="ext4" PARTUUID="..."

blkid reports each partition's UUID, label, and filesystem type — the primary source of information when writing /etc/fstab.

fdisk -l — Partition Table and Disk Size

sudo fdisk -l
Disk /dev/sda: 40 GiB, 42949672960 bytes, 83886080 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
Disklabel type: gpt

Device       Start      End  Sectors Size Type
/dev/sda1     2048  2099199  2097152   1G EFI System
/dev/sda2  2099200 83884031 81784832  39G Linux filesystem

fdisk -l without an argument lists every detected disk; with an argument (fdisk -l /dev/sda) it shows only that disk. This command is read-only — it changes nothing, which makes it safe for inspecting a system.

lsscsi — Listing SCSI Devices

sudo apt install lsscsi   # Debian/Ubuntu
lsscsi
[0:0:0:0]    disk    ATA      Samsung SSD 860   /dev/sda
[2:0:0:0]    disk    VMware   Virtual disk      /dev/sdb

lsscsi shows the disk at the physical/virtual controller level — model, manufacturer, and SCSI address (host:channel:target:lun) together. It's especially useful for telling apart multiple disks of identical size.

/sys/block — Kernel-Level Information

The kernel exposes information about every block device as virtual files under /sys/block/:

ls /sys/block/
cat /sys/block/sda/size
cat /sys/block/sda/queue/rotational
  • size — the disk's size in sectors (multiply by 512 to get the size in bytes);
  • queue/rotational1 for a spinning disk (HDD), 0 for an SSD/NVMe;
  • removable — whether the device is removable (e.g. a USB flash drive).
for d in /sys/block/sd*; do
  echo "$(basename $d): rotational=$(cat $d/queue/rotational)"
done

This script shows whether every sd* disk is an HDD or an SSD — information lsblk doesn't provide directly, which is why /sys/block is handy for low-level checks.

Logical vs. Physical Sector Size

Modern disks often report two distinct sector sizes:

  • Logical sector size — the minimal addressing unit the operating system sees (usually 512 bytes, for compatibility).
  • Physical sector size — the disk's actual physical write unit (often 4096 bytes on modern disks, referred to as "4Kn" or "512e").
sudo fdisk -l /dev/sda | grep "Sector size"
Sector size (logical/physical): 512 bytes / 4096 bytes

If a partition's boundaries don't align with physical sector boundaries, disk performance can drop noticeably — modern partitioning tools (fdisk, parted) account for this automatically, but knowing about it is useful when troubleshooting disk performance.

Practical Scenario: Identifying a New Disk

Problem. A new virtual disk was just added to a server, but its /dev/sd* name is unknown — picking the wrong disk on a production server risks losing data on it.

1. Record the state before adding the disk:

lsblk -d -o NAME,SIZE > /tmp/before.txt

2. Check again after adding the disk:

lsblk -d -o NAME,SIZE > /tmp/after.txt
diff /tmp/before.txt /tmp/after.txt
> sdc    50G

3. Confirm the new disk by size and model:

sudo fdisk -l /dev/sdc
lsscsi | grep sdc

4. Confirm the disk has no existing partition or filesystem:

sudo blkid /dev/sdc

If the command returns nothing (empty output), the disk is still unpartitioned and filesystem-free — safe to partition.

Conclusion. Comparing before/after with diff is the most reliable identification method when several disks share the same size. "Guessing" based on size and model number is risky in a production environment.

Warning

Never pick a disk based only on "the largest unused number" (e.g. /dev/sdd) — disk numbering can change after a reboot or when another disk is removed. Always positively confirm the disk with blkid, lsscsi, or its size, especially before a step that destroys data on it (fdisk, mkfs, dd).

Detecting a Hot-Added Disk Without a Reboot

The scenario above assumes the new disk already shows up in lsblk. On a running physical or virtual server, a freshly attached disk sometimes doesn't appear until the kernel is told to rescan the bus — and rebooting a production box just to see a new disk is rarely acceptable.

For a SATA/SAS/SCSI disk, trigger a rescan of every SCSI host:

for host in /sys/class/scsi_host/host*; do
  echo "- - -" | sudo tee "$host/scan"
done
lsblk

The - - - is channel target lun, and three dashes mean "any" — i.e. scan everything on that host.

If an existing disk was resized on the hypervisor/SAN side (a common cloud operation) but still shows the old size, rescan that specific device instead:

echo 1 | sudo tee /sys/class/block/sdb/device/rescan
lsblk /dev/sdb

For an NVMe namespace:

sudo nvme ns-rescan /dev/nvme0

Info

After the disk itself shows the new size, its partition and filesystem still won't have grown — those are separate layers resized with growpart + resize2fs/xfs_growfs, covered in Partitions and LVM: Resizing and Snapshots.

Persistent Device Names: /dev/disk/by-*

Before a filesystem (and therefore a UUID) exists, a disk still needs a stable name for scripts and automation — and /dev/sdb is exactly the name that can change on the next boot. The kernel maintains stable symlinks under /dev/disk/:

ls -l /dev/disk/by-id/
ls -l /dev/disk/by-path/
  • by-id — based on the hardware serial/WWN (e.g. wwn-0x5000c500..., nvme-Samsung_SSD_...); tied to the physical disk, so it survives reboots and cabling changes. This is the right identifier to pin a whole disk in mdadm/LVM automation.
  • by-path — based on the physical connection (PCI/SCSI path); stable as long as the disk stays in the same slot, but changes if moved.
  • by-uuid / by-label — appear only after a filesystem is created, and are what fstab uses.

Common Mistakes

Assuming /dev/sda Is a Permanent Name

Disk names can change across reboots or when a device is added or removed. Scripts and fstab should use a UUID rather than a hardcoded name (/dev/sdb1).

Not Knowing the Difference Between lsblk and fdisk -l

lsblk shows the current state as seen by the kernel, in a hierarchical view (with mount points). fdisk -l shows the partition table in more detail (sector boundaries, type codes), but requires sudo and doesn't show mount state.

Confusing a Partition with a Disk

/dev/sda is the whole disk; /dev/sda1 is the first partition on it. mkfs or mount should target the intended partition (or, in special cases like LVM, a logical volume) — never the whole disk.

Exercises

  1. Compare the output of lsblk, blkid, and fdisk -l — note which columns/fields each one provides.
  2. Check the rotational value for every disk under /sys/block/ on your system and determine which are HDDs and which are SSDs.
  3. Add a new virtual disk to a disposable test VM and identify it using the "before/after diff" method from this article, then confirm its size with fdisk -l.

Verification criterion: you should be able to identify a newly added disk with confidence, using at least two independent pieces of evidence (size, model, or a before/after comparison) rather than a guess.

Summary

Linux represents every disk as a block device under /dev, identified by major/minor numbers; naming differs by interface (sd*, nvme*, vd*). lsblk, blkid, fdisk -l, lsscsi, and /sys/block are the core, read-only tools for inspecting the disks on a system. Once a disk is correctly identified, the next step is partitioning it, using fdisk, gdisk, or parted.

References