xref: /reactos/ntoskrnl/cc/pin.c (revision cdf90707)
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