A great feature of the ZFS filesystem is its ability to create snapshots of datasets. When using snapshots as part of an incremental backup strategy, such as through zfs-auto-snapshots, you may encounter situations where these snapshots consume a considerable amount of space.

This scenario often arises when working with large media or image files. If such files are moved from one location that is being snaoshotted to another, they might inadvertently become part of a snapshot. Ideally, such operations should be done on a separate, non-snapshotted dataset or volume, but mistakes are easily made.

Since snapshots are read-only, the only way of freeing up the occupied space is by removing all snapshots that contain the respective file or directory. While the convenience of not having to worry about file deletion is appreciated, it comes with the drawback that you cannot remove them even if you are sure that they are no longer needed.

If you promptly notice a file or directory being accidentally included in a snapshot, deleting the most recent snapshot suffices. However, if time has passed before recognizing the issue, you need to remove all snapshots that include the files or directories.

Manually locating and removing the snapshots containing the relevant files or directories can be rather time-consuming. First, You need to search for a file or directory within the .zfs/snapshot directory and then reconstruct the snapshot name by prepending the dataset name.

Having encountered this issue multiple times, I created a script to automate the process: zfs-find-snapshots This script lists all snapshots containing a specified file or directory.

For instance, let’s assume you have a dataset tank with three snapshots.

$ zfs list -t snapshot tank
NAME     USED  AVAIL  REFER  MOUNTPOINT
test@A    22K      -    24K  -
test@B     0B      -  1.00G  -
test@C     0B      -  1.00G  -

You can find all snapshots containing fileA.

$ zfs-find-snapshot fileA
tank@B
tank@C

To remove these snapshots, you can use xargs.

$ zfs-find-snapshot fileA | xargs -I {} zfs destroy

Note that this action may also remove other files you want to preserve. Make sure you have backups in place before deleting any snapshots.

Space Usage of Snapshots

You can obtain the space used by snapshots using the usedbysnapshots option of the zfs list command.

$ zfs list -o name,used,usedbysnapshots tank
NAME   USED  USEDSNAP
tank  1.00G     1.00G

The output shows that the tank dataset uses one gigabyte of space in total, entirely allocated to the snapshots.

By specifying the type as snapshot, you can get a list showing the space used by each individual snapshot.

$ zfs list -t snapshot blek
NAME     USED  AVAIL  REFER  MOUNTPOINT
tank@A    22K      -    24K  -
tank@B  1.00G      -  1.00G  -
tank@C     0B      -    24K  -

In this example, tank@A was created on an empty directory, tank@B on a single one-gigabyte file, which was subsequently removed before tank@C was created. As expected, the one-gigabyte file is stored within the tank@B snapshot.

References