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