From 17f41118d303f6d8706ce772d7bf27a70bc78221 Mon Sep 17 00:00:00 2001 From: Axel Burri Date: Thu, 10 May 2018 12:26:15 +0200 Subject: [PATCH] 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). --- btrbk | 61 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/btrbk b/btrbk index eb8f95e..e681e9f 100755 --- a/btrbk +++ b/btrbk @@ -255,7 +255,7 @@ my %raw_info_sort = ( ); 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 %uuid_cache; # map UUID to btr_tree node my %realpath_cache; # map URL to realpath (symlink target) @@ -1800,9 +1800,6 @@ sub btrfs_mountpoint($) my $vol = shift // die; 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 my $realpath = $realpath_cache{$vol->{URL}}; @@ -1812,45 +1809,55 @@ sub btrfs_mountpoint($) } 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) { - $mounts = []; - my $all_mounts = system_list_mounts($vol); - - foreach my $mnt (@$all_mounts) { - if($mnt->{vfstype} ne 'btrfs') { - 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} // '') . "): $file"; - push @$mounts, $mnt; - } + $mounts = system_list_mounts($vol); + return undef unless($mounts); + # sort descending by file length + my @sorted = sort { length($b->{file}) <=> length($a->{file}) } @$mounts; + $mounts = \@sorted; $mountpoint_cache{$host} = $mounts; } # find longest match $realpath .= '/' unless($realpath =~ /\/$/); # correctly handle root path="/" - my $len = 0; - my $mounts_match; + my $mountpoint; foreach(@$mounts) { my $mnt_path = $_->{file}; $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} // '') . "): $mountpoint->{file}"; + unless($mountpoint->{vfstype} eq 'btrfs') { DEBUG "No btrfs mount point found for: $vol->{PRINT}"; return undef; } # list all mountpoints of same device my @spec_mounts; - my $spec_match = $mounts_match->{spec}; + my $spec_match = $mountpoint->{spec}; foreach my $mnt (@$mounts) { 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}) { # 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}"; @@ -1863,8 +1870,8 @@ sub btrfs_mountpoint($) } } - DEBUG "Btrfs mount point for \"$vol->{PRINT}\": $mounts_match->{file} (subvolid=$mounts_match->{MNTOPS}->{subvolid})"; - return ($mounts_match->{file}, $realpath, $mounts_match->{MNTOPS}->{subvolid}, $spec_match, \@spec_mounts); + DEBUG "Btrfs mount point for \"$vol->{PRINT}\": $mountpoint->{file} (subvolid=$mountpoint->{MNTOPS}->{subvolid})"; + return ($mountpoint->{file}, $realpath, $mountpoint->{MNTOPS}->{subvolid}, $spec_match, \@spec_mounts); }