From 271ede7116c7d57bf0ea1d48487d9190fe527b4d Mon Sep 17 00:00:00 2001 From: Christoph Klaffl Date: Mon, 7 Jan 2019 19:59:31 +0100 Subject: [PATCH 1/3] Revert "Revert "Zfs Recursion"" This reverts commit 50a237402156f816b7dbfba50f29a4e44e66dfd1. --- sanoid | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/sanoid b/sanoid index ce8207c..9fcbb88 100755 --- a/sanoid +++ b/sanoid @@ -502,7 +502,13 @@ sub take_snapshots { # update to most current possible datestamp %datestamp = get_date(); # print "we should have had a $type snapshot of $path $maxage seconds ago; most recent is $newestage seconds old.\n"; - push(@newsnaps, "$path\@autosnap_$datestamp{'sortable'}${dateSuffix}_$type"); + + # use zfs (atomic) recursion if specified in config + if ($config{$section}{'zfs_recursion'}) { + push(@newsnaps, "$path\@autosnap_$datestamp{'sortable'}${dateSuffix}_$type\@"); + } else { + push(@newsnaps, "$path\@autosnap_$datestamp{'sortable'}${dateSuffix}_$type"); + } } } } @@ -510,8 +516,14 @@ sub take_snapshots { if ( (scalar(@newsnaps)) > 0) { foreach my $snap ( @newsnaps ) { - my $dataset = (split '@', $snap)[0]; - my $snapname = (split '@', $snap)[1]; + my @split = split '@', $snap, -1; + my $recursiveFlag = 0; + if (scalar(@split) == 3) { + $recursiveFlag = 1; + chop $snap; + } + my $dataset = $split[0]; + my $snapname = $split[1]; my $presnapshotfailure = 0; if ($config{$dataset}{'pre_snapshot_script'} and !$args{'readonly'}) { $ENV{'SANOID_TARGET'} = $dataset; @@ -530,8 +542,13 @@ sub take_snapshots { } if ($args{'verbose'}) { print "taking snapshot $snap\n"; } if (!$args{'readonly'}) { - system($zfs, "snapshot", "$snap") == 0 - or warn "CRITICAL ERROR: $zfs snapshot $snap failed, $?"; + if ($recursiveFlag) { + system($zfs, "snapshot", "-r", "$snap") == 0 + or warn "CRITICAL ERROR: $zfs snapshot -r $snap failed, $?"; + } else { + system($zfs, "snapshot", "$snap") == 0 + or warn "CRITICAL ERROR: $zfs snapshot $snap failed, $?"; + } } if ($config{$dataset}{'post_snapshot_script'} and !$args{'readonly'}) { if (!$presnapshotfailure or $config{$dataset}{'force_post_snapshot_script'}) { @@ -846,7 +863,9 @@ sub init { my $recursive = $ini{$section}{'recursive'} && grep( /^$ini{$section}{'recursive'}$/, @istrue ); my $skipChildren = $ini{$section}{'skip_children'} && grep( /^$ini{$section}{'skip_children'}$/, @istrue ); my @datasets; - if ($recursive || $skipChildren) { + if ($ini{$section}{'recursive'} =~ /zfs/i) { + $config{$section}{'zfs_recursion'} = 1; + } elsif ($recursive || $skipChildren) { @datasets = getchilddatasets($config{$section}{'path'}); DATASETS: foreach my $dataset(@datasets) { chomp $dataset; From 0fc16b4903b98ef03a120f6c1f46a39ed050005e Mon Sep 17 00:00:00 2001 From: Christoph Klaffl Date: Mon, 7 Jan 2019 09:48:04 +0100 Subject: [PATCH 2/3] fixed uninitialzed variable warning and clarified recursive value --- sanoid | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sanoid b/sanoid index 9fcbb88..db5376b 100755 --- a/sanoid +++ b/sanoid @@ -765,6 +765,8 @@ sub init { # we'll use these later to normalize potentially true and false values on any toggle keys my @toggles = ('autosnap','autoprune','monitor_dont_warn','monitor_dont_crit','monitor','recursive','process_children_only','skip_children','no_inconsistent_snapshot','force_post_snapshot_script'); + # recursive is defined as toggle but can also have the special value "zfs", it is kept to be backward compatible + my @istrue=(1,"true","True","TRUE","yes","Yes","YES","on","On","ON"); my @isfalse=(0,"false","False","FALSE","no","No","NO","off","Off","OFF"); @@ -861,9 +863,10 @@ sub init { # how 'bout some recursion? =) my $recursive = $ini{$section}{'recursive'} && grep( /^$ini{$section}{'recursive'}$/, @istrue ); + my $zfsRecursive = $ini{$section}{'recursive'} && $ini{$section}{'recursive'} =~ /zfs/i; my $skipChildren = $ini{$section}{'skip_children'} && grep( /^$ini{$section}{'skip_children'}$/, @istrue ); my @datasets; - if ($ini{$section}{'recursive'} =~ /zfs/i) { + if ($zfsRecursive) { $config{$section}{'zfs_recursion'} = 1; } elsif ($recursive || $skipChildren) { @datasets = getchilddatasets($config{$section}{'path'}); From ab12540a96633ce92abfa11c099a0cfa4ef83950 Mon Sep 17 00:00:00 2001 From: Christoph Klaffl Date: Mon, 7 Jan 2019 18:22:54 +0100 Subject: [PATCH 3/3] added message if zfs recursion is used and fixed ordinary recursion in combination with zfs recursion --- sanoid | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/sanoid b/sanoid index db5376b..304f5f6 100755 --- a/sanoid +++ b/sanoid @@ -516,10 +516,12 @@ sub take_snapshots { if ( (scalar(@newsnaps)) > 0) { foreach my $snap ( @newsnaps ) { + my $extraMessage = ""; my @split = split '@', $snap, -1; my $recursiveFlag = 0; if (scalar(@split) == 3) { $recursiveFlag = 1; + $extraMessage = " (zfs recursive)"; chop $snap; } my $dataset = $split[0]; @@ -540,7 +542,7 @@ sub take_snapshots { $presnapshotfailure = 1; } } - if ($args{'verbose'}) { print "taking snapshot $snap\n"; } + if ($args{'verbose'}) { print "taking snapshot $snap$extraMessage\n"; } if (!$args{'readonly'}) { if ($recursiveFlag) { system($zfs, "snapshot", "-r", "$snap") == 0 @@ -862,29 +864,49 @@ sub init { } # how 'bout some recursion? =) + if ($config{$section}{'zfs_recursion'} && $config{$section}{'zfs_recursion'} == 1 && $config{$section}{'autosnap'} == 1) { + warn "ignored autosnap configuration for '$section' because it's part of a zfs recursion.\n"; + $config{$section}{'autosnap'} = 0; + } + my $recursive = $ini{$section}{'recursive'} && grep( /^$ini{$section}{'recursive'}$/, @istrue ); my $zfsRecursive = $ini{$section}{'recursive'} && $ini{$section}{'recursive'} =~ /zfs/i; my $skipChildren = $ini{$section}{'skip_children'} && grep( /^$ini{$section}{'skip_children'}$/, @istrue ); my @datasets; - if ($zfsRecursive) { - $config{$section}{'zfs_recursion'} = 1; - } elsif ($recursive || $skipChildren) { + if ($zfsRecursive || $recursive || $skipChildren) { + if ($zfsRecursive) { + $config{$section}{'zfs_recursion'} = 1; + } + @datasets = getchilddatasets($config{$section}{'path'}); DATASETS: foreach my $dataset(@datasets) { chomp $dataset; - if ($skipChildren) { - if ($args{'debug'}) { print "DEBUG: ignoring $dataset.\n"; } - delete $config{$dataset}; - next DATASETS; - } + if ($zfsRecursive) { + # don't try to take the snapshot ourself, recursive zfs snapshot will take care of that + $config{$dataset}{'autosnap'} = 0; - foreach my $key (keys %{$config{$section}} ) { - if (! ($key =~ /template|recursive|children_only/)) { - if ($args{'debug'}) { print "DEBUG: recursively setting $key from $section to $dataset.\n"; } - $config{$dataset}{$key} = $config{$section}{$key}; + foreach my $key (keys %{$config{$section}} ) { + if (! ($key =~ /template|recursive|children_only|autosnap/)) { + if ($args{'debug'}) { print "DEBUG: recursively setting $key from $section to $dataset.\n"; } + $config{$dataset}{$key} = $config{$section}{$key}; + } + } + } else { + if ($skipChildren) { + if ($args{'debug'}) { print "DEBUG: ignoring $dataset.\n"; } + delete $config{$dataset}; + next DATASETS; + } + + foreach my $key (keys %{$config{$section}} ) { + if (! ($key =~ /template|recursive|children_only/)) { + if ($args{'debug'}) { print "DEBUG: recursively setting $key from $section to $dataset.\n"; } + $config{$dataset}{$key} = $config{$section}{$key}; + } } } + $config{$dataset}{'path'} = $dataset; $config{$dataset}{'initialized'} = 1; }