1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/cc/pin.c 5 * PURPOSE: Implements cache managers pinning interface 6 * 7 * PROGRAMMERS: ? 8 Pierre Schweitzer (pierre@reactos.org) 9 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 /* GLOBALS *******************************************************************/ 18 19 extern NPAGED_LOOKASIDE_LIST iBcbLookasideList; 20 21 /* Counters: 22 * - Number of calls to CcMapData that could wait 23 * - Number of calls to CcMapData that couldn't wait 24 * - Number of calls to CcPinRead that could wait 25 * - Number of calls to CcPinRead that couldn't wait 26 * - Number of calls to CcPinMappedDataCount 27 */ 28 ULONG CcMapDataWait = 0; 29 ULONG CcMapDataNoWait = 0; 30 ULONG CcPinReadWait = 0; 31 ULONG CcPinReadNoWait = 0; 32 ULONG CcPinMappedDataCount = 0; 33 34 /* FUNCTIONS *****************************************************************/ 35 36 static 37 PINTERNAL_BCB 38 NTAPI 39 CcpFindBcb( 40 IN PROS_SHARED_CACHE_MAP SharedCacheMap, 41 IN PLARGE_INTEGER FileOffset, 42 IN ULONG Length, 43 IN BOOLEAN Pinned) 44 { 45 PINTERNAL_BCB Bcb; 46 BOOLEAN Found = FALSE; 47 PLIST_ENTRY NextEntry; 48 49 for (NextEntry = SharedCacheMap->BcbList.Flink; 50 NextEntry != &SharedCacheMap->BcbList; 51 NextEntry = NextEntry->Flink) 52 { 53 Bcb = CONTAINING_RECORD(NextEntry, INTERNAL_BCB, BcbEntry); 54 55 if (Bcb->PFCB.MappedFileOffset.QuadPart <= FileOffset->QuadPart && 56 (Bcb->PFCB.MappedFileOffset.QuadPart + Bcb->PFCB.MappedLength) >= 57 (FileOffset->QuadPart + Length)) 58 { 59 if ((Pinned && Bcb->PinCount > 0) || (!Pinned && Bcb->PinCount == 0)) 60 { 61 Found = TRUE; 62 break; 63 } 64 } 65 } 66 67 return (Found ? Bcb : NULL); 68 } 69 70 static 71 VOID 72 CcpDereferenceBcb( 73 IN PROS_SHARED_CACHE_MAP SharedCacheMap, 74 IN PINTERNAL_BCB Bcb) 75 { 76 ULONG RefCount; 77 KIRQL OldIrql; 78 79 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); 80 RefCount = --Bcb->RefCount; 81 if (RefCount == 0) 82 { 83 RemoveEntryList(&Bcb->BcbEntry); 84 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 85 86 ASSERT(Bcb->PinCount == 0); 87 /* 88 * Don't mark dirty, if it was dirty, 89 * the VACB was already marked as such 90 * following the call to CcSetDirtyPinnedData 91 */ 92 CcRosReleaseVacb(SharedCacheMap, 93 Bcb->Vacb, 94 TRUE, 95 FALSE, 96 FALSE); 97 98 ExDeleteResourceLite(&Bcb->Lock); 99 ExFreeToNPagedLookasideList(&iBcbLookasideList, Bcb); 100 } 101 else 102 { 103 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 104 } 105 } 106 107 static 108 PVOID 109 CcpGetAppropriateBcb( 110 IN PROS_SHARED_CACHE_MAP SharedCacheMap, 111 IN PROS_VACB Vacb, 112 IN PLARGE_INTEGER FileOffset, 113 IN ULONG Length, 114 IN ULONG PinFlags, 115 IN BOOLEAN ToPin) 116 { 117 KIRQL OldIrql; 118 BOOLEAN Result; 119 PINTERNAL_BCB iBcb, DupBcb; 120 121 iBcb = ExAllocateFromNPagedLookasideList(&iBcbLookasideList); 122 if (iBcb == NULL) 123 { 124 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); 125 return NULL; 126 } 127 128 RtlZeroMemory(iBcb, sizeof(*iBcb)); 129 iBcb->PFCB.NodeTypeCode = 0x2FD; /* As per KMTests */ 130 iBcb->PFCB.NodeByteSize = 0; 131 iBcb->PFCB.MappedLength = Length; 132 iBcb->PFCB.MappedFileOffset = *FileOffset; 133 iBcb->Vacb = Vacb; 134 iBcb->PinCount = 0; 135 iBcb->RefCount = 1; 136 ExInitializeResourceLite(&iBcb->Lock); 137 138 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); 139 140 /* Check if we raced with another BCB creation */ 141 DupBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, ToPin); 142 /* Yes, and we've lost */ 143 if (DupBcb != NULL) 144 { 145 /* We will return that BCB */ 146 ++DupBcb->RefCount; 147 Result = TRUE; 148 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 149 150 if (ToPin) 151 { 152 if (BooleanFlagOn(PinFlags, PIN_EXCLUSIVE)) 153 { 154 Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(PinFlags, PIN_WAIT)); 155 } 156 else 157 { 158 Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(PinFlags, PIN_WAIT)); 159 } 160 161 if (Result) 162 { 163 DupBcb->PinCount++; 164 } 165 else 166 { 167 CcpDereferenceBcb(SharedCacheMap, DupBcb); 168 DupBcb = NULL; 169 } 170 } 171 172 if (DupBcb != NULL) 173 { 174 /* Delete the loser */ 175 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); 176 ExDeleteResourceLite(&iBcb->Lock); 177 ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb); 178 } 179 180 /* Return the winner - no need to update buffer address, it's 181 * relative to the VACB, which is unchanged. 182 */ 183 iBcb = DupBcb; 184 } 185 /* Nope, insert ourselves */ 186 else 187 { 188 if (ToPin) 189 { 190 iBcb->PinCount++; 191 192 if (BooleanFlagOn(PinFlags, PIN_EXCLUSIVE)) 193 { 194 Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(PinFlags, PIN_WAIT)); 195 } 196 else 197 { 198 Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(PinFlags, PIN_WAIT)); 199 } 200 201 ASSERT(Result); 202 } 203 204 InsertTailList(&SharedCacheMap->BcbList, &iBcb->BcbEntry); 205 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 206 } 207 208 return iBcb; 209 } 210 211 static 212 BOOLEAN 213 CcpPinData( 214 IN PROS_SHARED_CACHE_MAP SharedCacheMap, 215 IN PLARGE_INTEGER FileOffset, 216 IN ULONG Length, 217 IN ULONG Flags, 218 OUT PVOID * Bcb, 219 OUT PVOID * Buffer) 220 { 221 PINTERNAL_BCB NewBcb; 222 KIRQL OldIrql; 223 ULONG VacbOffset; 224 NTSTATUS Status; 225 BOOLEAN Result; 226 227 VacbOffset = (ULONG)(FileOffset->QuadPart % VACB_MAPPING_GRANULARITY); 228 229 if ((VacbOffset + Length) > VACB_MAPPING_GRANULARITY) 230 { 231 /* Complain loudly, we shoud pin the whole range */ 232 DPRINT1("TRUNCATING DATA PIN FROM %lu to %lu!\n", Length, VACB_MAPPING_GRANULARITY - VacbOffset); 233 Length = VACB_MAPPING_GRANULARITY - VacbOffset; 234 } 235 236 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); 237 NewBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, TRUE); 238 239 if (NewBcb != NULL) 240 { 241 BOOLEAN Result; 242 243 ++NewBcb->RefCount; 244 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 245 246 if (BooleanFlagOn(Flags, PIN_EXCLUSIVE)) 247 Result = ExAcquireResourceExclusiveLite(&NewBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT)); 248 else 249 Result = ExAcquireSharedStarveExclusive(&NewBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT)); 250 251 if (!Result) 252 { 253 CcpDereferenceBcb(SharedCacheMap, NewBcb); 254 return FALSE; 255 } 256 257 NewBcb->PinCount++; 258 } 259 else 260 { 261 LONGLONG ROffset; 262 PROS_VACB Vacb; 263 264 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 265 266 if (BooleanFlagOn(Flags, PIN_IF_BCB)) 267 { 268 return FALSE; 269 } 270 271 /* Properly round offset and call internal helper for getting a VACB */ 272 ROffset = ROUND_DOWN(FileOffset->QuadPart, VACB_MAPPING_GRANULARITY); 273 Status = CcRosGetVacb(SharedCacheMap, ROffset, &Vacb); 274 if (!NT_SUCCESS(Status)) 275 { 276 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", 277 SharedCacheMap->FileObject, FileOffset, Length, Flags); 278 ExRaiseStatus(Status); 279 return FALSE; 280 } 281 282 NewBcb = CcpGetAppropriateBcb(SharedCacheMap, Vacb, FileOffset, Length, Flags, TRUE); 283 if (NewBcb == NULL) 284 { 285 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); 286 return FALSE; 287 } 288 } 289 290 Result = FALSE; 291 _SEH2_TRY 292 { 293 /* Ensure the pages are resident */ 294 Result = CcRosEnsureVacbResident(NewBcb->Vacb, 295 BooleanFlagOn(Flags, PIN_WAIT), 296 BooleanFlagOn(Flags, PIN_NO_READ), 297 VacbOffset, Length); 298 } 299 _SEH2_FINALLY 300 { 301 if (!Result) 302 { 303 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", 304 SharedCacheMap->FileObject, FileOffset, Length, Flags); 305 CcUnpinData(NewBcb); 306 return FALSE; 307 } 308 } 309 _SEH2_END; 310 311 *Bcb = &NewBcb->PFCB; 312 *Buffer = (PVOID)((ULONG_PTR)NewBcb->Vacb->BaseAddress + VacbOffset); 313 314 return TRUE; 315 } 316 317 /* 318 * @implemented 319 */ 320 BOOLEAN 321 NTAPI 322 CcMapData ( 323 IN PFILE_OBJECT FileObject, 324 IN PLARGE_INTEGER FileOffset, 325 IN ULONG Length, 326 IN ULONG Flags, 327 OUT PVOID *pBcb, 328 OUT PVOID *pBuffer) 329 { 330 KIRQL OldIrql; 331 PINTERNAL_BCB iBcb; 332 PROS_VACB Vacb; 333 PROS_SHARED_CACHE_MAP SharedCacheMap; 334 ULONG VacbOffset; 335 NTSTATUS Status; 336 BOOLEAN Result; 337 338 CCTRACE(CC_API_DEBUG, "CcMapData(FileObject 0x%p, FileOffset 0x%I64x, Length %lu, Flags 0x%lx," 339 " pBcb 0x%p, pBuffer 0x%p)\n", FileObject, FileOffset->QuadPart, 340 Length, Flags, pBcb, pBuffer); 341 342 ASSERT(FileObject); 343 ASSERT(FileObject->SectionObjectPointer); 344 ASSERT(FileObject->SectionObjectPointer->SharedCacheMap); 345 346 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 347 ASSERT(SharedCacheMap); 348 349 if (Flags & MAP_WAIT) 350 { 351 ++CcMapDataWait; 352 } 353 else 354 { 355 ++CcMapDataNoWait; 356 } 357 358 VacbOffset = (ULONG)(FileOffset->QuadPart % VACB_MAPPING_GRANULARITY); 359 /* KMTests seem to show that it is allowed to call accross mapping granularity */ 360 if ((VacbOffset + Length) > VACB_MAPPING_GRANULARITY) 361 { 362 DPRINT1("TRUNCATING DATA MAP FROM %lu to %lu!\n", Length, VACB_MAPPING_GRANULARITY - VacbOffset); 363 Length = VACB_MAPPING_GRANULARITY - VacbOffset; 364 } 365 366 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); 367 iBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, FALSE); 368 369 if (iBcb == NULL) 370 { 371 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 372 373 /* Call internal helper for getting a VACB */ 374 Status = CcRosGetVacb(SharedCacheMap, FileOffset->QuadPart, &Vacb); 375 if (!NT_SUCCESS(Status)) 376 { 377 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", 378 SharedCacheMap->FileObject, FileOffset, Length, Flags); 379 ExRaiseStatus(Status); 380 return FALSE; 381 } 382 383 iBcb = CcpGetAppropriateBcb(SharedCacheMap, Vacb, FileOffset, Length, 0, FALSE); 384 if (iBcb == NULL) 385 { 386 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); 387 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", 388 SharedCacheMap->FileObject, FileOffset, Length, Flags); 389 return FALSE; 390 } 391 } 392 else 393 { 394 ++iBcb->RefCount; 395 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 396 } 397 398 _SEH2_TRY 399 { 400 Result = FALSE; 401 /* Ensure the pages are resident */ 402 Result = CcRosEnsureVacbResident(iBcb->Vacb, BooleanFlagOn(Flags, MAP_WAIT), 403 BooleanFlagOn(Flags, MAP_NO_READ), VacbOffset, Length); 404 } 405 _SEH2_FINALLY 406 { 407 if (!Result) 408 { 409 CcpDereferenceBcb(SharedCacheMap, iBcb); 410 return FALSE; 411 } 412 } 413 _SEH2_END; 414 415 *pBcb = &iBcb->PFCB; 416 *pBuffer = (PVOID)((ULONG_PTR)iBcb->Vacb->BaseAddress + VacbOffset); 417 418 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> TRUE Bcb=%p, Buffer %p\n", 419 FileObject, FileOffset, Length, Flags, *pBcb, *pBuffer); 420 return Result; 421 } 422 423 /* 424 * @unimplemented 425 */ 426 BOOLEAN 427 NTAPI 428 CcPinMappedData ( 429 IN PFILE_OBJECT FileObject, 430 IN PLARGE_INTEGER FileOffset, 431 IN ULONG Length, 432 IN ULONG Flags, 433 OUT PVOID * Bcb) 434 { 435 BOOLEAN Result; 436 PVOID Buffer; 437 PINTERNAL_BCB iBcb; 438 PROS_SHARED_CACHE_MAP SharedCacheMap; 439 440 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx\n", 441 FileObject, FileOffset, Length, Flags); 442 443 ASSERT(FileObject); 444 ASSERT(FileObject->SectionObjectPointer); 445 ASSERT(FileObject->SectionObjectPointer->SharedCacheMap); 446 447 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 448 ASSERT(SharedCacheMap); 449 if (!SharedCacheMap->PinAccess) 450 { 451 DPRINT1("FIXME: Pinning a file with no pin access!\n"); 452 return FALSE; 453 } 454 455 iBcb = *Bcb ? CONTAINING_RECORD(*Bcb, INTERNAL_BCB, PFCB) : NULL; 456 457 ++CcPinMappedDataCount; 458 459 Result = CcpPinData(SharedCacheMap, FileOffset, Length, Flags, Bcb, &Buffer); 460 if (Result) 461 { 462 CcUnpinData(&iBcb->PFCB); 463 } 464 465 return Result; 466 } 467 468 /* 469 * @unimplemented 470 */ 471 BOOLEAN 472 NTAPI 473 CcPinRead ( 474 IN PFILE_OBJECT FileObject, 475 IN PLARGE_INTEGER FileOffset, 476 IN ULONG Length, 477 IN ULONG Flags, 478 OUT PVOID * Bcb, 479 OUT PVOID * Buffer) 480 { 481 PROS_SHARED_CACHE_MAP SharedCacheMap; 482 483 CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Flags=0x%lx\n", 484 FileObject, FileOffset, Length, Flags); 485 486 ASSERT(FileObject); 487 ASSERT(FileObject->SectionObjectPointer); 488 ASSERT(FileObject->SectionObjectPointer->SharedCacheMap); 489 490 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 491 ASSERT(SharedCacheMap); 492 if (!SharedCacheMap->PinAccess) 493 { 494 DPRINT1("FIXME: Pinning a file with no pin access!\n"); 495 return FALSE; 496 } 497 498 if (Flags & PIN_WAIT) 499 { 500 ++CcPinReadWait; 501 } 502 else 503 { 504 ++CcPinReadNoWait; 505 } 506 507 return CcpPinData(SharedCacheMap, FileOffset, Length, Flags, Bcb, Buffer); 508 } 509 510 /* 511 * @unimplemented 512 */ 513 BOOLEAN 514 NTAPI 515 CcPreparePinWrite ( 516 IN PFILE_OBJECT FileObject, 517 IN PLARGE_INTEGER FileOffset, 518 IN ULONG Length, 519 IN BOOLEAN Zero, 520 IN ULONG Flags, 521 OUT PVOID * Bcb, 522 OUT PVOID * Buffer) 523 { 524 CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Zero=%d Flags=0x%lx\n", 525 FileObject, FileOffset, Length, Zero, Flags); 526 527 /* 528 * FIXME: This is function is similar to CcPinRead, but doesn't 529 * read the data if they're not present. Instead it should just 530 * prepare the VACBs and zero them out if Zero != FALSE. 531 * 532 * For now calling CcPinRead is better than returning error or 533 * just having UNIMPLEMENTED here. 534 */ 535 return CcPinRead(FileObject, FileOffset, Length, Flags, Bcb, Buffer); 536 } 537 538 /* 539 * @implemented 540 */ 541 VOID NTAPI 542 CcSetDirtyPinnedData ( 543 IN PVOID Bcb, 544 IN PLARGE_INTEGER Lsn) 545 { 546 PINTERNAL_BCB iBcb = CONTAINING_RECORD(Bcb, INTERNAL_BCB, PFCB); 547 548 CCTRACE(CC_API_DEBUG, "Bcb=%p Lsn=%p\n", Bcb, Lsn); 549 550 /* Tell Mm */ 551 MmMakePagesDirty(NULL, 552 Add2Ptr(iBcb->Vacb->BaseAddress, iBcb->PFCB.MappedFileOffset.QuadPart - iBcb->Vacb->FileOffset.QuadPart), 553 iBcb->PFCB.MappedLength); 554 555 if (!iBcb->Vacb->Dirty) 556 { 557 CcRosMarkDirtyVacb(iBcb->Vacb); 558 } 559 } 560 561 562 /* 563 * @implemented 564 */ 565 VOID NTAPI 566 CcUnpinData ( 567 IN PVOID Bcb) 568 { 569 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb); 570 571 CcUnpinDataForThread(Bcb, (ERESOURCE_THREAD)PsGetCurrentThread()); 572 } 573 574 /* 575 * @unimplemented 576 */ 577 VOID 578 NTAPI 579 CcUnpinDataForThread ( 580 IN PVOID Bcb, 581 IN ERESOURCE_THREAD ResourceThreadId) 582 { 583 PINTERNAL_BCB iBcb = CONTAINING_RECORD(Bcb, INTERNAL_BCB, PFCB); 584 585 CCTRACE(CC_API_DEBUG, "Bcb=%p ResourceThreadId=%lu\n", Bcb, ResourceThreadId); 586 587 if (iBcb->PinCount != 0) 588 { 589 ExReleaseResourceForThreadLite(&iBcb->Lock, ResourceThreadId); 590 iBcb->PinCount--; 591 } 592 593 CcpDereferenceBcb(iBcb->Vacb->SharedCacheMap, iBcb); 594 } 595 596 /* 597 * @implemented 598 */ 599 VOID 600 NTAPI 601 CcRepinBcb ( 602 IN PVOID Bcb) 603 { 604 PINTERNAL_BCB iBcb = CONTAINING_RECORD(Bcb, INTERNAL_BCB, PFCB); 605 606 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb); 607 608 iBcb->RefCount++; 609 } 610 611 /* 612 * @unimplemented 613 */ 614 VOID 615 NTAPI 616 CcUnpinRepinnedBcb ( 617 IN PVOID Bcb, 618 IN BOOLEAN WriteThrough, 619 IN PIO_STATUS_BLOCK IoStatus) 620 { 621 PINTERNAL_BCB iBcb = CONTAINING_RECORD(Bcb, INTERNAL_BCB, PFCB); 622 KIRQL OldIrql; 623 PROS_SHARED_CACHE_MAP SharedCacheMap; 624 625 CCTRACE(CC_API_DEBUG, "Bcb=%p WriteThrough=%d\n", Bcb, WriteThrough); 626 627 SharedCacheMap = iBcb->Vacb->SharedCacheMap; 628 IoStatus->Status = STATUS_SUCCESS; 629 630 if (WriteThrough) 631 { 632 CcFlushCache(iBcb->Vacb->SharedCacheMap->FileObject->SectionObjectPointer, 633 &iBcb->PFCB.MappedFileOffset, 634 iBcb->PFCB.MappedLength, 635 IoStatus); 636 } 637 else 638 { 639 IoStatus->Status = STATUS_SUCCESS; 640 IoStatus->Information = 0; 641 } 642 643 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); 644 if (--iBcb->RefCount == 0) 645 { 646 RemoveEntryList(&iBcb->BcbEntry); 647 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 648 649 if (iBcb->PinCount != 0) 650 { 651 ExReleaseResourceLite(&iBcb->Lock); 652 iBcb->PinCount--; 653 ASSERT(iBcb->PinCount == 0); 654 } 655 656 /* 657 * Don't mark dirty, if it was dirty, 658 * the VACB was already marked as such 659 * following the call to CcSetDirtyPinnedData 660 */ 661 CcRosReleaseVacb(iBcb->Vacb->SharedCacheMap, 662 iBcb->Vacb, 663 TRUE, 664 FALSE, 665 FALSE); 666 667 ExDeleteResourceLite(&iBcb->Lock); 668 ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb); 669 } 670 else 671 { 672 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 673 } 674 } 675