3 Managing the Btrfs File System

The Btrfs file system is designed to meet the expanding scalability requirements of large storage subsystems. Because the Btrfs file system uses B-trees in its implementation, its name is derived from the name of those data structures, although it is not a true acronym. A B-tree is a tree-like data structure that enables file systems and databases to efficiently access and update large blocks of data, irrespective of how large the tree grows.

The Btrfs file system provides the following important features:

  • Copy-on-write functionality, which enables you to create both readable and writable snapshots and roll back a file system to a previous state, even after converting it from an ext3 or ext4 file system.

  • Checksum functionality, which ensures data integrity.

  • Snapshots send and receive for remote incremental backups.

  • Transparent compression, which saves disk space.

  • Transparent defragmentation for improved performance.

  • Integrated, logical volume management, which enables you to implement RAID 0, RAID 1, RAID 10, RAID1C3 or RAID1C4 configurations, and dynamically add or remove storage capacity.

For more information, visit https://btrfs.wiki.kernel.org/.

For an overview of local file system management, see About File System Management.

Note:

In Oracle Linux 8, the Btrfs file system type, as well as all of the features that are documented in this chapter is supported on the Unbreakable Enterprise Kernel (UEK) release only. Working with Btrfs file system features requires that you boot the system by using UEK R6 or later.

Setting Up and Administering a Btrfs File System

This section describes procedures to create a Btrfs file system as well as administering it for a more efficient use.

Creating a Btrfs File System

Note:

Note that the /sbin/mkfs.* tool is not provided by the same package as the kernel modules that are required by the btrfs command. Use the modinfo btrfs command to check whether the btrfs module is available in the kernel that is booted. Also, if the btrfs-progs package is not installed on your system, you will need to install it.

You can use the mkfs.btrfs command to create a Btrfs file system that is laid out across one or more block devices. The default configuration is to mirror the filesystem metadata across the devices. If you specify a single device, the metadata is duplicated on that device, unless you specify to use only one copy of the metadata. The devices can be whole block device(s), simple disk partitions, files, loopback devices (that is, disk images in memory), multipath devices, or LUNs that implement RAID in hardware.

See the mkfs.btrfs(8) manual page for more detailed information about the mkfs.btrfs command the various Btrfs configurations that you can create.

When you want to mount the file system, you can specify it by any of its component devices, for example:

sudo mkfs.btrfs -d raid10 -m raid10 /dev/sd[fghijk]
sudo mount /dev/sdf mountpoint

The mkfs.btrfs command automatically scans the new Btrfs devices into the kernel. To scan and assemble all of the relevant devices of the volume in the kernel you need to run the btrfs device scan command. You can undo this action by using the btrfs device scan --forget command. To assemble all of the relevant devices of the volume, you might need to run the btrfs device scan command.

You can obtain the RAID configuration for a mounted btrfs file system as follows:

sudo btrfs filesystem df mountpoint

Note that the btrfs filesystem df command displays more accurate information about the space that is used by a Btrfs file system than by using the df command.

You can also use the btrfs filesystem usage command to display information about all of the btrfs file systems that are on a system, for example:

sudo btrfs filesystem usage /btrfs
Overall:
    Device size: 1.95TiB
    Device allocated: 5.03GiB
    Device unallocated: 1.95TiB
    Device missing: 0.00B
    Used: 256.00KiB
    Free (estimated): 999.48GiB (min: 999.48GiB)
    Data ratio: 2.00
    Metadata ratio: 2.00
    Global reserve: 3.25MiB (used: 0.00B)

Data,RAID10: Size:2.00GiB, Used:0.00B (0.00%)
   /dev/nvme0n1p6 1.00GiB
   /dev/nvme0n1p7 1.00GiB
   /dev/nvme0n1p8 1.00GiB
   /dev/nvme0n1p9 1.00GiB

Metadata,RAID10: Size:512.00MiB, Used:112.00KiB (0.02%)
   /dev/nvme0n1p6 256.00MiB
   /dev/nvme0n1p7 256.00MiB
   /dev/nvme0n1p8 256.00MiB
   /dev/nvme0n1p9 256.00MiB

System,RAID10: Size:16.00MiB, Used:16.00KiB (0.10%)
   /dev/nvme0n1p6 8.00MiB
   /dev/nvme0n1p7 8.00MiB
   /dev/nvme0n1p8 8.00MiB
   /dev/nvme0n1p9 8.00MiB

Unallocated:
   /dev/nvme0n1p6 498.74GiB
   /dev/nvme0n1p7 498.74GiB
   /dev/nvme0n1p8 498.74GiB
   /dev/nvme0n1p9 498.74GiB

Modifying a Btrfs File System

You can use the btrfs command to add or remove devices and rebalance the layout of the file system data and metadata across devices. The following table describes each of the commands that can use to perform these tasks.

Command Description

btrfs device add device mountpoint

Add a device to the file system that is mounted on the specified mount point, for example:

btrfs device add /dev/sdd /myfs

btrfs device delete device mountpoint

Remove a device from a mounted file system, for example:

btrfs device delete /dev/sde /myfs

btrfs device delete missing mountpoint

Remove a failed device from the file system that is mounted in degraded mode, for example:

btrfs device remove missing /myfs

To mount a file system in degraded mode, specify the -o degraded option to the mount command.

For a RAID configuration, if the number of devices would fall below the minimum number that are required, you must add the replacement device before removing the failed device.

btrfs filesystem balance mountpoint

After adding or removing devices, redistribute the file system data and metadata across the available devices.

Compressing and Defragmenting a Btrfs File System

You can compress a Btrfs file system to increase its effective capacity, as well as defragment it to increase I/O performance.

The following three compression types are supported:

  • zlib

  • lzo

  • zstd

There are three ways in which you can enable compression:

  • By using the subvolume property, for example:

    sudo btrfs subvolume create /btrfs/sv1 
    sudo btrfs property set /btrfs/sv1 compression zstd
  • By using the mount option in one of the following ways:

    Use the lzo type to compress the file data on the whole file system:

    sudo mount -o compress=lzo /dev/sdb /btrfs

    Use the zstd type to compress a subvolume and then mount it at the /btrfs1 mount point:

    sudo mount -o compress=zstd,subvolume=sv1 /devsdb /btrfs1 
  • By using defragment, for example:

    sudo btrfs filesystem defragment -czlib /btrfs1/akzo

You can enable compression at any point and only the new writes are compressed or defragmentation is run.

You can compress a Btrfs file system at the same time that you defragment it.

To defragment a Btrfs file system, use the following command:

sudo btrfs filesystem defragment filesystem_name

To defragment a Btrfs file system and compress it at the same time, use the following command:

sudo btrfs filesystem defragment -c filesystem_name

You can use the following command to defragment and optionally compress individual file system objects such as directories and files within a Btrfs file system:

sudo btrfs filesystem defragment [-c] file_name ...  

To set up automatic defragmentation, specify the autodefrag option when you mount the file system. However, note that automatic defragmentation is not recommended for large databases or for images of virtual machines.

Note:

Defragmenting a file or a subvolume with a copy-on-write copy breaks the link between the file and its copy. For example, if you defragment a subvolume that has a snapshot, the disk usage by the subvolume and its snapshot will increase because the snapshot is no longer a copy-on-write image of the subvolume.

Resizing a Btrfs File System

You can use the btrfs command to increase the size of a mounted Btrfs file system as long as there is space on the underlying devices to accommodate the change. You also use the btrfs command to decrease its size, if the file system has sufficient available free space. Note that running the command does not have any effect on the layout or size of the underlying devices.

You would increase the size of /mybtrfs1 by 2 GB as follows:

sudo btrfs filesystem resize +2g /mybtrfs1

The following example shows how to set the size of /mybtrfs3 to 20 GB:

sudo btrfs filesystem resize 20g /mybtrfs3

The following command decreases the size of /mybtrfs2 by 4 GB:

sudo btrfs filesystem resize -4g /mybtrfs2

Creating Subvolumes and Snapshots

The top level of a Btrfs file system is a subvolume consisting of a named b-tree structure containing directories, files, and possibly further btrfs subvolumes that are also named b-trees, each of which also contains directories and files, and so on.

To create a subvolume, change directories to the position in the btrfs file system for which you want to create the subvolume, then run the following command:

sudo btrfs subvolume create subvolume_name

Snapshots are a type of subvolume that record the contents of their parent subvolumes at the time that you took the snapshot. If you take a snapshot of a btrfs file system and do not write to it, the snapshot records the state of the original file system and forms a stable image from which you can make a backup. If you make a snapshot writable, you can treat it as a alternate version of the original file system. The copy-on-write functionality of a btrfs file system means that snapshots are created quickly and consume very little disk space initially.

Note:

Taking snapshots of a subvolume is not a recursive process. If you create a snapshot of a subvolume, every subvolume or snapshot that the subvolume contains is mapped to an empty directory of the same name inside that snapshot.

The following table describes commands to use to perform some common snapshot operations.

Command Description

btrfs subvolume snapshot pathname pathname / snapshot_path

Create a snapshot snapshot_path of a parent subvolume or snapshot specified by pathname, for example:

btrfs subvolume snapshot /mybtrfs /mybtrfs/snapshot1

btrfs subvolume list pathname

List the subvolumes or snapshots of a subvolume or snapshot that is specified by pathname, for example:

btrfs subvolume list /mybtrfs

Note:

You can use this command to determine the ID of a subvolume or snapshot.

btrfs subvolume set-default ID pathname

By default, mount the snapshot or subvolume that is specified by its ID instead of the parent subvolume, for example:

btrfs subvolume set-default 4 /mybtrfs

btrfs subvolume get-default pathname

Displays the ID of the default subvolume that is mounted for the specified subvolume, for example:

btrfs subvolume get-default /mybtrfs

You can mount a Btrfs subvolume as though it were a disk device. If you mount a snapshot instead of its parent subvolume, you effectively roll back the state of the file system to when the snapshot was taken. By default, the operating system mounts the parent Btrfs volume, which has an ID of 0, unless you use the set-default option to change the default subvolume. If you set a new default subvolume, the system mounts that subvolume going forward. You can override the default setting by specifying any of the mount options that are described in the following table.

Mount Option Description

subvolid= snapshot-ID

Mount the subvolume or snapshot that is specified by its subvolume ID instead of the default subvolume.

subvol= pathname / snapshot_path

Mount the subvolume or snapshot that is specified by its pathname instead of the default subvolume.

Note:

The subvolume or snapshot must be located in the root of the Btrfs file system.

After you have rolled back a file system by mounting a snapshot, you can take snapshots of the snapshot to record its state.

When you no longer require a subvolume or snapshot, you can delete it as follows:

sudo btrfs subvolume delete subvolume_path

Deleting a subvolume deletes all of the subvolumes under it in the b-tree hierarchy. For this reason, you cannot remove the topmost subvolume of a btrfs file system, which has an ID of 0.

For information about using the snapper command to create and manage Btrfs snapshots, see Automating File System Snapshots With the Snapper Utility.

Attention:

Snapshots record the state of the file system at a moment in time. As such, it is not possible to guarantee file system integrity for transactional processes that may have been in operation at the time when a snapshot was taken. While utilities like the snapper command may help to capture before and after snapshots for particular operations, such as when using the dnf command, these snapshots are still unaware of other processes that may be running on the system at the same time. If you have processes that may have intensive I/O or memory usage, such as database or middleware applications, you should stop these or ensure that all activity is complete before taking a snapshot to help to reduce the likelihood of data integrity or file system corruption issues within the snapshot.

Creating Swap Files on a Btrfs File System

Swap space is used in Oracle Linux when the amount of physical memory (RAM) is full. If the system needs more memory resources, and the RAM is full, inactive pages in memory are moved to the swap space. Although swap space is helpful for systems with a small amount of RAM, don't use swap space as a replacement for more RAM. You can allocate swap space to a dedicated swap partition, which is the recommended method. Or, you can use a swap file; or, you can combine the use of swap partitions and swap files.

Swap files in Btrfs are supported with the following limitations:

  • A swap file can't be on a snapshotted subvolume. Instead, we recommend that you create a subvolume on which to place the swap file.

  • Btrfs doesn't support swap files on file systems that span several devices.

The following are step-by-step instructions for creating a swap file in Btrfs. Before creating the new swap file, calculate the size of the swap file in MB. Then, multiply that number by 1024 to find the number of blocks the file requires. For example, the block size of a 64 MB swap file is 65536.

  1. Create an empty file, for example:

    sudo dd if=/dev/zero of=/swapfile bs=1024 count=65536
  2. Set up the swap file by running the following command:

    sudo mkswap /swapfile
  3. Change the permissions on the file so that it's not world readable:

    sudo chmod 0600 /swapfile
  4. Enable the swap file at boot time by editing the /etc/fstab file as the root user to include the following entry:
    /swapfile swap swap defaults 0 0
  5. Regenerate the mount units and register the new configuration in the /etc/fstab file:

    sudo systemctl daemon-reload
  6. Activate the new swap file:

    sudo swapon /swapfile

    Running the previous command activates the new swap file immediately.

    Or, you can run the following command to test whether the new swap file was successfully created by inspecting the active swap space:

    sudo cat /proc/swaps
    sudo free -h

Creating Backups and Using the Btrfs Send/Receive Feature

Note:

Working with the Btrfs send/receive feature requires that you boot the system by using UEK R6 or later..

The send operation compares two subvolumes and writes a description of how to convert one subvolume, the parent subvolume, into the other subvolume, which is the sent subvolume. You would usually direct the output to a file for later use or pipe it to a receive operation for immediate use.

The simplest form of the send operation writes a complete description of a subvolume, for example:

sudo btrfs send [-v] [-f sent_file] ... subvol
               

You can specify many instances of the -v option to display increasing amounts of debugging output. The -f option is used to save the output to a file. Note that both of these options are implicit in the following usage examples.

The following form of the send operation writes a complete description of how to convert one subvolume to another subvolume:

sudo btrfs send -p parent_subvol sent_subvol

If a subvolume such as a snapshot of the parent volume, known as a clone source, will be available during the receive operation from which some data can be recovered, you can specify the clone source to reduce the size of the output file:

sudo btrfs send [-p parent_subvol] [-c clone_src] ... subvol

You can specify the -c option for each of the clone source that exist. If you don't specify the parent subvolume, btrfs chooses a suitable parent from the clone sources.

Use the receive operation to regenerate the sent subvolume at a specified path, for example:

sudo btrfs receive [-f sent_file] mountpoint

Creating a Reference Backup in Preparation for Creating an Incremental Backup

The following procedure describes how to create a reference backup, which is a prerequisite to setting up an incremental backup and restore process for a subvolume by using the send/receive feature.

  1. Create a read-only snapshot of the subvolume to serve as an initial reference point for the backup.

    sudo btrfs subvolume snapshot -r /vol /vol/backup_0
  2. Ensure that the snapshot has been written to disk by running the sync command.

    sudo sync
  3. Create a subvolume or directory on a Btrfs file system as a backup area to receive the snapshot, for example, /backupvol.

  4. Send the snapshot to /backupvol.

    sudo btrfs send /vol/backup_0 | btrfs receive /backupvol

    The previous command creates the /backupvol/backup_0 subvolume.

    After creating the reference backup, you can then create incremental backups, as needed. See Creating an Incremental Backup.

Creating an Incremental Backup

The following instructions describe how to create an incremental backup by using the send/receive feature. Note that before creating an incremental backup, you must first create a reference backup. See Creating a Reference Backup in Preparation for Creating an Incremental Backup.

To create an incremental backup:

  1. Create a snapshot of the subvolume.

    sudo btrfs subvolume snapshot -r /vol /vol/backup_1
  2. Ensure that the snapshot has been written to disk by running the sync command.

    sudo sync
  3. Send only the differences between the reference backup and the new backup to the backup area, for example:

    sudo btrfs send -p /vol/backup_0 /vol/backup_1 | btrfs receive /backupvol

    Running the previous comman creates the /backupvol/backup_1 subvolume.

Managing Quotas for Btrfs Subvolumes With Quota Groups

Note:

Be aware that the quota groups feature is available as a Technology Preview only in Oracle Linux 8. Working with this feature requires that you boot the system by using UEK R6 or later.

Enable quotas by running following command on a newly created Btrfs file system before any creating any subvolumes:

sudo btrfs quota enable volume

Assign a quota-group limit to a subvolume by using the following command:

sudo btrfs qgroup limit size /volume/subvolume

The following example shows how you would use this command:

sudo btrfs qgroup limit 1g /myvol/subvol1
sudo btrfs qgroup limit 512m /myvol/subvol2

To find out the quota usage for a subvolume, use the btrfs qgroup show path command.

Replacing Devices on a Live File System

You can replace devices on a live file system without unmounting the file system or stopping any tasks that are using the file system. If the system crashes or loses power while the replacement is taking place, the operation resumes when the system next mounts the file system.

To replace a device on a mounted Btrfs file system, use the following command:

sudo btrfs replace start source_dev target_dev [-r] mountpoint

In the previous command, source_dev and target_dev specify the source device to be replaced (source device) and the replacement device (target device). The mountpoint specifies the file system that is using the source device. The target device must be the same size or larger than the source device. If the source device is no longer available, or you specify the -r option, the data is reconstructed by using redundant data that is obtained from other devices,. such as another available mirror. The source device is removed from the file system when the operation is complete.

Use the btrfs replace status mountpoint command to check the progress of the replacement operation and the btrfs replace cancel mountpoint command to cancel the operation.

Creating Snapshots of Files

Use the cp command with the --reflink option to create lightweight copies of a file within the same subvolume of a Btrfs file system. The copy-on-write mechanism saves disk space and enables copy operations to be almost instantaneous. The Btrfs file system creates a new inode that shares the same disk blocks as the existing file, rather than creating a complete copy of the file's data or creating a link that points to the file's inode. The resulting file appears to be a copy of the original file, but the original data blocks are not duplicated. If you subsequently write to one of the files, the Btrfs file system makes copies of the blocks before they are written to, preserving the other file's content.

For example, you would create a snapshot named bar of a file named foo as follows:

cp -reflink foo bar

Automating File System Snapshots With the Snapper Utility

The Snapper utility can be used to automate the management of file system snapshots. The utility can make it easier to create and delete snapshots, while enabling users to compare the differences between snapshots and revert changes at the file level. For information about the Snapper utility, visit the upstream project page at http://snapper.io/.

Attention:

Snapshots record the state of the file system at a moment in time. As such, it is not possible to guarantee file system integrity for transactional processes that may have been in operation at the time when a snapshot was taken. While utilities like the snapper command may help to capture before and after snapshots for particular operations, such as when using the dnf command, these snapshots are still unaware of other processes that may be running on the system at the same time. If you have processes that may have intensive I/O or memory usage, such as database or middleware applications, you should stop these or ensure that all activity is complete before taking a snapshot to help to reduce the likelihood of data integrity or file system corruption issues within the snapshot.

If not already installed, you can install the Snapper utility from the ol8_UEKR6 yum repository, by running:

sudo dnf install -y snapper

Creating a Snapper Configuration for a Subvolume

You can use the snapper command to create and manage snapshots of Btrfs subvolumes.

To set up the snapper configuration for an existing mounted Btrfs subvolume:

sudo snapper -c config_name create-config -f btrfs fs_name

In the previous command, config_name is the name of the configuration and fs_name is the path of the mounted Btrfs subvolume. Running the command does the following:

  • Adds an entry for config_name to the /etc/sysconfig/snapper file.

  • Creates the configuration file /etc/snapper/configs/config_name .

  • Sets up a .snapshots subvolume for the snapshots.

For example, the following command sets up the snapper configuration for a Btrfs root file system:

sudo snapper -c root create-config -f btrfs /

Use the snapper list-configs command to list all of the existing configurations:

sudo snapper list-configs
Config      | Subvolume
------------+----------
home_config | /home    
root        | /        

Note:

The default snapper SELinux policy allows snapper to manage snapshots in the /, /etc, /mnt, /usr, /var and HOME_ROOT (usually /home). If you create a new directory, for example /data or /srv. You may need to set the SELinux file context for that directory so that snapper can create and manage snapshots for that directory. For example to enable snapper to manage snapshots on the /data directory, you can run:

$ sudo semanage fcontext -a -t snapperd_data_t "/data/\.snapshots(/.*)?"
$ sudo restorecon -R -v /data

Creating Different Types of Snapshots

You can create the following three types of snapshots by using the snapper command:

post

You use a post snapshot to record the state of a subvolume after a modification. A post snapshot should always be paired with a pre snapshot that you take immediately before you make the modification.

pre

You use a pre snapshot to record the state of a subvolume before a modification. A pre snapshot should always be paired with a post snapshot that you take immediately after you have completed the modification.

single

You use a single snapshot to record the state of a subvolume but it does not have any association with other snapshots of the subvolume.

To create a single snapshot of a subvolume, use the snapper create command, for example:

sudo snapper -c config_name create --description "description"

Single snapshots are useful for periodic backup purposes and can also be used to create a back-up timeline, as described in Automatic Snapper Snapshots. For actions that are likely to result in specific file system modifications that you may need to roll back, you can use pre and post snapshots to capture snapshots of the file system before and after a transaction.

For example, the following commands create pre and post snapshots of a subvolume:

sudo snapper -c config_name create -t pre -p N
... Modify the subvolume's contents...
sudo snapper -c config_name create -t post --pre-num N -p N'

Specifying the -p option with the snapper command displays the number of the snapshot so that you can reference it when creating the post snapshot or when comparing the contents of the pre and post snapshots.

Note that you can use the --command option with the snapper command to wrap an operation with pre and post snapshots. For example:

snapper -c root create --command "cd /tmp/build; make install" \
    --description "Installing a home built binary"

Pre and post snapshots are frequently used when performing system changes that may be too complex to revert manually, such as when installing or upgrading packages. The DNF snapper plugin that is described in Automatic Snapper Snapshots uses pre and post snapshots in exactly this way and uses the description field to store the DNF transaction that triggered the snapshot.

For example, in the following set of snapshots, you can identify periodic, single snapshots that are triggered as part of a timeline and then a pre and post snapshot that is triggered by the DNF snapper plugin when the vim package is installed.

$ sudo snapper -c root list
 # | Type   | Pre # | Date                         | User | Cleanup  | Description              | Userdata
---+--------+-------+------------------------------+------+----------+--------------------------+---------
0  | single |       |                              | root |          | current                  |         
1  | single |       | Wed 25 Nov 2020 07:00:30 EST | root | timeline | timeline                 |         
2  | single |       | Wed 25 Nov 2020 08:00:01 EST | root | timeline | timeline                 |         
3  | single |       | Wed 25 Nov 2020 09:00:01 EST | root | timeline | timeline                 |         
4  | pre    |       | Wed 25 Nov 2020 09:07:21 EST | root | number   | /usr/bin/dnf install vim |         
5  | post   |     4 | Wed 25 Nov 2020 09:07:25 EST | root | number   | /usr/bin/dnf install vim |         
6  | single |       | Wed 25 Nov 2020 10:00:01 EST | root | timeline | timeline                 |         

Automatic Snapper Snapshots

By default, each snapper configuration contains settings for a periodic backup, which is controlled by the TIMELINE_CREATE configuration variable in the /etc/snapper/configs/config_name file. Automatic snapshots are triggered by a systemd timer unit that you must enable to allow the timeline to be created:

sudo systemctl enable --now snapper-timeline.timer

A second systemd timer unit handles the cleanup of stale snapshots so that your snapshots remain manageable. You should enable this unit as well, for example:

sudo systemctl enable --now snapper-cleanup.timer

When the systemd timer units are enabled, periodic snapshot events trigger automatically for every snapper configuration that has the TIMELINE_CREATE variable enabled. If you wish to disable periodic snapshots for a particular configuration, change the variable value to no in the configuration file.

By default, the snapper timeline configuration keeps 10 hourly, 10 daily, 10 monthly, and 10 yearly snapshots. Snapshots are pruned by the cleanup timer. For busy subvolumes such as the root subvolume, you might want to modify these values to better cater to your requirements. You set these values by changing the following configuration variables:

TIMELINE_LIMIT_HOURLY="10"
TIMELINE_LIMIT_DAILY="10"
TIMELINE_LIMIT_WEEKLY="10"
TIMELINE_LIMIT_MONTHLY="10"
TIMELINE_LIMIT_YEARLY="10"

The cleanup timer also prunes other snapshots to keep the total number of snapshots reduced. See the SNAPPER(8) and SNAPPER-CONFIGS(5) manual pages for more information.

You can install the DNF snapper plugin on a system to automatically trigger pre and post snapshots for DNF transactions. This feature can help you roll back changes in cases where system package upgrades cause a failure that you need to debug or to enable you to analyze which files were modified during an installation or upgrade. Note that this plugin requires no user configuration or interaction to work. To install the plugin, use the following command:

sudo dnf install python3-dnf-plugin-snapper

When installed, a snapshot is triggered for each subsequent DNF transaction. See https://dnf-plugins-extras.readthedocs.io/en/latest/snapper.html for more information.

Working With Btrfs Snapshots by Using Snapper

To list the snapshots that exist for a snapper configuration or subvolume, run:

sudo snapper -c config_name list

To display the files and directories that have been added, removed, or modified between two snapshots, use the status subcommand and specify the numbers of the two snapshots that you want to compare:

sudo snapper -c config_name status N .. N'

To display the differences between the contents of all the files in between two snapshots, use the diff subcommand:

sudo snapper -c config_name diff N .. N'

You can also display the difference in a single file over two snapshots by providing the full path to the file:

sudo snapper -c config_name diff N .. N' /path/to/file

To delete a snapshot, specify its number to the delete subcommand:

sudo snapper -c config_name delete N''

To undo the changes in the subvolume from post snapshot N' to pre snapshot N':

sudo snapper -c config_name undochange N .. N'

Note that undoing a change does not revert the file system to the previous snapshot but it reverts modifications made to existing files in the snapshot. This means that files created after the snapshot was taken continue to remain after an undochange operation. The undochange subcommand does not check data integrity for its changes. You should be careful of using this command without clearly evaluating the implications of the changes that it is likely to make.

For more information, see the snapper(8) manual page.

You can mount any snapshot generated by snapper just as you would work with any other Btrfs snapshot. You may need to correlate the snapshot volume id with the snapper snapshot number to work out which snapshot you should mount or restore. Run the snapper list command to identify the number of the snapshot you wish to roll back to. For example, to see all pre and post snapshots, to roll back to a snapshot from before a DNF package update was run:

sudo snapper -c root list -t pre-post

Running the previous command produces the following output:

Pre # | Post # | Pre Date                     | Post Date                    | Description                     | Userdata
------+--------+------------------------------+------------------------------+---------------------------------+---------
   4  |     5  | Wed 25 Nov 2020 09:07:21 EST | Wed 25 Nov 2020 09:07:25 EST | /usr/bin/dnf install vim        |         
 127  |   128  | Mon 30 Nov 2020 08:25:42 EST | Mon 30 Nov 2020 08:30:57 EST | /usr/bin/dnf update             |         

Note that the number of the pre snapshot that we intend to mount is 127 in this case. Use the btrfs subvolume list command to obtain the subvolume ID for the snapper snapshot and use this or the path to the snapshot subvolume to mount the file system, for example:

sudo btrfs subvolume list /|grep .snapshots.*127  

The output of the previous command is as follows:

ID 521 gen 11533 top level 268 path .snapshots/127/snapshot

Then, run the following command:

sudo mount -o subvolid=521 /dev/sda2 /mnt

You can also use this information to boot into a snapshot of the root file system. See Mounting Alternate Snapshots as the root File System for more infomration.

Working With a Btrfs root File System

Important:

In Oracle Linux 8, the Btrfs file system and all the features that are documented in this chapter are supported in the Unbreakable Enterprise Kernel (UEK) release only. Working with Btrfs file system features requires that you boot the system by using UEK R6 or later.

You can create a Btrfs root file system during an installation. To do so, you must boot the system by using UEK R6 or later.

To find out the ID of the parent of the root file system subvolume, use the following command:

sudo btrfs subvolume list /

Note in the output of the previous command that the top level ID is set with an ID of 5. The top level of the file system is effectively the root of the file system and can be used to access all the subvolumes within the file system:

ID 256 gen 1591 top level 5 path boot
ID 258 gen 1591 top level 5 path root
ID 259 gen 1514 top level 5 path home
ID 262 gen 1514 top level 258 path var/lib/portables"

In the previous example, the installation root file system subvolume has an ID of 258. The subvolume with ID 258 (root) is mounted as /. The default subvolume (root) with ID 258 is mounted as the active root file system.

The mount command shows the device that's mounted as the root file system and indicates the subvolume ID (258):

sudo mount|grep 'on / '
/dev/sda2 on / type btrfs (rw,relatime,seclabel,space_cache,subvolid=258,subvol=/root)

Note that the top-level file system in the previous output isn't mounted by default. To mount the top-level file system volume, use the following commands:

sudo mkdir /mnt
sudo mount -o subvolid=5 /dev/sda2 /mnt

If you list the contents of /mnt, you can view each of the subvolumes within the file system volume, including the root subvolume, for example:

ls /mnt

Running the previous command displays the following output:

boot  home  root

Note that the contents of / and /mnt/root are identical, as s shown in the following example where a file (foo) that's created in /mnt/root is also visible in /:

sudo touch /mnt/root/foo
ls /

Running the previous command displays the following output:

bin   boot  dev  etc  foo  home  instroot  lib  lib64  media  mnt  opt  
proc  root  run  sbin  srv  sys    tmp  usr  var

Now, list the contents of /mnt/root:

sudo ls /mnt/root
bin   boot  dev  etc  foo  home  instroot  lib  lib64  media  mnt  opt  
proc  root  run  sbin  srv  sys    tmp  usr  var

Remove the /foo directory, then list the contents of /:

sudo rm -f /foo
sudo ls /
bin   boot  dev  etc  home  instroot  lib  lib64  media  mnt  opt  
proc  root  run  sbin  srv  sys    tmp  usr  var

List the contents of /mnt/root again:

sudo ls /mnt/root
bin   boot  dev  etc  home  instroot  lib  lib64  media  mnt  opt  
proc  root  run  sbin  srv  sys    tmp  usr  var

Creating Snapshots of the root File System

To take a snapshot of the current root file system:

  1. Mount the top level of the root file system on a suitable mount point.

    sudo mount -o subvolid=5 /dev/sda2 /mnt
  2. Change directories to the mount point, then take the snapshot. In the following example, the install subvolume is currently mounted as the root file system:

    sudo cd /mnt
    sudo mkdir -p /mnt/snapshots
    sudo btrfs subvolume snapshot root snapshots/root_snapshot_1
  3. Change directories to / and unmount the top level of the file system.

    sudo cd /
    sudo umount /mnt 

    The list of subvolumes now includes the newly created snapshot.

    sudo btrfs subvolume list /
    ID 256 gen 1332 top level 5 path boot
    ID 258 gen 1349 top level 5 path root
    ID 259 gen 1309 top level 5 path home
    ID 261 gen 1309 top level 258 path var/lib/portables
    ID 264 gen 1348 top level 5 path snapshots/root_snapshot_1

Mounting Alternate Snapshots as the root File System

If you want to roll back changes to your system, you can mount a snapshot as the root file system by specifying its ID as the default subvolume:

sudo btrfs subvolume set-default 264 /

To ensure that the GRUB command line does not overwrite your settings, make the following update:

current_grub_kernel=$(sudo grubby --default-kernel);
sudo grubby --remove-args="rootflags=subvol=root" --update-kernel $current_grub_kernel

Reboot the system for the changes to take effect.

Check that the snapshot subvolume ID and subvolume is mounted as the root filesystem:

sudo mount|grep 'on / '
/dev/sda2 on / type btrfs (rw,relatime,seclabel,space_cache,subvolid=264,subvol=/snapshots/root-snapshot1)

Deleting Snapshots of the root File System

Note:

A snapshot cannot be deleted if it is set as the default ID for a subvolume. Deleting a snapshot while it is in use as the root file system may cause system failure and requires a hard physical reset. Before deleting a snapshot that is set as the default subvolume for the root File System, change the default ID and reboot the system, for example:

sudo btrfs subvolume set-default 258 /
reboot

To delete a snapshot, do the following:

  1. Mount the top level of the file system, for example:

    sudo mount -o subvolid=5 /dev/sda2 /mnt
  2. Change directories to the mount point and delete the snapshot.

    $ sudo cd /mnt
    sudo btrfs subvolume delete snapshots/root-snapshot1
  3. Change directories to / and unmount the top level of the file system.

    sudo cd /
    sudo umount /mnt 

    The list of subvolumes now does not include snapshots/root-snapshot1.

    sudo btrfs subvolume list /
    ID 256 gen 1332 top level 5 path boot
    ID 258 gen 1349 top level 5 path root
    ID 259 gen 1309 top level 5 path home
    ID 261 gen 1309 top level 258 path var/lib/portables