diff -r 7067c6844088 -r 221af7ffe050 bin/fuse-imager --- a/bin/fuse-imager Thu Jul 28 16:32:18 2011 +0200 +++ b/bin/fuse-imager Fri Jul 29 14:04:19 2011 +0200 @@ -22,9 +22,18 @@ lock_keys %o; use constant ME => basename $0; +use constant BS => 4 * 1024; + my ($DATA, $IDX); sub tie_vars; +sub min { (sort {$a <=> $b} @_)[0] } +sub max { (sort {$a <=> $b} @_)[-1] } +my $debug = sub { print STDERR @_ }; + $debug = sub { }; + + +#$SIG{INT} = sub { warn "Got ^C or INT signal\n"; exit 1; }; MAIN: { @@ -57,7 +66,6 @@ $0 = "FUSE $src $mp"; open(STDOUT => ">/dev/null"); open(STDIN => "/dev/null"); - setpgid($$ => $$); } @@ -71,6 +79,7 @@ open => \&openfile, read => \&readbuffer, write => \&writebuffer, + release => \&release, ); exit; @@ -133,6 +142,13 @@ return 0; } + sub release { + my $path = $IDX . shift; + return 0 if not exists $IMAGE{$path}; + $debug->("Currently we have " . keys(%DIRTY) . " dirty blocks\n"); + return 0; + } + sub readbuffer { my $path = $IDX . shift; my ($size, $offset) = @_; @@ -149,36 +165,65 @@ sub _readblock { my ($finfo, $size, $offset) = @_; + my ($block, $blockoffset, $length); - my $block = int($offset / $finfo->{meta}{blocksize}); - my $blockoffset = $offset % $finfo->{meta}{blocksize}; + $debug->("<<< block offset:$offset size:$size\n"); + $debug->( " block @{[int($offset/BS)]} + @{[$offset % BS]}\n"); - my $length = $finfo->{meta}{blocksize} - $blockoffset; - $length = $size if $size <= $length; + # first check if it's an dirty block + $block = int($offset / BS); + if (exists $DIRTY{ $finfo . $block }) { + $blockoffset = $offset % BS; + $length = min(BS - $blockoffset, $size); - if (exists $DIRTY{ $finfo . $block }) { + $debug->("+++ dirty offset:$block*@{[BS]} + $blockoffset size:$length\n"); return substr $DIRTY{ $finfo . $block }, $blockoffset, $length; } + + # if not dirty, we've to find it on disk + + $block = int($offset / $finfo->{meta}{blocksize}); + $blockoffset = $offset % $finfo->{meta}{blocksize}; + $length = min($finfo->{meta}{blocksize} - $blockoffset, $size); + + # find the max length we can satisfy w/o colliding + # with dirty blocks + for (my $l = BS; $l < $length; $l += BS) { + my $b = int(($offset + $l)/BS); + if ($DIRTY{$finfo . $b}) { + $length = $l; + last; + } + } + + $debug->("=== $length\n"); + $debug->("+++ disk offset:$block*$finfo->{meta}{blocksize} + $blockoffset size:$length\n"); + my $fn = "$DATA/" . $finfo->{blocklist}{$block}; - if (-e $fn) { - open(my $fh => $fn); - binmode($fh); - seek($fh => $blockoffset, 0) or die "seek: $!"; - local $/ = \$length; - return scalar <$fh>; - } - elsif (-e "$fn.gz") { - open(my $fh => "$fn.gz"); - binmode($fh); - my $buffer; - gunzip($fh => \$buffer) - or die $GunzipError; - close($fh); - return substr($buffer, $blockoffset, $size); - } + + state %cache; + if (not defined $cache{fn} + or ($cache{fn} ne $fn)) { - die "$fn: $!\n"; + if (-e $fn) { + open(my $fh => $fn); + binmode($fh); + local $/ = undef; + $cache{data} = <$fh>; + } + elsif (-e "$fn.gz") { + open(my $fh => "$fn.gz"); + binmode($fh); + gunzip($fh => \$cache{data}) + or die $GunzipError; + } + $cache{fn} = $fn; + } + + return substr($cache{data}, $blockoffset, $size); + die "$fn: $!\n"; + } sub writebuffer { @@ -201,22 +246,22 @@ sub _writeblock { my ($finfo, $buffer, $offset) = @_; + my ($block, $blockoffset, $length); my $size = length($buffer); - my $block = int($offset / $finfo->{meta}{blocksize}); - my $blockoffset = $offset % $finfo->{meta}{blocksize}; + $block = int($offset / BS); + $blockoffset = $offset % BS; + $length = min(BS - $blockoffset, $size); + + $debug->(">>> offset:$offset size:$length of $size\n"); + $debug->(" block @{[int($offset/BS)]} + @{[$offset % BS]}\n"); if (not exists $DIRTY{ $finfo . $block }) { + $debug->("+++ missing $block+$blockoffset\n"); $DIRTY{ $finfo . $block } = _readblock( - $finfo, - $finfo->{meta}{blocksize}, - $block * $finfo->{meta}{blocksize} - ); + $finfo, BS, $block * BS); } - my $length = $finfo->{meta}{blocksize} - $blockoffset; - $length = $size if $size < $length; - substr($DIRTY{ $finfo . $block }, $blockoffset, $length) = substr($buffer, 0, $length);