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