After understanding the design of how x86 Storage works the next logical step is learning and using the various utilities to manipulate the MBR/GPT and partitions themselves. We'll focus on the most common utilities herein and common tasks and how they differ and their use with both partition types.
MBR vs. GPT
This topic is covered in detail in the Linux x86 Storage article; a quick recap of the basics:
|Max Partitions|| 4 Primary or
3 Primary, 1 Extended, Unlimited Logical
|Max Size||2 TiB ((2^32)*512 bytes)||8 ZiB ((2^64)*512 bytes)|
Extrapolating from this table we can then make a set of rules to live by:
- MBR format is limited to 2 TiB
- GPT format is limited to 8 ZiB
- Use GPT format if your storage is greater than 2 TiB
- Use GPT if your storage could grow larger than 2 TiB
- If a 4th MBR partition is marked Primary, you cannot use Extended
- If 3 MBR Primary partitions exist, make the 4th one Extended rest of device
- Logical MBR partitions 5+ live inside the 4th Extended partition
- Adding a new Logical partition requires growing the Extended partition first
MBR Extended/Logical Partitions
Having only 4 primary partitions is a limit of the original MBR design - as such, an extension was invented called the extended partition with a very wide open design. The 4th primary partition is created as a type extended which points to the first Extended Boot Record (EBR) of the first logical partition within. The extended partition is normally created with the rest of the disk as it's size, it will contain logical partitions inside.
Each EBR contains a pointer to the next EBR (along with it's logical partition info) which allows chaining EBRs together. The number of logical partitions within an extended partition is limited only by the amount of available disk space in the extended partition; all of this work is handled by the various tools and does not need to be manually manipulated by the end user.
With the traditional design of a 512-byte sector, starting the first partition at LBA 63 poses no problem in alignment of the physical device (sometimes called the radial geometry) with the logical use by the CPU. Modern devices are starting to use 4096-byte (4k) sector sizes - and in the case of SSD possibly 8192-bytes (8k), sometimes referred to as pages to match the CPU terminology. Externally they may emulate 512-byte sectors for compatibility (called 512e mode) but internally these devices are working with 4096.
Starting a partition at LBA 63 with 4k pages it problematic -- mathematically this is one 512-byte sector short of a natural 4096 boundary of the physical geometry. If history had worked out better, using LBA 64 would have worked out mathematically:
(63*512)/4096 = 7.8750 (63*512)/8192 = 3.9375 (64*512)/4096 = 8.0000 (64*512)/8192 = 4.0000
To overcome this issue, in modern use the first partition is started with at LBA 2048 - with a 512-byte sector this is 1 MiB, or 256 pages of a 4096-byte sector. This conservative approach allows for future changes that are not foreseen today, allowing enough space and performing meticulous boundary alignment on the classic power of 2^8. SSD drives use multiples of 128 KiB, 256 KiB or 512 KiB depending on device, again creating a natural alignment mechanism.
On a modern Linux distribution the userspace tools described below understand these alignment needs and default to using 2048 sector offset when creating the first partition on a drive.
The fdisk utility is the classic partitioning tool. It's usage is based around a menu driven text interface; all changes performed are held into memory until a command is issued to write them out to disk; this technique allows one to cancel/exit if desired without changes, making it an enticing tool to use. The fdisk binary itself is part of the util-linux (or util-linux-ng) package of tools that also includes utilities like fsck, mount and umount.
One of the most important things to note about using fdisk: the version shipped on most enterprise class distributions (RHEL/CentOS for instance) tends to be an older but stable version. The downside is that these older stable releases only support the MBR (aka "dos" or "msdos") style and partition design, limiting your disk to 2 TiB. The most recent fdisk release are beginning to support GPT style, but as they are not yet packaged as for these distros means another tool must be used.
Use the -c and -u options to fdisk to disable DOS compatibility mode (C/H/S) and use Sector mode. These options can also be toggled while in fdisk with the c and u commands.
The parted utility works the opposite of fdisk; as commands are issued the changes are made, whether it's used in pure commandline-only mode or when using the menu driven interface. This concept tends to make the usage of parted a bit scary to the beginning tech, and rightly so - once you do it, it's done. No backing out of a mistake (easily) like with fdisk.
The draw to parted tends to come in two parts: it's easily commandline scriptable and it fully supports GPT style disks (as well as MBR). This makes it the current de-facto utility for dealing with storage larger than 2 TiB and GPT partitions (required for UEFI). The parted package also includes the partprobe tool that many like.
The gdisk utility (sometimes called gptdisk or GPT fdisk) is a newer tool designed to combine the two worlds of fdisk and parted; it provides a bit of commandline and a bit of menu driven interface. It allows all the GPT functionality but with the capability of staging in memory first before writing to disk, allowing for an exit without write as needed. The gdisk package includes complementary targeted tools such as cgdisk, sgdisk and fixparts which are designed for GPT/MBR manipulation
One of the largest draws to gdisk is it's ability to repair (or attempt to repair) corrupted or broken MBR and GPT partition style types. It can extract and back up partition tables, load them from backups, repair the primary GPT from the secondary copy, convert GPT to MBR and all sorts of advanced features. The use of gdisk in certain situations can achieve results that fdisk and parted cannot.
At this time the gdisk package is hosted via the EPEL project for RHEL/CentOS distributions and is not present in the standard vendor repositories. Conversely the Ubuntu LTS repositories do contain it, however they may have an older version (0.8.1 for 12.04 LTS). If working on GPT disks be sure and use a stable relatively bug-free version.
The partx utility is useful for triggering the kernel subsystems to add/remove device nodes based on the partition map of a block device. It's akin to the partprobe tool however works a bit differently; in general it's a better choice than partprobe due to it's design and integration with the kernel. The most typical usage is to add new partition device nodes after new partitions were created, or delete in the reverse scenario. Normally these functions are handled by fdisk/parted/gdisk but in some cases they are not.
For example - if a device has partitions and devices nodes such as /dev/xvdb1, /dev/xvdb2, etc. and you utilize the zap feature of gdisk to zero out a disk, this does not trigger cleanup of the device nodes. Running partx -d /dev/xvdb will trigger a kernel level cleanup and remove them at runtime - likewise, it's common using fdisk /dev/sda to make a new partition results in an ioctl error when saving. You can use partx -a /dev/sda to trigger a kernel level refresh to create your new /dev/sdaX device node entry.
Utilizing fdisk and gdisk menu driven interfaces are nearly identical; while parted has a menu interface, the commands typed are the same as on the commandline scripted mode. A quick comparison of the most common operations being performed:
|List Partitions||fdisk -cul /dev/xvdb||parted /dev/xvdb unit s print||gdisk -l /dev/xvdb|
|Create MBR or GPT|| fdisk -cu /dev/xvdb
|parted -s -- /dev/xvdb mkpart table gpt|| gdisk /dev/xvdb|
|Create First Partition|| fdisk -cu /dev/xvdb
n, p, 1, 2048, size, w
|parted -s -- /dev/xvdb mkpart primary 2048s 100%|| gdisk /dev/xvdb|
n, 1, 2048, size, type, w
|Set Partition to LVM|| fdisk -cu /dev/xvdb
t, 1, 8e, w
|parted -s -- /dev/xvdb set 1 lvm on|| gdisk /dev/xvdb|
t, 1, 8e00, w
|Delete Partition|| fdisk -cu /dev/xvdb
d, 1, w
|parted -s -- /dev/xvdb rm 1|| gdisk /dev/xvdb|
d, 1, w
Resizing partitions is typically encountered when a disk is grown (expanded) or shrunk (reduced); remember that a higher level infrastructure sits on top of the partitions themselves in almost all cases. Given that, remember to take precautions such as:
- If reducing, unmount the filesystem or make it inactive as required for safety
- If reducing, resize the filesystem (ext3, ext4, etc.) before the container/partition
- If reducing, reduce the container (LVM, etc.) before the partition
- If expanding, expand the container (LVM, etc.) after the partition
- If expanding, resize the filesystem (ext3, ext4, XFS, etc.) after the container/partition
- Not all filesystem types can be reduced or expanded! XFS for example cannot be reduced
In practice using parted is the best tool for the job; however, remember that parted is a one shot tool - changes are immediate. Use gdisk for GPT or fdisk for MBR disks if you need to stage the work and double check it before executing. Do not use these tools to resize the filesystem itself! For example the parted tool has a resize command that works on some filesystem types and not others, and no way to ignore the filesystem.
Expanding MBR Primary
Warning: all data could be lost if this is done incorrectly! Pay very close attention to your start/end sectors and math
- Scenario: MBR, 3 Primary partitions
- Task: Increase partition 3 size +10G
Unmount the partition and record the layout; for this example only I'll show the disk in GiB to help in understanding the sector math first; we'll unmount it and fsck it to ensure the filesystem is OK before starting.
# df -h | grep xvdb3 /dev/xvdb3 9.9G 151M 9.2G 2% /mnt # umount /mnt # parted -s -- /dev/xvdb unit GiB print Model: Xen Virtual Block Device (xvd) Disk /dev/xvdb: 100GiB Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 0.00GiB 10.0GiB 10.0GiB primary 2 10.0GiB 20.0GiB 10.0GiB primary 3 20.0GiB 30.0GiB 10.0GiB primary ext4 # fsck -fC /dev/xvdb3 fsck from util-linux-ng 2.17.2 e2fsck 1.41.12 (17-May-2010) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information /dev/xvdb3: 11/655360 files (0.0% non-contiguous), 79663/2621440 blocks
Now let's do the work - first, the geometry needs to be recorded in sector mode as we must precisely recreate the starting sector of the partition:
# parted -s -- /dev/xvdb unit s print Model: Xen Virtual Block Device (xvd) Disk /dev/xvdb: 209715200s Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 2048s 20973568s 20971521s primary 2 20973569s 41945089s 20971521s primary 3 41945090s 62916610s 20971521s primary ext4
We use the built-in functionality of parted to simple change the starting and ending sectors. We will add 20971520 sectors (10 GiB @ 512-byte sector size) to the end of partition 3. We then tell parted to use the same starting sector (41945090s) and new ending sector (83888130s) we just computed.
Note that the numerical value ends in s to denote sectors! Do not forget your trailing s. Lastly, we resize (grow) the ext4 filesystem on top of it to the new size.
# echo "62916610 + 20971520" | bc -l 83888130 # parted -s -- /dev/xvdb rm 3 # parted -s -- /dev/xvdb mkpart primary 41945090s 83888130s # resize2fs /dev/xvdb3 # mount /dev/xvdb3 /mnt # parted /dev/xvdb unit s print Model: Xen Virtual Block Device (xvd) Disk /dev/xvdb: 209715200s Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 2048s 20973568s 20971521s primary 2 20973569s 41945089s 20971521s primary 3 41945090s 83888130s 41943041s primary ext4 # df -h | grep mnt /dev/xvdb3 20G 156M 19G 1% /mnt
Adding MBR Logical
Warning: all data could be lost if this is done incorrectly! Pay very close attention to your start/end sectors and math
- Scenario: MBR, 3 Primary partitions, 1 Extended partition, 1 Logical partition
- Task: Increase Extended partition, add new Logical partition
This builds upon the basic expansion of a primary partition concept, however the parted resize command is our saving grace; if it were done 100% manually (say, with fdisk) the process would go like this:
- Record geometry
- Delete Logical partition 1
- Delete Extended partition
- Recreate Extended partition larger
- Recreate Logical partition 1
- Add new Logical partition 2
Using parted however allows us to magically resize the Extended partition without having to perform all of the above steps. Once again, pay attention to your exact geometry and math!
# parted /dev/xvdb unit s print Model: Xen Virtual Block Device (xvd) Disk /dev/xvdb: 209715200s Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 2048s 20973568s 20971521s primary 2 20973569s 41945089s 20971521s primary 3 41945090s 62916610s 20971521s primary ext4 4 62916611s 83888131s 20971521s extended 5 62918659s 83888131s 20969473s logical ext4
Notice the Start of 4 (Extended) and 5 (Logical) do not match - watch out for this, especially if you intended to resize 5 after growing 4. We will add 10G (20971520s) to the end of 4, then add a new 6 (Logical) using this new space starting after the existing 5. Note that I am adding 2048 to the ending sector of 5 to determine my start of 6 for optimal performance (in theory - this disk is misaligned starting at partition 2 already):
# echo "83888131 + 20971520" | bc -l 104859651 # parted -s -- /dev/xvdb resize 4 62916611s 104859651s # parted /dev/xvdb unit s print Model: Xen Virtual Block Device (xvd) Disk /dev/xvdb: 209715200s Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 2048s 20973568s 20971521s primary 2 20973569s 41945089s 20971521s primary 3 41945090s 62916610s 20971521s primary ext4 4 62916611s 104859651s 41943041s extended 5 62918659s 83888131s 20969473s logical ext4 # parted -s -- /dev/xvdb mkpart logical 83890179s 104859651s # parted /dev/xvdb unit s print Model: Xen Virtual Block Device (xvd) Disk /dev/xvdb: 209715200s Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 2048s 20973568s 20971521s primary 2 20973569s 41945089s 20971521s primary 3 41945090s 62916610s 20971521s primary ext4 4 62916611s 104859651s 41943041s extended 5 62918659s 83888131s 20969473s logical ext4 6 83890179s 104859651s 20969473s logical
Zapping is the concept of completely wiping all traces of a MBR and/or GPT to result in clean device, as if it were brand new. All data is lost, use with caution! Use gdisk for this need:
# gdisk /dev/xvdb GPT fdisk (gdisk) version 0.8.10 Partition table scan: MBR: protective BSD: not present APM: not present GPT: present Found valid GPT with protective MBR; using GPT. Command (? for help): x Expert command (? for help): z About to wipe out GPT on /dev/xvdb. Proceed? (Y/N): Y GPT data structures destroyed! You may now partition the disk using fdisk or other utilities. Blank out MBR? (Y/N): Y