X
Tech

Btrfs hands on: An extremely cool file system

Resizing, Adding Partitions, Adding Disk Drives, Snapshots - all while the btrfs filesystem is still mounted!
Written by J.A. Watson, Contributor

In my first post on this subject, Btrfs basics, I discussed how to create a simple btrfs filesystem, or a complete btrfs Linux system. 

The information and examples in that post are going to be important because I am going to use them as the basis for what follows.

One subject that I did not dicuss in the previous post was disk partitioning. Hopefully the basic concepts are familiar: a physical disk drive can be logically divided into partitions. 

Btrfs hands on: My first experiments with a new Linux file system

For Linux users, the most common use of this partitioning is to load multiple operating systems on a single disk drive (such as Windows and Linux), or perhaps to segregate files into different groups, such as operating system files, boot files, user data files and such. 

The important characteristic of partitioning for this discussion is that the disk controller and driver enforce the partition boundaries. More advanced users or system administrators might have dealt with unpartitioned disk drives, usually in the context of a RAID system where the entire disk (multiple disks, actually) are given to the RAID controller for management. As we will see below, btrfs filesystems introduce some interesting new twists on this concept.

So, let's jump right in with a partitioning example (issue). In the previous post I gave this example of creating a btrfs filesystem:

    mkfs.btrfs /dev/sda16

That command assumes that the partition /dev/sda16 already exists, but then I quickly skirted that issue by saying that you could do the same thing with gparted — the important difference is that gparted will create the partition for you, and then create the btrfs filesystem within that partition. 

Either way, the result of the above command is a btrfs filesystem which fills the specified partition. In the case of my example, I had created a 16GB partition, so I then got a 16GB btrfs filesystem. Nice and easy. I can check that with the btrfs utility program:

    btrfs filesystem show /dev/sda16

        Label: 'btest'  uuid: a8a0ea98-5746-4d34-92b7-cfd447af9ddf

        Total devices 1 FS bytes used 28.00KiB

        devid    1 size 16.00GiB used 2.04GiB path /dev/sda16

Now, one of the really interesting things about btrfs filesystems is that you can resize them "on the fly" — while they are still mounted. 

That is just wonderful — how many times over the years have I had a filesystem fill up, and I had to create a whole new filesystem and then copy everything over — or worse yet, copy everything from the full filesystem to tape, then delete that filesystem and recreate it larger, then copy it all back again. Ugh. So the ability to do this without disturbing a running system makes me smile. A lot. 

The command for this is btrfs filesystem resize size <fs>. The size value may be given in absolute terms, with all sorts of human-friendly abbreviations (K or kilobytes, M or megabytes, G or gigabytes), and <fs> is where the filesystem is mounted. In use, to expand our filesystem to 20 Gigabytes, if I have it mounted on /mnt, it would be:

    btrfs filesystem resize 20G /mnt

        Resize '/mnt' of '20G'

        ERROR: unable to resize '/mnt' — File too large

Whoops. "File too large" — you didn't think I included that whole discussion above about partitioning for nothing, did you?  The partition that I created (well, gparted created) is 16GB, so I can't tell btrfs to make the filesystem any larger than that — in logical terms, my "disk" is full.  I could take the easy way out here, and go back to gparted to increase the size, of course. But that is not the point right now. So rather than increase the filesystem size, we will start by decreasing it:

    btrfs filesystem resize -4G /mnt

        Resize '/mnt' of '-4G

This shows a different notation, instead of giving the absolute size I have told it to reduce the size by 4GB.  That looks like more promising results, and we can check that it really worked: (note: the actual resizing of the filesystem will take a little bit of time, exactly how long depends on how fast or slow your system is, so don't be surprised if the result doesn't show up instantly)

     btrfs filesystem show /dev/sda16

        Label: 'btest'  uuid: a8a0ea98-5746-4d34-92b7-cfd447af9ddf

        Total devices 1 FS bytes used 284.00KiB

        devid    1 size 12.00GiB used 2.04GiB path /dev/sda16

Well, that is just extremely cool!  Other than being a generally useless example, since shrinking a filesystem is not something you want/need to do very often, but wow, it did it, while the filesystem was mounted!

Now that we have (artificially) created some free space within the partition, we can look at the other, more useful example — increasing the size of a filesystem. Again, the size can be given either as an increment (with "+" before the number), or as an absolute size:

    btrfs filesystem resize 14G /mnt

        Resize '/mnt' of '14G'

Finally, before this bit gets too boring, there is one more key word that can be used, to expand the filesystem to fill whatever its boundaries are:

    btrfs filesystem resize max /mnt

        Resize '/mnt' of 'max'

    btrfs filesystem show /dev/sda16

        Label: 'btest'  uuid: a8a0ea98-5746-4d34-92b7-cfd447af9ddf

        Total devices 1 FS bytes used 284.00KiB

        devid    1 size 16.00GiB used 2.04GiB path /dev/sda16

Hooray!  If had been able to do this many years ago, it would have saved me a lot of long nights and weekends moving files around and changing filesystems.

Oh, and there is one other way to keep this from getting boring... some of the documentation I read mentioned that if you needed to expand a filesystem in a partition that was already full, one option was to use fdisk to delete the partition and the create a new larger one — and be sure to use the same starting cylinder.

Well, let me tell you, if you are brave enough to delete and recreate a partition around a live filesystem, then ZOWIE, my hat is off to you!  Personally, I'll stick with gparted and its equivalents for that, thank you...

Ok, so now I can change filesystem sizes, within the bounds of the partition or disk drive that contains it.  Hmm... but that last bit can turn out to be a problem, because what if there is no more space available on the disk drive, or no adjacent space to expand the partition?  This is where the btrfs ability to span filesystems or even span devices is invaluable. (Note: at this point I am still only discussing simple files systems, I am not yet going to address RAID capabilities.)

For purposes of this illustration, I have created a new unformatted partition (/dev/sda17).  In the real world, this new partition is most likely to be on a different disk drive, but the key here is that as far as btrfs is conderned, it doesn't care where it is, it's just another partition. 

To add the new partition to the existing btrfs filesystem, I just use the btrfs command again.  To do this, the original btrfs filesystem has to be mounted, and you have to give the device name of the partition to be added, followed by the mount point of the original filesystem, like this:

    btrfs device add /dev/sda17 /mnt

This command produces no output — old Unix/Linux hands will be comfortable with the "no news is good news" philosophy, but if you want to be sure that it worked, you can check it again:

    btrfs filesystem show /dev/sda16

        Label: 'btest'  uuid: a8a0ea98-5746-4d34-92b7-cfd447af9ddf

        Total devices 2 FS bytes used 284.00KiB

        devid    2 size 16.00GiB used 0.00 path /dev/sda17

        devid    1 size 16.00GiB used 2.04GiB path /dev/sda16

Hey, cool, there it is, it worked!  Two devices listed, each with 16GB capacity.  Another way to check this would be to look at the total size of the mounted filesystem — remember, we originally created it as one 16GB partition:

    df -h /mnt

        Filesystem      Size  Used Avail Use% Mounted on

        /dev/sda16       32G  312K   30G   1% /mnt

Yes indeed, it is now 32GB! Very nice. Within that filesystem mounted on /mnt there is no distinction between the two devices, and we can use it completely normally.  The operating system will use the space from both parts as necessasry. We can check the distribution of data between the two parts with the btrfs command above. One other interesting note here, if I had done this because the existing filesystem was full, then after adding the new device I could redistribute the data evenly across the two partitions like this:

    btrfs filesystem balance /mnt

This is a one-time action command, it balances the current content across all of the devices within the filesystem; once it is done, distribution of subsequent data will be done normally again, not necessarily maintaining the balanced state.

Ok, I would like to cover just a couple more housekeeping commands before wrapping up.  First, if you are dealing with relatively large files and you want to cleanup whatever fragmentation of the file might have crept in over time, you can use the command:

    btrfs filesystem defragment <filename>

Oh my. Just think about that, defragmenting a single, specific file. To be honest, whenever someone starts talking about defragmenting, I immediately think about the old Dilbert comic strip, where Dogbert is working in Customer Support, and he says to someone on the phone: "Well, I could give you some false hope and tell you to try defragmenting your disk". 

But in this case, when I can specify a particular file which I know is large and would benefit, this could be very good indeed.  There are a number of options to this command, so you can specify file and fragment sizes, but the best one is — are you ready for this — you can also tell btrfs to turn on compression of the file contents as it defragments it! 

So, I have a large file, which has become scattered on the disk over time, and now I have a command which will gather the pieces and make them contiguous again, and at the same time it will compress the contents so that I can recover disk space at the same time?  I think I must have died and gone to heaven...

I haven't mentioned it until now, but another very important characteristic of btrfs is that it keeps checksums on data (and metadata, such as the directory structures).  These can help in identifying and possibly recovering corrupted data. Those of us who remember "alternate super blocks" in Unix filesystems might turn a bit green when we first learn about this. 

The btrfs utility includes a feature to use these checksums to verify data integrity, either of an entire filesystem or of individual devices or partitions within the filesystem:

    btrfs scrub start <path|device>

In its simplest form, this starts a scrub on the specified mount point or device, and the scrub will run in the background so that it doesn't tie up your terminal for what could be a rather long time.  What it actually does is read all of the data, and compare the cheksums to validate it.  If it finds an error it will attempt to fix it. In this simplest case, when it is run in the background, you will have to use the status command to get the results:

    btrfs scrub status <path|device>

If the scrub is still running, this will tell you what is happening; if it has finished it will give you the results.  Hmmm. Maybe this sounds a bit confusing, so a real example might help. On my completely trivial btrfs filesystem, it looks like this:

    # btrfs scrub start /mnt

    scrub started on /mnt, fsid a8a0ea98-5746-4d34-92b7-cfd447af9ddf (pid=3414)

 Some time later:

    # btrfs scrub status /mnt

    scrub status for a8a0ea98-5746-4d34-92b7-cfd447af9ddf

        scrub started at Fri Nov 29 09:58:44 2013 and finished after 1 seconds

        total bytes scrubbed: 312.00KiB with 0 errors

There are options for this command to set the priority it runs at, keep it from going into the background, make it more or less verbose, and even disable repair and simply report errors. So nice.

Ok, enough is enough.  This has been a lot of information, and my fingers are tired.  For the next post I will drag out an old deskside server which has two disk drives, and things will get even more interesting, with RAID, subvolumes and snapshots.  I hope it is becoming clear why btrfs is such an interesting and important development in Linux.

Further reading

Editorial standards