How Linux fdisk Partitions Raw Block Devices

This article explores how the standard Linux fdisk utility partitions raw block devices, covering its interaction with low-level storage architectures, the mechanics of manipulating partition tables in memory, and the process of updating the Linux kernel to recognize new storage boundaries.

Understanding Raw Block Devices

In Linux, a raw block device is an unformatted physical or virtual storage drive represented as a special device file in the /dev directory, such as /dev/sda for SATA/SCSI drives or /dev/nvme0n1 for NVMe drives. These devices transfer data in fixed-size blocks—typically 512 bytes or 4096 bytes (4Kn)—without any inherent logical organization, filesystems, or partition boundaries.

The Role of Partition Tables

To segment a raw block device into discrete logical sections, a partition table must be written to its designated sectors. The two primary partition table formats are:

While historically associated strictly with MBR, modern versions of fdisk support both MBR and GPT partition schemes.

In-Memory Partition Editing

When fdisk is launched against a device path (for example, fdisk /dev/sdb), it opens the target device descriptor with read and write permissions. Instead of modifying the physical disk immediately with every user action:

  1. Reading Existing Tables: fdisk reads the first few sectors of the disk to identify an existing MBR or GPT header.
  2. In-Memory Representation: It loads the partition map into system RAM.
  3. Staging Changes: Operations such as creating a new partition (n), changing a partition type (t), or deleting an entry (d) merely alter this in-memory data structure. No persistent alterations are committed to the hardware during this interactive phase.

Committing Changes to the Block Device

When the user enters the write command (w), fdisk translates the staged memory structures into raw binary data formatted according to the chosen scheme (MBR or GPT).

  1. Writing Sectors: fdisk writes the calculated sector offsets, sizes, partition types, and unique identifiers directly to the appropriate sectors (e.g., LBA 0 for MBR, or LBAs 1–33 and the end of the disk for GPT).
  2. Preserving Data Areas: Crucially, fdisk only touches the partition table areas. It does not overwrite the actual payload data blocks within the partitions, nor does it create filesystems.

Informing the Linux Kernel

Once the physical sectors are written, the Linux kernel must be informed of the change so it can expose the new partitions to user space:

  1. The BLKRRPART ioctl: fdisk issues an ioctl system call using the BLKRRPART (Block Reread Partition Table) request to the raw device file descriptor.
  2. Kernel Reparsing: The kernel reads the newly updated partition tables directly from the storage controller.
  3. Device Node Creation: The kernel updates its internal partition maps and emits uevents. The udev daemon captures these events and dynamically creates corresponding device nodes in /dev, such as /dev/sdb1 and /dev/sdb2.

If an existing partition on the block device is currently mounted or in use, the ioctl call fails with a busy warning. In this scenario, the disk headers are updated, but the kernel continues using the old table until the system is rebooted or the table is manually refreshed using tools like partx or blockdev.