FreeBSD Disk Partitioning
Posted on June 11, 2014 by Michael Lucas
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.
Disk Setup On FreeBSD
Warren Block wblock@wonkity.com 2016-05-23
The New Standard: GPT
GPT is the newer and more versatile partition method. Use it unless compatibility with the old standard MBR is required.
The disk device being set up here is da0.
Create a GPT partition scheme on /dev/da0. /dev/ is implied:
- gpart create -s gpt da0
da0 created
Create a boot partition to hold the loader, size of 512K. Give it a GPT label of gpboot, which will show up in /dev/gpt when the device is discovered:
- gpart add -t freebsd-boot -l gpboot -b 40 -s 512K da0
da0p1 added
Install the GPT bootcode into the boot partition:
- gpart bootcode -b /boot/pmbr -p /boot/gptboot -i 1 da0
bootcode written to da0
Create a partition for /. It should start at the 1M boundary for proper sector alignment on 4K sector drives or SSDs. This is compatible with GPT drive layout for many other systems. Give it a GPT label of gprootfs.
- gpart add -t freebsd-ufs -l gprootfs -b 1M -s 2G da0
da0p2 added
Create partitions for swap, /var, /tmp, /usr. Leaving the -s size option off the last uses the rest of the disk. As long as these are even sizes in M or G, the alignment will remain correct. Add -a 1M to force alignment of both starting position and size to one megabyte.
- gpart add -t freebsd-swap -l gpswap -s 512M da0
da0p3 added
- gpart add -t freebsd-ufs -l gpvarfs -s 1G da0
da0p4 added
- gpart add -t freebsd-ufs -l gptmpfs -s 256M da0
da0p5 added
- gpart add -t freebsd-ufs -l gpusrfs -a 1M da0
da0p6 added
- gpart show -l da0
=> 34 19640813 da0 GPT (9.4G)
34 6 - free - (3.0k) 40 1024 1 gpboot (512k) 1064 984 - free - (492k) 2048 4194304 2 gprootfs (2.0G) 4196352 1048576 3 gpswap (512M) 5244928 2097152 4 gpvarfs (1.0G) 7342080 524288 5 gptmpfs (256M) 7866368 11773952 6 gpusrfs (5.6G)
Tip
If there’s a need or desire to redo this partition layout, gpart(8) won’t destroy the "geom" until all of the partitions in it have been deleted:
- gpart delete -i 1 da0
da0p1 deleted
- gpart delete -i 2 da0
da0p2 deleted
- gpart delete -i 3 da0
da0p3 deleted
- gpart delete -i 4 da0
da0p4 deleted
- gpart delete -i 5 da0
da0p5 deleted
- gpart delete -i 6 da0
da0p6 deleted
- gpart destroy da0
Later versions of gpart(8) have a -F (force) option for destroy that makes things quicker but sort of blunt and stabby at the same time:
- gpart destroy -F da0
da0 destroyed
Format the new filesystems, enabling soft updates for performance. Filesystem labels can be added here, but probably should not be the same as the GPT labels already assigned.
- newfs -U /dev/gpt/gprootfs
- newfs -U /dev/gpt/gpvarfs
- newfs -U /dev/gpt/gptmpfs
- newfs -U /dev/gpt/gpusrfs
See http://www.freebsd.org/doc/en_US.ISO8859-1/books/faq/disks.html#SAFE-SOFTUPDATES for more information on using soft updates on the root filesystem.
Restore data. Labels are used in the mount command here because they’re easier to identify, but device names like /dev/da0p2 will work.
- mount /dev/gpt/gprootfs /mnt
- (cd /mnt && gzcat root.dump.gz | restore -ruf -)
- umount /mnt
Repeat for /var, /tmp, /usr.
Modify /etc/fstab:
- Device Mountpoint FStype Options Dump Pass#
/dev/gpt/gpswap none swap sw 0 0 /dev/gpt/gprootfs / ufs rw 1 1 /dev/gpt/gptmpfs /tmp ufs rw 2 2 /dev/gpt/gpusrfs /usr ufs rw 2 2 /dev/gpt/gpvarfs /var ufs rw 2 2
Done!