What it is
Linux exposes disks as block devices: files in /dev/ through which
the kernel gives access to storage in blocks. Unlike character devices
(terminals, /dev/null), block devices can seek by address, and I/O is
requested in chunks of N bytes.
Device names
| Type | Prefix | Example |
|---|---|---|
| SATA / SCSI / USB disk | /dev/sd* | /dev/sda, /dev/sdb1 |
| NVMe (PCIe SSD) | /dev/nvme* | /dev/nvme0n1, /dev/nvme0n1p1 |
| virtio (virtual machine) | /dev/vd* | /dev/vda |
| IDE (old) | /dev/hd* | /dev/hda |
| LVM logical volume | /dev/<vg>/<lv> or /dev/mapper/... | /dev/vg0/root |
| Loop (file as disk) | /dev/loop* | /dev/loop0 |
| RAID (md) | /dev/md* | /dev/md0 |
The trailing number is the partition: /dev/sda1 is the first partition
on /dev/sda. NVMe uses the scheme nvme0n1p1: controller 0, namespace 1,
partition 1.
lsblk: the main command
lsblk # tree of all block devices with partitions and mount points
lsblk -f # adds filesystem type, UUID, label
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,UUID
lsblk -d # disks only, without partitions
Tree output:
NAME SIZE TYPE FSTYPE MOUNTPOINT
sda 512G disk
├─sda1 512M part vfat /boot/efi
├─sda2 1G part ext4 /boot
└─sda3 511G part LVM2 -
└─vg0-root 50G lvm ext4 /
Stable identifiers
The names sda/sdb can change between boots (they depend on detection
order). In /etc/fstab, use a UUID or a label:
blkid # UUID and label of each partition
blkid /dev/sda1
ls -l /dev/disk/by-uuid/ # symlinks uuid → /dev/sd*
ls -l /dev/disk/by-label/
ls -l /dev/disk/by-id/ # stable per hardware (model + serial)
Size and geometry
cat /proc/partitions # size in 1K blocks
fdisk -l /dev/sda # partition table + size
blockdev --getsize64 /dev/sda # size in bytes
cat /sys/block/sda/queue/rotational # 1 = HDD, 0 = SSD
cat /sys/block/sda/queue/scheduler # current I/O scheduler
Creating partitions
For GPT (the modern standard):
sudo parted /dev/sda print # current layout
sudo parted /dev/sda mklabel gpt # create GPT (ERASES everything!)
sudo parted -a optimal /dev/sda mkpart primary ext4 0% 100%
For MBR (legacy, up to 2 TB):
sudo fdisk /dev/sda # interactive
sudo sgdisk /dev/sda --print # GPT-aware fdisk
After creating a partition you have to tell the kernel about it:
sudo partprobe /dev/sda
I/O scheduler
The kernel orders I/O requests before sending them to the disk:
- none / noop: for NVMe, which is its own good scheduler
- mq-deadline: fair, the default on servers
- bfq: for desktops, with per-process priorities
- kyber: low latency, for SSDs
cat /sys/block/sda/queue/scheduler
echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler
Loop device: a file as a disk
dd if=/dev/zero of=disk.img bs=1M count=100 # make a 100MB file
sudo losetup -f --show disk.img # bind it to /dev/loopX
sudo mkfs.ext4 /dev/loop0 # create a filesystem
sudo mount /dev/loop0 /mnt # mount it
sudo umount /mnt && sudo losetup -d /dev/loop0
This is how Docker used to build container filesystems, and it is how .iso
images are mounted.