‹ jan0sch.de

FreeBSD - Deleting old ZFS snapshots

2022-05-31

There are scenarios when you might want to automatically create snapshots via ZFS to have a backup ready if needed. The features of ZFS make this straightforward and easy. However this also means that you might run into trouble because of having too many snapshots.

While “too many” is a phrase with widely varying concrete values depending on your system configuration and ZFS can easily handle lots of snapshot, you still might want to delete snapshots older than a certain amount of time.

ZFS itself has no tooling for this but with a little scripting we can get things going. The script below uses a combination of date and the command line calculator bc to get an Epoch timestamp from the given number of $DAYS before. This is because on BSD you cannot do something like date --date="14 days ago".

Afterwards ZFS is queried for the snapshots of a certain dataset and told to skip the header line (-H), sort descending by creation date (-S creation), output only the name and the creation time (-o name,creation) and display numbers in exact values (-p). The latter meaning that we will get an Epoch seconds timestamp instead of a human readable date.

We then instrument awk to filter out all lines (snapshots) that are older than our given limit and have their names printed out. These names are then given to the xargs command which passes each one of them (-n 1) to the destroy command which will destroy not only the snapshot but all snapshots with this name in descendent file systems (-r).

Be sure to adjust the YOUR_POOL/AND/DATASET part in the script and maybe you have to add more lines if you want to work on several datasets.

#!/bin/sh

# Get EPOCH timestamp from $DAYS ago.
DAYS=30
DATE=$(echo "$(date +"%s") - $DAYS * 24 * 60 * 60" | bc)

echo "Deleting snapshots older than $DAYS days..."

# Delete all ZFS snapshots older than $DAYS.
zfs list -H -t snapshot -S creation -o name,creation -p YOUR_POOL/AND/DATASET | awk -v DATE=$DATE '$2<DATE {print $1}' | xargs -n 1 zfs destroy -r