+Check CcFlushCache().
[captive.git] / src / TraceFS / checktrace.pl
index 5e7b258..8cdd1ff 100755 (executable)
@@ -73,9 +73,10 @@ my %SharedCacheMap;
 my %Bcb;
 my %MdlChain;
 my %LastLeave; # $ProcessThread=>[$Object,$Object,...]
-my $LastLeave; # ref copy for the current $ProcessThread
+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([\%FileObject,\%SectionObjectPointer,\%SharedCacheMap,\%Bcb],
@@ -727,15 +728,13 @@ my($ByteOffset,$Lsn_check)=@_;
                }
        if (!@Bcbs) {
                do {
-                               warn "Non-Bcb IRP_MJ_WRITE ByteOffset=$ByteOffset but some functions"
-                                               ." (".join(",",map({ $_->{"line_enter"}.":".$_->{"by"}; } @{$EnterLeave{$ProcessThread}})).")"
-                                               ." are nested:";
+                               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{$ProcessThread}}
-                                               && !(${$EnterLeave{$ProcessThread}}[$#{$EnterLeave{$ProcessThread}}]->{"by"} eq "FlushToLsnRoutine");
+                               } if @$EnterLeave && !(${$EnterLeave}[$#$EnterLeave]->{"by"} eq "FlushToLsnRoutine");
                warn "Non-Bcb IRP_MJ_WRITE ByteOffset=$ByteOffset but FlushToLsnRoutine was preceding"
                                if $FlushToLsnRoutine;
                return;
@@ -758,6 +757,21 @@ my($ByteOffset,$Lsn_check)=@_;
                }
        warn "IRP_MJ_WRITE with FlushToLsnRoutine although not in AcquireForLazyWrite"
                        if $FlushToLsnRoutine && !($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"} eq "IRP_MJ_FILE_SYSTEM_CONTROL"
+                                            && ${$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"};
 }
@@ -783,6 +797,30 @@ sub IRP_MJ_WRITE_leave()
                }
 }
 
+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"} eq "IRP_MJ_FILE_SYSTEM_CONTROL"));
+       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)=@_;
@@ -844,12 +882,14 @@ 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);
@@ -1038,6 +1078,7 @@ while (<>) {
                }
 
        $LastLeave=${$LastLeave{$ProcessThread}}[$#{$LastLeave{$ProcessThread}}-1];
+       $EnterLeave=$EnterLeave{$ProcessThread};
 
        if (my($r)=
                        /^leave: IRP_MJ_\w+: r=($hex)/) {
@@ -1143,6 +1184,18 @@ while (<>) {
                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;