====== ZFS Snapshot Size ====== The ZFS filesystem does not provide an easy way to calculate the size taken up by snapshots. The following Perl script will do the calculation. Save the script and chmod 755 so it can be run, then use the following syntax to execute it. ./zfs_snap_total /path/to/dataset [-r] All it does is runs zfs list -t snap to get a list of all snapshots. Adding the -H option limites the output to the name and size of the snapshot. It sums all of the sizes (parsing from the Human Readable form which is the default), the displays the value in both human readable and byte format. The -r flag will calculate the total of all snapshots recursively, ie the dataset and all children. #!/usr/bin/env perl use strict; use warnings; my $usage = "Usage: $0 [-r] pool/dataset\n -r include snapshots of child datasets (recursive)\n"; my $recurse = 0; my $dataset; while (@ARGV) { my $a = shift @ARGV; if ($a eq '-r') { $recurse = 1; next } if (defined $dataset) { die $usage } $dataset = $a; } die $usage unless defined $dataset; my @cmd = ('zfs','list','-t','snapshot','-o','name,used','-H'); push @cmd, '-r' if $recurse; push @cmd, $dataset; open my $fh, "-|", @cmd or die "Failed to run zfs: $!\n"; sub parse_size { my ($s) = @_; return 0 unless defined $s && length $s; $s =~ s/,//g; if ($s =~ /([0-9.]+)\s*([BKMGTP]?)$/i) { my ($n,$u) = ($1, uc $2); my %m = ('B' => 1, ''=>1, 'K'=>1024, 'M'=>1024**2, 'G'=>1024**3, 'T'=>1024**4, 'P'=>1024**5); return int($n * $m{$u}); } # fallback: try to interpret as integer bytes return int($s); } sub human { my ($n) = @_; return "0 B" if $n == 0; my @units = qw(B K M G T P); my $i = 0; while ($n >= 1024 && $i < @units-1) { $n /= 1024; $i++ } return sprintf("%.2f %s", $n, $units[$i]); } my $sum = 0; while (my $line = <$fh>) { chomp $line; next unless $line =~ /\S/; my ($name, $used) = split /\s+/, $line, 2; $used =~ s/^\s+|\s+$//g if defined $used; $sum += parse_size($used); } close $fh; printf "%s (%d bytes)\n", human($sum), $sum; exit 0