Pruning External Btrfs snap-sync Snapshots

snap-sync is a utility that facilitates synchronizing snapshots from a local Btrfs file system to another one (either physically connected to the same machine or on another machine via SSH). Internally it uses snapper to create a local snapshot that functions as a base for incremental Btrfs send/receive to the other volume.

Once your first snapshot is synchronized, subsequent snapshots are very fast. After a few weeks or months — depending on how often you run snap-sync — your target volume will become full of snapshots and you might start having issues with disk space. Local snapshots are cleaned up according to the schedule configured by snapper, but there is currently no such mechanism for snap-sync. I wrote a shell script to do just that:

The desire for a “cleanup service” for snap-sync is a popular one. Every snap-sync user will eventually fill up their disk and realize that the only way to clean up old snapshots is manually. In 2019 one user posted a partially working example of a script they were using to clean up their snapshot target volume. I was grateful for this user’s script, which appeared to work, but noticed that it had some logic errors¹ and was written to remove all but the most recent snapshot.

While trying to understand the script and fix these issues I also ended up making several improvements: the ability to more easily configure the number of snapshots to keep, detecting and handling a few corner cases, and updating the output to be more informative.

Here is an example of the script running on an external USB target volume with a configuration to keep the latest two snapshots:

# ./ 
[DEBUG] Keeping the latest 2 snapshots on /mnt/backup.
 [DEBUG] Checking /mnt/backup/root
  [DEBUG] Found /mnt/backup/root/6603
   [INFO] Deleting /mnt/backup/root/6603
  [DEBUG] Found /mnt/backup/root/6602
   [INFO] Deleting /mnt/backup/root/6602
 [DEBUG] Checking /mnt/backup/home
 [DEBUG] Number of snapshots in /mnt/backup/home should be more than 2.

For now I'm happy with the script. Thank you to GitHub user FraYoshi for posting their example which inspired me to write mine. Other Btrfs volume maintenance tasks like scrub, balance, and defrag are left as an exercise to the reader!

Next I should write about my actual Btrfs setup.


A few ideas for how to improve the script in the future:

  • Make sure target volume is mounted!
  • Use -c like snapper and snap-sync to indicate the config to work on?
  • Specify the target mount point on the command line?
  • Specify the number of snapshots to delete on the command line?
  • Add -d to print debug messages?

  1. Notably, their use of the find command to get the oldest backups wasn't working as I'm sure they expected, and they didn't check to make sure that they didn't delete the latest incremental snapshot (if this is missing Btrfs send/receive will fail, complaining that the parent subvolume is missing).