Growing BTRFS in a Logical Volume

As you may know, I run quite a few nspawn containers which are responsible for running my entire home network, entertainment system, home automation, and a few other applications here & there. What you may not be aware of is the fact that I'm running everything on top of BTRFS and systemd-nspawn. Systemd-nspawn expects a volume mounted at /var/lib/machines using BTRFS. While you can run nspawn without BTRFS, doing so would mean missing out on features pre-packaged into systemd-nspawn. While BTRFS, nspawn, and systemd can do amazing things, the server and services still require periodic maintenance and today was one such day.

Overview

I received an alert today that one of my container hosts was filling up; it alerted notifying me that I was under a certain threshold of available storage. After logging into the node and ensuring everything was on the up-and-up I decided to grow the BTRFS partition by ~50GiB giving the server more room to breathe while also fulfilling some nerdy curiosity.

Here's what BTRFS was reporting when I logged into the box.

# btrfs filesystem df -h /var/lib/machines/
Data, single: total=50.00GiB, used=38.52GiB  
System, single: total=4.00MiB, used=16.00KiB  
Metadata, single: total=776.00MiB, used=355.91MiB  
GlobalReserve, single: total=128.00MiB, used=0.00B

# btrfs filesystem show  /var/lib/machines/
Label: none  uuid: ffa12758-857f-4416-957d-4cfd71f2e42a  
        Total devices 1 FS bytes used 38.87GiB
        devid    1 size 50.00GiB used 39.78GiB path /dev/mapper/vg--machines

The container file system /var/lib/machines was by no means full but it was getting close and I didn't want it full. So I decided to extend the logical volume housing my BTRFS partition and grow the underlying file system.

BTRFS in a Logical Volume

As mentioned before, I use logical volumes, like millions of other folks running linux servers, and while some may question the value of LVM and BTRFS, there's no right answer and I find myself in the camp of folks still believing in the power and flexibility of LVM, that is until qgroups are fully flushed out and I have some time to build a bit more trust with them.

A quick overview of the volume I'll be extending.
# lvs
  LV       VG                 Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  machines vg -wi-ao---- 50.00g
[...]

To extend my volume, as a traditional Linux system administrator, I would simply run lvresize -r -L+50G /dev/vg/machines, drink a beer, and be done, however, being BTRFS is in use things are a little different. If you happen to run this command on a logical volume that is also formatted BTRFS the lvresize command will fail when it detects the BTRFS volume (I did this).

fsadm: Filesystem "btrfs" on device "/dev/mapper/vg--machines" is not supported by this tool  
  fsadm failed: 1

While the resize command failed, the logical volume detail shows the command partially worked by adding the extents to the volume. This means I need to use the btrfs command to extend the volume instead of just assuming lvresize will do it for me.

# lvdisplay /dev/vg/machines
  --- Logical volume ---
  LV Path                /dev/vg/machines
  LV Name                machines
  VG Name                vg
  LV UUID                ucVj74-t7TN-HV8H-pokI-BYkW-grBY-4ryTn7
  LV Write Access        read/write
  LV Creation host, time carterhouse, 2017-04-23 11:30:31 -0500
  LV Status              available
  # open                 1
  LV Size                100.00 GiB
  Current LE             25600
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           252:2

In the future, when I need to do this elsewhere, the correct command for extending the volume is to run lvresize as I did before but to omit the -r flag.

BTRFS, a balancing & extension act

The lvresize command grew the logical volume but it didn't resize the underlying file system. This means the BTRFS partition is still only 50GiB even though the surface area of the partition is now larger.

This next step is Not Required but will make sure BTRFS is fully aware of where everything is supposed to exist. To ensure BTRFS is happy, I'm going to balance the file system which will redistribute data and metadata across all available devices, in my case this a logical volume. Normally, this would be used when adding a device to an existing BTRFS volume group or any time we want to ensure there's an equal spread of blocks across the disks but in this instance I'm running the balance command for piece of mind.

Using the btrfs command, balance the file system. While this will work online, the command may take a while, and tax the CPU, be patient.

btrfs balance start -v /var/lib/machines  

Once the balancing act has completed, which can take some time, the command will output what was done.

Dumping filters: flags 0x7, state 0x0, force is off  
  DATA (flags 0x0): balancing
  METADATA (flags 0x0): balancing
  SYSTEM (flags 0x0): balancing
Done, had to relocate 12 out of 12 chunks  

Assuming everything is happy and healthy, resize the partition to the max allowed.

btrfs filesystem resize max /var/lib/machines  

Verify that the BTRFS volume is as big as it's supposed to be

# btrfs filesystem show  /var/lib/machines/
Label: none  uuid: ffa12758-857f-4416-957d-4cfd71f2e42a  
        Total devices 1 FS bytes used 38.86GiB
        devid    1 size 100.00GiB used 39.78GiB path /dev/mapper/vg--machines

Finally, check the consumption size

# btrfs filesystem df -h /var/lib/machines/
Data, single: total=100.00GiB, used=38.52GiB  
System, single: total=4.00MiB, used=16.00KiB  
Metadata, single: total=776.00MiB, used=355.91MiB  
GlobalReserve, single: total=128.00MiB, used=0.00B  

Log out and time to go get that beer.

That's all folks

With those couple of commands, my logical volume was extended, my file system was balanced, curated, and I've grown the home for my containers. All of which was done while running local workloads without any service interruptions. That was easy!