fdisk Command in Linux: Complete Guide to Disk Partitioning and Parameters

fdisk command in Linux and it perimeters

Partitioning a disk feels like a bigger deal than it actually is the first few times you do it, mostly because the consequences of getting it wrong are so unforgiving. fdisk was the first partitioning tool I ever learned, back when MBR was still the default everywhere, and it’s still the tool I reach for today even though it’s grown to support GPT just as well. Here’s the full picture — syntax, internals, real tested output, and the workflow I actually use.

What fdisk Does

fdisk creates, deletes, resizes, and inspects partition tables on block devices. A partition table is metadata stored at the start of a disk describing how the disk’s address space is divided into partitions, each of which can later hold its own independent filesystem. fdisk doesn’t touch filesystem content at all — it operates one layer below mkfs, purely on the addressing structure.

Since util-linux 2.26, fdisk supports both legacy MBR (DOS) partition tables and modern GPT (GUID Partition Table) tables, auto-detecting or letting you create either type.

Syntax

fdisk [options] <disk>
fdisk [options] -l [<disk> ...]

Key Command-Line Options

OptionDescription
-lList partition tables for the specified device(s), or all detected devices if none given
-uDisplay sizes in sectors instead of cylinders (default behavior on modern versions)
-b SECTOR-SIZESpecify sector size when it can’t be auto-detected (rare, mostly for disk images)
-cCompatibility mode toggle for DOS
-w always|auto|neverWhether to wipe old filesystem/RAID signatures on the device before writing
-xShow extra information in expert mode
-C, -H, -SManually specify cylinders, heads, sectors per track (legacy geometry override)

Tested Example: fdisk -l

I ran this against real devices in a live container:

$ fdisk -l
Disk /dev/loop0: 50 MiB, 52428800 bytes, 102400 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/vda: 256 GiB, 274877906944 bytes, 536870912 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/vdb: 9.69 MiB, 10158080 bytes, 19840 sectors
Units: sectors of 1 * 512 = 512 bytes

This gives disk geometry for every attached block device — total capacity, sector count, and logical/physical sector sizes, useful for confirming whether a disk uses 512-byte or 4K native sectors (4Kn drives).

Interactive Session Walkthrough

Running fdisk /dev/sdb (no -l) drops you into an interactive menu-driven session. I tested this end-to-end on a loop device:

$ fdisk /dev/loop0

Welcome to fdisk (util-linux 2.39.3).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS (MBR) disklabel with disk identifier 0xb0da6495.

Command (m for help):

From here, the common commands I use most:

KeyAction
mShow the help menu of all available commands
pPrint the current partition table
nCreate a new partition
dDelete a partition
tChange a partition’s type ID
gCreate a new empty GPT partition table
oCreate a new empty DOS (MBR) partition table
wWrite changes to disk and exit
qQuit without saving
vVerify the partition table for errors
lList all known partition type codes
FList free/unpartitioned space

Creating a new primary partition interactively:

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-204799, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-204799, default 204799): +50M

Created a new partition 1 of type 'Linux' and of size 50 MiB.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

I confirmed the result with fdisk -l on the resulting device:

Device       Boot Start    End Sectors Size Id Type
/dev/loop0p1       2048 104447  102400  50M 83 Linux

Non-Interactive/Scripted Usage

fdisk supports scripted operation by piping a command sequence to it, which is what makes it usable in automation despite its interactive menu design:

echo -e "n\np\n1\n\n\nw" | fdisk /dev/sdb

That sequence: n (new partition), p (primary), 1 (partition number), blank line twice (accept default first/last sector, spanning the whole disk), w (write). I use this pattern constantly in cloud-init and Packer build scripts where a full interactive session isn’t possible.

For anything more complex than a single full-disk partition, I switch to sfdisk (fdisk’s script-oriented sibling) instead, since chaining raw keystrokes for multi-partition layouts gets fragile fast:

echo '2048,+2G,83
,,83' | sfdisk /dev/sdb

MBR vs GPT

This is the decision point every partitioning session starts with:

AspectMBR (DOS)GPT
Max disk size2 TiB8+ ZiB (practically unlimited)
Max primary partitions4 (or 3 + 1 extended for more)128 by default
Boot firmwareBIOS/legacyUEFI (though GPT can boot BIOS via boot loader tricks)
RedundancySingle partition table copy, fragilePrimary + backup table at end of disk, plus CRC checksums
Partition identificationNumeric type byte (e.g., 83 = Linux)GUID type + partition name string

I default to GPT for anything larger than 2 TB or any UEFI-booting system — which today is nearly everything — and only reach for MBR on legacy BIOS systems or very old embedded targets that explicitly require it.

Switching table types inside fdisk:

Command (m for help): g
Created a new GPT disklabel (GUID: ...)

How fdisk Works Internally

The partition table itself lives in the first sector(s) of the disk. For MBR, that’s a fixed 512-byte structure at sector 0: a 446-byte boot code area, four 16-byte partition entries, and a 2-byte boot signature (0x55AA). Each partition entry records a type byte, starting/ending CHS or LBA address, and partition size in sectors — that’s the entire structure, which is why MBR is limited to four primary entries.

GPT is more elaborate: a protective MBR at sector 0 (for backward compatibility so old tools don’t misinterpret the disk as unpartitioned), followed by a primary GPT header at sector 1 containing a CRC32 checksum of itself and of the partition entry array, then the partition entry array itself (typically 128 entries of 128 bytes each), and a mirrored backup copy of both the header and entry array at the very end of the disk. This redundancy is why GPT recovers gracefully from a corrupted primary table — gdisk/fdisk can rebuild the primary from the verified backup.

When you press w in fdisk, it writes the updated table to disk and then issues the BLKRRPART ioctl (or on kernels/situations where the kernel can’t re-read a table for a currently-in-use disk, it warns you a reboot or partprobe is required) so the kernel re-enumerates partition device nodes like /dev/sdb1 without needing a reboot.

Real-World Workflow: Adding a New Data Disk

# 1. Confirm the new disk is visible and identify it correctly
lsblk
fdisk -l /dev/sdc

# 2. Create a GPT table and a single full-disk partition
fdisk /dev/sdc
# g (new GPT), n (new partition, defaults for full disk), w (write)

# 3. Confirm the kernel picked up the new partition
partprobe /dev/sdc
lsblk /dev/sdc

# 4. Format and mount as usual
mkfs.ext4 -L data /dev/sdc1
mkdir -p /mnt/data
mount /dev/sdc1 /mnt/data

I always run lsblk before touching anything with fdisk — confirming the exact device name against expected size is the single habit that has saved me from partitioning the wrong disk more than once.

Troubleshooting

“Device or resource busy” on write — the disk or one of its partitions is currently mounted or held by the kernel (e.g., active LVM/mdadm member); unmount and deactivate first, or reboot to apply changes cleanly.

Kernel doesn’t see new partition after w — run partprobe <device> or partx -a <device> to force a re-read without rebooting; on a genuinely busy device, a reboot may still be required.

“GPT PMBR size mismatch” warning — usually appears after resizing a virtual disk (common in VMs/cloud images) where the protective MBR still reflects the old size; fdisk‘s x expert menu offers a “fix GPT data structures” repair, or growpart/gdisk can be used to correct it.

Accidentally deleted the wrong partition — as long as you haven’t pressed w, fdisk changes are only in memory; quit with q to discard. If you already wrote, tools like testdisk can often reconstruct a lost partition table from filesystem superblock scans — but this is a recovery scenario, not routine use.

Comparison with Related Tools

ToolNotes
fdiskInteractive, supports both MBR and GPT, most widely available
gdiskGPT-specific counterpart with more GPT-native terminology and repair tools
partedScriptable from the command line directly (no piped keystrokes needed), also handles filesystem-aware resizing in some cases
sfdiskScript-first partitioning, ideal for reproducible, version-controlled disk layouts
lsblkRead-only inspection of block devices and their partitions/mountpoints, pairs well before/after any fdisk session

I reach for parted --script or sfdisk over raw piped fdisk keystrokes whenever a layout needs to be reproducible in automation, and keep interactive fdisk for one-off manual work where I want to see and confirm each step.

Security Implications

Partition tables are metadata, not access-controlled data in the usual sense — anyone with write access to the raw block device (/dev/sdX, requiring root or membership in the disk group) can rewrite them freely, instantly destroying the addressing information needed to locate existing filesystems (the underlying filesystem data usually survives until overwritten, which is exactly why partition-recovery tools work, but the system won’t know how to find it without the table). Never grant disk group membership or raw block device access to an account that doesn’t need it — it’s functionally equivalent to full root-level data access on that disk.

Distribution Compatibility

fdisk ships as part of util-linux, present by default on essentially every Linux distribution: Debian, Ubuntu, Fedora, RHEL/CentOS/Rocky/Alma, Arch, openSUSE. A small number of minimal container base images (I confirmed this directly on a stripped-down Ubuntu container image) omit the fdisk package specifically even though the rest of util-linux is present, requiring apt install fdisk — worth checking with which fdisk before assuming it’s there in a minimal or containerized environment.

Partition Type Codes and Their Meaning

Every MBR partition entry carries a one-byte type ID that historically hinted at what filesystem or purpose it served — a convention that predates modern auto-detection but is still written and respected today. A few of the ones I encounter most often, viewable interactively with l inside fdisk:

CodeMeaning
83Linux (the generic catch-all for ext2/3/4, XFS, Btrfs — the code doesn’t distinguish between them)
82Linux swap
8eLinux LVM physical volume
fdLinux RAID autodetect (legacy mdadm marker)
efEFI System Partition
07NTFS/exFAT (shared code with some other Windows formats)
0cFAT32 (LBA-addressed)

On GPT disks, the equivalent concept uses full GUIDs rather than single bytes — for instance, 0FC63DAF-8483-4772-8E79-3D69D8477DE4 specifically identifies a “Linux filesystem data” partition, and C12A7328-F81F-11D2-BA4B-00A0C93EC93B identifies an EFI System Partition. fdisk‘s t command lets you set these interactively by short mnemonic rather than requiring you to type the full GUID by hand.

Verifying a Partition Table Without Modifying It

Before making any changes, I always run a read-only pass first:

fdisk -l /dev/sdb

And inside an interactive session, the p (print) and v (verify) commands let you inspect the current state and check for internal consistency issues — overlapping partitions, partitions extending beyond the disk’s addressable range — without writing anything, since nothing is committed until w is explicitly issued. This “look before you write” discipline is the single habit that separates routine partitioning work from data-loss incidents, and it costs nothing extra to practice consistently.

Handling Disks Already in Use by LVM or mdadm

A disk that’s already a member of an LVM volume group or an mdadm RAID array will often resist fdisk changes with “device busy” errors, precisely because the kernel is actively holding it open through that layer. The correct sequence is to tear down the higher layer first — vgremove/pvremove for LVM, or mdadm --stop/mdadm --zero-superblock for RAID — before fdisk can safely repartition the underlying device. Skipping this step and forcing a repartition while the layer above is still active is a reliable way to corrupt both the partition table and whatever LVM/RAID metadata was relying on the old layout.

Summary

fdisk sits at the foundation of disk management on Linux: before a filesystem, before a mount point, there has to be a partition table describing how the disk’s raw space is carved up, and fdisk is still the most direct, most universally available tool for building and inspecting that structure, whether you’re working with legacy MBR or modern GPT. The interactive menu takes a few sessions to feel natural, but the underlying model — geometry, partition entries, table types — carries over cleanly to every other partitioning tool you’ll ever touch.

References

Exit mobile version