How to create snapshots on Linux

A snapshot is an image of a filesystem state at a specific point in time. Snapshots are really useful to “turn back time” and bring the system to a known good state if something goes wrong. At the time of writing, there are two main native ways we can create atomic snapshots on Linux: by using LVM (Logical Volume Manager) or by creating a BTRFS filesystem, which has snapshots as a built-in feature. Working with lvm snapshots is one of the most reliable ways to protect your data.

In this tutorial, we learn the differences between LVM and BTRFS snapshots, how to create and manage them on Linux.

In this tutorial you will learn:

  • How to create and manage traditional and thin lvm snapshot operations
  • How to create and manage BTRFS snapshots
How to create snapshots on Linux
How to create snapshots on Linux
Category Requirements, Conventions or Software Version Used
System Distribution agnostic
Software LVM or BTRFS
Other Root privileges, being familiar with LVM and basic filesystem concepts
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user

LVM vs. BTRFS

Comparing LVM to BTRFS is not completely fair: while the latter is a filesystem, the former is a volume manager, which works as an abstraction layer over storage devices, providing additional flexibility in space management by introducing concepts as logical volumes and volume groups. While comparing the two, then? We do that because the BTRFS filesystem integrates at the filesystem level some functionalities which, at least on Linux, were traditionally implemented using LVM. A BTRFS filesystem can, for example, span over multiple devices; it can be used to implement RAID configurations, and, what interests us the most in this case, supports the creation of atomic snapshots.



Although LVM and BTRFS snapshots serve, more or less, the same purpose, they are completely different beasts: the former are created as block devices, while the latter are created using namespaces on the main filesystem.

Thick vs. Thin LVM snapshots

When talking about LVM, we have to distinguish between traditional (“thick”) and thin logical volumes and snapshots. We talked in detail about LVM thin provisioning in a recent article; here, in few words, we can say that the main difference between thick and thin volumes, is how space is allocated. When using traditional LVM logical volumes, space is allocated at creation time; “thin” volumes, instead, are created with a “virtual” size. They are part of thin storage pools from which space is allocated only when actually needed.

When creating a traditional, or “thick” snapshot, just as when creating a regular logical volume, we must specify how much space in a volume group we want to allocate for it. The space is immediately reserved to the snapshot, which doesn’t need to be as big as its origin, since it is used only to store the blocks that are going to be changed on the source volume. Before being changed, data on the origin volume is preserved by being copied to the snapshot: this strategy is called Copy On Write (CoW). A traditional LVM snapshot must be big enough to store all the changes occurring to its origin: if they become full, they are automatically dropped.



Thick snapshots are not meant to be stored for long periods of time: they are typically used to get a “frozen” filesystem state, useful to create consistent backups; they are usually discarded immediately after such backups are completed. This is because they have a big impact on performance. Since they don’t share data, a change on the origin requires as many CoW operations as the number of existing snapshots.

Creating and managing a thick snapshot of a traditional LVM logical volume

Let’s see how to create a thick snapshot of a traditional LVM logical volume. In the example below, we have a logical volume named “root”. The logical volume exists in the volume group called “fedora”, which, as you can see in the output of the vgdisplay command, has some free space:

 --- Volume group ---
 VG Name fedora
 System ID 
 Format lvm2
 Metadata Areas 1
 Metadata Sequence No 6
 VG Access read/write
 VG Status resizable
 MAX LV 0
 Cur LV 1
 Open LV 1
 Max PV 0
 Cur PV 1
 Act PV 1
 VG Size 48.41 GiB
 PE Size 4.00 MiB
 Total PE 12393
 Alloc PE / Size 5120 / 20.00 GiB
 Free PE / Size 7273 / 28.41 GiB
 VG UUID ZX67es-BWk3-SENV-L25P-VwvI-mqsx-qCqxVJ

Suppose we want to create a backup of the “root” logical volume, which is mounted on “/”. Performing a backup of a mounted filesytem is not a good idea, since files could be modified as the backup itself is performed. By creating a snapshot of the volume, we can obtain a “frozen” view of the filesystem without turning the system down. As we already said, our snapshot must be big enough to hold all the changes which may occur to the source volume, during a given period of time. In the example below, we create a snapshot with a size of 5 GiB:

$ sudo lvcreate -s /dev/fedora/root -L 5GiB -n root-snapshot0



To create the snapshot, we invoke lvcreate with the -s option (short for --snapshot). We provide the amount of space we want to allocate for the snapshot as argument to -L (short for --size), and the snapshot name as argument to -n (short for --name). Once created, a snapshot is visible in the output of the lvs command:

 LV             VG     Attr       LSize  Pool Origin Data% Meta% Move Log Cpy%Sync Convert
 root           fedora owi-aos--- 20.00g 
 root-snapshot0 fedora swi-a-s---  5.00g      root   0.01

We can recognize a traditional LVM snapshot by looking at the value of the “Attr” column: there, we will find the first attribute bit to be “s”. In the “Origin” column we can also see the name of the volume on which the snapshot is based (“root”, in this case). Again, since we are dealing with a traditional snapshot, the space we allocated to it, is immediately withdrawn from the volume group:

 --- Volume group ---
 VG Name fedora
 System ID 
 Format lvm2
 Metadata Areas 1
 Metadata Sequence No 13
 VG Access read/write
 VG Status resizable
 MAX LV 0
 Cur LV 2
 Open LV 1
 Max PV 0
 Cur PV 1
 Act PV 1
 VG Size 48.41 GiB
 PE Size 4.00 MiB
 Total PE 12393
 Alloc PE / Size 6400 / 25.00 GiB
 Free PE / Size 5993 / 23.41 GiB
 VG UUID ZX67es-BWk3-SENV-L25P-VwvI-mqsx-qCqxVJ

Beside using the snapshot to create a consistent backup of the original volume, we can “merge” it back to the origin, to delete all changes happened since the snapshot was created. To merge a snapshot back to its origin, we use the lvconvert command with the --merge option, providing the path of the snapshot as argument. To merge the root-snapshot0 snapshot back to the root volume, for example, we would run:

$ sudo lvconvert --merge /dev/fedora/root-snapshot0

If the both the origin volume and the snapshot can be closed, the “merge” happens immediately; if this is not possibile, as in this case, the merge will happen on their next activation (most probably on the next reboot). After being merged, a snapshot is deleted. If instead of merging the snapshot, we want to delete it right away, we use the lvremove command:

$ sudo lvremove /dev/fedora/root-snapshot0

Creating and managing thin snapshots of LVM thin logical volumes

Thin LVM snapshots are much more efficient than traditional ones, because they live inside the same storage pool of their origin: they share data with them, and with other snapshots. Suppose we have a thin LVM volume called “root” inside a thin pool called “pool00”:

 LV     VG     Attr       LSize   Pool   Origin Data% Meta% Move Log Cpy%Sync Convert
 pool00 fedora twi-aotz-- <38.61g               5.63   12.15 
 root   fedora Vwi-aotz-- <38.61g pool00        5.63

To create a snapshot of the “root” volume, once again, we use the lvcreate command; this time, however, we don’t specify a size for it. Thin snapshots are always created with the same virtual size of their origin:

$ sudo lvcreate -s /dev/fedora/root -n root-snapshot0

Here is the output of the lvscommand, after the snapshot is created:

LV             VG     Attr       LSize   Pool   Origin Data% Meta% Move Log Cpy%Sync Convert
pool00         fedora twi-aotz-- <38.61g               5.64  12.26 
root           fedora Vwi-aotz-- <38.61g pool00        5.63 
root-snapshot0 fedora Vwi---tz-k <38.61g pool00 root



As we can see, the “root” volume is reported as the origin of the snapshot; the snapshot and the original volume have the same virtual size. In this case, we are over-provisioning, since the sum of the virtual sizes of the origin volume and the snapshot is bigger than the actual pool space.

Thin snapshots are created with the “activations skip” flag, which is reported as a “k” in the last bit of the “Attr” column value. This prevents their activation when using activation commands. To activate all logical volumes in a volume group, for example, we would use the vgchange -ay command. This would not activate volumes with the activation skip flag, unless we use the the -K option (short for --ignoreactivationskip), e.g:

$ sudo vgchange -a y -K /dev/fedora

To remove the skip activation flag from a thin volume, we can use the lvchange command with the -k option. To remove the “skip activation” flag from the “root-snapshot0” snapshot, for example, we would run:

$ sudo lvchange -k n /dev/fedora/root-snapshot0

As we already said, we can efficiently create multiple thin snapshots of the same thin logical volume, and even snapshots of a snapshot. Let’s create another snapshot of the “root” volume:

$ sudo lvcreate -s /dev/fedora/root -n root-snapshot1

Once again, the snapshot is created with the same virtual size of its origin:

LV             VG     Attr       LSize   Pool   Origin Data% Meta% Move Log Cpy%Sync Convert
pool00         fedora twi-aotz-- <38.61g               5.89  12.57 
root           fedora Vwi-aotz-- <38.61g pool00        5.84 
root-snapshot0 fedora Vwi---tz-k <38.61g pool00 root 
root-snapshot1 fedora Vwi---tz-k <38.61g pool00 root

Just as when using standard logical volumes and snapshots, we can directly merge a thin snapshot back to its origin using the lvconvert command. As in the case of traditional snapshots, this causes the deletion of the merged snapshot. When using thin volumes, however, the merging of a snapshot has also the effect of removing the “origin” reference from other snapshots based on the same original volume. Although they will still contain the data which represents the state of the origin at the time they were created, we won’t be able to merge them directly using the lvconvert command.

When using thin volumes, however, instead of merging the snapshot to its origin, we can use another strategy: first, we rename (or delete, depending on the case) the original thin volume, then, we create a snapshot of the snapshot we want to revert to, and name it as the original volume. This way we can both revert to a certain state, and keep the snapshot.

Suppose, for example, we want to revert to the state represented by the root-snapshot0 snapshot. First of all, we would rename the “root” thin logical volume, perhaps by adding the current date to the original name:

$ sudo lvrename /dev/fedora/root "root-$(date "+%Y-%m-%d")"

Then, we take a snapshot of the snapshot we want to use, and we name it “root”:

$ sudo lvcreate -s /dev/fedora/root-snapshot0 -n root

Deleting an LVM snapshot

An LVM snapshot can be easily removed as any other logical volume, by using the “lvremove” command. To remove the “root-snapshot0” snapshot we created in the previous example, we would run:

$ sudo lvremove /dev/fedora/root-snapshot0

Notice that in the case of thin volumes, as we specified in the dedicated tutorial, when removing a logical volume, the space is not returned to the pool until we run the fstrim command.

BTRFS snapshots

BTRFS is a modern filesystem which has snapshots as a built-in feature; it is used by default on Fedora, OpenSUSE and SUSE Linux Enterprise, and is supported by practically all the other major distributions (RHEL and clones being the exception). Unlike LVM logical volumes, BTRFS subvolumes are not separated block devices, but rather zones of the filesystem which uses separated namespaces and have their own directory hierarchies. To obtain the list of the available subvolumes on a BTRFS filesystem, we can run:

$ sudo btrfs subvolume list /

On a freshly installed Fedora system, the command above returns the following output:

ID 256 gen 46 top level 5 path root
ID 257 gen 45 top level 5 path home
ID 258 gen 41 top level 256 path var/lib/portables



For every existing subvolume the command returns the id, the generation number (an internal counter which increases at every transaction), the top level (parent) ID, and the relative path of the subvolume inside its parent. Above we can see “root” and “home” are subvolumes of the top-level volume (the “main” btrfs filesystem), which has always 5 as id. We can easily verify this by mounting the top-level volume, which, in this case, is on the third partition of the disk:

$ sudo mount /dev/vda3 /mnt

After mounting the filesystem, if we examine the content of the /mnt directory, we will see the two subvolumes, as directories:

$ ls -l /mnt
total 0
drwxr-xr-x. 1 root root 6 Aug 29 13:56 home
dr-xr-xr-x. 1 root root 138 Aug 29 13:48 root

Creating a BTRFS snapshot

BTRFS snapshots are just additional subvolumes. To create a snapshot, we use the “snapshot” subcommand, passing the path of the source subvolume, and the path where the snapshot should be created, as arguments. To create a snapshot of the “root” subvolume, which is mounted on “/”, and save it as “/.snapshot0”, we would run:

$ sudo btrfs subvolume snapshot / /.snapshot0

By default, snapshots are created in read-write mode, to make them read-only we add the the -r option to the command above. If we examine the content of the /.snapshot0 directory, we can see it contains its own directory structure:

$ ls -l /.snapshot0
dr-xr-xr-x. 1 root root 0 Jan 23 2024 afs
lrwxrwxrwx. 1 root root 7 Jan 23 2024 bin -> usr/bin
drwxr-xr-x. 1 root root 0 Aug 29 13:44 boot
drwxr-xr-x. 1 root root 0 Aug 29 13:44 dev
drwxr-xr-x. 1 root root 2658 Aug 30 03:54 etc
drwxr-xr-x. 1 root root 0 Aug 29 13:44 home
lrwxrwxrwx. 1 root root 7 Jan 23 2024 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Jan 23 2024 lib64 -> usr/lib64
drwxr-xr-x. 1 root root 0 Jan 23 2024 media
drwxr-xr-x. 1 root root 0 Jan 23 2024 mnt
drwxr-xr-x. 1 root root 0 Jan 23 2024 opt
drwxr-xr-x. 1 root root 0 Aug 29 13:44 proc
dr-xr-x---. 1 root root 128 Aug 29 13:57 root
drwxr-xr-x. 1 root root 0 Aug 29 13:44 run
lrwxrwxrwx. 1 root root 8 Jan 23 2024 sbin -> usr/sbin
drwxr-xr-x. 1 root root 0 Jan 23 2024 srv
drwxr-xr-x. 1 root root 0 Aug 29 13:44 sys
drwxrwxrwt. 1 root root 0 Aug 29 13:44 tmp
drwxr-xr-x. 1 root root 100 Aug 29 13:48 usr
drwxr-xr-x. 1 root root 170 Aug 30 03:54 var

Snapshots are not recursive, they include only the content of their parent subvolume: if we examine the content of the /.snapshot0/home/ directory, for example, we will notice it is empty, since the “home” subvolume is mounted on that position in our system. The snapshot, as expected, appears in the list of subvolumes:

$ sudo btrfs subvol list /
ID 256 gen 65 top level 5 path root
ID 257 gen 61 top level 5 path home
ID 258 gen 41 top level 256 path var/lib/portables
ID 261 gen 61 top level 256 path .snapshot0

Using a BTRFS snapshot

While there is not a specific command designed to revert a subvolume to a state represented by a snapshot, there are several ways we can use one. Since, as we saw, BTRFS snasphots are at the file-level, specific versions of files can be easily retrieved just by navigating the fileystem.

To return to a previous filesystem state, we can also adopt the same strategy used by graphical programs like btrfs-assistant. In the previous example, we took a snapshot of the “root” subvolume; that snapshot captured the state of the parent subvolume at that specific point in time. To revert to that point, we can simply replace the original subvolume with its snapshot. First we mount the top-level filesystem:

$ sudo mount /dev/vda3 /mnt

Now, we rename the “root” volume by adding the current date. We can rename a subvolume just by using the mv command:

$ sudo mv /mnt/root "/mnt/root-$(date "+%Y-%m-%d")"

In order to keep a copy of the snapshot we want to revert to, we create a new snapshot of it, and save it as /mnt/root:

$ sudo btrfs subvolume snapshot /.snapshot0 /mnt/root

Deleting a BTRFS snapshot

To remove a snapshot we use the “delete” subcommand and pass the path of the snapshot as argument. Just as an example, to remove the /.snapshot0 snapshot, we would run:

$ sudo btrfs subvolume delete /.snapshot0

Deleting a subvolume will not remove exising nested subvolumes.

Conclusions

Snapshots allow us to freeze the state of a filesystem at a certain point in time. On Linux, we can create snapshots by using LVM or the BTRFS filesystem. In this article, we saw how to create traditional and thin LVM snapshots; we learned the difference between the two, and between them and BTRFS snapshots. ZFS is another advanced filesystem which has snapshots as a built-in feature; due to licensing problems, however, it is not supported by the Linux kernel, and needs to be compiled as an external module, thus we didn’t include it in this tutorial.



Comments and Discussions
Linux Forum