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