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