Friday afternoon. You’re trying out a script that you wrote to mass-rename and move some files around. You finish the script and test it out.

Oops.

All the files now have all the wrong names, and some have been randomly moved 10 folders deep. It’s a mess.

And you didn’t make a backup of your files right before this step because you thought that you wouldn’t need it. It’s just a simple script, after all…

If you’ve found yourself in a similar situation and want to know how to avoid problems in the future, then this article is for you

btrfs: overview

image

btrfs (butter-fs, bee-tee-arr-eff-ess) is a modern filesystem present in the Linux kernel that has a lot of great features:

  • different RAID levels: RAID0, RAID1, RAID10…
  • data integrity guarantees
  • snapshots
  • and many more!

btrfs does have some downsides and has had its fair share of issues and controversy in the past, but at least during the last couple of years it’s been fine in my simple RAID1 + snapshots use cases.

In this post, we’ll focus on the snapshots feature that btrfs offers.

If you’re not sure what snapshots are, then you can think of them as a still image of the state of your filesystem at a certain point in time. You can create a snapshot of the filesystem, delete all your files, and still be able to get your files back just like you left them.

If you’re a developer who has used git and doesn’t mind oversimplified (and probably incorrect) explanations: you can think of snapshots like git commits. You can take snapshots (commit), roll back to a previous snapshot (reset/revert) or view the contents of a previous snapshot (checkout commit).

One thing to keep in mind with snapshots is that they will take up space, especially if you make a lot of them and move files around a lot.

There are many tools available to manage btrfs snapshots. The one I’ve opted for is snapper.

Snapper quick-start

Here’s a quick guide on how to get started with snapshotting your btrfs filesystem. The example is based on a system with a btrfs filesystem mounted on /home

  • Install snapper
    • Ubuntu/Debian: sudo apt install snapper
    • Fedora: sudo dnf install snapper
  • Setup the configuration: sudo snapper -c home create-config /home
  • /etc/snapper/configs now has a text file named home that you can configure to your liking. My personal recommendation is to use the TIMELINE snapshots configuration to configure the maximum number of hourly and daily snapshots.
  • snapper ships with two systemd timers that automatically take new snapshots and remove old ones. Make sure that they are enabled:
    • sudo systemctl enable --now snapper-timeline.timer snapper-cleanup.timer
  • After a while, you should be able to see snapshots appear in the output of sudo snapper list.
  • If you want to browse the files for the old snapshots, go to /home/.snapshots.

Example output of sudo snapper list on my machine:

> sudo snapper list

    # | Type   | Pre # | Date                     | User | Cleanup  | Description | Userdata
------+--------+-------+--------------------------+------+----------+-------------+---------
   0  | single |       |                          | root |          | current     |         
   1  | single |       | K 16 märts 2022 08:12:01 | root | timeline |             |         
 242  | single |       | K 16 märts 2022 13:00:16 | root | timeline |             |         
 302  | single |       | K 16 märts 2022 14:00:05 | root | timeline |             |         
 362  | single |       | K 16 märts 2022 15:00:10 | root | timeline |             |         
 422  | single |       | K 16 märts 2022 16:00:19 | root | timeline |             |         
 461  | single |       | K 16 märts 2022 17:20:29 | root | timeline |             |         
 501  | single |       | K 16 märts 2022 18:00:02 | root | timeline |             |
...         

That’s it!

Snapper tech tips

If you’re new to snapshots, then I recommend keeping an eye on your disk usage and tuning the snapper timeline related configurations to your liking. For my /home folder, my configuration looks like this:

# create hourly snapshots
TIMELINE_CREATE="yes"

# cleanup hourly snapshots after some time
TIMELINE_CLEANUP="yes"

# limits for timeline cleanup
TIMELINE_MIN_AGE="300"
TIMELINE_LIMIT_HOURLY="48"
TIMELINE_LIMIT_DAILY="7"
TIMELINE_LIMIT_WEEKLY="0"
TIMELINE_LIMIT_MONTHLY="0"
TIMELINE_LIMIT_YEARLY="0"

With this configuration, I can undo my screw-ups for up to 7 days, with more granular control for changes done within the last 48 hours.

If you have data that changes more often than other data on the same filesystem, then I recommend utilizing btrfs subvolumes and creating separate snapper configurations for each.

For example: a folder containing gigabytes of cat pictures is unlikely to change all that often, so a longer snapshot retention policy of 24 hourly/30 daily snapshots is a sensible one.

However, the contents of my downloads folder changes more frequently and may contain bigger files that I need temporarily, such as the ISO file for the latest Fedora/Debian release. In a situation like that, having a 6 hourly/7 daily snapshots policy will make more sense, especially if I don’t want to run out of space due to excessive number of snapshots taken for that filesystem.

Further reading: ZFS snapshots

ZFS is a fantastic filesystem that offers many of the features boasted by btrfs, and some that btrfs doesn’t have. ZFS also supports snapshots. To set up automatic snapshot creation and pruning on ZFS, I can recommend sanoid.