diff --git a/btrbk b/btrbk index 20fe8f6..34908d9 100755 --- a/btrbk +++ b/btrbk @@ -2358,9 +2358,10 @@ sub filefrag_extentmap($) sub aio_extentmap($) { my $vol = shift || die; + my $starttime = time; INFO("Fetching extent information (IO::AIO) for: $vol->{PRINT}"); - my $starttime = time; + # NOTE: this returns exitstatus=0 if file is not found, or no files found my $ret = run_cmd( cmd => [ 'find', { unsafe => $vol->{PATH} }, '-xdev', '-type', 'f' ], large_output => 1 ); @@ -2369,44 +2370,42 @@ sub aio_extentmap($) return undef; } - DEBUG("Reading ioctl FIEMAP on all files"); + DEBUG("Reading ioctl FIEMAP of " . scalar(@$ret) . " files"); - IO::AIO::max_outstanding(512); # < 1024 (max file descriptors) + IO::AIO::max_outstanding(128); # < 1024 (max file descriptors) + IO::AIO::max_poll_reqs(32); - # not sure how IO::AIO does its threading, it says we should not care about it (?). - # anyway, it works without "my @range :shared" (from threads::shared). # Note: aio_fiemap returns byte range (not blocks) my @range; - my $relax = 0; my $count = 0; + my $inline = 0; foreach my $file (@$ret) { IO::AIO::aio_open($file, IO::AIO::O_RDONLY(), 0, sub { - my $fh = shift or die "failed to open $file: $!"; - #aioreq_pri 4; - # aio_fiemap $fh, $start, $length, $flags, $count, $cb->(\@extents) - IO::AIO::aio_fiemap($fh, 0, undef, 0, undef, sub { - my $aref = shift; # [$logical, $physical, $length, $flags] - # ignore inline data: for some reason, filefrag reports different size (x 4096 ?) - push @range, map { ($_->[3] & IO::AIO::FIEMAP_EXTENT_DATA_INLINE()) ? () : - [ $_->[1], $_->[1] + $_->[2] - 1 ] } @$aref; + return unless($_[0]); # graceful abort on file open errors (check $count below) + IO::AIO::aio_fiemap($_[0], 0, undef, 0, undef, sub { $count++; - close $fh; + foreach(@{$_[0]}) { # [$logical, $physical, $length, $flags] + if($_->[3] & IO::AIO::FIEMAP_EXTENT_DATA_INLINE() ) { + # ignore inline data: for some reason, filefrag reports different size (x 4096 ?) + $inline++; + next; + } + push @range, [ $_->[1], $_->[1] + $_->[2] - 1 ]; + } }); }); - # the above eats up all our filedescriptors, relax every now and then - $relax++; - if($relax > 256) { - # poll_cb is slow, no need to call it every time - IO::AIO::poll_cb(); # max_outstanding is only unsed if poll_cb is called - TRACE "aio_fiemap: processed $count files, " . scalar(@range) . " regions" if($loglevel >= 4); - $relax = 0; - } + # poll, or the above eats up all our filedescriptors + IO::AIO::poll_cb(); # takes "max_outstanding" and "max_poll_reqs" settings + #TRACE "aio_fiemap: processed $ret : $count files (inline=$inline), " . scalar(@range) . " regions" if($loglevel >= 4); } IO::AIO::flush(); - DEBUG("parsed FIEMAP of $count files: " . scalar(@range) . " regions in " . (time - $starttime) . "s for: $vol->{PRINT}"); + WARN "Failed to open $count / " . scalar(@$ret) . " files" if($count != scalar(@$ret)); + + DEBUG("Parsed " . scalar(@range) . " regions for $count files in " . (time - $starttime) . "s for: $vol->{PRINT}"); + DEBUG("Ignored $inline \"inline\" extents for: $vol->{PRINT}") if($inline); return extentmap_merge(\@range); }