xref: /reactos/ntoskrnl/cc/pin.c (revision 84344399)
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     _SEH2_VOLATILE 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             *Bcb = NULL;
306             *Buffer = NULL;
307         }
308     }
309     _SEH2_END;
310 
311     if (Result)
312     {
313         *Bcb = &NewBcb->PFCB;
314         *Buffer = (PVOID)((ULONG_PTR)NewBcb->Vacb->BaseAddress + VacbOffset);
315     }
316 
317     return Result;
318 }
319 
320 /*
321  * @implemented
322  */
323 BOOLEAN
324 NTAPI
325 CcMapData (
326     IN PFILE_OBJECT FileObject,
327     IN PLARGE_INTEGER FileOffset,
328     IN ULONG Length,
329     IN ULONG Flags,
330     OUT PVOID *pBcb,
331     OUT PVOID *pBuffer)
332 {
333     KIRQL OldIrql;
334     PINTERNAL_BCB iBcb;
335     PROS_VACB Vacb;
336     PROS_SHARED_CACHE_MAP SharedCacheMap;
337     ULONG VacbOffset;
338     NTSTATUS Status;
339     _SEH2_VOLATILE BOOLEAN Result;
340 
341     CCTRACE(CC_API_DEBUG, "CcMapData(FileObject 0x%p, FileOffset 0x%I64x, Length %lu, Flags 0x%lx,"
342            " pBcb 0x%p, pBuffer 0x%p)\n", FileObject, FileOffset->QuadPart,
343            Length, Flags, pBcb, pBuffer);
344 
345     ASSERT(FileObject);
346     ASSERT(FileObject->SectionObjectPointer);
347     ASSERT(FileObject->SectionObjectPointer->SharedCacheMap);
348 
349     SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
350     ASSERT(SharedCacheMap);
351 
352     if (Flags & MAP_WAIT)
353     {
354         ++CcMapDataWait;
355     }
356     else
357     {
358         ++CcMapDataNoWait;
359     }
360 
361     VacbOffset = (ULONG)(FileOffset->QuadPart % VACB_MAPPING_GRANULARITY);
362     /* KMTests seem to show that it is allowed to call accross mapping granularity */
363     if ((VacbOffset + Length) > VACB_MAPPING_GRANULARITY)
364     {
365         DPRINT1("TRUNCATING DATA MAP FROM %lu to %lu!\n", Length, VACB_MAPPING_GRANULARITY - VacbOffset);
366         Length = VACB_MAPPING_GRANULARITY - VacbOffset;
367     }
368 
369     KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
370     iBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, FALSE);
371 
372     if (iBcb == NULL)
373     {
374         KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
375 
376         /* Call internal helper for getting a VACB */
377         Status = CcRosGetVacb(SharedCacheMap, FileOffset->QuadPart, &Vacb);
378         if (!NT_SUCCESS(Status))
379         {
380             CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
381                 SharedCacheMap->FileObject, FileOffset, Length, Flags);
382             ExRaiseStatus(Status);
383         }
384 
385         iBcb = CcpGetAppropriateBcb(SharedCacheMap, Vacb, FileOffset, Length, 0, FALSE);
386         if (iBcb == NULL)
387         {
388             CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE);
389             CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
390                 SharedCacheMap->FileObject, FileOffset, Length, Flags);
391             *pBcb = NULL; // If you ever remove this for compat, make sure to review all callers for using an unititialized value
392             ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
393         }
394     }
395     else
396     {
397         ++iBcb->RefCount;
398         KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
399     }
400 
401     _SEH2_TRY
402     {
403         Result = FALSE;
404         /* Ensure the pages are resident */
405         Result = CcRosEnsureVacbResident(iBcb->Vacb, BooleanFlagOn(Flags, MAP_WAIT),
406                 BooleanFlagOn(Flags, MAP_NO_READ), VacbOffset, Length);
407     }
408     _SEH2_FINALLY
409     {
410         if (!Result)
411         {
412             CcpDereferenceBcb(SharedCacheMap, iBcb);
413             *pBcb = NULL;
414             *pBuffer = NULL;
415         }
416     }
417     _SEH2_END;
418 
419     if (Result)
420     {
421         *pBcb = &iBcb->PFCB;
422         *pBuffer = (PVOID)((ULONG_PTR)iBcb->Vacb->BaseAddress + VacbOffset);
423     }
424 
425     CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> TRUE Bcb=%p, Buffer %p\n",
426         FileObject, FileOffset, Length, Flags, *pBcb, *pBuffer);
427     return Result;
428 }
429 
430 /*
431  * @unimplemented
432  */
433 BOOLEAN
434 NTAPI
435 CcPinMappedData (
436     IN	PFILE_OBJECT FileObject,
437     IN	PLARGE_INTEGER FileOffset,
438     IN	ULONG Length,
439     IN	ULONG Flags,
440     OUT	PVOID * Bcb)
441 {
442     BOOLEAN Result;
443     PVOID Buffer;
444     PINTERNAL_BCB iBcb;
445     PROS_SHARED_CACHE_MAP SharedCacheMap;
446 
447     CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
448         FileObject, FileOffset, Length, Flags);
449 
450     ASSERT(FileObject);
451     ASSERT(FileObject->SectionObjectPointer);
452     ASSERT(FileObject->SectionObjectPointer->SharedCacheMap);
453 
454     SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
455     ASSERT(SharedCacheMap);
456     if (!SharedCacheMap->PinAccess)
457     {
458         DPRINT1("FIXME: Pinning a file with no pin access!\n");
459         return FALSE;
460     }
461 
462     iBcb = *Bcb ? CONTAINING_RECORD(*Bcb, INTERNAL_BCB, PFCB) : NULL;
463 
464     ++CcPinMappedDataCount;
465 
466     Result = CcpPinData(SharedCacheMap, FileOffset, Length, Flags, Bcb, &Buffer);
467     if (Result)
468     {
469         CcUnpinData(&iBcb->PFCB);
470     }
471 
472     return Result;
473 }
474 
475 /*
476  * @unimplemented
477  */
478 BOOLEAN
479 NTAPI
480 CcPinRead (
481     IN	PFILE_OBJECT FileObject,
482     IN	PLARGE_INTEGER FileOffset,
483     IN	ULONG Length,
484     IN	ULONG Flags,
485     OUT	PVOID * Bcb,
486     OUT	PVOID * Buffer)
487 {
488     PROS_SHARED_CACHE_MAP SharedCacheMap;
489 
490     CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
491         FileObject, FileOffset, Length, Flags);
492 
493     ASSERT(FileObject);
494     ASSERT(FileObject->SectionObjectPointer);
495     ASSERT(FileObject->SectionObjectPointer->SharedCacheMap);
496 
497     SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
498     ASSERT(SharedCacheMap);
499     if (!SharedCacheMap->PinAccess)
500     {
501         DPRINT1("FIXME: Pinning a file with no pin access!\n");
502         return FALSE;
503     }
504 
505     if (Flags & PIN_WAIT)
506     {
507         ++CcPinReadWait;
508     }
509     else
510     {
511         ++CcPinReadNoWait;
512     }
513 
514     return CcpPinData(SharedCacheMap, FileOffset, Length, Flags, Bcb, Buffer);
515 }
516 
517 /*
518  * @unimplemented
519  */
520 BOOLEAN
521 NTAPI
522 CcPreparePinWrite (
523     IN	PFILE_OBJECT FileObject,
524     IN	PLARGE_INTEGER FileOffset,
525     IN	ULONG Length,
526     IN	BOOLEAN Zero,
527     IN	ULONG Flags,
528     OUT	PVOID * Bcb,
529     OUT	PVOID * Buffer)
530 {
531     CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Zero=%d Flags=0x%lx\n",
532         FileObject, FileOffset, Length, Zero, Flags);
533 
534     /*
535      * FIXME: This is function is similar to CcPinRead, but doesn't
536      * read the data if they're not present. Instead it should just
537      * prepare the VACBs and zero them out if Zero != FALSE.
538      *
539      * For now calling CcPinRead is better than returning error or
540      * just having UNIMPLEMENTED here.
541      */
542     return CcPinRead(FileObject, FileOffset, Length, Flags, Bcb, Buffer);
543 }
544 
545 /*
546  * @implemented
547  */
548 VOID NTAPI
549 CcSetDirtyPinnedData (
550     IN PVOID Bcb,
551     IN PLARGE_INTEGER Lsn)
552 {
553     PINTERNAL_BCB iBcb = CONTAINING_RECORD(Bcb, INTERNAL_BCB, PFCB);
554 
555     CCTRACE(CC_API_DEBUG, "Bcb=%p Lsn=%p\n", Bcb, Lsn);
556 
557     /* Tell Mm */
558     MmMakePagesDirty(NULL,
559                      Add2Ptr(iBcb->Vacb->BaseAddress, iBcb->PFCB.MappedFileOffset.QuadPart - iBcb->Vacb->FileOffset.QuadPart),
560                      iBcb->PFCB.MappedLength);
561 
562     if (!iBcb->Vacb->Dirty)
563     {
564         CcRosMarkDirtyVacb(iBcb->Vacb);
565     }
566 }
567 
568 
569 /*
570  * @implemented
571  */
572 VOID NTAPI
573 CcUnpinData (
574     IN PVOID Bcb)
575 {
576     CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb);
577 
578     CcUnpinDataForThread(Bcb, (ERESOURCE_THREAD)PsGetCurrentThread());
579 }
580 
581 /*
582  * @unimplemented
583  */
584 VOID
585 NTAPI
586 CcUnpinDataForThread (
587     IN	PVOID Bcb,
588     IN	ERESOURCE_THREAD ResourceThreadId)
589 {
590     PINTERNAL_BCB iBcb = CONTAINING_RECORD(Bcb, INTERNAL_BCB, PFCB);
591 
592     CCTRACE(CC_API_DEBUG, "Bcb=%p ResourceThreadId=%lu\n", Bcb, ResourceThreadId);
593 
594     if (iBcb->PinCount != 0)
595     {
596         ExReleaseResourceForThreadLite(&iBcb->Lock, ResourceThreadId);
597         iBcb->PinCount--;
598     }
599 
600     CcpDereferenceBcb(iBcb->Vacb->SharedCacheMap, iBcb);
601 }
602 
603 /*
604  * @implemented
605  */
606 VOID
607 NTAPI
608 CcRepinBcb (
609     IN	PVOID Bcb)
610 {
611     PINTERNAL_BCB iBcb = CONTAINING_RECORD(Bcb, INTERNAL_BCB, PFCB);
612 
613     CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb);
614 
615     iBcb->RefCount++;
616 }
617 
618 /*
619  * @unimplemented
620  */
621 VOID
622 NTAPI
623 CcUnpinRepinnedBcb (
624     IN	PVOID Bcb,
625     IN	BOOLEAN WriteThrough,
626     IN	PIO_STATUS_BLOCK IoStatus)
627 {
628     PINTERNAL_BCB iBcb = CONTAINING_RECORD(Bcb, INTERNAL_BCB, PFCB);
629     KIRQL OldIrql;
630     PROS_SHARED_CACHE_MAP SharedCacheMap;
631 
632     CCTRACE(CC_API_DEBUG, "Bcb=%p WriteThrough=%d\n", Bcb, WriteThrough);
633 
634     SharedCacheMap = iBcb->Vacb->SharedCacheMap;
635     IoStatus->Status = STATUS_SUCCESS;
636 
637     if (WriteThrough)
638     {
639         CcFlushCache(iBcb->Vacb->SharedCacheMap->FileObject->SectionObjectPointer,
640                      &iBcb->PFCB.MappedFileOffset,
641                      iBcb->PFCB.MappedLength,
642                      IoStatus);
643     }
644     else
645     {
646         IoStatus->Status = STATUS_SUCCESS;
647         IoStatus->Information = 0;
648     }
649 
650     KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
651     if (--iBcb->RefCount == 0)
652     {
653         RemoveEntryList(&iBcb->BcbEntry);
654         KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
655 
656         if (iBcb->PinCount != 0)
657         {
658             ExReleaseResourceLite(&iBcb->Lock);
659             iBcb->PinCount--;
660             ASSERT(iBcb->PinCount == 0);
661         }
662 
663         /*
664          * Don't mark dirty, if it was dirty,
665          * the VACB was already marked as such
666          * following the call to CcSetDirtyPinnedData
667          */
668         CcRosReleaseVacb(iBcb->Vacb->SharedCacheMap,
669                          iBcb->Vacb,
670                          FALSE,
671                          FALSE);
672 
673         ExDeleteResourceLite(&iBcb->Lock);
674         ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb);
675     }
676     else
677     {
678         KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
679     }
680 }
681