X-Git-Url: http://git.jankratochvil.net/?p=captive.git;a=blobdiff_plain;f=src%2FTraceFS%2Fchecktrace.pl;h=61c63e89abaef4f84d7ba0767dbf82fead92ff8d;hp=6439405720e8916599c4c0e6448410a34361a796;hb=HEAD;hpb=095f675195194fbe86f5feb0eea97ed1e5d99c77 diff --git a/src/TraceFS/checktrace.pl b/src/TraceFS/checktrace.pl index 6439405..61c63e8 100755 --- a/src/TraceFS/checktrace.pl +++ b/src/TraceFS/checktrace.pl @@ -20,258 +20,1405 @@ use strict; use warnings; -use Carp qw(cluck confess); use Data::Dumper; +use Carp qw(cluck confess); my $filter=0; $Data::Dumper::Sortkeys=1; +my $ntfs_blocksize=0x200; + +# $Object->{"by"}="CcSomeFunction"; +# $Object->{"line_enter"}=123; +# $Object->{"line_leave"}=124; +# $Object->{"ProcessThread"}="0x12345678/0x12345678"; +# $Object->{"data"}[dataline]{"FileObject"}="0x12345678"; +# $Object->{"data"}[dataline]{"FileName"}="\filename" or undef() if NULL; +# $Object->{"data"}[dataline]{"Flags"}="0x40100"; +# $Object->{"data"}[dataline]{"SectionObjectPointer"}="0x12345678"; +# $Object->{"data"}[dataline]{"SharedCacheMap"}="0x12345678"; +# $FileObject{$FileObject}{"FileObject"}="0x12345678"; +# $FileObject{$FileObject}{"SectionObjectPointer"}="0x12345678"; +# $SectionObjectPointer{$SectionObjectPointer}{"SectionObjectPointer"}="0x12345678"; +# $SectionObjectPointer{$SectionObjectPointer}{"SharedCacheMap"}="0x12345678"; +# $SharedCacheMap{$SharedCacheMap}{"SharedCacheMap"}="0x12345678"; +# $SharedCacheMap{$SharedCacheMap}{"SectionObjectPointer"}="0x12345678"; +# $SharedCacheMap{$SharedCacheMap}{"AllocationSize"}="0x12345"; +# $SharedCacheMap{$SharedCacheMap}{"FileSize"}="0x12345"; +# $SharedCacheMap{$SharedCacheMap}{"ref_count"}=1; +# $SharedCacheMap{$SharedCacheMap}{"map"}="0x12345678" (Bcb); +# $SharedCacheMap{$SharedCacheMap}{"pin"}{"0x1000"}="0x12345678" (Bcb) if !Bcb->{"OwnerPointer"}; +# $SharedCacheMap{$SharedCacheMap}{"PinAccess"}=0 or 1; +# $SharedCacheMap{$SharedCacheMap}{"LogHandle"}="0x12345678" optional; +# $SharedCacheMap{$SharedCacheMap}{"AcquireForLazyWrite"}=0; # count +# $SharedCacheMap{$SharedCacheMap}{"in_memory"}{"0x4000"}=1; # mapped page? +# $SharedCacheMap{$SharedCacheMap}{"Buffer"}="0x12345678"; +# $LogHandle{$LogHandle}{"LogHandle"}="0x12345678"; +# $Bcb{$Bcb}{"Bcb"}="0x12345678"; +# $Bcb{$Bcb}{"SharedCacheMap"}="0x12345678"; +# $Bcb{$Bcb}{"type"}="pin" or "map"; +# $Bcb{$Bcb}{"ref_count"}=1; +# $Bcb{$Bcb}{"FileOffset"}="0x1000" if {"type"} eq "pin"; +# $Bcb{$Bcb}{"Buffer"}="0x12345678"; # PAGE_SIZE-aligned for "pin", FileOffset_0-aligned for "map" +# $Bcb{$Bcb}{"OwnerPointer"}="0x12345678" optional; +# $Bcb{$Bcb}{"Lsn"}="0x12345678" optional; +# $Bcb{$Bcb}{"dirty"}=1 optional; +# $MdlChain{$MdlChain}{"MdlChain"}="0x12345678"; +# $MdlChain{$MdlChain}{"FileObject"}="0x12345678"; +# $MdlChain{$MdlChain}{"FileOffset"}="0x5000"; +# $MdlChain{$MdlChain}{"Length"}="0x9000"; -my %init; +my %FileObject; +my %LogHandle; +my %SectionObjectPointer; +my %SharedCacheMap; my %Bcb; +my %MdlChain; +my %LastLeave; # $ProcessThread=>[$Object,$Object,...] +my $LastLeave; # ref copy of the last item for the current $ProcessThread +my $ProcessThread; +my %EnterLeave; +my $EnterLeave; # ref copy of the list for the current $ProcessThread END { - print Data::Dumper->Dump([\%init,\%Bcb],[qw(%init %Bcb)]) if !$filter; + print Data::Dumper->Dump([\%FileObject,\%SectionObjectPointer,\%SharedCacheMap,\%Bcb], + [qw(%FileObject %SectionObjectPointer %SharedCacheMap %Bcb)]) if !$filter; } +my $Object; + +sub tohex($) +{ +my($num)=@_; + + return sprintf("0x%X",$num); +} + +sub FObject($) +{ +my($FileObject)=@_; + + my $FObject=$FileObject{$FileObject}; + if (!$FObject) { + my($package,$filename,$line,$subroutine)=caller 0; + warn "Non-existent FileObject $FileObject by line $line"; + } + return $FObject; +} + +sub delete_FObject($) +{ +my($FObject)=@_; + + my $FileObject=$FObject->{"FileObject"}; + delete $FileObject{$FileObject}; +} + +sub SObject($) +{ +my($SectionObjectPointer)=@_; + + my $SObject=$SectionObjectPointer{$SectionObjectPointer}; + if (!$SObject) { + my($package,$filename,$line,$subroutine)=caller 0; + warn "Non-existent SectionObjectPointer $SectionObjectPointer by line $line" + } + return $SObject; +} + +sub SObject_from_FileObject($) +{ +my($FileObject)=@_; + + return if !(my $FObject=FObject $FileObject); + my $SObject=SObject $FObject->{"SectionObjectPointer"}; + if (!$SObject) { + my($package,$filename,$line,$subroutine)=caller 0; + warn "by line $line"; + } + return $SObject; +} + +sub delete_CObject($) +{ +my($CObject)=@_; + + my $SharedCacheMap=$CObject->{"SharedCacheMap"}; + do { warn "Trailing map $_ of SharedCacheMap $SharedCacheMap during its deletion" if $_; } for ($CObject->{"map"}); + do { warn "Trailing pin $_ of SharedCacheMap $SharedCacheMap during its deletion" if $_; } for (values(%{$CObject->{"pin"}})); + if (my $LogHandle=$CObject->{"LogHandle"}) { + do { warn "INTERNAL: Missing LogHandle $LogHandle for SharedCacheMap $SharedCacheMap"; return; } + if !(my $LObject=$LogHandle{$LogHandle}); + # Do not delete $LogHandle as it may be used by many SharedCacheMap-s + } + warn "ref_count=".$CObject->{"ref_count"}." of SharedCacheMap $SharedCacheMap during its deletion" + if $CObject->{"ref_count"}; + delete $SharedCacheMap{$SharedCacheMap}; +} + +sub CObject($) +{ +my($SharedCacheMap)=@_; + + my $CObject=$SharedCacheMap{$SharedCacheMap}; + if (!$CObject) { + my($package,$filename,$line,$subroutine)=caller 0; + warn "Non-existent SharedCacheMap $SharedCacheMap by line $line"; + } + return $CObject; +} + +sub CObject_from_FileObject($) +{ +my($FileObject)=@_; + + return if !(my $SObject=SObject_from_FileObject $FileObject); + return if !(my $CObject=CObject $SObject->{"SharedCacheMap"}); + return $CObject; +} + +sub SharedCacheMap_valid($) +{ +my($SharedCacheMap)=@_; + + cluck if !defined $SharedCacheMap; + return 0 if "0x".("F"x8) eq $SharedCacheMap; + return 0 if !eval $SharedCacheMap; + return 1; +} + +sub check_data($) +{ +my($data)=@_; + + if (!eval $data->{"SectionObjectPointer"}) { + return if $Object->{"by"} eq "IRP_MJ_CREATE"; # SectionObjectPointer is not yet initialized + warn "Existing FileObject ".$data->{"FileObject"}." but no SectionObjectPointer found" + if $FileObject{$data->{"FileObject"}} && eval($FileObject{$data->{"FileObject"}}{"SectionObjectPointer"}); + return; + } + my $SectionObjectPointer=$data->{"SectionObjectPointer"}; + if (!SharedCacheMap_valid $data->{"SharedCacheMap"} && $SectionObjectPointer{$SectionObjectPointer}) { + return if !(my $SObject=SObject $SectionObjectPointer); + my $SharedCacheMap=$SObject->{"SharedCacheMap"}; + return if !eval $SharedCacheMap; + my $CObject=CObject $SharedCacheMap; + warn "Existing SectionObjectPointer ".$data->{"SectionObjectPointer"}." but no SharedCacheMap found," + ." ref_count of SharedCacheMap is ".$CObject->{"ref_count"} + if $CObject->{"ref_count"}; +# if $SectionObjectPointer{$data->{"SectionObjectPointer"}}; + # SharedCacheMap was droppped by async task as it had ref_count==0. + delete_CObject $CObject; + $SObject->{"SharedCacheMap"}=tohex(0); + # FileObject is still valid! + return; + } + return if !$FileObject{$data->{"FileObject"}}; + return if !(my $FObject=FObject $data->{"FileObject"}); + $SectionObjectPointer=$FObject->{"SectionObjectPointer"}; + return if !(my $SObject=SObject $SectionObjectPointer); + warn "FileObject ".$FObject->{"FileObject"} + ." expected SectionObjectPointer $SectionObjectPointer" + ." but found SectionObjectPointer ".$data->{"SectionObjectPointer"} + if $SectionObjectPointer ne $data->{"SectionObjectPointer"}; + my $SharedCacheMap=$SObject->{"SharedCacheMap"}; + warn "FileObject ".$FObject->{"FileObject"}." SectionObjectPointer ".$SObject->{"SectionObjectPointer"} + ." expected SharedCacheMap $SharedCacheMap" + ." but found SharedCacheMap ".$data->{"SharedCacheMap"} + if $SharedCacheMap ne $data->{"SharedCacheMap"}; + warn "INTERNAL: SharedCacheMap $SharedCacheMap of FileObject ".$FObject->{"FileObject"}." got destroyed" + if !$SharedCacheMap{$SharedCacheMap}; +} + +sub CcInitializeCacheMap($$$$$) +{ +my($FileObject,$AllocationSize,$FileSize,$ValidDataLength,$PinAccess)=@_; + + $ValidDataLength=$FileSize if $ValidDataLength==eval("0x".("F"x8)); + $Object->{"ref_count"}=1; + $Object->{"AllocationSize"}=tohex($AllocationSize); + $Object->{"FileSize"}=tohex($FileSize); + $Object->{"ValidDataLength"}=tohex($ValidDataLength); + $Object->{"map"}=undef(); + $Object->{"pin"}={}; + $Object->{"PinAccess"}=$PinAccess; + $Object->{"FileObject"}=$FileObject; +} + +sub CcInitializeCacheMap_leave() +{ + my $SharedCacheMap=$Object->{"data"}[1]{"SharedCacheMap"}; + $Object->{"SharedCacheMap"}=$SharedCacheMap; + my $old=$SharedCacheMap{$SharedCacheMap}; + if (!SharedCacheMap_valid $Object->{"data"}[0]{"SharedCacheMap"} && $old) { + # SharedCacheMap got deleted in the meantime + delete_CObject CObject $SharedCacheMap; + # Either it got deleted of some foreign SectionObjectPointer + # or of the current one: + if (my $SObject=$SectionObjectPointer{$Object->{"data"}[0]{"SectionObjectPointer"}}) { + $SObject->{"SharedCacheMap"}=tohex(0); + } + $old=undef(); + } + if (!$old != !SharedCacheMap_valid $Object->{"data"}[0]{"SharedCacheMap"}) { + warn "Expecting old SharedCacheMap validity ".(!!$old) + ." but found old SharedCacheMap ".$Object->{"data"}[0]{"SharedCacheMap"}; + } + warn "New SharedCacheMap ".$Object->{"data"}[1]{"SharedCacheMap"}." is not valid" + if !SharedCacheMap_valid $Object->{"data"}[1]{"SharedCacheMap"}; + if (SharedCacheMap_valid $Object->{"data"}[0]{"SharedCacheMap"}) { + warn "Existing SharedCacheMap changed" + ." from ".$Object->{"data"}[0]{"SharedCacheMap"}." to ".$Object->{"data"}[1]{"SharedCacheMap"} + if $Object->{"data"}[0]{"SharedCacheMap"} ne $Object->{"data"}[1]{"SharedCacheMap"}; + } + if ($old) { + for my $field (qw(AllocationSize FileSize PinAccess)) { + warn "SharedCacheMap $SharedCacheMap old instance $field ".$old->{$field} + ." != new instance $field ".$Object->{$field} + if $old->{$field} ne $Object->{$field}; + } + do { warn "Existing map Bcb $_ during CcInitializeCacheMap()" if $_; } for ($old->{"map"}); + do { warn "Existing pin Bcb $_ during CcInitializeCacheMap()" if $_; } for (values(%{$old->{"pin"}})); + $Object->{"ref_count"}+=$old->{"ref_count"}; + } + $SharedCacheMap{$SharedCacheMap}=$Object; + + warn "Changed SectionObjectPointer inside CcInitializeCacheMap()" + ." from ".$Object->{"data"}[0]{"SectionObjectPointer"}." to ".$Object->{"data"}[1]{"SectionObjectPointer"} + if $Object->{"data"}[0]{"SectionObjectPointer"} ne $Object->{"data"}[1]{"SectionObjectPointer"}; + my $SectionObjectPointer=$Object->{"data"}[1]{"SectionObjectPointer"}; + + my $FileObject=$Object->{"FileObject"}; + if (my $FObject=$FileObject{$FileObject}) { + if (my $SObject=$SectionObjectPointer{$FObject->{"SectionObjectPointer"}}) { + warn "Changed SectionObjectPointer of FileObject $FileObject" + ." from ".$FObject->{"SectionObjectPointer"}." to ".$SectionObjectPointer + if $FObject->{"SectionObjectPointer"} ne $SectionObjectPointer; + } + # Otherwise SectionObjectPointer could be deleted and rebuilt async in the meantime. + } + $FileObject{$FileObject}={ + "FileObject"=>$FileObject, + "SectionObjectPointer"=>$SectionObjectPointer, + }; + + if (my $SObject=$SectionObjectPointer{$SectionObjectPointer}) { + warn "Changed SharedCacheMap of SectionObjectPointer $SectionObjectPointer" + ." from ".$SObject->{"SharedCacheMap"}." to ".$SharedCacheMap + if $SObject->{"SharedCacheMap"} ne $SharedCacheMap && eval($SObject->{"SharedCacheMap"}); + } + $SectionObjectPointer{$SectionObjectPointer}={ + "SectionObjectPointer"=>$SectionObjectPointer, + "SharedCacheMap"=>$SharedCacheMap, + }; + + CcSetFileSizes($FileObject,map({ eval($Object->{$_}); } qw(AllocationSize FileSize ValidDataLength))); + delete $Object->{$_} for (qw(FileObject ValidDataLength)); +} + +sub CcUninitializeCacheMap($$) +{ +my($FileObject,$TruncateSize)=@_; + + $Object->{"FileObject"}=$FileObject; +} + +sub CcUninitializeCacheMap_leave($) +{ +my($r)=@_; + + my $FileObject=$Object->{"FileObject"}; + # 'r' means function success. + # r=0 either if no CcInitializeCacheMap() was called at all + # or if Cc was unable to detach SharedCacheMap and it remains valid + # (FIXME: Do we SharedCacheMap->ref_count-- on in such case?). + my $SectionObjectPointer=$FileObject{$FileObject}->{"SectionObjectPointer"} if $FileObject{$FileObject}; + my $SharedCacheMap=$SectionObjectPointer{$SectionObjectPointer}->{"SharedCacheMap"} + if $SectionObjectPointer && $SectionObjectPointer{$SectionObjectPointer}; + warn "Unexpected 'r' result $r for CcUninitializeCacheMap of FileObject $FileObject" + if !(eval($SharedCacheMap) && !SharedCacheMap_valid($Object->{"data"}[1]{"SharedCacheMap"})) != !$r; + if (!eval $SharedCacheMap) { + for my $SharedCacheMap ($Object->{"data"}[0]{"SharedCacheMap"},$Object->{"data"}[1]{"SharedCacheMap"}) { + warn "Not expecting valid SharedCacheMap $SharedCacheMap" + if SharedCacheMap_valid $SharedCacheMap; + } + return; + } + for my $SharedCacheMap ($Object->{"data"}[0]{"SharedCacheMap"}) { + warn "Expecting valid SharedCacheMap $SharedCacheMap" + if !SharedCacheMap_valid $SharedCacheMap; + } + return if !(my $FObject=FObject $FileObject); + return if !(my $SObject=SObject $FObject->{"SectionObjectPointer"}); + return if !(my $CObject=CObject $SObject->{"SharedCacheMap"}); + if (--$CObject->{"ref_count"}) { + for my $SharedCacheMap ($Object->{"data"}[1]{"SharedCacheMap"}) { + warn "Expecting still valid SharedCacheMap $SharedCacheMap after CcUninitializeCacheMap()" + ." with ref_count=".$CObject->{"ref_count"} + if !SharedCacheMap_valid $SharedCacheMap; + } + return; + } + if (!SharedCacheMap_valid $Object->{"data"}[1]{"SharedCacheMap"}) { + delete_CObject $CObject; + $SObject->{"SharedCacheMap"}=tohex(0); + # FileObject is still valid! + } + else { + # FIXME: Do we SharedCacheMap->ref_count-- on in such case? + } +} + +sub CcSetFileSizes($$$$) +{ +my($FileObject,$AllocationSize,$FileSize,$ValidDataLength)=@_; + + return if !(my $CObject=CObject_from_FileObject $FileObject); + my $SharedCacheMap=$CObject->{"SharedCacheMap"}; + if ($AllocationSize!=eval($CObject->{"AllocationSize"})) { + do { warn "Existing map $_ of FileObject $FileObject SharedCacheMap $SharedCacheMap during CcSetAllocationSizes()," + ." AllocationSize=".$CObject->{"AllocationSize"} if $_; } + for ($CObject->{"map"}); + do { warn "Existing pin $_ of FileObject $FileObject SharedCacheMap $SharedCacheMap during CcSetAllocationSizes()," + ." AllocationSize=".$CObject->{"AllocationSize"} if $_; } + for (values(%{$CObject->{"pin"}})); + # Do not: delete $CObject->{"in_memory"}; + # as its keep is required by W32. Squeeze it instead: + $CObject->{"in_memory"}={ map({ + (eval($_)<$AllocationSize ? ($_=>1) : ()); + } keys(%{$CObject->{"in_memory"}})) }; + } + # $ValidDataLength can be > $CObject->{"FileSize"}; + warn "ValidDataLength ".tohex($ValidDataLength)." > FileSize ".tohex($FileSize) + if $ValidDataLength>$FileSize; + warn "0 != AllocationSize ".tohex($AllocationSize)." % ntfs_blocksize ".tohex($ntfs_blocksize) + if 0!=($AllocationSize%$ntfs_blocksize); + # $AllocationSize can be higher + warn "FileSize ".tohex($FileSize)." > AllocationSize ".tohex($AllocationSize) + if $FileSize>$AllocationSize; + $CObject->{"FileSize"}=tohex($FileSize); + $CObject->{"AllocationSize"}=tohex($AllocationSize); + delete $CObject->{"Buffer"} if !eval $AllocationSize; +} + +sub IRP_MJ_CREATE_leave() +{ + do { warn "Non-NULL SectionObjectPointer $_ not expected" if eval($_); } for ($Object->{"data"}[0]{"SectionObjectPointer"}); + my $FileObject=$Object->{"data"}[0]{"FileObject"}; + warn "Existing FileObject $FileObject not expected" if $FileObject{$FileObject}; + my $SectionObjectPointer=$Object->{"data"}[1]{"SectionObjectPointer"}; + # We want to track even FileObject without SectionObjectPointer yet. +# if ($SectionObjectPointer && $SectionObjectPointer{$SectionObjectPointer}) + { + $FileObject{$FileObject}={ + "FileObject"=>$FileObject, + "SectionObjectPointer"=>$SectionObjectPointer, + }; + } + if (eval $SectionObjectPointer) { + my $SharedCacheMap=$Object->{"data"}[1]{"SharedCacheMap"}; + if (my $SObject=$SectionObjectPointer{$SectionObjectPointer}) { + warn "Changed SharedCacheMap from stored ".$SObject->{"SharedCacheMap"}." to ".$SharedCacheMap + if $SObject->{"SharedCacheMap"} ne $SharedCacheMap && $Object->{"by"} ne "IRP_MJ_CREATE"; + } + $SectionObjectPointer{$SectionObjectPointer}={ + "SectionObjectPointer"=>$SectionObjectPointer, + "SharedCacheMap"=>$SharedCacheMap, + }; + } +} + +sub BObject($) +{ +my($Bcb)=@_; + + cluck if !defined $Bcb; + my $BObject=$Bcb{$Bcb}; + if (!$BObject) { + my($package,$filename,$line,$subroutine)=caller 0; + warn "Non-existent Bcb $Bcb by line $line" + } + return $BObject; +} + +sub delete_BObject($) +{ +my($BObject)=@_; + + my $Bcb=$BObject->{"Bcb"}; +# warn "XXX delete_BObject 0x811799B8 line $. BObject=".Dumper $BObject if $Bcb eq "0x811799B8"; + warn "Deleting ref_count=".$BObject->{"ref_count"}." Bcb $Bcb" if $BObject->{"ref_count"}; + # Do not: warn "Deleting dirty Bcb $Bcb" if $BObject->{"dirty"}; + # as it is valid to allow sanity check below. + warn "Deleting dirty Bcb $Bcb" if $BObject->{"dirty"} && $BObject->{"ref_count"}; + return if !(my $CObject=CObject $BObject->{"SharedCacheMap"}); + if ($BObject->{"type"} eq "map") { + for my $pin (values(%{$CObject->{"pin"}})) { + next if !defined $pin; + warn "unpin map but CcPinMappedData pin $pin still exists" + if $Bcb{$pin}->{"by"} eq "CcPinMappedData"; + } + } + else { + warn "unpin of pin Bcb $Bcb of SharedCacheMap ".$CObject->{"SharedCacheMap"} + ." although FileOffset ".$BObject->{"FileOffset"}." not in_memory" + if !($CObject->{"in_memory"}{$BObject->{"FileOffset"}}); + # Do not: delete $CObject->{"in_memory"}{$BObject->{"FileOffset"}}; + # as Cache Manager is not forced to drop it. +# warn "UNMARK: SharedCacheMap ".$CObject->{"SharedCacheMap"}." FileOffset ".$BObject->{"FileOffset"}; + } + for my $ref ($BObject->{"type"} eq "map" ? \$CObject->{"map"} : \$CObject->{"pin"}{$BObject->{"FileOffset"}}) { + warn "Final unpin but ".$BObject->{"type"}." Bcb $Bcb not registered" + ." in SharedCacheMap ".$CObject->{"SharedCacheMap"}." ref ".($$ref || "") + if !defined($BObject->{"OwnerPointer"}) && !($$ref && $$ref eq $Bcb) + && !($BObject->{"ref_count"}==0 && $BObject->{"dirty"}); + if ($$ref && $$ref eq $Bcb) { + $$ref=undef(); + # Do not: delete $CObject->{"pin"}{$BObject->{"FileOffset"}} if $BObject->{"type"} eq "pin"; + # as it would destroy $$ref slot in &Bcb_checkref '($$ref && $Bcb ne $$ref)' codepath. + } + } + delete $Bcb{$Bcb}; +# warn "XXX delete_BObject 0x811799B8 line $. CObject=".Dumper $CObject if $Bcb eq "0x811799B8"; + CObject_Buffer_check($CObject); +} + +sub MObject($) +{ +my($MdlChain)=@_; + + cluck if !defined $MdlChain; + my $MObject=$MdlChain{$MdlChain}; + warn "Non-existent MdlChain $MdlChain" if !$MObject; + return $MObject; +} + +sub CObject_Buffer_check($) +{ +my($CObject)=@_; + + my $any; + for my $BObject ($CObject->{"map"},values(%{$CObject->{"pin"}})) { + # There may exist OwnerPointer-ed or dirty&unreffed standalone Bcbs bound to this SharedCacheMap + # but these are not important for Buffer reset. + next if !$BObject; + $any=1; + last; + } + if (!$any) { + delete $CObject->{"Buffer"}; + } +} + +sub Bcb_conflict($;@) +{ +my($CObject,@Bcb_list)=@_; + + my $arg=0; + my %check=( + "map"=>$CObject->{"map"}, + map(("arg".($arg++)=>$_),@Bcb_list), + %{$CObject->{"pin"}}, + ); + my %reversed; + my $BufferBase; # relativized to FileOffset 0 + my $BufferBase_val; + if ($CObject->{"Buffer"}) { + $BufferBase=eval $CObject->{"Buffer"}; + $BufferBase_val="SharedCacheMap Buffer"; + } + while (my($key,$val)=each(%check)) { + next if !defined $val; + warn "Conflicting Bcb $val of keys $key and ".$reversed{$val}." of SharedCacheMap ".$CObject->{"SharedCacheMap"} + if $reversed{$val}; + # Buffer base should match even between 'map's and 'pin's + # as the data are always mapped only once. + my $BObject=$Bcb{$val}; + warn "Non-existent key=$key Bcb $val" +# ." XXX line $. CObject=".Dumper $CObject + if !$BObject; + if ($BObject) { + my $Buffer=eval $BObject->{"Buffer"}; + $Buffer-=eval($BObject->{"FileOffset"}) if exists $BObject->{"FileOffset"}; + warn "INTERNAL: Non page aligned Buffer ".tohex($Buffer)." of Bcb $val" + if $Buffer & 0xFFF; + warn "Non-matching Bcb ".$BObject->{"type"}." $val Buffer base ".tohex($Buffer) + ." with".($BufferBase_val=~/^SharedCacheMap / ? "" : " Bcb ".$Bcb{$BufferBase_val}->{"type"}) + ." $BufferBase_val BufferBase ".tohex($BufferBase)."; SharedCacheMap=".$CObject->{"SharedCacheMap"} +# ." XXX line $. ".Dumper($CObject,\%Bcb) + if defined($BufferBase) && $Buffer!=$BufferBase; + $BufferBase=$Buffer; + $BufferBase_val=$val; + } + $reversed{$val}=$key; + } +} + +# New $BObject will always be forced as the last stored reference. +sub Bcb_checkref($$) +{ +my($BObject,$ref)=@_; + + return if !(my $CObject=CObject $BObject->{"SharedCacheMap"}); + my $type=$BObject->{"type"}; + my $Bcb=$BObject->{"Bcb"}; + if ($$ref && $Bcb ne $$ref) { + my $BObject2=$Bcb{$$ref}; + warn "new $type Bcb $Bcb != old ".$BObject2->{"type"}." Bcb $$ref"; + delete_BObject $BObject2; + } + if ($Bcb{$Bcb}) { + my $BObject2=$Bcb{$Bcb}; + warn "new $type $Bcb type ".$BObject->{"type"}." != old type $type $Bcb type ".$BObject2->{"type"} + if $BObject->{"type"} ne $BObject2->{"type"}; + warn "new $type $Bcb Buffer ".($BObject->{"Buffer"} || "") + ." != old $type $Bcb Buffer ".($BObject2->{"Buffer"} || "") +# ." XXX line $. ".Dumper($BObject,$BObject2) + if $BObject->{"Buffer"} ne $BObject2->{"Buffer"}; + } + if ($Bcb{$Bcb}) { + warn "Equal Bcb?" if $Bcb{$Bcb} eq $BObject; + $Bcb{$Bcb}->{"ref_count"}+=$BObject->{"ref_count"}; + $BObject=$Bcb{$Bcb}; + } + $Bcb{$Bcb}=$BObject; # &Bcb_conflict needs this reference + Bcb_conflict $CObject,($$ref && $$ref eq $Bcb ? () : ($Bcb)); + $$ref=$Bcb; +} + +sub map_new($;$$) +{ +my($SharedCacheMap,$FileOffset,$Length)=@_; + + return if !(my $CObject=CObject $SharedCacheMap); + if (defined($FileOffset) && defined($Length)) { + warn "Mapping data (end ".tohex($FileOffset+$Length).") out of FileSize ".$CObject->{"FileSize"} + if $FileOffset+$Length>eval($CObject->{"FileSize"}); + } + $Object->{"SharedCacheMap"}=$CObject->{"SharedCacheMap"}; + if (defined $FileOffset) { + $Object->{"FileOffset"}=tohex($FileOffset); + } + $Object->{"type"}="map"; + $Object->{"ref_count"}=1; +} + +sub map_new_from_FileObject($;$$) +{ +my($FileObject,$FileOffset,$Length)=@_; + + return if !(my $CObject=CObject_from_FileObject $FileObject); + map_new $CObject->{"SharedCacheMap"},$FileOffset,$Length; +} + +sub map_new_leave($;$) +{ +my($Bcb,$Buffer)=@_; + + $Object->{"Bcb"}=$Bcb; + return if !(my $CObject=CObject $Object->{"SharedCacheMap"}); + + if (defined $Buffer) { + $Object->{"Buffer"}=tohex(eval($Buffer)-(eval($Object->{"FileOffset"}) || 0)); + } + delete $Object->{"FileOffset"}; + $CObject->{"Buffer"}=$Object->{"Buffer"} if !$CObject->{"Buffer"}; + warn "Unknown Buffer during map_new_leave" if !$Object->{"Buffer"}; + + my $ref=\$CObject->{"map"}; + # There may exist some pin bcbs even if we are creating the new map bcb. + Bcb_checkref $Object,$ref; +} + +sub CcMapData($$$) +{ +my($FileObject,$FileOffset,$Length)=@_; + + map_new_from_FileObject $FileObject,$FileOffset,$Length; +} + +sub CcMapData_leave($$) +{ +my($Bcb,$Buffer)=@_; + + map_new_leave $Bcb,$Buffer; +} + +sub pin_new($$$) +{ +my($FileObject,$FileOffset,$Length)=@_; + + return if !(my $CObject=CObject_from_FileObject $FileObject); + warn "Pinning of non-PinAccess FileObject $FileObject" if !$CObject->{"PinAccess"}; + warn "Mapping data (end ".tohex($FileOffset+$Length).") out of FileSize ".$CObject->{"FileSize"} + if $FileOffset+$Length>eval($CObject->{"FileSize"}); + warn "Pinning Length ".tohex($Length)." > 0x1000" if $Length>0x1000; + warn "Pinning across file page (start=".tohex($FileOffset).",end-1=".tohex($FileOffset+$Length-1).")" + if ($FileOffset&~0xFFF)!=(($FileOffset+$Length-1)&~0xFFF); + $Object->{"SharedCacheMap"}=$CObject->{"SharedCacheMap"}; + $Object->{"FileOffset"}=tohex($FileOffset); + $Object->{"type"}="pin"; + $Object->{"ref_count"}=1; +} + +sub pin_new_leave($$) +{ +my($Bcb,$Buffer)=@_; + + $Object->{"Bcb"}=$Bcb; + return if !(my $CObject=CObject $Object->{"SharedCacheMap"}); + $Object->{"Buffer"}=tohex(eval($Buffer)-(eval($Object->{"FileOffset"})&0xFFF)); + my $shift=eval($Object->{"FileOffset"})&0xFFF; + $Object->{"FileOffset"}=tohex(eval($Object->{"FileOffset"})-$shift); + $Object->{"Buffer"}=tohex(eval($Buffer)-$shift); + + my $Buffer_base=tohex(eval($Object->{"Buffer"})-eval($Object->{"FileOffset"})); + $CObject->{"Buffer"}=$Buffer_base if !$CObject->{"Buffer"}; + + warn "pin_new_leave() while FileOffset ".$Object->{"FileOffset"}." not in_memory" + ." of SharedCacheMap ".$CObject->{"SharedCacheMap"} + if !$CObject->{"in_memory"}{$Object->{"FileOffset"}}; + + my $ref=\$CObject->{"pin"}{$Object->{"FileOffset"}}; + # There may not exist map bcb even if we are creating the new pin bcb. + Bcb_checkref $Object,$ref; +# warn "XXX pin_new_leave line $. BObject=".Dumper $Object if $Bcb eq "0x811799B8"; +} + +sub CcPinRead($$$) +{ +my($FileObject,$FileOffset,$Length)=@_; + + pin_new $FileObject,$FileOffset,$Length; +} + +sub CcPinRead_leave($$) +{ +my($Bcb,$Buffer)=@_; + + pin_new_leave $Bcb,$Buffer; +} + +sub CcPreparePinWrite($$$) +{ +my($FileObject,$FileOffset,$Length)=@_; + + return if !(my $CObject=CObject_from_FileObject $FileObject); + # Full pages do not need to be read: + if (!($FileOffset&0xFFF)) { + $CObject->{"in_memory"}{tohex $FileOffset}=1; + } + + pin_new $FileObject,$FileOffset,$Length; +} + +sub CcPreparePinWrite_leave($$) +{ +my($Bcb,$Buffer)=@_; + + pin_new_leave $Bcb,$Buffer; + my $BObject=BObject $Bcb; + $BObject->{"dirty"}=1; +} + +sub CcPinMappedData($$$) +{ +my($FileObject,$FileOffset,$Length)=@_; + + pin_new $FileObject,$FileOffset,$Length; +} + +sub CcPinMappedData_leave($) +{ +my($Bcb)=@_; + + return if !(my $CObject=CObject $Object->{"SharedCacheMap"}); + # Do not: do { warn "CcPinMappedData() with Bcb $Bcb on non-CcMapData()ed SharedCacheMap ".$CObject->{"SharedCacheMap"}; return; } + # if !$CObject->{"map"}; + # as the only requirement of CcPinMappedData() is to have all the pages already 'in_memory'. + my $Buffer=$CObject->{"Buffer"}; + warn "SharedCacheMap ".$CObject->{"SharedCacheMap"}." Buffer not known during CcPinMappedData()" + if !$Buffer; + $Buffer=tohex(eval($Buffer)+eval($Object->{"FileOffset"})) if $Buffer; + +# my $Bcb2=$CObject->{"pin"}{tohex(eval($Object->{"FileOffset"})&~0xFFF)}; +# my $BObject2=BObject $Bcb2 if $Bcb2; + + pin_new_leave $Bcb,$Buffer; +} + +sub CcSetDirtyPinnedData($$) +{ +my($Bcb,$Lsn)=@_; + + return if !(my $BObject=BObject $Bcb); + # Do not: warn "Lsn already set for Bcb $Bcb as ".$BObject->{"Lsn"}." while current Lsn=$Lsn" if $BObject->{"Lsn"}; + # as it is permitted. + warn "Lsn goes backward for Bcb $Bcb old Lsn ".$BObject->{"Lsn"}." to a new Lsn=$Lsn" + if $BObject->{"Lsn"} && eval($BObject->{"Lsn"})>eval($Lsn); + $BObject->{"Lsn"}=$Lsn if $Lsn ne "0x".("F"x8); + $BObject->{"dirty"}=1; + return if !(my $CObject=CObject $BObject->{"SharedCacheMap"}); +} + +sub FlushToLsnRoutine($$) +{ +my($LogHandle,$Lsn)=@_; + + $Object->{"LogHandle"}=$LogHandle; + $Object->{"Lsn"}=$Lsn; + + my $obj=${$EnterLeave}[$#$EnterLeave-1]; + warn "FLUSH" if $obj->{"by"} eq "CcFlushCache"; +} + +my $LogHandle_static; +sub CcSetLogHandleForFile($$$) +{ +my($FileObject,$LogHandle,$FlushToLsnRoutine)=@_; + + return if !(my $CObject=CObject_from_FileObject $FileObject); + warn "LogHandle ".$CObject->{"LogHandle"}." already exists for SharedCacheMap ".$CObject->{"SharedCacheMap"} + if $CObject->{"LogHandle"}; + return if !eval $LogHandle; # $LogHandle may be "0x0" + # ntfs.sys uses single LogHandle for its whole session: + warn "Non-unique LogHandle $LogHandle while last LogHandle was $LogHandle_static" + if $LogHandle_static && $LogHandle ne $LogHandle_static; + $CObject->{"LogHandle"}=$LogHandle; + if (!$LogHandle{$LogHandle}) { + $LogHandle{$LogHandle}={ + "LogHandle"=>$LogHandle, + }; + } +} + +sub IRP_MJ_WRITE_leave_page($$) +{ +my($ByteOffset,$Lsn_check)=@_; + + my $SharedCacheMap=$Object->{"data"}[0]{"SharedCacheMap"}; + return if !(my $CObject=CObject $SharedCacheMap); + my $FlushToLsnRoutine=$LastLeave if $LastLeave->{"by"} eq "FlushToLsnRoutine"; + # Do not: my $Bcb=$CObject->{"pin"}{$ByteOffset}; + # as Bcbs with $BObject->{"OwnerPointer"} are no longer stored in $CObject->{"pin"}. + my @Bcbs; + for my $Bcb (keys(%Bcb)) { + my $BObject=BObject $Bcb; + if (1 + && $BObject->{"type"} eq "pin" + && $BObject->{"SharedCacheMap"} eq $SharedCacheMap + && $BObject->{"FileOffset"} eq $ByteOffset) { + push @Bcbs,$Bcb; + } + } + if (!@Bcbs) { + do { + warn "Non-Bcb IRP_MJ_WRITE ByteOffset=$ByteOffset as non-toplevel function" + ." (".join(",",map({ $_->{"line_enter"}.":".$_->{"by"}; } @$EnterLeave)).")"; +# warn Dumper $CObject; + # Direct IRP_MJ_WRITE can be from callbacked 'FlushToLsnRoutine'. + # It can occur even from other callbacks ('DirtyPageRoutine' etc.) + # but it was not needed here yet. + } if @$EnterLeave && !(${$EnterLeave}[$#$EnterLeave]->{"by"}=~/^(?:FlushToLsnRoutine\b|IRP_MJ_)/); + warn "Non-Bcb IRP_MJ_WRITE ByteOffset=$ByteOffset but FlushToLsnRoutine was preceding" + if $FlushToLsnRoutine; + return; + } + $CObject->{"in_memory"}{$ByteOffset}=1; + warn "Ambiguous matching Bcbs ".join(",",@Bcbs) + ." to SharedCacheMap $SharedCacheMap WRITE ByteOffset $ByteOffset" + if @Bcbs>=2; + my $Bcb=$Bcbs[0]; + return if !(my $BObject=BObject $Bcb); + warn "IRP_MJ_WRITE on non-dirty Bcb $Bcb" if !$BObject->{"dirty"}; + if ($FlushToLsnRoutine) { + push @$Lsn_check,{ + "Bcb"=>$Bcb, + "Bcb_Lsn",$BObject->{"Lsn"}, + } if $Lsn_check; + } + else { + warn "Missing preceding FlushToLsnRoutine during IRP_MJ_WRITE of Bcb $Bcb with Lsn ".$BObject->{"Lsn"} + if $BObject->{"Lsn"}; + } + warn "IRP_MJ_WRITE with FlushToLsnRoutine although not in AcquireForLazyWrite or CcFlushCache" + if $FlushToLsnRoutine && !((1==@$EnterLeave && ${$EnterLeave}[0]->{"by"} eq "CcFlushCache") + || (2==@$EnterLeave && ${$EnterLeave}[0]->{"by"}=~/^IRP_MJ_/ + && ${$EnterLeave}[1]->{"by"} eq "CcFlushCache")) + && !($CObject->{"AcquireForLazyWrite"}>=1); + warn "IRP_MJ_WRITE not the toplevel function" + ." (".join(",",map({ $_->{"line_enter"}.":".$_->{"by"}; } @$EnterLeave)).")" + if !(0==@$EnterLeave + || (1==@$EnterLeave && ${$EnterLeave}[0]->{"by"} eq "CcFlushCache") + || (2==@$EnterLeave && ${$EnterLeave}[0]->{"by"}=~/^IRP_MJ_/ + && ${$EnterLeave}[1]->{"by"} eq "CcFlushCache")); + my $CcFlushCache=${$EnterLeave}[$#$EnterLeave]; + if ($CcFlushCache && $CcFlushCache->{"by"} eq "CcFlushCache") { + $CcFlushCache->{"CcFlushCached"}++; + if ($CcFlushCache->{"FileOffset"} ne "0x".("F"x8) || $CcFlushCache->{"Length"} ne "0x0") { + warn "IRP_MJ_WRITE outside of range of active CcFlushCache()" + if eval($ByteOffset)< eval($CcFlushCache->{"FileOffset"}) + || eval($ByteOffset)>=eval($CcFlushCache->{"FileOffset"})+eval($CcFlushCache->{"Length"}); + } + } + # Keep $BObject->{"dirty"} there for &delete_BObject sanity checks. + delete_BObject $BObject if $BObject->{"dirty"} && !$BObject->{"ref_count"}; +} + +sub IRP_MJ_WRITE_leave() +{ + return if !(my $CObject=CObject $Object->{"data"}[0]{"SharedCacheMap"}); + # toplevel IRP_MJ_WRITE has no requirements + return if 0==@$EnterLeave + # We do not need any outer function, just 'AcquireForLazyWrite' is enough + # for flushing Cache Manager buffers by some its LazyWriter task. + && !$CObject->{"AcquireForLazyWrite"}; + do { warn "Length $_ not divisible by 0x1000" if eval($_)%0x1000; } for ($Object->{"WRITE"}{"Length"}); + my @Lsn_check; + for my $reloffs (0..(eval($Object->{"WRITE"}{"Length"})/0x1000)-1) { + IRP_MJ_WRITE_leave_page tohex(eval($Object->{"WRITE"}{"ByteOffset"})+0x1000*$reloffs),\@Lsn_check; + } + + if ($LastLeave->{"by"} eq "FlushToLsnRoutine" && (my $FlushToLsnRoutine=$LastLeave)) { + my $Lsn_max; + for (@Lsn_check) { + my $Lsn=eval $_->{"Bcb_Lsn"}; + $Lsn_max=$Lsn if !defined($Lsn_max) || $Lsn_max<$Lsn; + } + warn "FlushToLsnRoutine of line_enter ".$FlushToLsnRoutine->{"line_enter"} + ." got Lsn ".$FlushToLsnRoutine->{"Lsn"}." although Bcbs have " + .join(",",map({ "(".$_->{"Bcb"}.":".$_->{"Bcb_Lsn"}.")"; } @Lsn_check)) + if tohex($Lsn_max) ne $FlushToLsnRoutine->{"Lsn"}; + } +} + +sub IRP_MJ_READ_leave() +{ + # toplevel IRP_MJ_READ has no requirements + return if 0==@$EnterLeave; + my @stack=map({ $_->{"by"}=~/^IRP_MJ_/ ? () : $_ } @$EnterLeave); + my $opObject=$stack[0] if 1==@stack; + warn "IRP_MJ_READ not the expected function stack" + ." (".join(",",map({ $_->{"line_enter"}.":".$_->{"by"}; } @$EnterLeave)).")" + if !($opObject->{"by"} eq "CcMapData" + || $opObject->{"by"} eq "CcCopyRead" + || $opObject->{"by"} eq "CcMdlRead" + || $opObject->{"by"} eq "CcPinRead"); + if ($opObject->{"by"} eq "CcMdlRead") { + do { warn "Length $_ not divisible by 0x1000" if eval($_)%0x1000; } for ($Object->{"READ"}{"Length"}); + } + else { + do { warn "Length $_ not 0x1000" if eval($_)!=0x1000; } for ($Object->{"READ"}{"Length"}); + } + my $SharedCacheMap=$Object->{"data"}[0]{"SharedCacheMap"}; + return if !(my $CObject=CObject $SharedCacheMap); + for my $reloffs (0..eval($Object->{"READ"}{"Length"})/0x1000-1) { + my $ByteOffset=tohex(eval($Object->{"READ"}{"ByteOffset"})+$reloffs*0x1000); + # Do not: warn "Reading ByteOffset $ByteOffset into SharedCacheMap $SharedCacheMap twice" + # if $CObject->{"in_memory"}{$ByteOffset}; + # as it may be still cached there as Cache Manager is not forced to drop it. + $CObject->{"in_memory"}{$ByteOffset}=1; +# warn "MARK: SharedCacheMap ".$CObject->{"SharedCacheMap"}." FileOffset $ByteOffset"; + } +} + +sub CcPurgeCacheSection($$$$$) +{ +my($SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length,$UninitializeCacheMaps)=@_; + + return if !(my $CObject=CObject $SharedCacheMap); + warn "Unexpected UninitializeCacheMaps $UninitializeCacheMaps" if $UninitializeCacheMaps ne "0"; + my $all=($FileOffset eq "0x".("F"x8) && !eval $Length); + warn "Not yet implemented ranged CcPurgeCacheSection()" if !$all; + do { warn "Existing map Bcb $_ during CcPurgeCacheSection()" if $_; } for ($CObject->{"map"}); + do { warn "Existing pin Bcb $_ during CcPurgeCacheSection()" if $_; } for (values(%{$CObject->{"pin"}})); + # Primary goal of this function: + delete $CObject->{"in_memory"}; + # Really needed: + delete $CObject->{"Buffer"}; +} + +sub CcFlushCache($$$$) +{ +my($SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length)=@_; + + $Object->{"CcFlushCached"}=0; + $Object->{"FileOffset"}=$FileOffset; + $Object->{"Length"}=$Length; +} + +sub CcFlushCache_leave($$) +{ +my($Status,$Information)=@_; + + warn "CcFlushCache() not the toplevel function" + ." (".join(",",map({ $_->{"line_enter"}.":".$_->{"by"}; } @$EnterLeave)).")" + if !(0==@$EnterLeave + || (1==@$EnterLeave && ${$EnterLeave}[0]->{"by"}=~/^IRP_MJ_/)); + if ($Status ne "0x".("F"x8) || $Information ne "0x".("F"x8)) { + warn "Unexpected Status $Status" if eval $Status; + warn "Unexpected Information $Information while CcFlushCached=".$Object->{"CcFlushCached"} + if eval($Information)!=eval($Object->{"CcFlushCached"})*0x1000; + } +} + +sub CcPrepareMdlWrite($$$) +{ +my($FileObject,$FileOffset,$Length)=@_; + + $Object->{"FileObject"}=$FileObject; + warn "FileOffset $FileOffset not divisible by 0x1000" if eval($FileOffset)%0x1000; + $Object->{"FileOffset"}=$FileOffset; + warn "Length $Length not divisible by 0x1000" if eval($Length)%0x1000; + $Object->{"Length"}=$Length; +} + +sub CcPrepareMdlWrite_leave($$$) +{ +my($MdlChain,$Status,$Information)=@_; + + do { warn "Unexpected Status $Status"; return; } if eval $Status; + warn "Unexpected Information $Information" if $Information ne $Object->{"Length"}; + warn "MdlChain $MdlChain already exists" if $MdlChain{$MdlChain}; + $MdlChain{$MdlChain}=$Object; +} + +sub CcMdlWriteComplete($$$) +{ +my($FileObject,$FileOffset,$MdlChain)=@_; + + return if !(my $MObject=MObject $MdlChain); + warn "CcMdlWriteComplete() parameter FileObject $FileObject" + ." not matching MdlChain $MdlChain FileObject ".$MObject->{"FileObject"} + if $FileObject ne $MObject->{"FileObject"}; + warn "CcMdlWriteComplete() parameter FileOffset $FileOffset" + ." not matching MdlChain $MdlChain FileOffset ".$MObject->{"FileOffset"} + if $FileOffset ne $MObject->{"FileOffset"}; + # Propose MdlChain to a simulated Bcb. + # We must split it by pages as pin can be just 0x1000 sized. + return if !(my $CObject=CObject_from_FileObject $MObject->{"FileObject"}); + for my $reloffs (0..eval($MObject->{"Length"})/0x1000-1) { + my $BObject={ %$MObject }; + $BObject->{"Bcb"}="MdlChain $MdlChain reloffs $reloffs"; + $BObject->{"FileOffset"}=tohex(eval($MObject->{"FileOffset"})+$reloffs*0x1000); + $BObject->{"SharedCacheMap"}=$CObject->{"SharedCacheMap"}; + $BObject->{"type"}="pin"; + $BObject->{"ref_count"}=0; + $BObject->{"dirty"}=1; + warn "Bcb ".$BObject->{"Bcb"}." already exists" if $Bcb{$BObject->{"Bcb"}}; + $Bcb{$BObject->{"Bcb"}}=$BObject; + } + delete $MdlChain{$MdlChain}; +} + +sub CcMdlWriteAbort($$) +{ +my($FileObject,$MdlChain)=@_; + + warn "CcMdlWriteAbort() not handled"; +} + +sub AcquireForLazyWrite_leave($) +{ +my($r)=@_; + + warn "Unexpected 'r' $r" if $r ne "1"; + warn "AcquireForLazyWrite() not the toplevel function" if @$EnterLeave; + return if !(my $CObject=CObject $Object->{"data"}[0]{"SharedCacheMap"}); + $CObject->{"AcquireForLazyWrite"}++; +} + +sub ReleaseFromLazyWrite_leave() +{ + warn "ReleaseFromLazyWrite() not the toplevel function" if @$EnterLeave; + return if !(my $CObject=CObject $Object->{"data"}[0]{"SharedCacheMap"}); + warn "Invalid 'AcquireForLazyWrite' value ".$CObject->{"AcquireForLazyWrite"} + if !($CObject->{"AcquireForLazyWrite"}>=1); + $CObject->{"AcquireForLazyWrite"}--; +} + +sub CcRemapBcb($) +{ +my($Bcb)=@_; + + return if !(my $BObject=BObject $Bcb); + map_new $BObject->{"SharedCacheMap"}; + $Object->{"Buffer"}=tohex(eval($BObject->{"Buffer"})-eval($BObject->{"FileOffset"} || 0)); +} + +sub CcRemapBcb_leave($) +{ +my($r)=@_; + + map_new_leave $r; +} + +sub unpin($) +{ +my($Bcb)=@_; + + return if !(my $BObject=BObject $Bcb); + return if --$BObject->{"ref_count"}; + if ($BObject->{"dirty"}) { + # last unpin of unreferenced dirty Bcb will no longer allow reincarnation + # of the same Bcb to the pin map of its SharedCacheMap. + return if !(my $CObject=CObject $BObject->{"SharedCacheMap"}); + warn "unpin() of pin Bcb $Bcb but it is already not registered in SharedCacheMap ".$BObject->{"SharedCacheMap"}." pin map" + if (!$CObject->{"pin"}{$BObject->{"FileOffset"}} || $CObject->{"pin"}{$BObject->{"FileOffset"}} ne $Bcb) + && !$BObject->{"OwnerPointer"}; + delete $CObject->{"pin"}{$BObject->{"FileOffset"}} + if $CObject->{"pin"}{$BObject->{"FileOffset"}} && ($CObject->{"pin"}{$BObject->{"FileOffset"}} eq $Bcb); + CObject_Buffer_check $CObject; + return; + } + delete_BObject $BObject; +} + +sub CcUnpinData($) +{ +my($Bcb)=@_; + + unpin $Bcb; +} + +sub CcUnpinDataForThread($) +{ +my($Bcb)=@_; + + unpin $Bcb; +} + +sub CcSetBcbOwnerPointer($$) +{ +my($Bcb,$OwnerPointer)=@_; + + return if !(my $BObject=BObject $Bcb); + warn "CcSetBcbOwnerPointer() on map Bcb $Bcb" if $BObject->{"type"} ne "pin"; + return if !(my $CObject=CObject $BObject->{"SharedCacheMap"}); + warn "Double CcSetBcbOwnerPointer() on Bcb $Bcb" if defined $BObject->{"OwnerPointer"}; + my $val=$CObject->{"pin"}{$BObject->{"FileOffset"}}; + warn "CcSetBcbOwnerPointer() on unregistered pin Bcb $Bcb" if !$val || $val ne $Bcb; + delete $CObject->{"pin"}{$BObject->{"FileOffset"}} if $val && $val eq $Bcb; + $BObject->{"OwnerPointer"}=$OwnerPointer; + CObject_Buffer_check $CObject; +} + +sub IRP_MJ_CLOSE_leave() +{ + my $FileObject=$Object->{"data"}[0]{"FileObject"}; +# # IRP_MJ_CLOSE of FileObject w/o CcInitializeCacheMap()? +# return if !$FileObject{$FileObject}; + return if !(my $FObject=FObject $FileObject); + if (eval(my $SectionObjectPointer=$FObject->{"SectionObjectPointer"})) { + return if !(my $SObject=SObject $SectionObjectPointer); + my $SharedCacheMap=$SObject->{"SharedCacheMap"}; + if (eval $SharedCacheMap) { + return if !(my $CObject=CObject $SObject->{"SharedCacheMap"}); + # SharedCacheMap may still exist for FCB although this FileObject gets destroyed now. +# warn "SectionObjectPointer $SectionObjectPointer still exists during IRP_MJ_CLOSE" +# ." while SharedCacheMap ".$CObject->{"SharedCacheMap"}." ref_count ".$CObject->{"ref_count"} +# if $SectionObjectPointer && $CObject->{"ref_count"}; + } + } + delete_FObject $FObject; +} + + local $_; my $hex='0x[\dA-F]+'; -my(@lastmap_CcMapData,@lastmap_CcPinRead,@lastmap_CcPreparePinWrite,@lastmap_CcPinMappedData,@lastmap_CcRemapBcb); -my $last_irp_mj; +my %last_irp_mj; while (<>) { chomp; - s#^ *TraceFS[(]($hex)/($hex)[)]: ## or do { print "$_\n" if $filter; next; }; - my($process,$thread)=($1,$2); + s/\r$//; + # We may get some foreign garbage without '\n' before our debug data line: + # Do not use '\bTraceFS' as there really can be precediny _any_ data. + s#^.*?TraceFS[(]($hex/$hex)[)]: ## or do { print "$_\n" if $filter; next; }; + $ProcessThread=$1; - if (my($FileObject,$AllocationSize,$FileSize,$ValidDataLength)= - /^enter: CcInitializeCacheMap: FileObject=($hex),FileSizes,->AllocationSize=($hex),->FileSize=($hex),->ValidDataLength=($hex),PinAccess=([01]),/) { - $AllocationSize=eval($AllocationSize); - $FileSize=eval($FileSize); - 0==($AllocationSize%0x200) or die; - int($AllocationSize/0x200)==int(($FileSize+0x1FF)/0x200) or die; - $ValidDataLength eq "0x".("F"x8) or eval($ValidDataLength)==$FileSize or die; - !exists $init{$FileObject} or die; - $init{$FileObject}={ - "FileObject"=>$FileObject, - "size"=>$FileSize, - "unmaps"=>0, - "maps"=>[], - "line"=>$., - "Bcb_map"=>undef(), - "Bcb_pin"=>{}, + $Object=undef(); + if (/^enter: (\w+)/) { + $Object={}; + $Object->{"by"}=$1; + $Object->{"line_enter"}=$.; + $Object->{"ProcessThread"}=$ProcessThread; + push @{$EnterLeave{$ProcessThread}},$Object; + } + elsif (/^leave: (\w+)/) { + warn "Empty pop stack during 'leave' of $1" if !($Object=pop @{$EnterLeave{$ProcessThread}}); + warn "Non-matching popped 'by' ".$Object->{"by"}." ne current 'leave' $1" + if $Object->{"by"} ne $1; + $Object->{"line_leave"}=$.; + push @{$LastLeave{$ProcessThread}},$Object; + } + elsif (my($FileObject,$FileName,$Flags,$SectionObjectPointer,$SharedCacheMap)= + /^FileObject=($hex): FileName=(?:NULL|'(.*)'),(?:ref=[+-]\d+,)?Flags=($hex),SectionObjectPointer=($hex),->SharedCacheMap=($hex)/) { + my $aref=$EnterLeave{$ProcessThread}; + warn "Empty stack during 'data' line" if !($Object=${$aref}[$#$aref]); + my $data={ + "FileObject"=>$FileObject, + "FileName"=>$FileName, + "Flags"=>$Flags, + "SectionObjectPointer"=>$SectionObjectPointer, + "SharedCacheMap"=>$SharedCacheMap, + "line"=>$., + }; + push @{$Object->{"data"}},$data; + my $isinit={ map(($_=>1),qw( + CcInitializeCacheMap + CcUninitializeCacheMap + IRP_MJ_CREATE + )) }->{$Object->{"by"}}; + check_data $data + if 1==@{$Object->{"data"}} || !$isinit; + if ($isinit) { + # Prevent 'SharedCacheMap' 0->N change by CcInitializeCacheMap() called inside. + for my $ref (@$aref[0..$#$aref-1]) { + $ref->{"data"}[0]->{"SharedCacheMap"}=$SharedCacheMap; + } + } + if (2<=@{$Object->{"data"}}) { + my $data_prev=$Object->{"data"}[$#{$Object->{"data"}}-1]; + for my $field (qw(FileObject FileName Flags),($isinit ? () : qw(SharedCacheMap))) { + next if !defined(my $prev=$data_prev->{$field}); + next if !defined(my $now=$data->{$field}); + my $by=$Object->{"by"}; + if ($field eq "Flags") { + next if $by eq "IRP_MJ_CREATE" && $field eq "Flags"; + my $FO_CLEANUP_COMPLETE=0x4000; + $now=tohex(eval($now)&~$FO_CLEANUP_COMPLETE) if $by eq "IRP_MJ_CLEANUP"; + my $FO_FILE_FAST_IO_READ=0x80000; + $prev=tohex(eval($prev)&~$FO_FILE_FAST_IO_READ) if $by eq "IRP_MJ_CLEANUP"; + $now=tohex(eval($now)&~$FO_FILE_FAST_IO_READ) if $by eq "IRP_MJ_READ" && !(eval($prev)&$FO_FILE_FAST_IO_READ); + my $FO_FILE_MODIFIED=0x1000; + $now=tohex(eval($now)&~$FO_FILE_MODIFIED) if $by eq "IRP_MJ_WRITE" && !(eval($prev)&$FO_FILE_MODIFIED); + my $FO_FILE_SIZE_CHANGED=0x2000; + $prev=tohex(eval($prev)&~$FO_FILE_MODIFIED) + if $by eq "IRP_MJ_SET_INFORMATION" && !(eval($now)&$FO_FILE_MODIFIED); + $prev=tohex(eval($prev)&~$FO_FILE_SIZE_CHANGED) + if $by eq "IRP_MJ_SET_INFORMATION" && !(eval($now)&$FO_FILE_SIZE_CHANGED); + } + next if $by eq "IRP_MJ_CLOSE" && $field eq "FileName"; + $prev=~s#\\$## if $by eq "IRP_MJ_CREATE"; + $prev="\\" if $by eq "IRP_MJ_CREATE" && $prev eq ""; + $prev=~s#:.*## if $by eq "IRP_MJ_CREATE" && $prev ne $now; + next if $field eq "SharedCacheMap" && !SharedCacheMap_valid $prev && !SharedCacheMap_valid $now; + do { warn "Changed data field $field, prev=".$data_prev->{$field}.", now=".$data->{$field}." by $by"; +# print STDERR Dumper $data_prev,$data; + } if $prev ne $now; + } + } + next; + } + elsif (my($op,$ByteOffset,$Length)= + /^(READ|WRITE): ByteOffset=($hex),Length=($hex)/) { + my $aref=$EnterLeave{$ProcessThread}; + warn "Empty stack during 'data' line" if !($Object=${$aref}[$#$aref]); + $Object->{$op}={ + "ByteOffset"=>$ByteOffset, + "Length"=>$Length, }; next; } + + $LastLeave=${$LastLeave{$ProcessThread}}[$#{$LastLeave{$ProcessThread}}-1]; + $EnterLeave=$EnterLeave{$ProcessThread}; + + if (my($r)= + /^leave: IRP_MJ_\w+: r=($hex)/) { + # Failed requests should make no consequences. + next if eval($r); + } + + if (my($FileObject,$AllocationSize,$FileSize,$ValidDataLength,$PinAccess)= + /^enter: CcInitializeCacheMap: FileObject=($hex),FileSizes,->AllocationSize=($hex),->FileSize=($hex),->ValidDataLength=($hex),PinAccess=([01]),/) { + CcInitializeCacheMap $FileObject,eval($AllocationSize),eval($FileSize),eval($ValidDataLength),eval($PinAccess); + next; + } + if (/^leave: CcInitializeCacheMap\b/) { + CcInitializeCacheMap_leave; + next; + } + if (my($FileObject,$TruncateSize)= /^enter: CcUninitializeCacheMap: FileObject=($hex),TruncateSize=($hex),/) { - $TruncateSize=eval($TruncateSize); - next if !exists $init{$FileObject}; - $init{$FileObject}->{"unmaps"}==@{$init{$FileObject}->{"maps"}} or die; - delete $init{$FileObject}; + CcUninitializeCacheMap $FileObject,eval($TruncateSize); + next; + } + if (my($r)= + /^leave: CcUninitializeCacheMap: r=([01])/) { + CcUninitializeCacheMap_leave $r; + next; + } + + if (my($FileObject,$AllocationSize,$FileSize,$ValidDataLength)= + /^enter: CcSetFileSizes: FileObject=($hex),FileSizes,->AllocationSize=($hex),->FileSize=($hex),->ValidDataLength=($hex)/) { + CcSetFileSizes $FileObject,eval($AllocationSize),eval($FileSize),eval($ValidDataLength); + next; + } + + if (/^leave: IRP_MJ_CREATE\b/) { + IRP_MJ_CREATE_leave; + next; + } + + if (/^leave: IRP_MJ_CLOSE\b/) { + IRP_MJ_CLOSE_leave; next; } if (my($FileObject,$FileOffset,$Length)= /^enter: CcMapData: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) { - $FileOffset=eval $FileOffset; - $Length=eval $Length; - die if !(my $reg=$init{$FileObject}); - die if $FileOffset+$Length>$reg->{"size"}; - my $newmap={ - "FileOffset"=>$FileOffset, - "Length"=>$Length, - "init"=>$reg, - "line"=>$., - "by"=>"CcMapData", - }; - push @{$reg->{"maps"}},$newmap; - push @lastmap_CcMapData,$newmap; + CcMapData $FileObject,eval($FileOffset),eval($Length); next; } if (my($Bcb,$Buffer)= /^leave: CcMapData: r=1,Bcb=($hex),Buffer=($hex)/) { - die if !(my $lastmap=pop @lastmap_CcMapData); - $lastmap->{"Bcb"}=$Bcb; - $lastmap->{"Buffer"}=$Buffer; - $lastmap->{"process"}=$process; - $lastmap->{"thread"}=$thread; - $Bcb{$Bcb}=$lastmap->{"init"}; - die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} ne $Bcb; - $lastmap->{"init"}->{"Bcb_map"}=$Bcb; - for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) { - die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb; - } + CcMapData_leave $Bcb,$Buffer; next; } if (my($FileObject,$FileOffset,$Length)= /^enter: CcPinRead: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) { - $FileOffset=eval $FileOffset; - $Length=eval $Length; - die if !(my $reg=$init{$FileObject}); - die if $FileOffset+$Length>$reg->{"size"}; - my $newmap={ - "FileOffset"=>$FileOffset, - "Length"=>$Length, - "init"=>$reg, - "line"=>$., - "by"=>"CcPinRead", - }; - push @{$reg->{"maps"}},$newmap; - push @lastmap_CcPinRead,$newmap; + CcPinRead $FileObject,eval($FileOffset),eval($Length); next; } if (my($Bcb,$Buffer)= /^leave: CcPinRead: r=1,Bcb=($hex),Buffer=($hex)/) { - die if !(my $lastmap=pop @lastmap_CcPinRead); - $lastmap->{"Bcb"}=$Bcb; - $lastmap->{"Buffer"}=$Buffer; - $lastmap->{"process"}=$process; - $lastmap->{"thread"}=$thread; - $Bcb{$Bcb}=$lastmap->{"init"}; - my $myoffs=$lastmap->{"FileOffset"}&~0xFFF; - die if defined $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} && $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} ne $Bcb; - for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) { - next if $pinoffs==$myoffs; - die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb; - } - $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs}=$Bcb; - die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} eq $Bcb; + CcPinRead_leave $Bcb,$Buffer; next; } if (my($FileObject,$FileOffset,$Length)= /^enter: CcPreparePinWrite: FileObject=($hex),FileOffset=($hex),Length=($hex),Zero=([01]),Flags=0x1/) { - $FileOffset=eval $FileOffset; - $Length=eval $Length; - die if !(my $reg=$init{$FileObject}); - die if $FileOffset+$Length>$reg->{"size"}; - my $newmap={ - "FileOffset"=>$FileOffset, - "Length"=>$Length, - "init"=>$reg, - "line"=>$., - "by"=>"CcPreparePinWrite", - }; - push @{$reg->{"maps"}},$newmap; - push @lastmap_CcPreparePinWrite,$newmap; + CcPreparePinWrite $FileObject,eval($FileOffset),eval($Length); next; } if (my($Bcb,$Buffer)= /^leave: CcPreparePinWrite: r=1,Bcb=($hex),Buffer=($hex)/) { - die if !(my $lastmap=pop @lastmap_CcPreparePinWrite); - $lastmap->{"Bcb"}=$Bcb; - $lastmap->{"Buffer"}=$Buffer; - $lastmap->{"process"}=$process; - $lastmap->{"thread"}=$thread; - $Bcb{$Bcb}=$lastmap->{"init"}; - my $myoffs=$lastmap->{"FileOffset"}&~0xFFF; - die if defined $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} && $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} ne $Bcb; - for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) { - next if $pinoffs==$myoffs; - die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb; - } - $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs}=$Bcb; - die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} eq $Bcb; + CcPreparePinWrite_leave $Bcb,$Buffer; next; } if (my($FileObject,$FileOffset,$Length)= /^enter: CcPinMappedData: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) { - $FileOffset=eval $FileOffset; - $Length=eval $Length; - die if !(my $reg=$init{$FileObject}); - die if $FileOffset+$Length>$reg->{"size"}; - my $newmap={ - "FileOffset"=>$FileOffset, - "Length"=>$Length, - "init"=>$reg, - "line"=>$., - "by"=>"CcPinMappedData", - }; - push @{$reg->{"maps"}},$newmap; - push @lastmap_CcPinMappedData,$newmap; + CcPinMappedData $FileObject,eval($FileOffset),eval($Length); next; } - if (my($Bcb,$Buffer)= + if (my($Bcb)= /^leave: CcPinMappedData: r=1,Bcb=($hex)/) { - die if !(my $lastmap=pop @lastmap_CcPinMappedData); - $lastmap->{"Bcb"}=$Bcb; - $lastmap->{"process"}=$process; - $lastmap->{"thread"}=$thread; - $Bcb{$Bcb}=$lastmap->{"init"}; - my $myoffs=$lastmap->{"FileOffset"}&~0xFFF; - die if defined $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} && $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} ne $Bcb; - for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) { - next if $pinoffs==$myoffs; - die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb; - } - $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs}=$Bcb; - die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} eq $Bcb; + CcPinMappedData_leave $Bcb; + next; + } + + if (my($BcbVoid,$Lsn)= + /^enter: CcSetDirtyPinnedData: BcbVoid=($hex),Lsn=($hex)/) { + CcSetDirtyPinnedData $BcbVoid,$Lsn; + next; + } + + if (my($LogHandle,$Lsn)= + /^enter: FlushToLsnRoutine: LogHandle=($hex),Lsn=($hex)/) { + FlushToLsnRoutine $LogHandle,$Lsn; + next; + } + + if (/^leave: IRP_MJ_READ\b/) { + IRP_MJ_READ_leave; + next; + } + + if (my($SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length,$UninitializeCacheMaps)= + /^enter: CcPurgeCacheSection: SectionObjectPointer=($hex),->SharedCacheMap=($hex),FileOffset=($hex),Length=($hex),UninitializeCacheMaps=([01])/) { + CcPurgeCacheSection $SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length,$UninitializeCacheMaps; + next; + } + + if (/^leave: IRP_MJ_WRITE\b/) { + IRP_MJ_WRITE_leave; + next; + } + + if (my($SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length)= + /^enter: CcFlushCache: SectionObjectPointer=($hex),->SharedCacheMap=($hex),FileOffset=($hex),Length=($hex)/) { + CcFlushCache $SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length; + next; + } + + if (my($Status,$Information)= + /^leave: CcFlushCache: IoStatus->Status=($hex),IoStatus->Information=($hex)/) { + CcFlushCache_leave $Status,$Information; + next; + } + + if (my($r)= + /^leave: AcquireForLazyWrite: r=([01])/) { + AcquireForLazyWrite_leave $r; + } + + if (/^leave: ReleaseFromLazyWrite\b/) { + ReleaseFromLazyWrite_leave; + } + + if (my($FileObject,$LogHandle,$FlushToLsnRoutine)= + /^enter: CcSetLogHandleForFile: FileObject=($hex),LogHandle=($hex),FlushToLsnRoutine=($hex)/) { + CcSetLogHandleForFile $FileObject,$LogHandle,$FlushToLsnRoutine; + next; + } + + if (my($FileObject,$FileOffset,$Length)= + /^enter: CcPrepareMdlWrite: FileObject=($hex),FileOffset=($hex),Length=($hex)/) { + CcPrepareMdlWrite $FileObject,$FileOffset,$Length; + next; + } + if (my($MdlChain,$Status,$Information)= + /^leave: CcPrepareMdlWrite: MdlChain=($hex),IoStatus->Status=($hex),IoStatus->Information=($hex)/) { + CcPrepareMdlWrite_leave $MdlChain,$Status,$Information; + next; + } + + if (my($FileObject,$FileOffset,$MdlChain)= + /^enter: CcMdlWriteComplete: FileObject=($hex),FileOffset=($hex),MdlChain=($hex)/) { + CcMdlWriteComplete $FileObject,$FileOffset,$MdlChain; + next; + } + + if (my($FileObject,$MdlChain)= + /^enter: CcMdlWriteAbort: FileObject=($hex),MdlChain=($hex)/) { + CcMdlWriteAbort $FileObject,$MdlChain; next; } if (my($Bcb)= /^enter: CcRemapBcb: Bcb=($hex)/) { - die if !(my $reg=$Bcb{$Bcb}); - my $newmap={ - "remap"=>1, - "Bcb"=>$Bcb, - "init"=>$reg, - "line"=>$., - "by"=>"CcRemapBcb of $Bcb", - }; - push @{$reg->{"maps"}},$newmap; - push @lastmap_CcRemapBcb,$newmap; + CcRemapBcb $Bcb; + next; } if (my($r)= /^leave: CcRemapBcb: r=($hex)/) { - die if !(my $lastmap=pop @lastmap_CcRemapBcb); - $lastmap->{"process"}=$process; - $lastmap->{"thread"}=$thread; - die "CcRemapBcb enterBcb ".$lastmap->{"Bcb"}." != leaveBcb ".$r - if $lastmap->{"Bcb"} ne $r; + CcRemapBcb_leave $r; next; } if (my($Bcb)= - /^enter: CcUnpinData(?:|ForThread): Bcb=($hex)/) { - die if !(my $regbcb=$Bcb{$Bcb}); - $regbcb->{"unmaps"}++; - die if $regbcb->{"unmaps"}>@{$regbcb->{"maps"}}; - if ($regbcb->{"unmaps"}==@{$regbcb->{"maps"}}) { - warn "Full CcUnPinData for FileObject ".$regbcb->{"FileObject"}; -# $regbcb->{"unmaps"}=0; -# $regbcb->{"maps"}=[]; - $regbcb->{"unmaps"}++; - push @{$regbcb->{"maps"}},{ - "unpinned"=>"=========================================", - "line"=>$., - }; - } - $regbcb->{"Bcb_map"}=undef() if $regbcb->{"Bcb_map"} && $regbcb->{"Bcb_map"} eq $Bcb; - for my $pinoffs (keys(%{$regbcb->{"Bcb_pin"}})) { - delete $regbcb->{"Bcb_pin"}->{$pinoffs} if $regbcb->{"Bcb_pin"}->{$pinoffs} eq $Bcb; - } + /^enter: CcUnpinData: Bcb=($hex)/) { + CcUnpinData $Bcb; next; } - - if (my($irp_mj)= - /^enter: (IRP_MJ_.*)/) { - $last_irp_mj=$irp_mj; + if (my($Bcb)= + /^enter: CcUnpinDataForThread: Bcb=($hex)/) { + CcUnpinDataForThread $Bcb; next; } - if (my($FileObject)= - /^debug_irp: IoStackLocation->FileObject=($hex):/) { - next if $last_irp_mj ne "IRP_MJ_CLOSE"; - warn "IRP_MJ_CLOSE: still mapped $FileObject" if $init{$FileObject}->{"unmaps"}!=@{$init{$FileObject}->{"maps"}}; - delete $init{$FileObject}; + if (my($Bcb,$OwnerPointer)= + /^enter: CcSetBcbOwnerPointer: Bcb=($hex),OwnerPointer=($hex)/) { + CcSetBcbOwnerPointer $Bcb,$OwnerPointer; next; } print "$_\n" if $filter; } -for my $key (keys(%init)) { - warn "EXIT: still mapped $key" if $init{$key}->{"unmaps"}!=@{$init{$key}->{"maps"}}; +for my $FileObject (keys(%FileObject)) { + warn "EXIT: still CcInitializeCacheMap FileObject $FileObject"; + next if !(my $FObject=FObject $FileObject); }