Btrfs/Adding and removing devices

From Forza's ramblings

Btrfs Volume Management[edit | edit source]

Photograph of a hard-drive with its cover removed. The actuator and individual platters are visible.
A 2.5" hard disk device with Serial-ATA connections.

Part of what makes Btrfs so flexible is its volume management features. It allows Btrfs to utilise and combine the disk space on several devices and use it a single filesystem. Btrfs allows adding and removing devices from mounted filesystems without down-time, and it is possible to combine devices of different size. This makes it possible to gradually increase the filesystem size by adding additional devices over time.

For example, you have a 256GB SSD as root filesystem that is starting to get full. Btrfs makes it possible to simply add another SSD and combine the space of both devices, without having to re-create the filesystem.

Btrfs supports different types of profiles (usually called RAID modes), when combining devices. It is also possible to use different profiles for METADATA and DATA chunks. See the Btrfs/Profiles page.

Adding devices to an existing filesystem[edit | edit source]

As with most Btrfs operations, the filesystem needs to be mounted before modifying it.

Adding a device is as simple as using btrfs device add <device> <mountpoint>.

# btrfs device add /dev/loop2p1 /mnt/my-btrfs/

Depending on the profile of the existing filesystem it may be necessary to balance the filesystem to take full advantage of the added disk space or enabling extra resiliency. See the example below.

NOTE: Although Btrfs can use raw disks, it is recommended to partition the disk first. This makes management easier, and helps other tools understand that there is a filesystem on the device.

When balance is needed[edit | edit source]

When making changes to the disk layout by adding or removing devices, it is usually necessary to balance the filesystem so that block groups are spread out evenly, utilising all available space. Balancing is not needed when the allocator can fill up the remaining unallocated space (including the new devices) without leaving unusable space. The goal with balancing is to ensure that there is enough unallocated space on each device to satisfy the requirements of the given profile.

NOTE: See the chapter Btrfs/ENOSPC on the consequences (and remedies) if there isn't enough unallocated space available.
Balancing is needed when...[edit | edit source]
  • Adding a device to a RAID0, RAID10 or RAID5/6 filesystem.
  • Converting from single to a RAID profile.
  • Converting from DUP to a RAID profile.
  • Adding a device to a filesystem using a RAID profile which was very full.

One example is if you have 2 device RAID1 filesystem and add a 3rd device. A balance s needed to spread out the block groups evenly among the three devices. Otherwise the filesystem may end up with no free disk space (Btrfs/ENOSPC) error even though there is available space on the new device. This is because RAID1 requires free space on two devices for each new block group allocation.

Another example if you have a 2 device RAID0 filesystem and add a 3rd device. A balance is needed to convert from a 2-striped filesystem to a 3-striped filesystem. Without balancing, old data will still only be striped over the two old devices.

If you have a single device filesystem and simply want to add another device, no balance is needed for normal operation. However, it is recommended to convert METADATA to RAID1 instead of DUP. This will increase resiliency against metadata corruption for free as RAID1 does not cost any extra disk space than DUP.

Removing devices from a filesystem[edit | edit source]

Use btrfs device remove <device-or-devid> <mountpoint> to remove a device.

device and devid can be found using btrfs filesystem usage <mountpoint> or btrfs filesystem show <mountpoint>.

# btrfs filesystem show /mnt/my-btrfs/
Label: 'my-btrfs'  uuid:  01dc0ff9-b1e1-4930-a51a-1b0207674cbe
    Total devices 3 FS bytes used 1.08GiB                                           
    devid    1 size 10.00GiB used 1.28GiB path /dev/loop0p1
    devid    2 size 10.00GiB used 1.28GiB path /dev/loop1p1
    devid    3 size 10.00GiB used 2.00GiB path /dev/loop2p1

Any existing data on the removed device will automatically moved over to other devices in the same filesystem. This can take a considerable amount of time. Use btrfs filesystem usage <mountpoint> to monitor the progress.

Limitations when removing devices[edit | edit source]

  • All of the data must fit on the remaining devices.
  • It is not possible to go below the minimum number of devices given the data or metadata profile used. For example on a 3 device RAID1 filesystem it is possible to remove 1 device but not 2.

See more about the limitations of different profiles on the Btrfs/Profiles page.

Replacing an existing device[edit | edit source]

Btrfs has a dedicated method to replace a device. Instead of adding a new device and then remove the old, btrfs replace should be used. It is several times faster and can also handle corruptions and problems better than btrfs device remove.

Btrfs replace works with all profiles and can be used with single device and multi device filesystems.

There is a dedicated page for Btrfs replace with more information.

Complete example of adding a second device to single disk filesystem[edit | edit source]

Let's create an example filesystem to work with.

Preparing new devices[edit | edit source]

Btrfs supports using raw devices without partition tables, however it is usually better to create a partition table first as it makes future management easier.

You can use fdisk or cfdisk from the util-linux package or GNU parted to create a partition table and a partion to hold your new btrfs filesystem. Use a GUID Partition Table (GPT) instead of the old DOS MBR style partition table. GPT supports devices larger than 2TiB and also stores a backup copy at the end of the device.

If you have an NVME or SSD disk, it is good practice to empty it using blkdiscard. Discard tells the drive's firmware that the disk is empty and it improves it's performance and wear. Do this before you create any partition tables as it will erase everything of the disk.

# blkdiscard /dev/loop4 -v
/dev/loop4: Discarded 10737418240 bytes from the offset 0

Here we use GNU parted to create a partition that fills the whole device /dev/loop4

# parted /dev/loop4
GNU Parted 3.4
Using /dev/loop4
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
(parted) mkpart primary btrfs 4MiB 100%
(parted) print
Model: Loopback device (loopback)
Disk /dev/loop4: 10.7GB
Sector size (logical/physical): 4096B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name     Flags
 1      4194kB  10.7GB  10.7GB  btrfs        primary

(parted) quit
Information: You may need to update /etc/fstab.

Now the device is ready to be added to the filesystem.

# btrfs device add /dev/nvme0n4p1 /mnt/my-btrfs/
Performing full device TRIM /dev/nvme0n4p1 (10.00GiB) ...

Create an initial filesystem on a single device[edit | edit source]

# mkfs.btrfs /dev/loop0p1 -L my-btrfs
# mount /dev/loop0p1 /mnt/my-btrfs/

By default Btrfs creates a filesystem with single data and DUP metadata profiles on single device filesystem. We can see details about this newly created filesystem using btrfs filesystem usage <mountpoint>. Adding -T displays the output in table mode which can be easier to read when there are multiple devices in the filesystem.

# btrfs filesystem usage -T /mnt/my-btrfs/
Overall:
    Device size:                  10.00GiB
    Device allocated:            536.00MiB
    Device unallocated:            9.47GiB
    Device missing:                  0.00B
    Used:                        288.00KiB
    Free (estimated):              9.48GiB      (min: 4.74GiB)
    Free (statfs, df):             9.48GiB
    Data ratio:                       1.00
    Metadata ratio:                   2.00
    Global reserve:                3.25MiB      (used: 0.00B)
    Multiple profiles:                  no

                Data    Metadata  System
Id Path         single  DUP       DUP      Unallocated
-- ------------ ------- --------- -------- -----------
 1 /dev/loop0p1 8.00MiB 512.00MiB 16.00MiB     9.47GiB
-- ------------ ------- --------- -------- -----------
   Total        8.00MiB 256.00MiB  8.00MiB     9.47GiB
   Used           0.00B 128.00KiB 16.00KiB

We can see that there is only one device /dev/loop0 in this filesystem. We can also see that single data and DUP metadata profiles are used.

Let's add some data to the filesystem to see how it looks like.

# btrfs filesystem usage -T /mnt/my-btrfs/
Overall:
    Device size:                  10.00GiB
    Device allocated:              1.52GiB
    Device unallocated:            8.47GiB
    Device missing:                  0.00B
    Used:                        100.55MiB
    Free (estimated):              9.38GiB      (min: 5.15GiB)
    Free (statfs, df):             9.38GiB
    Data ratio:                       1.00
    Metadata ratio:                   2.00
    Global reserve:                3.25MiB      (used: 0.00B)
    Multiple profiles:                  no

                Data      Metadata  System
Id Path         single    DUP       DUP      Unallocated
-- ------------ --------- --------- -------- -----------
 1 /dev/loop0p1   1.01GiB 512.00MiB 16.00MiB     8.47GiB
-- ------------ --------- --------- -------- -----------
   Total          1.01GiB 256.00MiB  8.00MiB     8.47GiB
   Used         100.02MiB 256.00KiB 16.00KiB

Now we can see that a block group of 1GiB was created and of that, 100MiB of data is used.

Adding a second device to the filesystem[edit | edit source]

Adding a second device is done using btrfs device add <device> <mountpoint>

# btrfs device add /dev/loop1p1 /mnt/my-btrfs/
Performing full device TRIM /dev/loop1p1 (10.00GiB) ...
# btrfs filesystem usage /mnt/my-btrfs/
# btrfs filesystem usage -T /mnt/my-btrfs/
Overall:
    Device size:                  19.99GiB
    Device allocated:              1.52GiB
    Device unallocated:           18.47GiB
    Device missing:                  0.00B
    Used:                        100.55MiB
    Free (estimated):             19.38GiB      (min: 10.14GiB)
    Free (statfs, df):            19.37GiB
    Data ratio:                       1.00
    Metadata ratio:                   2.00
    Global reserve:                3.25MiB      (used: 0.00B)
    Multiple profiles:                  no

                Data      Metadata  System
Id Path         single    DUP       DUP      Unallocated
-- ------------ --------- --------- -------- -----------
 1 /dev/loop0p1   1.00GiB 512.00MiB 16.00MiB     8.48GiB
 2 /dev/loop1p1         -         -        -    10.00GiB
-- ------------ --------- --------- -------- -----------
   Total          1.00GiB 256.00MiB  8.00MiB    18.47GiB
   Used         100.02MiB 256.00KiB 16.00KiB

The second device is added but no data or metadata is used on it yet.

As more data is added to the filesystem, Btrfs will start allocating block groups on both devices. Btrfs allocation algorithm allocates new block groups on the device with most available unallocated space.

# btrfs filesystem usage -T /mnt/my-btrfs/
Overall:
    Device size:                  19.99GiB
    Device allocated:              2.52GiB
    Device unallocated:           17.47GiB
    Device missing:                  0.00B
    Used:                          1.08GiB
    Free (estimated):             18.40GiB      (min: 9.66GiB)
    Free (statfs, df):            18.40GiB
    Data ratio:                       1.00
    Metadata ratio:                   2.00
    Global reserve:                3.25MiB      (used: 0.00B)
    Multiple profiles:                  no

                Data    Metadata  System
Id Path         single  DUP       DUP      Unallocated
-- ------------ ------- --------- -------- -----------
 1 /dev/loop0p1 1.00GiB 512.00MiB 16.00MiB     8.48GiB
 2 /dev/loop1p1 1.00GiB         -        -     9.00GiB
-- ------------ ------- --------- -------- -----------
   Total        2.00GiB 256.00MiB  8.00MiB    17.47GiB
   Used         1.07GiB   1.58MiB 16.00KiB
NOTE: The metadata profile will remain as DUP after adding a device. It is important to convert the profile to RAID1 to take advantage of better resilience and healing ability of this mode. See Btrfs/Profiles for more information.

Converting DUP metadata profile to RAID1[edit | edit source]

When Btrfs is used on multiple devices, the recommended profile for metadata is RAID1. By default, Btrfs is using RAID1 metadata profile when using mkfs.btrfs on multiple devices, and DUP metadata profile on single devices.

As we can see from the example used earlier, the metadata profile remains as DUP after adding the second device. Btrfs supports conversion between profiles using the btrfs balance command.

# btrfs balance start -mconvert=raid1 /mnt/my-btrfs/
Done, had to relocate 2 out of 4 chunks
# btrfs filesystem usage -T /mnt/my-btrfs/
Overall:
    Device size:                  19.99GiB
    Device allocated:              2.56GiB
    Device unallocated:           17.43GiB
    Device missing:                  0.00B
    Used:                          1.08GiB
    Free (estimated):             18.35GiB      (min: 9.64GiB)
    Free (statfs, df):            18.35GiB
    Data ratio:                       1.00
    Metadata ratio:                   2.00
    Global reserve:                3.25MiB      (used: 0.00B)
    Multiple profiles:                  no

                Data    Metadata  System
Id Path         single  RAID1     RAID1    Unallocated
-- ------------ ------- --------- -------- -----------
 1 /dev/loop0p1 1.00GiB 256.00MiB 32.00MiB     8.71GiB
 2 /dev/loop1p1 1.00GiB 256.00MiB 32.00MiB     8.71GiB
-- ------------ ------- --------- -------- -----------
   Total        2.00GiB 256.00MiB 32.00MiB    17.43GiB
   Used         1.07GiB   1.58MiB 16.00KiB