4 # Checks assumptions on Cc* (Cache Manager) behaviour by reading TraceFS log
5 # Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; exactly version 2 of June 1991 is required
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 use Carp qw(cluck confess);
28 $Data::Dumper::Sortkeys=1;
29 my $ntfs_blocksize=0x200;
31 # $Object->{"by"}="CcSomeFunction";
32 # $Object->{"line_enter"}=123;
33 # $Object->{"line_leave"}=124;
34 # $Object->{"ProcessThread"}="0x12345678/0x12345678";
35 # $Object->{"data"}[dataline]{"FileObject"}="0x12345678";
36 # $Object->{"data"}[dataline]{"FileName"}="\filename" or undef() if NULL;
37 # $Object->{"data"}[dataline]{"Flags"}="0x40100";
38 # $Object->{"data"}[dataline]{"SectionObjectPointer"}="0x12345678";
39 # $Object->{"data"}[dataline]{"SharedCacheMap"}="0x12345678";
40 # $FileObject{$FileObject}{"FileObject"}="0x12345678";
41 # $FileObject{$FileObject}{"SectionObjectPointer"}="0x12345678";
42 # $SectionObjectPointer{$SectionObjectPointer}{"SectionObjectPointer"}="0x12345678";
43 # $SectionObjectPointer{$SectionObjectPointer}{"SharedCacheMap"}="0x12345678";
44 # $SharedCacheMap{$SharedCacheMap}{"SharedCacheMap"}="0x12345678";
45 # $SharedCacheMap{$SharedCacheMap}{"SectionObjectPointer"}="0x12345678";
46 # $SharedCacheMap{$SharedCacheMap}{"AllocationSize"}="0x12345";
47 # $SharedCacheMap{$SharedCacheMap}{"FileSize"}="0x12345";
48 # $SharedCacheMap{$SharedCacheMap}{"ref_count"}=1;
49 # $SharedCacheMap{$SharedCacheMap}{"map"}="0x12345678" (Bcb);
50 # $SharedCacheMap{$SharedCacheMap}{"pin"}{"0x1000"}="0x12345678" (Bcb) if !Bcb->{"OwnerPointer"};
51 # $SharedCacheMap{$SharedCacheMap}{"PinAccess"}=0 or 1;
52 # $SharedCacheMap{$SharedCacheMap}{"LogHandle"}="0x12345678" optional;
53 # $SharedCacheMap{$SharedCacheMap}{"AcquireForLazyWrite"}=0; # count
54 # $SharedCacheMap{$SharedCacheMap}{"in_memory"}{"0x4000"}=1; # mapped page?
55 # $SharedCacheMap{$SharedCacheMap}{"Buffer"}="0x12345678";
56 # $LogHandle{$LogHandle}{"LogHandle"}="0x12345678";
57 # $Bcb{$Bcb}{"Bcb"}="0x12345678";
58 # $Bcb{$Bcb}{"SharedCacheMap"}="0x12345678";
59 # $Bcb{$Bcb}{"type"}="pin" or "map";
60 # $Bcb{$Bcb}{"ref_count"}=1;
61 # $Bcb{$Bcb}{"FileOffset"}="0x1000" if {"type"} eq "pin";
62 # $Bcb{$Bcb}{"Buffer"}="0x12345678"; # PAGE_SIZE-aligned for "pin", FileOffset_0-aligned for "map"
63 # $Bcb{$Bcb}{"OwnerPointer"}="0x12345678" optional;
64 # $Bcb{$Bcb}{"Lsn"}="0x12345678" optional;
65 # $Bcb{$Bcb}{"dirty"}=1 optional;
66 # $MdlChain{$MdlChain}{"MdlChain"}="0x12345678";
67 # $MdlChain{$MdlChain}{"FileObject"}="0x12345678";
68 # $MdlChain{$MdlChain}{"FileOffset"}="0x5000";
69 # $MdlChain{$MdlChain}{"Length"}="0x9000";
73 my %SectionObjectPointer;
77 my %LastLeave; # $ProcessThread=>[$Object,$Object,...]
78 my $LastLeave; # ref copy of the last item for the current $ProcessThread
81 my $EnterLeave; # ref copy of the list for the current $ProcessThread
84 print Data::Dumper->Dump([\%FileObject,\%SectionObjectPointer,\%SharedCacheMap,\%Bcb],
85 [qw(%FileObject %SectionObjectPointer %SharedCacheMap %Bcb)]) if !$filter;
94 return sprintf("0x%X",$num);
101 my $FObject=$FileObject{$FileObject};
103 my($package,$filename,$line,$subroutine)=caller 0;
104 warn "Non-existent FileObject $FileObject by line $line";
109 sub delete_FObject($)
113 my $FileObject=$FObject->{"FileObject"};
114 delete $FileObject{$FileObject};
119 my($SectionObjectPointer)=@_;
121 my $SObject=$SectionObjectPointer{$SectionObjectPointer};
123 my($package,$filename,$line,$subroutine)=caller 0;
124 warn "Non-existent SectionObjectPointer $SectionObjectPointer by line $line"
129 sub SObject_from_FileObject($)
133 return if !(my $FObject=FObject $FileObject);
134 my $SObject=SObject $FObject->{"SectionObjectPointer"};
136 my($package,$filename,$line,$subroutine)=caller 0;
137 warn "by line $line";
142 sub delete_CObject($)
146 my $SharedCacheMap=$CObject->{"SharedCacheMap"};
147 do { warn "Trailing map $_ of SharedCacheMap $SharedCacheMap during its deletion" if $_; } for ($CObject->{"map"});
148 do { warn "Trailing pin $_ of SharedCacheMap $SharedCacheMap during its deletion" if $_; } for (values(%{$CObject->{"pin"}}));
149 if (my $LogHandle=$CObject->{"LogHandle"}) {
150 do { warn "INTERNAL: Missing LogHandle $LogHandle for SharedCacheMap $SharedCacheMap"; return; }
151 if !(my $LObject=$LogHandle{$LogHandle});
152 # Do not delete $LogHandle as it may be used by many SharedCacheMap-s
154 warn "ref_count=".$CObject->{"ref_count"}." of SharedCacheMap $SharedCacheMap during its deletion"
155 if $CObject->{"ref_count"};
156 delete $SharedCacheMap{$SharedCacheMap};
161 my($SharedCacheMap)=@_;
163 my $CObject=$SharedCacheMap{$SharedCacheMap};
165 my($package,$filename,$line,$subroutine)=caller 0;
166 warn "Non-existent SharedCacheMap $SharedCacheMap by line $line";
171 sub CObject_from_FileObject($)
175 return if !(my $SObject=SObject_from_FileObject $FileObject);
176 return if !(my $CObject=CObject $SObject->{"SharedCacheMap"});
180 sub SharedCacheMap_valid($)
182 my($SharedCacheMap)=@_;
184 cluck if !defined $SharedCacheMap;
185 return 0 if "0x".("F"x8) eq $SharedCacheMap;
186 return 0 if !eval $SharedCacheMap;
194 if (!eval $data->{"SectionObjectPointer"}) {
195 return if $Object->{"by"} eq "IRP_MJ_CREATE"; # SectionObjectPointer is not yet initialized
196 warn "Existing FileObject ".$data->{"FileObject"}." but no SectionObjectPointer found"
197 if $FileObject{$data->{"FileObject"}} && eval($FileObject{$data->{"FileObject"}}{"SectionObjectPointer"});
200 my $SectionObjectPointer=$data->{"SectionObjectPointer"};
201 if (!SharedCacheMap_valid $data->{"SharedCacheMap"} && $SectionObjectPointer{$SectionObjectPointer}) {
202 return if !(my $SObject=SObject $SectionObjectPointer);
203 my $SharedCacheMap=$SObject->{"SharedCacheMap"};
204 return if !eval $SharedCacheMap;
205 my $CObject=CObject $SharedCacheMap;
206 warn "Existing SectionObjectPointer ".$data->{"SectionObjectPointer"}." but no SharedCacheMap found,"
207 ." ref_count of SharedCacheMap is ".$CObject->{"ref_count"}
208 if $CObject->{"ref_count"};
209 # if $SectionObjectPointer{$data->{"SectionObjectPointer"}};
210 # SharedCacheMap was droppped by async task as it had ref_count==0.
211 delete_CObject $CObject;
212 $SObject->{"SharedCacheMap"}=tohex(0);
213 # FileObject is still valid!
216 return if !$FileObject{$data->{"FileObject"}};
217 return if !(my $FObject=FObject $data->{"FileObject"});
218 $SectionObjectPointer=$FObject->{"SectionObjectPointer"};
219 return if !(my $SObject=SObject $SectionObjectPointer);
220 warn "FileObject ".$FObject->{"FileObject"}
221 ." expected SectionObjectPointer $SectionObjectPointer"
222 ." but found SectionObjectPointer ".$data->{"SectionObjectPointer"}
223 if $SectionObjectPointer ne $data->{"SectionObjectPointer"};
224 my $SharedCacheMap=$SObject->{"SharedCacheMap"};
225 warn "FileObject ".$FObject->{"FileObject"}." SectionObjectPointer ".$SObject->{"SectionObjectPointer"}
226 ." expected SharedCacheMap $SharedCacheMap"
227 ." but found SharedCacheMap ".$data->{"SharedCacheMap"}
228 if $SharedCacheMap ne $data->{"SharedCacheMap"};
229 warn "INTERNAL: SharedCacheMap $SharedCacheMap of FileObject ".$FObject->{"FileObject"}." got destroyed"
230 if !$SharedCacheMap{$SharedCacheMap};
233 sub CcInitializeCacheMap($$$$$)
235 my($FileObject,$AllocationSize,$FileSize,$ValidDataLength,$PinAccess)=@_;
237 $ValidDataLength=$FileSize if $ValidDataLength==eval("0x".("F"x8));
238 $Object->{"ref_count"}=1;
239 $Object->{"AllocationSize"}=tohex($AllocationSize);
240 $Object->{"FileSize"}=tohex($FileSize);
241 $Object->{"ValidDataLength"}=tohex($ValidDataLength);
242 $Object->{"map"}=undef();
244 $Object->{"PinAccess"}=$PinAccess;
245 $Object->{"FileObject"}=$FileObject;
248 sub CcInitializeCacheMap_leave()
250 my $SharedCacheMap=$Object->{"data"}[1]{"SharedCacheMap"};
251 $Object->{"SharedCacheMap"}=$SharedCacheMap;
252 my $old=$SharedCacheMap{$SharedCacheMap};
253 if (!SharedCacheMap_valid $Object->{"data"}[0]{"SharedCacheMap"} && $old) {
254 # SharedCacheMap got deleted in the meantime
255 delete_CObject CObject $SharedCacheMap;
256 # Either it got deleted of some foreign SectionObjectPointer
257 # or of the current one:
258 if (my $SObject=$SectionObjectPointer{$Object->{"data"}[0]{"SectionObjectPointer"}}) {
259 $SObject->{"SharedCacheMap"}=tohex(0);
263 if (!$old != !SharedCacheMap_valid $Object->{"data"}[0]{"SharedCacheMap"}) {
264 warn "Expecting old SharedCacheMap validity ".(!!$old)
265 ." but found old SharedCacheMap ".$Object->{"data"}[0]{"SharedCacheMap"};
267 warn "New SharedCacheMap ".$Object->{"data"}[1]{"SharedCacheMap"}." is not valid"
268 if !SharedCacheMap_valid $Object->{"data"}[1]{"SharedCacheMap"};
269 if (SharedCacheMap_valid $Object->{"data"}[0]{"SharedCacheMap"}) {
270 warn "Existing SharedCacheMap changed"
271 ." from ".$Object->{"data"}[0]{"SharedCacheMap"}." to ".$Object->{"data"}[1]{"SharedCacheMap"}
272 if $Object->{"data"}[0]{"SharedCacheMap"} ne $Object->{"data"}[1]{"SharedCacheMap"};
275 for my $field (qw(AllocationSize FileSize PinAccess)) {
276 warn "SharedCacheMap $SharedCacheMap old instance $field ".$old->{$field}
277 ." != new instance $field ".$Object->{$field}
278 if $old->{$field} ne $Object->{$field};
280 do { warn "Existing map Bcb $_ during CcInitializeCacheMap()" if $_; } for ($old->{"map"});
281 do { warn "Existing pin Bcb $_ during CcInitializeCacheMap()" if $_; } for (values(%{$old->{"pin"}}));
282 $Object->{"ref_count"}+=$old->{"ref_count"};
284 $SharedCacheMap{$SharedCacheMap}=$Object;
286 warn "Changed SectionObjectPointer inside CcInitializeCacheMap()"
287 ." from ".$Object->{"data"}[0]{"SectionObjectPointer"}." to ".$Object->{"data"}[1]{"SectionObjectPointer"}
288 if $Object->{"data"}[0]{"SectionObjectPointer"} ne $Object->{"data"}[1]{"SectionObjectPointer"};
289 my $SectionObjectPointer=$Object->{"data"}[1]{"SectionObjectPointer"};
291 my $FileObject=$Object->{"FileObject"};
292 if (my $FObject=$FileObject{$FileObject}) {
293 if (my $SObject=$SectionObjectPointer{$FObject->{"SectionObjectPointer"}}) {
294 warn "Changed SectionObjectPointer of FileObject $FileObject"
295 ." from ".$FObject->{"SectionObjectPointer"}." to ".$SectionObjectPointer
296 if $FObject->{"SectionObjectPointer"} ne $SectionObjectPointer;
298 # Otherwise SectionObjectPointer could be deleted and rebuilt async in the meantime.
300 $FileObject{$FileObject}={
301 "FileObject"=>$FileObject,
302 "SectionObjectPointer"=>$SectionObjectPointer,
305 if (my $SObject=$SectionObjectPointer{$SectionObjectPointer}) {
306 warn "Changed SharedCacheMap of SectionObjectPointer $SectionObjectPointer"
307 ." from ".$SObject->{"SharedCacheMap"}." to ".$SharedCacheMap
308 if $SObject->{"SharedCacheMap"} ne $SharedCacheMap && eval($SObject->{"SharedCacheMap"});
310 $SectionObjectPointer{$SectionObjectPointer}={
311 "SectionObjectPointer"=>$SectionObjectPointer,
312 "SharedCacheMap"=>$SharedCacheMap,
315 CcSetFileSizes($FileObject,map({ eval($Object->{$_}); } qw(AllocationSize FileSize ValidDataLength)));
316 delete $Object->{$_} for (qw(FileObject ValidDataLength));
319 sub CcUninitializeCacheMap($$)
321 my($FileObject,$TruncateSize)=@_;
323 $Object->{"FileObject"}=$FileObject;
326 sub CcUninitializeCacheMap_leave($)
330 my $FileObject=$Object->{"FileObject"};
331 # 'r' means function success.
332 # r=0 either if no CcInitializeCacheMap() was called at all
333 # or if Cc was unable to detach SharedCacheMap and it remains valid
334 # (FIXME: Do we SharedCacheMap->ref_count-- on in such case?).
335 my $SectionObjectPointer=$FileObject{$FileObject}->{"SectionObjectPointer"} if $FileObject{$FileObject};
336 my $SharedCacheMap=$SectionObjectPointer{$SectionObjectPointer}->{"SharedCacheMap"}
337 if $SectionObjectPointer && $SectionObjectPointer{$SectionObjectPointer};
338 warn "Unexpected 'r' result $r for CcUninitializeCacheMap of FileObject $FileObject"
339 if !(eval($SharedCacheMap) && !SharedCacheMap_valid($Object->{"data"}[1]{"SharedCacheMap"})) != !$r;
340 if (!eval $SharedCacheMap) {
341 for my $SharedCacheMap ($Object->{"data"}[0]{"SharedCacheMap"},$Object->{"data"}[1]{"SharedCacheMap"}) {
342 warn "Not expecting valid SharedCacheMap $SharedCacheMap"
343 if SharedCacheMap_valid $SharedCacheMap;
347 for my $SharedCacheMap ($Object->{"data"}[0]{"SharedCacheMap"}) {
348 warn "Expecting valid SharedCacheMap $SharedCacheMap"
349 if !SharedCacheMap_valid $SharedCacheMap;
351 return if !(my $FObject=FObject $FileObject);
352 return if !(my $SObject=SObject $FObject->{"SectionObjectPointer"});
353 return if !(my $CObject=CObject $SObject->{"SharedCacheMap"});
354 if (--$CObject->{"ref_count"}) {
355 for my $SharedCacheMap ($Object->{"data"}[1]{"SharedCacheMap"}) {
356 warn "Expecting still valid SharedCacheMap $SharedCacheMap after CcUninitializeCacheMap()"
357 ." with ref_count=".$CObject->{"ref_count"}
358 if !SharedCacheMap_valid $SharedCacheMap;
362 if (!SharedCacheMap_valid $Object->{"data"}[1]{"SharedCacheMap"}) {
363 delete_CObject $CObject;
364 $SObject->{"SharedCacheMap"}=tohex(0);
365 # FileObject is still valid!
368 # FIXME: Do we SharedCacheMap->ref_count-- on in such case?
372 sub CcSetFileSizes($$$$)
374 my($FileObject,$AllocationSize,$FileSize,$ValidDataLength)=@_;
376 return if !(my $CObject=CObject_from_FileObject $FileObject);
377 my $SharedCacheMap=$CObject->{"SharedCacheMap"};
378 if ($AllocationSize!=eval($CObject->{"AllocationSize"})) {
379 do { warn "Existing map $_ of FileObject $FileObject SharedCacheMap $SharedCacheMap during CcSetAllocationSizes(),"
380 ." AllocationSize=".$CObject->{"AllocationSize"} if $_; }
381 for ($CObject->{"map"});
382 do { warn "Existing pin $_ of FileObject $FileObject SharedCacheMap $SharedCacheMap during CcSetAllocationSizes(),"
383 ." AllocationSize=".$CObject->{"AllocationSize"} if $_; }
384 for (values(%{$CObject->{"pin"}}));
385 # Do not: delete $CObject->{"in_memory"};
386 # as its keep is required by W32. Squeeze it instead:
387 $CObject->{"in_memory"}={ map({
388 (eval($_)<$AllocationSize ? ($_=>1) : ());
389 } keys(%{$CObject->{"in_memory"}})) };
391 # $ValidDataLength can be > $CObject->{"FileSize"};
392 warn "ValidDataLength ".tohex($ValidDataLength)." > FileSize ".tohex($FileSize)
393 if $ValidDataLength>$FileSize;
394 warn "0 != AllocationSize ".tohex($AllocationSize)." % ntfs_blocksize ".tohex($ntfs_blocksize)
395 if 0!=($AllocationSize%$ntfs_blocksize);
396 # $AllocationSize can be higher
397 warn "FileSize ".tohex($FileSize)." > AllocationSize ".tohex($AllocationSize)
398 if $FileSize>$AllocationSize;
399 $CObject->{"FileSize"}=tohex($FileSize);
400 $CObject->{"AllocationSize"}=tohex($AllocationSize);
401 delete $CObject->{"Buffer"} if !eval $AllocationSize;
404 sub IRP_MJ_CREATE_leave()
406 do { warn "Non-NULL SectionObjectPointer $_ not expected" if eval($_); } for ($Object->{"data"}[0]{"SectionObjectPointer"});
407 my $FileObject=$Object->{"data"}[0]{"FileObject"};
408 warn "Existing FileObject $FileObject not expected" if $FileObject{$FileObject};
409 my $SectionObjectPointer=$Object->{"data"}[1]{"SectionObjectPointer"};
410 # We want to track even FileObject without SectionObjectPointer yet.
411 # if ($SectionObjectPointer && $SectionObjectPointer{$SectionObjectPointer})
413 $FileObject{$FileObject}={
414 "FileObject"=>$FileObject,
415 "SectionObjectPointer"=>$SectionObjectPointer,
418 if (eval $SectionObjectPointer) {
419 my $SharedCacheMap=$Object->{"data"}[1]{"SharedCacheMap"};
420 if (my $SObject=$SectionObjectPointer{$SectionObjectPointer}) {
421 warn "Changed SharedCacheMap from stored ".$SObject->{"SharedCacheMap"}." to ".$SharedCacheMap
422 if $SObject->{"SharedCacheMap"} ne $SharedCacheMap && $Object->{"by"} ne "IRP_MJ_CREATE";
424 $SectionObjectPointer{$SectionObjectPointer}={
425 "SectionObjectPointer"=>$SectionObjectPointer,
426 "SharedCacheMap"=>$SharedCacheMap,
435 cluck if !defined $Bcb;
436 my $BObject=$Bcb{$Bcb};
438 my($package,$filename,$line,$subroutine)=caller 0;
439 warn "Non-existent Bcb $Bcb by line $line"
444 sub delete_BObject($)
448 my $Bcb=$BObject->{"Bcb"};
449 # warn "XXX delete_BObject 0x811799B8 line $. BObject=".Dumper $BObject if $Bcb eq "0x811799B8";
450 warn "Deleting ref_count=".$BObject->{"ref_count"}." Bcb $Bcb" if $BObject->{"ref_count"};
451 # Do not: warn "Deleting dirty Bcb $Bcb" if $BObject->{"dirty"};
452 # as it is valid to allow sanity check below.
453 warn "Deleting dirty Bcb $Bcb" if $BObject->{"dirty"} && $BObject->{"ref_count"};
454 return if !(my $CObject=CObject $BObject->{"SharedCacheMap"});
455 if ($BObject->{"type"} eq "map") {
456 for my $pin (values(%{$CObject->{"pin"}})) {
457 next if !defined $pin;
458 warn "unpin map but CcPinMappedData pin $pin still exists"
459 if $Bcb{$pin}->{"by"} eq "CcPinMappedData";
463 warn "unpin of pin Bcb $Bcb of SharedCacheMap ".$CObject->{"SharedCacheMap"}
464 ." although FileOffset ".$BObject->{"FileOffset"}." not in_memory"
465 if !($CObject->{"in_memory"}{$BObject->{"FileOffset"}});
466 # Do not: delete $CObject->{"in_memory"}{$BObject->{"FileOffset"}};
467 # as Cache Manager is not forced to drop it.
468 # warn "UNMARK: SharedCacheMap ".$CObject->{"SharedCacheMap"}." FileOffset ".$BObject->{"FileOffset"};
470 for my $ref ($BObject->{"type"} eq "map" ? \$CObject->{"map"} : \$CObject->{"pin"}{$BObject->{"FileOffset"}}) {
471 warn "Final unpin but ".$BObject->{"type"}." Bcb $Bcb not registered"
472 ." in SharedCacheMap ".$CObject->{"SharedCacheMap"}." ref ".($$ref || "<undef>")
473 if !defined($BObject->{"OwnerPointer"}) && !($$ref && $$ref eq $Bcb)
474 && !($BObject->{"ref_count"}==0 && $BObject->{"dirty"});
475 if ($$ref && $$ref eq $Bcb) {
477 # Do not: delete $CObject->{"pin"}{$BObject->{"FileOffset"}} if $BObject->{"type"} eq "pin";
478 # as it would destroy $$ref slot in &Bcb_checkref '($$ref && $Bcb ne $$ref)' codepath.
482 # warn "XXX delete_BObject 0x811799B8 line $. CObject=".Dumper $CObject if $Bcb eq "0x811799B8";
483 CObject_Buffer_check($CObject);
490 cluck if !defined $MdlChain;
491 my $MObject=$MdlChain{$MdlChain};
492 warn "Non-existent MdlChain $MdlChain" if !$MObject;
496 sub CObject_Buffer_check($)
501 for my $BObject ($CObject->{"map"},values(%{$CObject->{"pin"}})) {
502 # There may exist OwnerPointer-ed or dirty&unreffed standalone Bcbs bound to this SharedCacheMap
503 # but these are not important for Buffer reset.
509 delete $CObject->{"Buffer"};
513 sub Bcb_conflict($;@)
515 my($CObject,@Bcb_list)=@_;
519 "map"=>$CObject->{"map"},
520 map(("arg".($arg++)=>$_),@Bcb_list),
521 %{$CObject->{"pin"}},
524 my $BufferBase; # relativized to FileOffset 0
526 if ($CObject->{"Buffer"}) {
527 $BufferBase=eval $CObject->{"Buffer"};
528 $BufferBase_val="SharedCacheMap Buffer";
530 while (my($key,$val)=each(%check)) {
531 next if !defined $val;
532 warn "Conflicting Bcb $val of keys $key and ".$reversed{$val}." of SharedCacheMap ".$CObject->{"SharedCacheMap"}
534 # Buffer base should match even between 'map's and 'pin's
535 # as the data are always mapped only once.
536 my $BObject=$Bcb{$val};
537 warn "Non-existent key=$key Bcb $val"
538 # ." XXX line $. CObject=".Dumper $CObject
541 my $Buffer=eval $BObject->{"Buffer"};
542 $Buffer-=eval($BObject->{"FileOffset"}) if exists $BObject->{"FileOffset"};
543 warn "INTERNAL: Non page aligned Buffer ".tohex($Buffer)." of Bcb $val"
545 warn "Non-matching Bcb ".$BObject->{"type"}." $val Buffer base ".tohex($Buffer)
546 ." with".($BufferBase_val=~/^SharedCacheMap / ? "" : " Bcb ".$Bcb{$BufferBase_val}->{"type"})
547 ." $BufferBase_val BufferBase ".tohex($BufferBase)."; SharedCacheMap=".$CObject->{"SharedCacheMap"}
548 # ." XXX line $. ".Dumper($CObject,\%Bcb)
549 if defined($BufferBase) && $Buffer!=$BufferBase;
551 $BufferBase_val=$val;
553 $reversed{$val}=$key;
557 # New $BObject will always be forced as the last stored reference.
560 my($BObject,$ref)=@_;
562 return if !(my $CObject=CObject $BObject->{"SharedCacheMap"});
563 my $type=$BObject->{"type"};
564 my $Bcb=$BObject->{"Bcb"};
565 if ($$ref && $Bcb ne $$ref) {
566 my $BObject2=$Bcb{$$ref};
567 warn "new $type Bcb $Bcb != old ".$BObject2->{"type"}." Bcb $$ref";
568 delete_BObject $BObject2;
571 my $BObject2=$Bcb{$Bcb};
572 warn "new $type $Bcb type ".$BObject->{"type"}." != old type $type $Bcb type ".$BObject2->{"type"}
573 if $BObject->{"type"} ne $BObject2->{"type"};
574 warn "new $type $Bcb Buffer ".($BObject->{"Buffer"} || "<undef>")
575 ." != old $type $Bcb Buffer ".($BObject2->{"Buffer"} || "<undef>")
576 # ." XXX line $. ".Dumper($BObject,$BObject2)
577 if $BObject->{"Buffer"} ne $BObject2->{"Buffer"};
580 warn "Equal Bcb?" if $Bcb{$Bcb} eq $BObject;
581 $Bcb{$Bcb}->{"ref_count"}+=$BObject->{"ref_count"};
584 $Bcb{$Bcb}=$BObject; # &Bcb_conflict needs this reference
585 Bcb_conflict $CObject,($$ref && $$ref eq $Bcb ? () : ($Bcb));
591 my($SharedCacheMap,$FileOffset,$Length)=@_;
593 return if !(my $CObject=CObject $SharedCacheMap);
594 if (defined($FileOffset) && defined($Length)) {
595 warn "Mapping data (end ".tohex($FileOffset+$Length).") out of FileSize ".$CObject->{"FileSize"}
596 if $FileOffset+$Length>eval($CObject->{"FileSize"});
598 $Object->{"SharedCacheMap"}=$CObject->{"SharedCacheMap"};
599 if (defined $FileOffset) {
600 $Object->{"FileOffset"}=tohex($FileOffset);
602 $Object->{"type"}="map";
603 $Object->{"ref_count"}=1;
606 sub map_new_from_FileObject($;$$)
608 my($FileObject,$FileOffset,$Length)=@_;
610 return if !(my $CObject=CObject_from_FileObject $FileObject);
611 map_new $CObject->{"SharedCacheMap"},$FileOffset,$Length;
614 sub map_new_leave($;$)
618 $Object->{"Bcb"}=$Bcb;
619 return if !(my $CObject=CObject $Object->{"SharedCacheMap"});
621 if (defined $Buffer) {
622 $Object->{"Buffer"}=tohex(eval($Buffer)-(eval($Object->{"FileOffset"}) || 0));
624 delete $Object->{"FileOffset"};
625 $CObject->{"Buffer"}=$Object->{"Buffer"} if !$CObject->{"Buffer"};
626 warn "Unknown Buffer during map_new_leave" if !$Object->{"Buffer"};
628 my $ref=\$CObject->{"map"};
629 # There may exist some pin bcbs even if we are creating the new map bcb.
630 Bcb_checkref $Object,$ref;
635 my($FileObject,$FileOffset,$Length)=@_;
637 map_new_from_FileObject $FileObject,$FileOffset,$Length;
640 sub CcMapData_leave($$)
644 map_new_leave $Bcb,$Buffer;
649 my($FileObject,$FileOffset,$Length)=@_;
651 return if !(my $CObject=CObject_from_FileObject $FileObject);
652 warn "Pinning of non-PinAccess FileObject $FileObject" if !$CObject->{"PinAccess"};
653 warn "Mapping data (end ".tohex($FileOffset+$Length).") out of FileSize ".$CObject->{"FileSize"}
654 if $FileOffset+$Length>eval($CObject->{"FileSize"});
655 warn "Pinning Length ".tohex($Length)." > 0x1000" if $Length>0x1000;
656 warn "Pinning across file page (start=".tohex($FileOffset).",end-1=".tohex($FileOffset+$Length-1).")"
657 if ($FileOffset&~0xFFF)!=(($FileOffset+$Length-1)&~0xFFF);
658 $Object->{"SharedCacheMap"}=$CObject->{"SharedCacheMap"};
659 $Object->{"FileOffset"}=tohex($FileOffset);
660 $Object->{"type"}="pin";
661 $Object->{"ref_count"}=1;
664 sub pin_new_leave($$)
668 $Object->{"Bcb"}=$Bcb;
669 return if !(my $CObject=CObject $Object->{"SharedCacheMap"});
670 $Object->{"Buffer"}=tohex(eval($Buffer)-(eval($Object->{"FileOffset"})&0xFFF));
671 my $shift=eval($Object->{"FileOffset"})&0xFFF;
672 $Object->{"FileOffset"}=tohex(eval($Object->{"FileOffset"})-$shift);
673 $Object->{"Buffer"}=tohex(eval($Buffer)-$shift);
675 my $Buffer_base=tohex(eval($Object->{"Buffer"})-eval($Object->{"FileOffset"}));
676 $CObject->{"Buffer"}=$Buffer_base if !$CObject->{"Buffer"};
678 warn "pin_new_leave() while FileOffset ".$Object->{"FileOffset"}." not in_memory"
679 ." of SharedCacheMap ".$CObject->{"SharedCacheMap"}
680 if !$CObject->{"in_memory"}{$Object->{"FileOffset"}};
682 my $ref=\$CObject->{"pin"}{$Object->{"FileOffset"}};
683 # There may not exist map bcb even if we are creating the new pin bcb.
684 Bcb_checkref $Object,$ref;
685 # warn "XXX pin_new_leave line $. BObject=".Dumper $Object if $Bcb eq "0x811799B8";
690 my($FileObject,$FileOffset,$Length)=@_;
692 pin_new $FileObject,$FileOffset,$Length;
695 sub CcPinRead_leave($$)
699 pin_new_leave $Bcb,$Buffer;
702 sub CcPreparePinWrite($$$)
704 my($FileObject,$FileOffset,$Length)=@_;
706 return if !(my $CObject=CObject_from_FileObject $FileObject);
707 # Full pages do not need to be read:
708 if (!($FileOffset&0xFFF)) {
709 $CObject->{"in_memory"}{tohex $FileOffset}=1;
712 pin_new $FileObject,$FileOffset,$Length;
715 sub CcPreparePinWrite_leave($$)
719 pin_new_leave $Bcb,$Buffer;
720 my $BObject=BObject $Bcb;
721 $BObject->{"dirty"}=1;
724 sub CcPinMappedData($$$)
726 my($FileObject,$FileOffset,$Length)=@_;
728 pin_new $FileObject,$FileOffset,$Length;
731 sub CcPinMappedData_leave($)
735 return if !(my $CObject=CObject $Object->{"SharedCacheMap"});
736 # Do not: do { warn "CcPinMappedData() with Bcb $Bcb on non-CcMapData()ed SharedCacheMap ".$CObject->{"SharedCacheMap"}; return; }
737 # if !$CObject->{"map"};
738 # as the only requirement of CcPinMappedData() is to have all the pages already 'in_memory'.
739 my $Buffer=$CObject->{"Buffer"};
740 warn "SharedCacheMap ".$CObject->{"SharedCacheMap"}." Buffer not known during CcPinMappedData()"
742 $Buffer=tohex(eval($Buffer)+eval($Object->{"FileOffset"})) if $Buffer;
744 # my $Bcb2=$CObject->{"pin"}{tohex(eval($Object->{"FileOffset"})&~0xFFF)};
745 # my $BObject2=BObject $Bcb2 if $Bcb2;
747 pin_new_leave $Bcb,$Buffer;
750 sub CcSetDirtyPinnedData($$)
754 return if !(my $BObject=BObject $Bcb);
755 # Do not: warn "Lsn already set for Bcb $Bcb as ".$BObject->{"Lsn"}." while current Lsn=$Lsn" if $BObject->{"Lsn"};
756 # as it is permitted.
757 warn "Lsn goes backward for Bcb $Bcb old Lsn ".$BObject->{"Lsn"}." to a new Lsn=$Lsn"
758 if $BObject->{"Lsn"} && eval($BObject->{"Lsn"})>eval($Lsn);
759 $BObject->{"Lsn"}=$Lsn if $Lsn ne "0x".("F"x8);
760 $BObject->{"dirty"}=1;
761 return if !(my $CObject=CObject $BObject->{"SharedCacheMap"});
764 sub FlushToLsnRoutine($$)
766 my($LogHandle,$Lsn)=@_;
768 $Object->{"LogHandle"}=$LogHandle;
769 $Object->{"Lsn"}=$Lsn;
771 my $obj=${$EnterLeave}[$#$EnterLeave-1];
772 warn "FLUSH" if $obj->{"by"} eq "CcFlushCache";
775 my $LogHandle_static;
776 sub CcSetLogHandleForFile($$$)
778 my($FileObject,$LogHandle,$FlushToLsnRoutine)=@_;
780 return if !(my $CObject=CObject_from_FileObject $FileObject);
781 warn "LogHandle ".$CObject->{"LogHandle"}." already exists for SharedCacheMap ".$CObject->{"SharedCacheMap"}
782 if $CObject->{"LogHandle"};
783 return if !eval $LogHandle; # $LogHandle may be "0x0"
784 # ntfs.sys uses single LogHandle for its whole session:
785 warn "Non-unique LogHandle $LogHandle while last LogHandle was $LogHandle_static"
786 if $LogHandle_static && $LogHandle ne $LogHandle_static;
787 $CObject->{"LogHandle"}=$LogHandle;
788 if (!$LogHandle{$LogHandle}) {
789 $LogHandle{$LogHandle}={
790 "LogHandle"=>$LogHandle,
795 sub IRP_MJ_WRITE_leave_page($$)
797 my($ByteOffset,$Lsn_check)=@_;
799 my $SharedCacheMap=$Object->{"data"}[0]{"SharedCacheMap"};
800 return if !(my $CObject=CObject $SharedCacheMap);
801 my $FlushToLsnRoutine=$LastLeave if $LastLeave->{"by"} eq "FlushToLsnRoutine";
802 # Do not: my $Bcb=$CObject->{"pin"}{$ByteOffset};
803 # as Bcbs with $BObject->{"OwnerPointer"} are no longer stored in $CObject->{"pin"}.
805 for my $Bcb (keys(%Bcb)) {
806 my $BObject=BObject $Bcb;
808 && $BObject->{"type"} eq "pin"
809 && $BObject->{"SharedCacheMap"} eq $SharedCacheMap
810 && $BObject->{"FileOffset"} eq $ByteOffset) {
816 warn "Non-Bcb IRP_MJ_WRITE ByteOffset=$ByteOffset as non-toplevel function"
817 ." (".join(",",map({ $_->{"line_enter"}.":".$_->{"by"}; } @$EnterLeave)).")";
818 # warn Dumper $CObject;
819 # Direct IRP_MJ_WRITE can be from callbacked 'FlushToLsnRoutine'.
820 # It can occur even from other callbacks ('DirtyPageRoutine' etc.)
821 # but it was not needed here yet.
822 } if @$EnterLeave && !(${$EnterLeave}[$#$EnterLeave]->{"by"}=~/^(?:FlushToLsnRoutine\b|IRP_MJ_)/);
823 warn "Non-Bcb IRP_MJ_WRITE ByteOffset=$ByteOffset but FlushToLsnRoutine was preceding"
824 if $FlushToLsnRoutine;
827 $CObject->{"in_memory"}{$ByteOffset}=1;
828 warn "Ambiguous matching Bcbs ".join(",",@Bcbs)
829 ." to SharedCacheMap $SharedCacheMap WRITE ByteOffset $ByteOffset"
832 return if !(my $BObject=BObject $Bcb);
833 warn "IRP_MJ_WRITE on non-dirty Bcb $Bcb" if !$BObject->{"dirty"};
834 if ($FlushToLsnRoutine) {
837 "Bcb_Lsn",$BObject->{"Lsn"},
841 warn "Missing preceding FlushToLsnRoutine during IRP_MJ_WRITE of Bcb $Bcb with Lsn ".$BObject->{"Lsn"}
842 if $BObject->{"Lsn"};
844 warn "IRP_MJ_WRITE with FlushToLsnRoutine although not in AcquireForLazyWrite or CcFlushCache"
845 if $FlushToLsnRoutine && !((1==@$EnterLeave && ${$EnterLeave}[0]->{"by"} eq "CcFlushCache")
846 || (2==@$EnterLeave && ${$EnterLeave}[0]->{"by"}=~/^IRP_MJ_/
847 && ${$EnterLeave}[1]->{"by"} eq "CcFlushCache"))
848 && !($CObject->{"AcquireForLazyWrite"}>=1);
849 warn "IRP_MJ_WRITE not the toplevel function"
850 ." (".join(",",map({ $_->{"line_enter"}.":".$_->{"by"}; } @$EnterLeave)).")"
852 || (1==@$EnterLeave && ${$EnterLeave}[0]->{"by"} eq "CcFlushCache")
853 || (2==@$EnterLeave && ${$EnterLeave}[0]->{"by"}=~/^IRP_MJ_/
854 && ${$EnterLeave}[1]->{"by"} eq "CcFlushCache"));
855 my $CcFlushCache=${$EnterLeave}[$#$EnterLeave];
856 if ($CcFlushCache && $CcFlushCache->{"by"} eq "CcFlushCache") {
857 $CcFlushCache->{"CcFlushCached"}++;
858 if ($CcFlushCache->{"FileOffset"} ne "0x".("F"x8) || $CcFlushCache->{"Length"} ne "0x0") {
859 warn "IRP_MJ_WRITE outside of range of active CcFlushCache()"
860 if eval($ByteOffset)< eval($CcFlushCache->{"FileOffset"})
861 || eval($ByteOffset)>=eval($CcFlushCache->{"FileOffset"})+eval($CcFlushCache->{"Length"});
864 # Keep $BObject->{"dirty"} there for &delete_BObject sanity checks.
865 delete_BObject $BObject if $BObject->{"dirty"} && !$BObject->{"ref_count"};
868 sub IRP_MJ_WRITE_leave()
870 return if !(my $CObject=CObject $Object->{"data"}[0]{"SharedCacheMap"});
871 # toplevel IRP_MJ_WRITE has no requirements
872 return if 0==@$EnterLeave
873 # We do not need any outer function, just 'AcquireForLazyWrite' is enough
874 # for flushing Cache Manager buffers by some its LazyWriter task.
875 && !$CObject->{"AcquireForLazyWrite"};
876 do { warn "Length $_ not divisible by 0x1000" if eval($_)%0x1000; } for ($Object->{"WRITE"}{"Length"});
878 for my $reloffs (0..(eval($Object->{"WRITE"}{"Length"})/0x1000)-1) {
879 IRP_MJ_WRITE_leave_page tohex(eval($Object->{"WRITE"}{"ByteOffset"})+0x1000*$reloffs),\@Lsn_check;
882 if ($LastLeave->{"by"} eq "FlushToLsnRoutine" && (my $FlushToLsnRoutine=$LastLeave)) {
885 my $Lsn=eval $_->{"Bcb_Lsn"};
886 $Lsn_max=$Lsn if !defined($Lsn_max) || $Lsn_max<$Lsn;
888 warn "FlushToLsnRoutine of line_enter ".$FlushToLsnRoutine->{"line_enter"}
889 ." got Lsn ".$FlushToLsnRoutine->{"Lsn"}." although Bcbs have "
890 .join(",",map({ "(".$_->{"Bcb"}.":".$_->{"Bcb_Lsn"}.")"; } @Lsn_check))
891 if tohex($Lsn_max) ne $FlushToLsnRoutine->{"Lsn"};
895 sub IRP_MJ_READ_leave()
897 # toplevel IRP_MJ_READ has no requirements
898 return if 0==@$EnterLeave;
899 my @stack=map({ $_->{"by"}=~/^IRP_MJ_/ ? () : $_ } @$EnterLeave);
900 my $opObject=$stack[0] if 1==@stack;
901 warn "IRP_MJ_READ not the expected function stack"
902 ." (".join(",",map({ $_->{"line_enter"}.":".$_->{"by"}; } @$EnterLeave)).")"
903 if !($opObject->{"by"} eq "CcMapData"
904 || $opObject->{"by"} eq "CcCopyRead"
905 || $opObject->{"by"} eq "CcMdlRead"
906 || $opObject->{"by"} eq "CcPinRead");
907 if ($opObject->{"by"} eq "CcMdlRead") {
908 do { warn "Length $_ not divisible by 0x1000" if eval($_)%0x1000; } for ($Object->{"READ"}{"Length"});
911 do { warn "Length $_ not 0x1000" if eval($_)!=0x1000; } for ($Object->{"READ"}{"Length"});
913 my $SharedCacheMap=$Object->{"data"}[0]{"SharedCacheMap"};
914 return if !(my $CObject=CObject $SharedCacheMap);
915 for my $reloffs (0..eval($Object->{"READ"}{"Length"})/0x1000-1) {
916 my $ByteOffset=tohex(eval($Object->{"READ"}{"ByteOffset"})+$reloffs*0x1000);
917 # Do not: warn "Reading ByteOffset $ByteOffset into SharedCacheMap $SharedCacheMap twice"
918 # if $CObject->{"in_memory"}{$ByteOffset};
919 # as it may be still cached there as Cache Manager is not forced to drop it.
920 $CObject->{"in_memory"}{$ByteOffset}=1;
921 # warn "MARK: SharedCacheMap ".$CObject->{"SharedCacheMap"}." FileOffset $ByteOffset";
925 sub CcPurgeCacheSection($$$$$)
927 my($SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length,$UninitializeCacheMaps)=@_;
929 return if !(my $CObject=CObject $SharedCacheMap);
930 warn "Unexpected UninitializeCacheMaps $UninitializeCacheMaps" if $UninitializeCacheMaps ne "0";
931 my $all=($FileOffset eq "0x".("F"x8) && !eval $Length);
932 warn "Not yet implemented ranged CcPurgeCacheSection()" if !$all;
933 do { warn "Existing map Bcb $_ during CcPurgeCacheSection()" if $_; } for ($CObject->{"map"});
934 do { warn "Existing pin Bcb $_ during CcPurgeCacheSection()" if $_; } for (values(%{$CObject->{"pin"}}));
935 # Primary goal of this function:
936 delete $CObject->{"in_memory"};
938 delete $CObject->{"Buffer"};
941 sub CcFlushCache($$$$)
943 my($SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length)=@_;
945 $Object->{"CcFlushCached"}=0;
946 $Object->{"FileOffset"}=$FileOffset;
947 $Object->{"Length"}=$Length;
950 sub CcFlushCache_leave($$)
952 my($Status,$Information)=@_;
954 warn "CcFlushCache() not the toplevel function"
955 ." (".join(",",map({ $_->{"line_enter"}.":".$_->{"by"}; } @$EnterLeave)).")"
957 || (1==@$EnterLeave && ${$EnterLeave}[0]->{"by"}=~/^IRP_MJ_/));
958 if ($Status ne "0x".("F"x8) || $Information ne "0x".("F"x8)) {
959 warn "Unexpected Status $Status" if eval $Status;
960 warn "Unexpected Information $Information while CcFlushCached=".$Object->{"CcFlushCached"}
961 if eval($Information)!=eval($Object->{"CcFlushCached"})*0x1000;
965 sub CcPrepareMdlWrite($$$)
967 my($FileObject,$FileOffset,$Length)=@_;
969 $Object->{"FileObject"}=$FileObject;
970 warn "FileOffset $FileOffset not divisible by 0x1000" if eval($FileOffset)%0x1000;
971 $Object->{"FileOffset"}=$FileOffset;
972 warn "Length $Length not divisible by 0x1000" if eval($Length)%0x1000;
973 $Object->{"Length"}=$Length;
976 sub CcPrepareMdlWrite_leave($$$)
978 my($MdlChain,$Status,$Information)=@_;
980 do { warn "Unexpected Status $Status"; return; } if eval $Status;
981 warn "Unexpected Information $Information" if $Information ne $Object->{"Length"};
982 warn "MdlChain $MdlChain already exists" if $MdlChain{$MdlChain};
983 $MdlChain{$MdlChain}=$Object;
986 sub CcMdlWriteComplete($$$)
988 my($FileObject,$FileOffset,$MdlChain)=@_;
990 return if !(my $MObject=MObject $MdlChain);
991 warn "CcMdlWriteComplete() parameter FileObject $FileObject"
992 ." not matching MdlChain $MdlChain FileObject ".$MObject->{"FileObject"}
993 if $FileObject ne $MObject->{"FileObject"};
994 warn "CcMdlWriteComplete() parameter FileOffset $FileOffset"
995 ." not matching MdlChain $MdlChain FileOffset ".$MObject->{"FileOffset"}
996 if $FileOffset ne $MObject->{"FileOffset"};
997 # Propose MdlChain to a simulated Bcb.
998 # We must split it by pages as pin can be just 0x1000 sized.
999 return if !(my $CObject=CObject_from_FileObject $MObject->{"FileObject"});
1000 for my $reloffs (0..eval($MObject->{"Length"})/0x1000-1) {
1001 my $BObject={ %$MObject };
1002 $BObject->{"Bcb"}="MdlChain $MdlChain reloffs $reloffs";
1003 $BObject->{"FileOffset"}=tohex(eval($MObject->{"FileOffset"})+$reloffs*0x1000);
1004 $BObject->{"SharedCacheMap"}=$CObject->{"SharedCacheMap"};
1005 $BObject->{"type"}="pin";
1006 $BObject->{"ref_count"}=0;
1007 $BObject->{"dirty"}=1;
1008 warn "Bcb ".$BObject->{"Bcb"}." already exists" if $Bcb{$BObject->{"Bcb"}};
1009 $Bcb{$BObject->{"Bcb"}}=$BObject;
1011 delete $MdlChain{$MdlChain};
1014 sub CcMdlWriteAbort($$)
1016 my($FileObject,$MdlChain)=@_;
1018 warn "CcMdlWriteAbort() not handled";
1021 sub AcquireForLazyWrite_leave($)
1025 warn "Unexpected 'r' $r" if $r ne "1";
1026 warn "AcquireForLazyWrite() not the toplevel function" if @$EnterLeave;
1027 return if !(my $CObject=CObject $Object->{"data"}[0]{"SharedCacheMap"});
1028 $CObject->{"AcquireForLazyWrite"}++;
1031 sub ReleaseFromLazyWrite_leave()
1033 warn "ReleaseFromLazyWrite() not the toplevel function" if @$EnterLeave;
1034 return if !(my $CObject=CObject $Object->{"data"}[0]{"SharedCacheMap"});
1035 warn "Invalid 'AcquireForLazyWrite' value ".$CObject->{"AcquireForLazyWrite"}
1036 if !($CObject->{"AcquireForLazyWrite"}>=1);
1037 $CObject->{"AcquireForLazyWrite"}--;
1044 return if !(my $BObject=BObject $Bcb);
1045 map_new $BObject->{"SharedCacheMap"};
1046 $Object->{"Buffer"}=tohex(eval($BObject->{"Buffer"})-eval($BObject->{"FileOffset"} || 0));
1049 sub CcRemapBcb_leave($)
1060 return if !(my $BObject=BObject $Bcb);
1061 return if --$BObject->{"ref_count"};
1062 if ($BObject->{"dirty"}) {
1063 # last unpin of unreferenced dirty Bcb will no longer allow reincarnation
1064 # of the same Bcb to the pin map of its SharedCacheMap.
1065 return if !(my $CObject=CObject $BObject->{"SharedCacheMap"});
1066 warn "unpin() of pin Bcb $Bcb but it is already not registered in SharedCacheMap ".$BObject->{"SharedCacheMap"}." pin map"
1067 if (!$CObject->{"pin"}{$BObject->{"FileOffset"}} || $CObject->{"pin"}{$BObject->{"FileOffset"}} ne $Bcb)
1068 && !$BObject->{"OwnerPointer"};
1069 delete $CObject->{"pin"}{$BObject->{"FileOffset"}}
1070 if $CObject->{"pin"}{$BObject->{"FileOffset"}} && ($CObject->{"pin"}{$BObject->{"FileOffset"}} eq $Bcb);
1071 CObject_Buffer_check $CObject;
1074 delete_BObject $BObject;
1084 sub CcUnpinDataForThread($)
1091 sub CcSetBcbOwnerPointer($$)
1093 my($Bcb,$OwnerPointer)=@_;
1095 return if !(my $BObject=BObject $Bcb);
1096 warn "CcSetBcbOwnerPointer() on map Bcb $Bcb" if $BObject->{"type"} ne "pin";
1097 return if !(my $CObject=CObject $BObject->{"SharedCacheMap"});
1098 warn "Double CcSetBcbOwnerPointer() on Bcb $Bcb" if defined $BObject->{"OwnerPointer"};
1099 my $val=$CObject->{"pin"}{$BObject->{"FileOffset"}};
1100 warn "CcSetBcbOwnerPointer() on unregistered pin Bcb $Bcb" if !$val || $val ne $Bcb;
1101 delete $CObject->{"pin"}{$BObject->{"FileOffset"}} if $val && $val eq $Bcb;
1102 $BObject->{"OwnerPointer"}=$OwnerPointer;
1103 CObject_Buffer_check $CObject;
1106 sub IRP_MJ_CLOSE_leave()
1108 my $FileObject=$Object->{"data"}[0]{"FileObject"};
1109 # # IRP_MJ_CLOSE of FileObject w/o CcInitializeCacheMap()?
1110 # return if !$FileObject{$FileObject};
1111 return if !(my $FObject=FObject $FileObject);
1112 if (eval(my $SectionObjectPointer=$FObject->{"SectionObjectPointer"})) {
1113 return if !(my $SObject=SObject $SectionObjectPointer);
1114 my $SharedCacheMap=$SObject->{"SharedCacheMap"};
1115 if (eval $SharedCacheMap) {
1116 return if !(my $CObject=CObject $SObject->{"SharedCacheMap"});
1117 # SharedCacheMap may still exist for FCB although this FileObject gets destroyed now.
1118 # warn "SectionObjectPointer $SectionObjectPointer still exists during IRP_MJ_CLOSE"
1119 # ." while SharedCacheMap ".$CObject->{"SharedCacheMap"}." ref_count ".$CObject->{"ref_count"}
1120 # if $SectionObjectPointer && $CObject->{"ref_count"};
1123 delete_FObject $FObject;
1128 my $hex='0x[\dA-F]+';
1133 # We may get some foreign garbage without '\n' before our debug data line:
1134 # Do not use '\bTraceFS' as there really can be precediny _any_ data.
1135 s#^.*?TraceFS[(]($hex/$hex)[)]: ## or do { print "$_\n" if $filter; next; };
1139 if (/^enter: (\w+)/) {
1142 $Object->{"line_enter"}=$.;
1143 $Object->{"ProcessThread"}=$ProcessThread;
1144 push @{$EnterLeave{$ProcessThread}},$Object;
1146 elsif (/^leave: (\w+)/) {
1147 warn "Empty pop stack during 'leave' of $1" if !($Object=pop @{$EnterLeave{$ProcessThread}});
1148 warn "Non-matching popped 'by' ".$Object->{"by"}." ne current 'leave' $1"
1149 if $Object->{"by"} ne $1;
1150 $Object->{"line_leave"}=$.;
1151 push @{$LastLeave{$ProcessThread}},$Object;
1153 elsif (my($FileObject,$FileName,$Flags,$SectionObjectPointer,$SharedCacheMap)=
1154 /^FileObject=($hex): FileName=(?:NULL|'(.*)'),(?:ref=[+-]\d+,)?Flags=($hex),SectionObjectPointer=($hex),->SharedCacheMap=($hex)/) {
1155 my $aref=$EnterLeave{$ProcessThread};
1156 warn "Empty stack during 'data' line" if !($Object=${$aref}[$#$aref]);
1158 "FileObject"=>$FileObject,
1159 "FileName"=>$FileName,
1161 "SectionObjectPointer"=>$SectionObjectPointer,
1162 "SharedCacheMap"=>$SharedCacheMap,
1165 push @{$Object->{"data"}},$data;
1166 my $isinit={ map(($_=>1),qw(
1167 CcInitializeCacheMap
1168 CcUninitializeCacheMap
1170 )) }->{$Object->{"by"}};
1172 if 1==@{$Object->{"data"}} || !$isinit;
1174 # Prevent 'SharedCacheMap' 0->N change by CcInitializeCacheMap() called inside.
1175 for my $ref (@$aref[0..$#$aref-1]) {
1176 $ref->{"data"}[0]->{"SharedCacheMap"}=$SharedCacheMap;
1179 if (2<=@{$Object->{"data"}}) {
1180 my $data_prev=$Object->{"data"}[$#{$Object->{"data"}}-1];
1181 for my $field (qw(FileObject FileName Flags),($isinit ? () : qw(SharedCacheMap))) {
1182 next if !defined(my $prev=$data_prev->{$field});
1183 next if !defined(my $now=$data->{$field});
1184 my $by=$Object->{"by"};
1185 if ($field eq "Flags") {
1186 next if $by eq "IRP_MJ_CREATE" && $field eq "Flags";
1187 my $FO_CLEANUP_COMPLETE=0x4000;
1188 $now=tohex(eval($now)&~$FO_CLEANUP_COMPLETE) if $by eq "IRP_MJ_CLEANUP";
1189 my $FO_FILE_FAST_IO_READ=0x80000;
1190 $prev=tohex(eval($prev)&~$FO_FILE_FAST_IO_READ) if $by eq "IRP_MJ_CLEANUP";
1191 $now=tohex(eval($now)&~$FO_FILE_FAST_IO_READ) if $by eq "IRP_MJ_READ" && !(eval($prev)&$FO_FILE_FAST_IO_READ);
1192 my $FO_FILE_MODIFIED=0x1000;
1193 $now=tohex(eval($now)&~$FO_FILE_MODIFIED) if $by eq "IRP_MJ_WRITE" && !(eval($prev)&$FO_FILE_MODIFIED);
1194 my $FO_FILE_SIZE_CHANGED=0x2000;
1195 $prev=tohex(eval($prev)&~$FO_FILE_MODIFIED)
1196 if $by eq "IRP_MJ_SET_INFORMATION" && !(eval($now)&$FO_FILE_MODIFIED);
1197 $prev=tohex(eval($prev)&~$FO_FILE_SIZE_CHANGED)
1198 if $by eq "IRP_MJ_SET_INFORMATION" && !(eval($now)&$FO_FILE_SIZE_CHANGED);
1200 next if $by eq "IRP_MJ_CLOSE" && $field eq "FileName";
1201 $prev=~s#\\$## if $by eq "IRP_MJ_CREATE";
1202 $prev="\\" if $by eq "IRP_MJ_CREATE" && $prev eq "";
1203 $prev=~s#:.*## if $by eq "IRP_MJ_CREATE" && $prev ne $now;
1204 next if $field eq "SharedCacheMap" && !SharedCacheMap_valid $prev && !SharedCacheMap_valid $now;
1205 do { warn "Changed data field $field, prev=".$data_prev->{$field}.", now=".$data->{$field}." by $by";
1206 # print STDERR Dumper $data_prev,$data;
1212 elsif (my($op,$ByteOffset,$Length)=
1213 /^(READ|WRITE): ByteOffset=($hex),Length=($hex)/) {
1214 my $aref=$EnterLeave{$ProcessThread};
1215 warn "Empty stack during 'data' line" if !($Object=${$aref}[$#$aref]);
1217 "ByteOffset"=>$ByteOffset,
1223 $LastLeave=${$LastLeave{$ProcessThread}}[$#{$LastLeave{$ProcessThread}}-1];
1224 $EnterLeave=$EnterLeave{$ProcessThread};
1227 /^leave: IRP_MJ_\w+: r=($hex)/) {
1228 # Failed requests should make no consequences.
1232 if (my($FileObject,$AllocationSize,$FileSize,$ValidDataLength,$PinAccess)=
1233 /^enter: CcInitializeCacheMap: FileObject=($hex),FileSizes,->AllocationSize=($hex),->FileSize=($hex),->ValidDataLength=($hex),PinAccess=([01]),/) {
1234 CcInitializeCacheMap $FileObject,eval($AllocationSize),eval($FileSize),eval($ValidDataLength),eval($PinAccess);
1237 if (/^leave: CcInitializeCacheMap\b/) {
1238 CcInitializeCacheMap_leave;
1242 if (my($FileObject,$TruncateSize)=
1243 /^enter: CcUninitializeCacheMap: FileObject=($hex),TruncateSize=($hex),/) {
1244 CcUninitializeCacheMap $FileObject,eval($TruncateSize);
1248 /^leave: CcUninitializeCacheMap: r=([01])/) {
1249 CcUninitializeCacheMap_leave $r;
1253 if (my($FileObject,$AllocationSize,$FileSize,$ValidDataLength)=
1254 /^enter: CcSetFileSizes: FileObject=($hex),FileSizes,->AllocationSize=($hex),->FileSize=($hex),->ValidDataLength=($hex)/) {
1255 CcSetFileSizes $FileObject,eval($AllocationSize),eval($FileSize),eval($ValidDataLength);
1259 if (/^leave: IRP_MJ_CREATE\b/) {
1260 IRP_MJ_CREATE_leave;
1264 if (/^leave: IRP_MJ_CLOSE\b/) {
1269 if (my($FileObject,$FileOffset,$Length)=
1270 /^enter: CcMapData: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) {
1271 CcMapData $FileObject,eval($FileOffset),eval($Length);
1274 if (my($Bcb,$Buffer)=
1275 /^leave: CcMapData: r=1,Bcb=($hex),Buffer=($hex)/) {
1276 CcMapData_leave $Bcb,$Buffer;
1280 if (my($FileObject,$FileOffset,$Length)=
1281 /^enter: CcPinRead: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) {
1282 CcPinRead $FileObject,eval($FileOffset),eval($Length);
1285 if (my($Bcb,$Buffer)=
1286 /^leave: CcPinRead: r=1,Bcb=($hex),Buffer=($hex)/) {
1287 CcPinRead_leave $Bcb,$Buffer;
1291 if (my($FileObject,$FileOffset,$Length)=
1292 /^enter: CcPreparePinWrite: FileObject=($hex),FileOffset=($hex),Length=($hex),Zero=([01]),Flags=0x1/) {
1293 CcPreparePinWrite $FileObject,eval($FileOffset),eval($Length);
1296 if (my($Bcb,$Buffer)=
1297 /^leave: CcPreparePinWrite: r=1,Bcb=($hex),Buffer=($hex)/) {
1298 CcPreparePinWrite_leave $Bcb,$Buffer;
1302 if (my($FileObject,$FileOffset,$Length)=
1303 /^enter: CcPinMappedData: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) {
1304 CcPinMappedData $FileObject,eval($FileOffset),eval($Length);
1308 /^leave: CcPinMappedData: r=1,Bcb=($hex)/) {
1309 CcPinMappedData_leave $Bcb;
1313 if (my($BcbVoid,$Lsn)=
1314 /^enter: CcSetDirtyPinnedData: BcbVoid=($hex),Lsn=($hex)/) {
1315 CcSetDirtyPinnedData $BcbVoid,$Lsn;
1319 if (my($LogHandle,$Lsn)=
1320 /^enter: FlushToLsnRoutine: LogHandle=($hex),Lsn=($hex)/) {
1321 FlushToLsnRoutine $LogHandle,$Lsn;
1325 if (/^leave: IRP_MJ_READ\b/) {
1330 if (my($SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length,$UninitializeCacheMaps)=
1331 /^enter: CcPurgeCacheSection: SectionObjectPointer=($hex),->SharedCacheMap=($hex),FileOffset=($hex),Length=($hex),UninitializeCacheMaps=([01])/) {
1332 CcPurgeCacheSection $SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length,$UninitializeCacheMaps;
1336 if (/^leave: IRP_MJ_WRITE\b/) {
1341 if (my($SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length)=
1342 /^enter: CcFlushCache: SectionObjectPointer=($hex),->SharedCacheMap=($hex),FileOffset=($hex),Length=($hex)/) {
1343 CcFlushCache $SectionObjectPointer,$SharedCacheMap,$FileOffset,$Length;
1347 if (my($Status,$Information)=
1348 /^leave: CcFlushCache: IoStatus->Status=($hex),IoStatus->Information=($hex)/) {
1349 CcFlushCache_leave $Status,$Information;
1354 /^leave: AcquireForLazyWrite: r=([01])/) {
1355 AcquireForLazyWrite_leave $r;
1358 if (/^leave: ReleaseFromLazyWrite\b/) {
1359 ReleaseFromLazyWrite_leave;
1362 if (my($FileObject,$LogHandle,$FlushToLsnRoutine)=
1363 /^enter: CcSetLogHandleForFile: FileObject=($hex),LogHandle=($hex),FlushToLsnRoutine=($hex)/) {
1364 CcSetLogHandleForFile $FileObject,$LogHandle,$FlushToLsnRoutine;
1368 if (my($FileObject,$FileOffset,$Length)=
1369 /^enter: CcPrepareMdlWrite: FileObject=($hex),FileOffset=($hex),Length=($hex)/) {
1370 CcPrepareMdlWrite $FileObject,$FileOffset,$Length;
1373 if (my($MdlChain,$Status,$Information)=
1374 /^leave: CcPrepareMdlWrite: MdlChain=($hex),IoStatus->Status=($hex),IoStatus->Information=($hex)/) {
1375 CcPrepareMdlWrite_leave $MdlChain,$Status,$Information;
1379 if (my($FileObject,$FileOffset,$MdlChain)=
1380 /^enter: CcMdlWriteComplete: FileObject=($hex),FileOffset=($hex),MdlChain=($hex)/) {
1381 CcMdlWriteComplete $FileObject,$FileOffset,$MdlChain;
1385 if (my($FileObject,$MdlChain)=
1386 /^enter: CcMdlWriteAbort: FileObject=($hex),MdlChain=($hex)/) {
1387 CcMdlWriteAbort $FileObject,$MdlChain;
1392 /^enter: CcRemapBcb: Bcb=($hex)/) {
1397 /^leave: CcRemapBcb: r=($hex)/) {
1398 CcRemapBcb_leave $r;
1403 /^enter: CcUnpinData: Bcb=($hex)/) {
1408 /^enter: CcUnpinDataForThread: Bcb=($hex)/) {
1409 CcUnpinDataForThread $Bcb;
1413 if (my($Bcb,$OwnerPointer)=
1414 /^enter: CcSetBcbOwnerPointer: Bcb=($hex),OwnerPointer=($hex)/) {
1415 CcSetBcbOwnerPointer $Bcb,$OwnerPointer;
1419 print "$_\n" if $filter;
1421 for my $FileObject (keys(%FileObject)) {
1422 warn "EXIT: still CcInitializeCacheMap FileObject $FileObject";
1423 next if !(my $FObject=FObject $FileObject);