How to determine whether any of the ZFS snapshots are truly redundant and safe to delete without data loss

freebsdzfs

I'm using FreeBSD 11.1 and the output of zfs list -t snap -r poolname shows a large number of my snapshots with "0" under "USED". I've read up on how ZFS accounts for space so I understand the basics, and they suggest to me that

  1. "0" means the snapshot uses no disk space, in the sense that deleting it recovers no disk space.
  2. If a file is present in 2 snapshots, this wont improve redundancy on that file because all it means is multiple pointers (references) to that file exist (or more exactly, to the series of blocks making up that file), not that extra copies exist.

So logic suggests that any snapshot with USED=0 is likely to be an identical copy of the previous snapshot of rhat object, and safe to delete if you don't want to keep snapshots for which nothing changed from the previous snapshot, and no redundancy is lost by doing so.

I'm very attached to not deleting old data or reducing redundancy if it reduces data safety, and I can think of at least a couple of possible reasons it might not be all that simple:

  • Snapshot USED values can change when other snapshots are destroyed, but equally the presence of zero size should strongly suggest in almost any normal usage, that another snap exists of non-zero size that it's identical to. But "strongly suggests" doesn't mean "implausible that it's not so", and zero means all blocks exist not that they are identically organised and the files are the same. Are there any cases where it's not necessarily safe to "out of hand" delete all zero-size snaps?

  • As an example of this, imagine we (1) create a 100MB file and snapshot the pool, then (2) create two other 75MB files containing the first and last 75% of the 100MB file respectively, and delete the 100MB file, then snapshot again. The second snapshot will show 0 space used because all blocks exist in the previous snap, but the files in that snapshot are in fact unique. I can't think of a way to detect this because space accounting in ZFS is block not file based. Perhaps with dedup in use and some types of file that get appended or 'tail'ed this might be common if rare, not just a pathological edge case.

So I'm unsure. Perhaps snap size is a red herring and I need to check other properties instead.

Are there any non-trivial circumstances one can safely and quickly determine whether a ZFS snapshot is redundant (in the sense I'm using the term), and that its safe to delete it?

Or is there another better (quick+effective) way to tell, from other properties or ZFS diffing or whatever, whether two sequential snaps actually point to the same point in time/pool write sequence number in the pool's history (which would categorically confirm they reference identical data)?

Best Answer

USED=0 is a reasonable indicator for a snapshot being a duplicate of the one before it. However, you should make sure it’s actually zero, and not some rounded version of zero (like 0.1KB, rounded to the nearest KB). You can use the -p (“parseable”) flag to get the exact number measured in bytes. Also note that it can take a few seconds for the space accounting numbers to be updated after you make a snapshot.

Like you suggest, you could also use zfs diff to achieve the same thing. This has the added benefit of telling you what changed.

The example you gave (where blocks are shared across files) can only happen if you have dedup enabled. Otherwise, ZFS would still store multiple copies of the blocks and account for that space appropriately. Even with dedup, both of the methods above will show differences — the snapshot wouldn’t take zero USED space because you’d need new metadata for the two files (two inodes plus the indirect blocks pointing to the deduped blocks; maybe other stuff as well), and zfs diff will show +<filename> for the two new files.

EDIT: The last user-visible way I can think of to check this is by running zfs send -nv (dry run, verbose) incrementally between snapshots. This won’t generate the full send stream but may tell you what would be sent, which should be nothing if the two snapshots are the same.

Related Question