FreeBSD Disk Partitioning

A couple weeks ago, I monopolized the freebsd-hackers mailing list by asking a couple simple, innocent questions about managing disks using gpart(8) instead of the classic fdisk(8) and disklabel(8). This is my attempt to rationalize and summarize a small cup of the flood of information I received.

The FreeBSD kernel understands several different disk partitioning schemes, including the traditional x86 MBR (slices), the current GPT, BSD disklabels, as well as schemes from Apple, Microsoft, NEC (PC98), and Sun. The gpart(8) tool is intended as a generic interface that lets you manage disk partitioning in all of these schemes, and abstract away all of the innards in favor of saying “Use X partitioning system on this disk, and put these partitions on it.” It’s a great goal.

FreeBSD storage, and computing storage in general, is in a transitory state today. The older tools, fdisk and bsdlabel, aren’t exactly deprecated but they are not encouraged. x86 hardware is moving towards GPT, but there’s an awful lot of MBR-only gear deployed. Disks themselves are moving from the long-standing 512B sector size to 4KB, eight times larger.

And as gravy on top of all this, disks lie about their sector size. Because why wouldn’t they?

Traditional disks have a geometry defined by cylinders, heads, and sectors. MBR-style partitions (aka slices) are expected to end on cylinder boundaries — that is, slices are measured in full cylinders. Cylinders and heads aren’t really relevant to modern disks–they use LBA. With flash drives, SSDs, and whatever other sort of storage people come up with, disk geometry is increasingly obsolete. The traditional MBR partitions expect to run on top of cylinder-based partitions, however, and any BSD throws a wobbler if you use a MBR partition that doesn’t respect this.

gpart must handle those traditional cylinder boundaries as well as partitioning schemes without such boundaries. If you create a 1GB MBR partition, it will round the size to the nearest cylinder.

The sector size changes create orthogonal problems. If you write to the disk in 512B sectors, but the underlying disk has 4K sectors, the disk will perform many more writes than necessary. If you write to the disk in 4K sectors, but the underlying disk uses 512B sectors, there’s no real harm done.

But if your logical 4K sectors don’t line up with the disk’s physical 4K sectors, performance will drop in half.

For best results, create all partitions aligned to a 4K sector. If the underlying disk has 512B sectors, it won’t matter; you must do more writes to fill those sectors anyway. Use the -a 4k arguments with gpart to have created partitions aligned to 4K sectors.

How do you do this? It depends on if you’re using GPT or MBR partitions.

For GPT partitions, you must start partitioning the disk at a multiple of 4K. The front of your disk might have all kinds of boot code or boot managers in it, however. Start your first partition at the 1MB mark, and only create partitions that are even multiples of a megabyte. Today you’d have to go out of your way to create a partitions that was 1.5MB, so this isn’t a huge constraint.

For MBR partitions, it’s slightly more difficult. Use the -a 4k command-line arguments to gpart when creating BSD partitions inside a MBR slice. This tells gpart that even if the slice isn’t 4k aligned, the BSD partitions must be.

I could put a bunch of instructions here, but Warren Block has a nice detailed walk-through of the actual commands used to partition disks with these standards.

2 comments to FreeBSD Disk Partitioning

  • If you want the 2nd partition (the 1st is the boot code) to start at 1mb, and be a multiple of 1mb, you can just use -a 1m

    You probably don’t really care about the alignment of the first bit, probably better not to align it to avoid leaving free space at the start of the disk that might confuse some BIOS or other

    gpart create -s GPT ada0
    gpart add -s 512k -t freebsd-boot ada0
    gpart add -a 1m -s 8G -t freebsd-swap ada0
    gpart add -a 1m -t freebsd-zfs ada0

    will result in:

    => 34 41942973 ada1 GPT (20G)
    34 1024 1 freebsd-boot (512K)
    1058 990 – free – (495K)
    2048 16777216 2 freebsd-swap (8.0G)
    16779264 25161728 3 freebsd-zfs (12G)
    41940992 2015 – free – (1.0M)

    The other advantage of this, is you leave the leftover fraction of a megabyte at the end of the drive. In the future, if the replacement drive is a slightly different number of sectors, you have wiggle room. Although in our case, we have the swap and the free space before the swap that we can wiggle as well, to result in a ZFS partition big enough to use as a replacement disk.