How to Take Backup with Btrfs Snapshots

Take Backup with Btrfs Snapshots

BTRFS is an open-source and modern filesystem implemented with advanced features. It works on copy on write (CoW) mechanism.

It is included in the mainline Linux kernel. Notable features of Btrfs are copy-on-write data and metadata, snapshots, Built-in RAID support, online resizing and defragmentation, transparent compression, efficient storage for small files, etc.

Snapshot is a given time copy of Btrfs subvolume. Snapshots are writeable by default. Btrfs allows creating readable snapshots which is helpful to take backup.

In this tutorial, we learn how to create Btrfs snapshots, Incremental backups, and restore it.

System information

I am using Fedora and now Fedora 33 has Btrfs by default. My system has 20GB boot disk and 10GB additional disk with Btrfs filesystem on it.

Here sda is boot disk while sdb is the additional disk we will use for btrfs snapshot.

Listing the disk information:

$ ls -l /dev | grep sd
brw-rw----. 1 root disk      8,     0 Nov 21 08:42 sda
brw-rw----. 1 root disk      8,     1 Nov 21 08:42 sda1
brw-rw----. 1 root disk      8,     2 Nov 21 08:42 sda2
brw-rw----. 1 root disk      8,    16 Nov 21 08:57 sdb
brw-rw----. 1 root disk      8,    17 Nov 21 08:57 sdb1

To explain I have created LVM and mounted it at /mnt/linoxide_btrfs1 with btrfs filesystem.

Listing PV, VG, and LV created:

$ pvs && vgs && lvs
PV         VG          Fmt  Attr PSize   PFree 
/dev/sdb1  linoxide_vg lvm2 a--  <10.00g <5.00g
VG          #PV #LV #SN Attr   VSize   VFree 
linoxide_vg   1   1   0 wz--n- <10.00g <5.00g
LV           VG          Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
linoxide_lv1 linoxide_vg -wi-a----- 5.00g

The output of mount information:

$ df -h
Filesystem                            Size  Used Avail Use% Mounted on
devtmpfs                              286M     0  286M   0% /dev
tmpfs                                 294M     0  294M   0% /dev/shm
tmpfs                                 294M  4.5M  289M   2% /run
tmpfs                                 294M     0  294M   0% /sys/fs/cgroup
/dev/sda2                              20G  2.3G   18G  12% /
/dev/sda1                             200M   12M  189M   6% /boot/efi
tmpfs                                  59M     0   59M   0% /run/user/1000
tmpfs                                  59M     0   59M   0% /run/user/0
/dev/mapper/linoxide_vg-linoxide_lv1  5.0G   17M  4.5G   1% /mnt/linoxide_btrfs1

Btrfs Snapshot

In order to create btrfs snapshot, first create a subvolume.

Step 1. Create subvolume

To create a subvolume named '/mnt/linoxide_btrfs1/subvol1', run:

$ sudo btrfs subvolume create /mnt/linoxide_btrfs1/subvol1

Step 2. Copy files to subvolume

Let's copy some data files to subvolume. The following command copy some files from /etc/ to subvol1.

$ cd /mnt/linoxide_btrfs1/subvol1
$ cp /etc/[abc]* .
$ ls -l
-rw-r--r--. 1 root root    16 Nov 21 09:25 adjtime
-rw-r--r--. 1 root root  1529 Nov 21 09:25 aliases
-rw-r--r--. 1 root root 12288 Nov 21 09:25 aliases.db
-rw-------. 1 root root   541 Nov 21 09:25 anacrontab
-rw-r--r--. 1 root root    55 Nov 21 09:25 asound.conf
-rw-r--r--. 1 root root  2853 Nov 21 09:25 bashrc
-rw-r--r--. 1 root root   112 Nov 21 09:25 boto.cfg
-rw-r--r--. 1 root root    37 Nov 21 09:25 centos-release
-rw-r--r--. 1 root root    51 Nov 21 09:25 centos-release-upstream
-rw-r--r--. 1 root root  1053 Nov 21 09:25 chrony.conf

Step 3. Create snapshot

Let's create a snapshot of the subvolume1 (/mnt/linoxide_btrfs1/subvol1).

Note the -r flag for readonly. Make sure to create snapshot as read-only if like use send/receive commands (explained in the next section).

To create a readonly snapshot of '/mnt/linoxide_btrfs1/subvol1' in '/mnt/linoxide_btrfs1/.snapshots/subvol1-day1', run:

$ sudo btrfs subvolume snapshot -r /mnt/linoxide_btrfs1/subvol1 /mnt/linoxide_btrfs1/.snapshots/subvol1-day1

Check the contents of snapshot:

$ cd .snapshots/
$ ls -l
drwxr-xr-x. 1 root root 446 Nov 21 09:25 subvol1-day1
$ cd subvol1-day1/
$ ls -l
-rw-r--r--. 1 root root    16 Nov 21 09:25 adjtime
-rw-r--r--. 1 root root  1529 Nov 21 09:25 aliases
-rw-r--r--. 1 root root 12288 Nov 21 09:25 aliases.db
-rw-------. 1 root root   541 Nov 21 09:25 anacrontab
-rw-r--r--. 1 root root    55 Nov 21 09:25 asound.conf
-rw-r--r--. 1 root root  2853 Nov 21 09:25 bashrc
-rw-r--r--. 1 root root   112 Nov 21 09:25 boto.cfg
-rw-r--r--. 1 root root    37 Nov 21 09:25 centos-release
-rw-r--r--. 1 root root    51 Nov 21 09:25 centos-release-upstream
-rw-r--r--. 1 root root  1053 Nov 21 09:25 chrony.conf

Btrfs Snapshot using send

We have taken a snapshot on the same disk as subvolume which is not good for backup strategy, In case of a disaster like disk corruption, will lose the recovery optionl.

BTRFS has a solution for that. We can send snapshots to a remote system or external hard drive using the command btrfs send and btrfs receive. They are based on SSH. The remote system should be formatted as BTRFS as well.

Let me explain with example.

Create a new disk with btrfs files system mounted at /mnt/linoxide_btrfs2.

$ df -h
Filesystem                             Size  Used Avail Use% Mounted on
devtmpfs                               286M     0  286M   0% /dev
tmpfs                                  294M     0  294M   0% /dev/shm
tmpfs                                  294M  4.5M  289M   2% /run
tmpfs                                  294M     0  294M   0% /sys/fs/cgroup
/dev/sda2                               20G  2.3G   18G  12% /
/dev/sda1                              200M   12M  189M   6% /boot/efi
tmpfs                                   59M     0   59M   0% /run/user/1000
tmpfs                                   59M     0   59M   0% /run/user/0
/dev/mapper/linoxide_vg-linoxide_lv1   5.0G   17M  4.5G   1% /mnt/linoxide_btrfs1
/dev/mapper/linoxide_vg2-linoxide_lv2  5.0G   17M  4.5G   1% /mnt/linoxide_btrfs2

In this example, the destination Btrfs volume is the second btrfs disk mounted as /mnt/linoxide_btrfs2 .

The following command to send snapshot to remote destination:

$ sudo sudo btrfs send /mnt/linoxide_btrfs1/.snapshots/subvol1-day1 | sudo btrfs receive /mnt/linoxide_btrfs2
At subvol /mnt/linoxide_btrfs1/.snapshots/subvol1-day1
At subvol subvol1-day1

Verify the data files:

$ cd /mnt/linoxide_btrfs2/
$ ls -l
drwxr-xr-x. 1 root root 446 Nov 21 09:25 subvol1-day1
$ cd subvol1-day1/
$ ls -l
-rw-r--r--. 1 root root    16 Nov 21 09:25 adjtime
-rw-r--r--. 1 root root  1529 Nov 21 09:25 aliases
-rw-r--r--. 1 root root 12288 Nov 21 09:25 aliases.db
-rw-------. 1 root root   541 Nov 21 09:25 anacrontab
-rw-r--r--. 1 root root    55 Nov 21 09:25 asound.conf
-rw-r--r--. 1 root root  2853 Nov 21 09:25 bashrc
-rw-r--r--. 1 root root   112 Nov 21 09:25 boto.cfg
-rw-r--r--. 1 root root    37 Nov 21 09:25 centos-release
-rw-r--r--. 1 root root    51 Nov 21 09:25 centos-release-upstream
-rw-r--r--. 1 root root  1053 Nov 21 09:25 chrony.conf

Now, You have a full backup which can be used as DR as well.

Incremental backup

Snapshot can also send backups in an incremental way. When some directory is renamed, Rsync deletes the directory and transfers all data again, while BTRFs just transfer some bytes of metadata.

Let's take another snapshot.

$ sudo btrfs subvolume snapshot -r /mnt/linoxide_btrfs1/subvol1 /mnt/linoxide_btrfs1/.snapshots/subvol1-day2

Using -p flag you need to specify base snapshot and this snapshot has to exist in the source and destination. The following command will send the difference between two base snapshots to the destination.

$ sudo btrfs send -p /mnt/linoxide_btrfs1/.snapshots/subvol1-day1 /mnt/linoxide_btrfs1/.snapshots/subvol1-day2 | sudo btrfs receive /mnt/linoxide_btrfs2

How to restore Btrfs snapshot

In this section, I will explain how to restore data from snapshot taken earlier. Let’s take scenario where file is deleted by mistake. You can get it back last snapshot, or even recover an older version of the file from an older snapshots.

You can simply use the cp command to restore the deleted file:

$ sudo cp /mnt/linoxide_btrfs1/.snapshots/subvol1-day1/chrony.conf  /mnt/linoxide_btrfs1/subvol1

Let's assume that you deleted the entire subvolume, Even in that case, with the use of cp command, You can restore the entire content from the snapshot:

$ sudo cp -r /mnt/linoxide_btrfs1/.snapshots/subvol1-day1 /mnt/linoxide_btrfs1/subvol1

Or you can restore the subvolume by using the btrfs snapshot command:

$ sudo btrfs subvolume snapshot /mnt/linoxide_btrfs1/.snapshots/subvol1-day1 /mnt/linoxide_btrfs1/subvol1

Snapshot cleanup

When you are taking periodic incremental backup with btrfs snapshot, you can have lots of them piling up. This can create confusion and occupy a lots of space on disk. You can also purge old unwanted snapshot using snapshot delete. While purging keep in mind that in order to perform an incremental send, you need the last snapshot.

$ sudo btrfs subvolume delete /mnt/linoxide_btrfs1/.snapshots/subvol1-day1

Conclusion

Btrfs has matured at a fast pace. Today, it has a wide range of capabilities like compression, snapshots, data integrity and performance that make it to an production ready file system. I hope this article will be helpful in using snapshots of BTRFS. Let me know your views in comment section.

Leave a Comment