Btrfs/Getting Started

From Forza's ramblings

Getting Started with Btrfs[edit | edit source]

A disassembled Hard Disk.

Welcome,

This guide is designed to introduce you to the Btrfs filesystem, covering basic setup, advanced features like snapshots and compression, and best practices for managing your volumes. Before diving in, familiarize yourself with Btrfs's unique features.

Preparing your disks[edit | edit source]

For Btrfs, using a partition table is recommended to avoid issues with other tools and operating systems. Use a GUID Partition Table (GPT) for modern compatibility. Tools like GNU Parted, cfdisk, and fdisk are excellent for partitioning. In this guide we will use GNU Parted.

Btrfs also supports the use of unpartitioned/raw devices, allowing for flexibility in how storage devices are utilized. Additionally, Btrfs can be used on top of LVM (Logical Volume Manager) and MD (Multiple Device) devices, enabling advanced volume management and RAID configurations. This versatility makes Btrfs suitable for a wide range of storage setups, from simple single-disk systems to complex multi-device RAID arrays.

Single, multi-disk and RAID[edit | edit source]

Btrfs is versatile, working on single or multiple disks and supporting a variety of RAID modes, or Profiles, not all of which are traditional RAID modes. These profiles include DUP, SINGLE, and MIXED, in addition to the conventional RAID levels. Each profile offers different advantages in terms of redundancy, storage efficiency, and performance, allowing users to tailor the filesystem to their specific needs. For detailed information on configuring these profiles, refer to the Profiles section.

Tools such as the Btrfs disk space calculator can help you effectively plan your disk setup by considering the different profiles. Additionally, the python-btrfs package provides a command-line space calculator, useful for understanding the space allocation and redundancy benefits of each profile.

Screenshot of the disk space calculator.
Disk space calculator showing 3 devices in a RAID-1 configuration
# btrfs-space-calculator -m raid1 -d raid1 4TiB 6TiB 8TiB
Target metadata profile: RAID1
Target data profile: RAID1
Mixed block groups: False
Total raw filesystem size: 18.00TiB
Device sizes:
  Device 1: 4.00TiB
  Device 2: 6.00TiB
  Device 3: 8.00TiB
Metadata to data ratio: 1:200
Estimated virtual space to use for metadata: 46.00GiB
Estimated virtual space to use for data: 8.96TiB
Total unallocatable raw amount: 0.00B
Unallocatable raw bytes per device:
  Device 1: 0.00B
  Device 2: 0.00B
  Device 3: 0.00B

SSD and NVME disks[edit | edit source]

For NVMe or SSD drives, using blkdiscard before partitioning can improve performance and longevity by informing the firmware the disk is unused. Warning: Do this before you create any partition tables as this erases all data on the disk.

Partitioning[edit | edit source]

Create a partition table using GNU Parted, ensuring partitions start on a 4MiB boundary for optimal alignment. This alignment matches the internal erase block sizes of many SSDs, which can improve performance and reduce wear. It also ensures enough space at the beginning of the disk if you need to add a BIOS Boot partition later on.

Invoke parted using parted /dev/<disk> for each disk that you want to include in your Btrfs system. We will use /dev/sdb in the following example:

# parted /dev/sdb
 GNU Parted 3.2
 Using /dev/sdb
 Welcome to GNU Parted! Type 'help' to view a list of commands.
 (parted)

First check there is no existing partitions or partition tables on the disk:

(parted) print
 Error: /dev/sdb: unrecognised disk label
 Model: ATA VBOX HARDDISK (scsi)
 Disk /dev/sdb: 102400MiB
 Sector size (logical/physical): 512B/512B
 Partition Table: unknown
 Disk Flags:

Change the display unit to MiB (Megabytes):

(parted) unit MiB

Create a GPT partition table:

(parted) mklabel gpt

Create a partition labelled my-btrfs (you can choose any name you like):

(parted) mkpart my-btrfs btrfs 4MiB 100%

You can list the resulting layout using print command:

(parted) print
 Model: ATA VBOX HARDDISK (scsi)
 Disk /dev/sdb: 51200MiB
 Sector size (logical/physical): 512B/512B
 Partition Table: gpt
 Disk Flags:
 
 Number  Start    End       Size      File system  Name      Flags
  1      4.00MiB  51299MiB  51295MiB  btrfs        my-btrfs

You should repeat this for each disk you want to add to your Btrfs filesystem.

The result should be something like this:

Partition Filesystem Start End Partition type
/dev/sdb1 Btrfs 4MiB 100% Linux filesystem
/dev/sdc1 Btrfs 4MiB 100% Linux filesystem

Create the filesystem - mkfs.btrfs[edit | edit source]

Use the following command to create a Btrfs filesystem across your disks:

# mkfs.btrfs -L <label> --metadata <profile> --data <profile> <device_1> <device_2> <device_n>

Have a look at profiles for a list of supported Profiles and RAID modes,

This will create a standard btrfs filesystem spanning both disks and give it the name my-data. The filesystem will have the size of the sum of both disks, in this case 150GiB.

# mkfs.btrfs -L my-data --data single /dev/sdb1 /dev/sdc1
Label:              my-data
UUID:               a36f20ff-f0b1-466d-a7dc-355c189b3e39
Node size:          16384
Sector size:        4096
Filesystem size:    149.99GiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         RAID1             1.00GiB
  System:           RAID1             8.00MiB
SSD detected:       yes
Incompat features:  extref, skinny-metadata
Number of devices:  2
Devices:
   ID        SIZE  PATH
    1    50.00GiB  /dev/sdb1
    2   100.00GiB  /dev/sdc1

If you rather want to use RAID1 (mirroring) you would do:

# mkfs.btrfs -L my-data --data RAID1 /dev/sdb1 /dev/sdc1

Btrfs as root filesystem[edit | edit source]

For a single disk setup, consider separate partitions for boot, swap (if necessary), and root. Recent kernels support Btrfs swap files, but limitations exist, making swap partitions a safer choice.

Follow the guide in the Partitioning section to prepare your partitions.

Partition Filesystem Start End Partition type
/dev/sda(none) (bootloader) 0 4MiB BIOS boot
/dev/sda1 FAT32* 4MiB 1GiB Boot or EFI system partition (ESP)
/dev/sda2 Swap 1GiB 4GiB Swap partition*
/dev/sda3 Btrfs 4GiB 100% Linux filesystem
Note that with UEFI boot, you must use a FAT32 formatted EFI System Partition for the boot loader.

There is a very good guide in the Gentoo handbook on how to choose and determine a suitable partition layout.

When deciding on swap space you should choose a size based on systems RAM size and if you are going to use Hibernation. There is a good guide over at the Ubuntu Community pages that explains why you need swap and how to determine an appropriate size. Generally RAM size * 2 is a safe choice.

Swap size guideline
RAM No hibernation With Hibernation Maximum
1GiB 1GiB 2GiB 2GiB
2GiB 1GiB 3GiB 4GiB
3GiB 2GiB 5GiB 6GiB
4GiB 2GiB 6GiB 8GiB
5GiB 2GiB 7GiB 10GiB
6GiB 2GiB 8GiB 12GiB
8GiB 3GiB 11GiB 16GiB
12GiB 3GiB 15GiB 24GiB
16GiB 4GiB 20GiB 32GiB
24GiB 5GiB 29GiB 48GiB
32GiB 6GiB 38GiB 64GiB
64GiB 8GiB 72GiB 128GiB

Subvolumes[edit | edit source]

Btrfs subvolumes is one of the unique features of Btrfs. Subvolumes allow for logical data separation within a single filesystem. They share all the space in the filesystem, supports independent snapshots and backups. Subvolumes can also be mounted independently. In most ways, a subvolume looks like a normal directory, but has additional super powers.

Upon creation, Btrfs establishes a default subvolume, often referred to as top-level or root subvolume. This will be the used when mounting the filesystem without subvol or subvolid options.

I usually make two directories, volume and snapshots in which I create all subvolumes. This makes it easy to separate snapshots from normal subvolumes. Having all subvolumes in a single directory is called a flat structure. Avoid making nested subvolumes as it makes things more complicated to manage later on.

toplevel            (default subvolume root directory)
+-- dir_1           (normal directory)
|   +-- file_2      (normal file)
|   \-- file_3      (normal file)
\-- volume          (directory)
    +-- root        (subvolume)
    |   \-- file_4  (normal file)
    +-- home        (subvolume)
    +-- tmp         (subvolume)
    \-- file_5      (normal file)
\-- snapshots       (directory)

Use the -o subvol= mount option to specify the subvolume to mount.

# mount /dev/sdb1 /home    -o subvol=volume/home # mounts the home subvolume in /home
# mount /dev/sdb1 /var/tmp -o subvol=volume/tmp  # mounts the tmp  subvolume in /var/tmp

Btrfs does not impose any restrictions on the layout or naming of subvolumes or snapshots. Subvolumes can be created and removed at anytime so it is a good choice to start with few and expand you need to a later time. Many Linux distributions use an @ character to denote a subvolume.

fstab[edit | edit source]

The Filesystem Table, or fstab, is a configuration file located at /etc/fstab that defines how and where the different filesystems and storage devices should be mounted, including required mount options.

Using UUIDs (Universally Unique Identifiers) instead of traditional device paths (like /dev/sda1) in fstab is recommended for several reasons:

  • Uniqueness: UUIDs are unique for each filesystem, which eliminates the risk of confusion between devices, especially when the hardware configuration changes.
  • Consistency: Device paths can change between reboots due to hardware changes or the addition of new drives. UUIDs, however, remain consistent regardless of these changes, ensuring that the system always mounts the correct filesystem.

To find the UUID of a filesystem, you can use the blkid command:

# blkid -s UUID -s TYPE
/dev/sda2: UUID="6f6353bf-d63a-40b4-99d1-b221138e268c" TYPE="btrfs"
/dev/sda3: UUID="3f08368e-841e-42eb-807e-da3f447b6144" TYPE="btrfs"
/dev/sdb:  UUID="a8830497-a304-492e-8b08-e034958ca7b5" TYPE="swap"

This is the fstab on my Linux Mint machine:

File: /etc/fstab
UUID=3f08368e-841e-42eb-807e-da3f447b6144 /               btrfs   noatime,compress=zstd:1,subvol=@      0 0
UUID=3f08368e-841e-42eb-807e-da3f447b6144 /home           btrfs   noatime,compress=zstd:1,subvol=@home  0 0
UUID=6f6353bf-d63a-40b4-99d1-b221138e268c /boot           btrfs   noatime                               0 0
LABEL=swap                                none            swap    sw,discard                            0 0
UUID=3f08368e-841e-42eb-807e-da3f447b6144 /mnt/rootvol    btrfs   noatime,compress=zstd:1,subvol=/      0 0

Here is a the fstab from one of my Gentoo Linux machines:

File: /etc/fstab
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /                   btrfs   compress=zstd:1,noatime,subvol=volume/root           0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /home               btrfs   compress=zstd:1,noatime,subvol=volume/home           0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /usr/src            btrfs   compress=zstd:1,noatime,subvol=volume/src            0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /var/cache          btrfs   compress=zstd:1,noatime,subvol=volume/var_cache      0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /var/tmp            btrfs   compress=zstd:1,nodev,subvol=volume/var_tmp          0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /var/db/repos       btrfs   compress=zstd:1,noatime,subvol=volume/repos          0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /var/lib/mysql      btrfs   compress=zstd:1,noatime,subvol=volume/mysql          0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /var/lib/unifi      btrfs   compress=zstd:1,noatime,subvol=volume/unifi          0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /var/lib/redis      btrfs   compress=zstd:1,noatime,subvol=volume/redis          0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /var/log            btrfs   compress=zstd:1,noatime,subvol=volume/var_log        0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /var/spool/mail     btrfs   compress=zstd:1,noatime,subvol=volume/mail           0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /var/www            btrfs   compress=zstd:1,noatime,subvol=volume/www            0 0
UUID=c08bb98b-3b98-4dbb-a7c0-5540c2af781b   /mnt/rootvol        btrfs   noatime,compress=zstd:1                              0 0
UUID=65539fe2-c83d-41ea-9066-c85d40569bb7   none    swap    sw,pri=0,discard     0 0
UUID=7885b944-0b12-45e4-9319-a52e62758086   none    swap    sw,pri=100,discard   0 0
UUID=be4f6376-f113-4382-9f47-1cac32499f22   none    swap    sw,pri=100,discard   0 0

Take a note of the /mnt/rootvol lines. This is the top-level subvolume for the filesystem. In here you can access all subvolumes, snapshot them, and do maintenance tasks.

# ls -l /mnt/rootvol/
 drwxr-xr-x 1 root root 6224 Aug  2 13:01 snapshots/
 drwxr-xr-x 1 root root  190 Apr 30 22:28 volume/
# ls -l /mnt/rootvol/volume
drwxr-xr-x 1 root   root     36 Jul 30 22:27 home/
drwxr-xr-x 1 root   root    306 Jul 23 12:22 root/
drwxrwxrwx 1 root   root     96 Aug  2 11:43 var_tmp/
# ls -l /mnt/rootvol/snapshots
drwxr-xr-x 1 root   root     36 Jul 30 22:27 home.20200730T2301/
drwxr-xr-x 1 root   root     36 Jul 30 22:27 home.20200731T0001/
drwxr-xr-x 1 root   root     36 Jul 30 22:27 home.20200801T2201/
drwxr-xr-x 1 root   root    306 Jul 23 12:22 root.20200730T0001/
drwxr-xr-x 1 root   root    306 Jul 23 12:22 root.20200731T0001/
drwxr-xr-x 1 root   root    306 Jul 23 12:22 root.20200802T1401/

GRUB / Boot loader[edit | edit source]

The boot process in Linux involves several key steps to initialize the system. At a high level, the process begins with the BIOS or UEFI firmware initializing the hardware, followed by the execution of a boot loader stored on the hard drive or other bootable media. The boot loader is responsible for loading the kernel and the initial ramdisk (initramfs) into memory.

  1. BIOS/UEFI: The system's firmware performs POST (Power-On Self Test) and identifies the boot device.
  2. Boot Loader: A small piece of software on the boot device, the boot loader is responsible for loading the Linux kernel and the initramfs into memory.
  3. Kernel Initialization: The kernel takes over, initializes the hardware devices, and loads the initramfs, a temporary root filesystem loaded into memory.
  4. Switch to Real Root: The system switches from the initramfs to real root filesystem.
  5. Hand over the remainder of the boot process to the operating system.

Initial RAM filesystem[edit | edit source]

The initramfs is a temporary root filesystem that is loaded into memory during the boot process. It contains essential drivers (kernel modules) and scripts required to mount the real root filesystem and continue the boot process.

Common Boot Loaders[edit | edit source]

Several boot loaders are available for Linux, each with its features and configuration methods. Some of the most common ones include: GRUB (GRand Unified Bootloader): The most widely used boot loader, offering extensive configuration options and support for multiple operating systems.

  • rEFInd: A fork of the rEFIt boot manager for EFI and UEFI systems, known for its ease of use and graphical menu system. rEFInd can automatically detect kernels, making it a popular choice for dual-booting and systems with multiple operating systems.
  • EFISTUB: Allows the UEFI firmware to directly boot the kernel without a traditional bootloader.
  • systemd-boot (previously gummiboot): A simple UEFI boot manager that provides a straightforward boot menu and configuration.
  • Syslinux: A lightweight bootloader.
  • LILO (Linux Loader): An older boot loader that directly loads the Linux kernel without a menu system. It is no longer maintained.

Each boot loader offers unique advantages, and choosing the right one depends on your specific needs, such as support for UEFI or BIOS, ease of configuration, and the ability to boot multiple operating systems. rEFInd, in particular, is noted for its user-friendly approach to managing EFI boot options, making it a great choice for users looking for a customizable and visually appealing boot menu.

For a detailed comparison of boot loaders, visit Comparison of Bootloaders.

Distribution-Specific Guides[edit | edit source]

Different Linux distributions have their own preferred methods for setting up the boot loader and initramfs. For detailed instructions and guidelines, refer to the documentation specific to your distribution:

Further Reading and Support[edit | edit source]

The official home for Btrfs documentation is at https://btrfs.readthedocs.io/

If you need support I suggest going to the Btrfs/IRC channel. It is a very active and friendly community.