775b105a2fdc8c1c37e0ec5123200f4146d129fa
[reactos.git] / ntoskrnl / cc / pin.c
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 }