From e9a517f161fa4803651dd3ec9855d00ed464e56f Mon Sep 17 00:00:00 2001 From: Axel Burri Date: Mon, 2 Oct 2017 14:00:09 +0200 Subject: [PATCH] btrbk: add options "{snapshot,target,archive}_qgroup_destroy": destroy qgroups whenever a subvolume is deleted Btrfs does not destroy qgroups when subvolumes are deleted (see https://bugzilla.kernel.org/show_bug.cgi?id=91751). As a workaround for this, btrbk can be configured to always destroy the corresponding default qgroup "0/" whenever a subvolume (snapshot, backup or archive) is deleted. Added configuration options: - snapshot_qgroup_destroy - target_qgroup_destroy - archive_qgroup_destroy --- ChangeLog | 2 ++ btrbk | 44 ++++++++++++++++++++++++++++++++++++++++++++ doc/btrbk.conf.5 | 13 +++++++++++++ 3 files changed, 59 insertions(+) diff --git a/ChangeLog b/ChangeLog index dba7fd7..15f627e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,8 @@ btrbk-current * Change raw backup format (sidecar file instead of uuid in file). * Honor target_preserve for raw targets (delete raw targets). * Add symmetric encryption for raw targets (close #157). + * Add "{snapshot,target,archive}_qgroup_destroy" configuration + options (close #49, #189). * Do not run in "perl taint mode" by default: remove "perl -T" in hashbang; hardcode $PATH only if taint mode is enabled. * Remove "duration" column from transaction_log/transaction_syslog. diff --git a/btrbk b/btrbk index 990c73b..a82c055 100755 --- a/btrbk +++ b/btrbk @@ -124,6 +124,10 @@ my %config_options = ( backend_local => { default => undef, accept => [ "no", "btrfs-progs", "btrfs-progs-btrbk", "btrfs-progs-sudo" ] }, backend_remote => { default => undef, accept => [ "no", "btrfs-progs", "btrfs-progs-btrbk", "btrfs-progs-sudo" ] }, + snapshot_qgroup_destroy => { default => undef, accept => [ "yes", "no" ], context => [ "root", "volume", "subvolume" ] }, + target_qgroup_destroy => { default => undef, accept => [ "yes", "no" ] }, + archive_qgroup_destroy => { default => undef, accept => [ "yes", "no" ], context => [ "root" ] }, + # deprecated options btrfs_progs_compat => { default => undef, accept => [ "yes", "no" ], deprecated => { DEFAULT => { ABORT => 1, warn => 'This feature has been dropped in btrbk-v0.23.0. Please update to newest btrfs-progs, AT LEAST >= $BTRFS_PROGS_MIN' } } }, @@ -214,6 +218,7 @@ my %backend_cmd_map = ( "btrfs subvolume delete" => [ "btrfs-subvolume-delete" ], "btrfs send" => [ "btrfs-send" ], "btrfs receive" => [ "btrfs-receive" ], + "btrfs qgroup destroy" => [ "btrfs-qgroup-destroy" ], }, "btrfs-progs-sudo" => { "btrfs subvolume list" => [ "sudo", "-n", "btrfs", "subvolume", "list" ], "btrfs subvolume show" => [ "sudo", "-n", "btrfs", "subvolume", "show" ], @@ -221,6 +226,7 @@ my %backend_cmd_map = ( "btrfs subvolume delete" => [ "sudo", "-n", "btrfs", "subvolume", "delete" ], "btrfs send" => [ "sudo", "-n", "btrfs", "send" ], "btrfs receive" => [ "sudo", "-n", "btrfs", "receive" ], + "btrfs qgroup destroy" => [ "sudo", "-n", "btrfs", "qgroup", "destroy" ], }, ); @@ -1280,6 +1286,33 @@ sub btrfs_subvolume_delete($@) } +sub btrfs_qgroup_destroy($@) +{ + my $vol = shift // die; + my %opts = @_; + my $vol_id = $vol->{node}{id}; + unless($vol_id) { + ERROR "Unknown subvolume_id for: $vol->{PRINT}"; + return undef; + } + my $path = $vol->{PATH} // die; + my $qgroup_id = "0/$vol_id"; + INFO "[qgroup-destroy] qgroup_id: $qgroup_id"; + INFO "[qgroup-destroy] subvolume: $vol->{PRINT}"; + start_transaction($opts{type} // "qgroup_destroy", + vinfo_prefixed_keys("target", $vol)); + my $ret = run_cmd(cmd => vinfo_cmd($vol, "btrfs qgroup destroy", $qgroup_id, { unsafe => $path }), + rsh => vinfo_rsh($vol), + ); + end_transaction($opts{type} // "qgroup_destroy", defined($ret)); + unless(defined($ret)) { + ERROR "Failed to destroy qgroup \"$qgroup_id\" for subvolume: $vol->{PRINT}"; + return undef; + } + return $vol; +} + + sub btrfs_send_receive($$$$) { my $snapshot = shift || die; @@ -3512,6 +3545,11 @@ sub macro_delete($$$$$;@) preserve_date_in_future => 1, ); + if($delete_options{qgroup}->{destroy}) { + # NOTE: we do not abort on qgroup destroy errors + btrfs_qgroup_destroy($_, %{$delete_options{qgroup}}) foreach(@$delete); + } + my @delete_success = btrfs_subvolume_delete($delete, %delete_options); $subvol_dir .= '/' if($subvol_dir ne ""); INFO "Deleted " . scalar(@delete_success) . " subvolumes in: $root_subvol->{PRINT}/$subvol_dir$subvol_basename.*"; @@ -4605,6 +4643,8 @@ MAIN: }, commit => config_key($droot, "btrfs_commit_delete"), type => "delete_archive", + qgroup => { destroy => config_key($droot, "archive_qgroup_destroy"), + type => "qgroup_destroy_archive" }, ); } } @@ -5751,6 +5791,8 @@ MAIN: }, commit => config_key($droot, "btrfs_commit_delete"), type => "delete_target", + qgroup => { destroy => config_key($droot, "target_qgroup_destroy"), + type => "qgroup_destroy_target" }, )) { $target_aborted = 1; @@ -5780,6 +5822,8 @@ MAIN: }, commit => config_key($svol, "btrfs_commit_delete"), type => "delete_snapshot", + qgroup => { destroy => config_key($svol, "snapshot_qgroup_destroy"), + type => "qgroup_destroy_snapshot" }, ); } } diff --git a/doc/btrbk.conf.5 b/doc/btrbk.conf.5 index daeb7c2..9570b06 100644 --- a/doc/btrbk.conf.5 +++ b/doc/btrbk.conf.5 @@ -320,6 +320,19 @@ For convenience, it is also possible to set \fIbackend_local\fR or local or remote sources/targets (e.g. "backend_remote btrfs-progs-btrbk"). .RE +.PP +\fBsnapshot_qgroup_destroy\fR yes|no \fI*experimental*\fR +.PD 0 +.PP +\fBtarget_qgroup_destroy\fR yes|no \fI*experimental*\fR +.PP +\fBarchive_qgroup_destroy\fR yes|no \fI*experimental*\fR +.PD +.RS 4 +Whenever a subvolume is deleted, also destroy corresponding default +qgroup "0/". Only useful if you have enabled btrfs quota +support. See also: +.RE .SH RETENTION POLICY btrbk uses separate retention policies for snapshots and backups, which are defined by the \fIsnapshot_preserve_min\fR,