btrbk: bugfix: compare all mountpoints while resolving

When comparing longest match in mounts, all mountpoints have to be
taken into account (not only the btrfs mount points).
pull/235/head
Axel Burri 2018-05-10 12:26:15 +02:00
parent 847be88142
commit 17f41118d3
1 changed files with 34 additions and 27 deletions

61
btrbk
View File

@ -255,7 +255,7 @@ my %raw_info_sort = (
); );
my %raw_url_cache; # map URL to (fake) btr_tree node my %raw_url_cache; # map URL to (fake) btr_tree node
my %mountpoint_cache;# map HOST to btrfs mount points my %mountpoint_cache;# map HOST to mount points (sorted descending by file length)
my %spec_cache; # map HOST:fs_spec (aka device) to btr_tree node my %spec_cache; # map HOST:fs_spec (aka device) to btr_tree node
my %uuid_cache; # map UUID to btr_tree node my %uuid_cache; # map UUID to btr_tree node
my %realpath_cache; # map URL to realpath (symlink target) my %realpath_cache; # map URL to realpath (symlink target)
@ -1800,9 +1800,6 @@ sub btrfs_mountpoint($)
my $vol = shift // die; my $vol = shift // die;
DEBUG "Resolving btrfs mount point for: $vol->{PRINT}"; DEBUG "Resolving btrfs mount point for: $vol->{PRINT}";
my $host = $vol->{HOST} || "localhost";
my $mounts = $mountpoint_cache{$host};
TRACE "mountpoint_cache " . ($mounts ? "HIT" : "MISS") . ": $host";
# get real path # get real path
my $realpath = $realpath_cache{$vol->{URL}}; my $realpath = $realpath_cache{$vol->{URL}};
@ -1812,45 +1809,55 @@ sub btrfs_mountpoint($)
} }
return undef unless($realpath); return undef unless($realpath);
# get all mountpoints
my $host = $vol->{HOST} || "localhost";
my $mounts = $mountpoint_cache{$host};
TRACE "mountpoint_cache " . ($mounts ? "HIT" : "MISS") . ": $host";
unless($mounts) { unless($mounts) {
$mounts = []; $mounts = system_list_mounts($vol);
my $all_mounts = system_list_mounts($vol); return undef unless($mounts);
# sort descending by file length
foreach my $mnt (@$all_mounts) { my @sorted = sort { length($b->{file}) <=> length($a->{file}) } @$mounts;
if($mnt->{vfstype} ne 'btrfs') { $mounts = \@sorted;
TRACE "non-btrfs mount point: $mnt->{spec} $mnt->{file} $mnt->{vfstype}";
next;
}
my $file = $mnt->{file} // die;
unless($file =~ /^$file_match$/) {
WARN "Skipping non-parseable file in btrfs mounts of $host: \"$file\"";
next;
}
TRACE "btrfs mount point (spec=$mnt->{spec}, subvolid=" . ($mnt->{MNTOPS}->{subvolid} // '<undef>') . "): $file";
push @$mounts, $mnt;
}
$mountpoint_cache{$host} = $mounts; $mountpoint_cache{$host} = $mounts;
} }
# find longest match # find longest match
$realpath .= '/' unless($realpath =~ /\/$/); # correctly handle root path="/" $realpath .= '/' unless($realpath =~ /\/$/); # correctly handle root path="/"
my $len = 0; my $mountpoint;
my $mounts_match;
foreach(@$mounts) { foreach(@$mounts) {
my $mnt_path = $_->{file}; my $mnt_path = $_->{file};
$mnt_path .= '/' unless($mnt_path =~ /\/$/); # correctly handle root path="/" $mnt_path .= '/' unless($mnt_path =~ /\/$/); # correctly handle root path="/"
$mounts_match = $_ if((length($mnt_path) > $len) && ($realpath =~ /^\Q$mnt_path\E/)); if($realpath =~ /^\Q$mnt_path\E/) {
$mountpoint = $_;
last;
}
} }
unless($mounts_match) { unless($mountpoint) {
# should never happen, as "/" should always be present in mounts
ERROR "No mount point found for: $vol->{PRINT} (realpath=\"$realpath\")";
return undef;
}
TRACE "resolved mount point (spec=$mountpoint->{spec}, subvolid=" . ($mountpoint->{MNTOPS}->{subvolid} // '<undef>') . "): $mountpoint->{file}";
unless($mountpoint->{vfstype} eq 'btrfs') {
DEBUG "No btrfs mount point found for: $vol->{PRINT}"; DEBUG "No btrfs mount point found for: $vol->{PRINT}";
return undef; return undef;
} }
# list all mountpoints of same device # list all mountpoints of same device
my @spec_mounts; my @spec_mounts;
my $spec_match = $mounts_match->{spec}; my $spec_match = $mountpoint->{spec};
foreach my $mnt (@$mounts) { foreach my $mnt (@$mounts) {
if($mnt->{spec} eq $spec_match) { if($mnt->{spec} eq $spec_match) {
unless($mnt->{vfstype} eq 'btrfs') {
# should never happen, same device should always have vfstype=btrfs
DEBUG "Ignoring non-btrfs mount point: $mnt->{spec} $mnt->{file} $mnt->{vfstype}";
next;
}
unless($mnt->{file} =~ /^$file_match$/) {
WARN "Ignoring non-parseable btrfs mountpoint on $host: \"$mnt->{file}\"";
next;
}
unless($mnt->{MNTOPS}->{subvolid}) { unless($mnt->{MNTOPS}->{subvolid}) {
# kernel <= 4.2 does not have subvolid=NN in /proc/self/mounts, read it with btrfs-progs # kernel <= 4.2 does not have subvolid=NN in /proc/self/mounts, read it with btrfs-progs
DEBUG "No subvolid provided in mounts for: $mnt->{file}"; DEBUG "No subvolid provided in mounts for: $mnt->{file}";
@ -1863,8 +1870,8 @@ sub btrfs_mountpoint($)
} }
} }
DEBUG "Btrfs mount point for \"$vol->{PRINT}\": $mounts_match->{file} (subvolid=$mounts_match->{MNTOPS}->{subvolid})"; DEBUG "Btrfs mount point for \"$vol->{PRINT}\": $mountpoint->{file} (subvolid=$mountpoint->{MNTOPS}->{subvolid})";
return ($mounts_match->{file}, $realpath, $mounts_match->{MNTOPS}->{subvolid}, $spec_match, \@spec_mounts); return ($mountpoint->{file}, $realpath, $mountpoint->{MNTOPS}->{subvolid}, $spec_match, \@spec_mounts);
} }