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
8 Pierre Schweitzer (pierre@reactos.org)
11 /* INCLUDES ******************************************************************/
17 /* GLOBALS *******************************************************************/
19 extern NPAGED_LOOKASIDE_LIST iBcbLookasideList
;
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
28 ULONG CcMapDataWait
= 0;
29 ULONG CcMapDataNoWait
= 0;
30 ULONG CcPinReadWait
= 0;
31 ULONG CcPinReadNoWait
= 0;
32 ULONG CcPinMappedDataCount
= 0;
34 /* FUNCTIONS *****************************************************************/
40 IN PROS_SHARED_CACHE_MAP SharedCacheMap
,
41 IN PLARGE_INTEGER FileOffset
,
46 BOOLEAN Found
= FALSE
;
47 PLIST_ENTRY NextEntry
;
49 for (NextEntry
= SharedCacheMap
->BcbList
.Flink
;
50 NextEntry
!= &SharedCacheMap
->BcbList
;
51 NextEntry
= NextEntry
->Flink
)
53 Bcb
= CONTAINING_RECORD(NextEntry
, INTERNAL_BCB
, BcbEntry
);
55 if (Bcb
->PFCB
.MappedFileOffset
.QuadPart
<= FileOffset
->QuadPart
&&
56 (Bcb
->PFCB
.MappedFileOffset
.QuadPart
+ Bcb
->PFCB
.MappedLength
) >=
57 (FileOffset
->QuadPart
+ Length
))
59 if ((Pinned
&& Bcb
->PinCount
> 0) || (!Pinned
&& Bcb
->PinCount
== 0))
67 return (Found
? Bcb
: NULL
);
73 IN PROS_SHARED_CACHE_MAP SharedCacheMap
,
79 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
80 RefCount
= --Bcb
->RefCount
;
83 RemoveEntryList(&Bcb
->BcbEntry
);
84 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
86 ASSERT(Bcb
->PinCount
== 0);
88 * Don't mark dirty, if it was dirty,
89 * the VACB was already marked as such
90 * following the call to CcSetDirtyPinnedData
92 CcRosReleaseVacb(SharedCacheMap
,
97 ExDeleteResourceLite(&Bcb
->Lock
);
98 ExFreeToNPagedLookasideList(&iBcbLookasideList
, Bcb
);
102 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
108 CcpGetAppropriateBcb(
109 IN PROS_SHARED_CACHE_MAP SharedCacheMap
,
111 IN PLARGE_INTEGER FileOffset
,
118 PINTERNAL_BCB iBcb
, DupBcb
;
120 iBcb
= ExAllocateFromNPagedLookasideList(&iBcbLookasideList
);
123 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
);
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
;
135 ExInitializeResourceLite(&iBcb
->Lock
);
137 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
139 /* Check if we raced with another BCB creation */
140 DupBcb
= CcpFindBcb(SharedCacheMap
, FileOffset
, Length
, ToPin
);
141 /* Yes, and we've lost */
144 /* We will return that BCB */
147 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
151 if (BooleanFlagOn(PinFlags
, PIN_EXCLUSIVE
))
153 Result
= ExAcquireResourceExclusiveLite(&iBcb
->Lock
, BooleanFlagOn(PinFlags
, PIN_WAIT
));
157 Result
= ExAcquireSharedStarveExclusive(&iBcb
->Lock
, BooleanFlagOn(PinFlags
, PIN_WAIT
));
166 CcpDereferenceBcb(SharedCacheMap
, DupBcb
);
173 /* Delete the loser */
174 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
);
175 ExDeleteResourceLite(&iBcb
->Lock
);
176 ExFreeToNPagedLookasideList(&iBcbLookasideList
, iBcb
);
179 /* Return the winner - no need to update buffer address, it's
180 * relative to the VACB, which is unchanged.
184 /* Nope, insert ourselves */
191 if (BooleanFlagOn(PinFlags
, PIN_EXCLUSIVE
))
193 Result
= ExAcquireResourceExclusiveLite(&iBcb
->Lock
, BooleanFlagOn(PinFlags
, PIN_WAIT
));
197 Result
= ExAcquireSharedStarveExclusive(&iBcb
->Lock
, BooleanFlagOn(PinFlags
, PIN_WAIT
));
203 InsertTailList(&SharedCacheMap
->BcbList
, &iBcb
->BcbEntry
);
204 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
213 IN PROS_SHARED_CACHE_MAP SharedCacheMap
,
214 IN PLARGE_INTEGER FileOffset
,
220 PINTERNAL_BCB NewBcb
;
226 VacbOffset
= (ULONG
)(FileOffset
->QuadPart
% VACB_MAPPING_GRANULARITY
);
228 if ((VacbOffset
+ Length
) > VACB_MAPPING_GRANULARITY
)
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
;
235 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
236 NewBcb
= CcpFindBcb(SharedCacheMap
, FileOffset
, Length
, TRUE
);
243 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
245 if (BooleanFlagOn(Flags
, PIN_EXCLUSIVE
))
246 Result
= ExAcquireResourceExclusiveLite(&NewBcb
->Lock
, BooleanFlagOn(Flags
, PIN_WAIT
));
248 Result
= ExAcquireSharedStarveExclusive(&NewBcb
->Lock
, BooleanFlagOn(Flags
, PIN_WAIT
));
252 CcpDereferenceBcb(SharedCacheMap
, NewBcb
);
263 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
265 if (BooleanFlagOn(Flags
, PIN_IF_BCB
))
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
))
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
);
281 NewBcb
= CcpGetAppropriateBcb(SharedCacheMap
, Vacb
, FileOffset
, Length
, Flags
, TRUE
);
284 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
);
292 /* Ensure the pages are resident */
293 Result
= CcRosEnsureVacbResident(NewBcb
->Vacb
,
294 BooleanFlagOn(Flags
, PIN_WAIT
),
295 BooleanFlagOn(Flags
, PIN_NO_READ
),
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
);
310 *Bcb
= &NewBcb
->PFCB
;
311 *Buffer
= (PVOID
)((ULONG_PTR
)NewBcb
->Vacb
->BaseAddress
+ VacbOffset
);
322 IN PFILE_OBJECT FileObject
,
323 IN PLARGE_INTEGER FileOffset
,
332 PROS_SHARED_CACHE_MAP SharedCacheMap
;
337 CCTRACE(CC_API_DEBUG
, "CcMapData(FileObject 0x%p, FileOffset 0x%I64x, Length %lu, Flags 0x%lx,"
338 " pBcb 0x%p, pBuffer 0x%p)\n", FileObject
, FileOffset
->QuadPart
,
339 Length
, Flags
, pBcb
, pBuffer
);
342 ASSERT(FileObject
->SectionObjectPointer
);
343 ASSERT(FileObject
->SectionObjectPointer
->SharedCacheMap
);
345 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
346 ASSERT(SharedCacheMap
);
348 if (Flags
& MAP_WAIT
)
357 VacbOffset
= (ULONG
)(FileOffset
->QuadPart
% VACB_MAPPING_GRANULARITY
);
358 /* KMTests seem to show that it is allowed to call accross mapping granularity */
359 if ((VacbOffset
+ Length
) > VACB_MAPPING_GRANULARITY
)
361 DPRINT1("TRUNCATING DATA MAP FROM %lu to %lu!\n", Length
, VACB_MAPPING_GRANULARITY
- VacbOffset
);
362 Length
= VACB_MAPPING_GRANULARITY
- VacbOffset
;
365 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
366 iBcb
= CcpFindBcb(SharedCacheMap
, FileOffset
, Length
, FALSE
);
370 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
372 /* Call internal helper for getting a VACB */
373 Status
= CcRosGetVacb(SharedCacheMap
, FileOffset
->QuadPart
, &Vacb
);
374 if (!NT_SUCCESS(Status
))
376 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
377 SharedCacheMap
->FileObject
, FileOffset
, Length
, Flags
);
378 ExRaiseStatus(Status
);
381 iBcb
= CcpGetAppropriateBcb(SharedCacheMap
, Vacb
, FileOffset
, Length
, 0, FALSE
);
384 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
);
385 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
386 SharedCacheMap
->FileObject
, FileOffset
, Length
, Flags
);
387 *pBcb
= NULL
; // If you ever remove this for compat, make sure to review all callers for using an unititialized value
388 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
394 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
400 /* Ensure the pages are resident */
401 Result
= CcRosEnsureVacbResident(iBcb
->Vacb
, BooleanFlagOn(Flags
, MAP_WAIT
),
402 BooleanFlagOn(Flags
, MAP_NO_READ
), VacbOffset
, Length
);
408 CcpDereferenceBcb(SharedCacheMap
, iBcb
);
415 *pBuffer
= (PVOID
)((ULONG_PTR
)iBcb
->Vacb
->BaseAddress
+ VacbOffset
);
417 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> TRUE Bcb=%p, Buffer %p\n",
418 FileObject
, FileOffset
, Length
, Flags
, *pBcb
, *pBuffer
);
428 IN PFILE_OBJECT FileObject
,
429 IN PLARGE_INTEGER FileOffset
,
437 PROS_SHARED_CACHE_MAP SharedCacheMap
;
439 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
440 FileObject
, FileOffset
, Length
, Flags
);
443 ASSERT(FileObject
->SectionObjectPointer
);
444 ASSERT(FileObject
->SectionObjectPointer
->SharedCacheMap
);
446 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
447 ASSERT(SharedCacheMap
);
448 if (!SharedCacheMap
->PinAccess
)
450 DPRINT1("FIXME: Pinning a file with no pin access!\n");
454 iBcb
= *Bcb
? CONTAINING_RECORD(*Bcb
, INTERNAL_BCB
, PFCB
) : NULL
;
456 ++CcPinMappedDataCount
;
458 Result
= CcpPinData(SharedCacheMap
, FileOffset
, Length
, Flags
, Bcb
, &Buffer
);
461 CcUnpinData(&iBcb
->PFCB
);
473 IN PFILE_OBJECT FileObject
,
474 IN PLARGE_INTEGER FileOffset
,
480 PROS_SHARED_CACHE_MAP SharedCacheMap
;
482 CCTRACE(CC_API_DEBUG
, "FileOffset=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
483 FileObject
, FileOffset
, Length
, Flags
);
486 ASSERT(FileObject
->SectionObjectPointer
);
487 ASSERT(FileObject
->SectionObjectPointer
->SharedCacheMap
);
489 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
490 ASSERT(SharedCacheMap
);
491 if (!SharedCacheMap
->PinAccess
)
493 DPRINT1("FIXME: Pinning a file with no pin access!\n");
497 if (Flags
& PIN_WAIT
)
506 return CcpPinData(SharedCacheMap
, FileOffset
, Length
, Flags
, Bcb
, Buffer
);
515 IN PFILE_OBJECT FileObject
,
516 IN PLARGE_INTEGER FileOffset
,
523 CCTRACE(CC_API_DEBUG
, "FileOffset=%p FileOffset=%p Length=%lu Zero=%d Flags=0x%lx\n",
524 FileObject
, FileOffset
, Length
, Zero
, Flags
);
527 * FIXME: This is function is similar to CcPinRead, but doesn't
528 * read the data if they're not present. Instead it should just
529 * prepare the VACBs and zero them out if Zero != FALSE.
531 * For now calling CcPinRead is better than returning error or
532 * just having UNIMPLEMENTED here.
534 return CcPinRead(FileObject
, FileOffset
, Length
, Flags
, Bcb
, Buffer
);
541 CcSetDirtyPinnedData (
543 IN PLARGE_INTEGER Lsn
)
545 PINTERNAL_BCB iBcb
= CONTAINING_RECORD(Bcb
, INTERNAL_BCB
, PFCB
);
547 CCTRACE(CC_API_DEBUG
, "Bcb=%p Lsn=%p\n", Bcb
, Lsn
);
550 MmMakePagesDirty(NULL
,
551 Add2Ptr(iBcb
->Vacb
->BaseAddress
, iBcb
->PFCB
.MappedFileOffset
.QuadPart
- iBcb
->Vacb
->FileOffset
.QuadPart
),
552 iBcb
->PFCB
.MappedLength
);
554 if (!iBcb
->Vacb
->Dirty
)
556 CcRosMarkDirtyVacb(iBcb
->Vacb
);
568 CCTRACE(CC_API_DEBUG
, "Bcb=%p\n", Bcb
);
570 CcUnpinDataForThread(Bcb
, (ERESOURCE_THREAD
)PsGetCurrentThread());
578 CcUnpinDataForThread (
580 IN ERESOURCE_THREAD ResourceThreadId
)
582 PINTERNAL_BCB iBcb
= CONTAINING_RECORD(Bcb
, INTERNAL_BCB
, PFCB
);
584 CCTRACE(CC_API_DEBUG
, "Bcb=%p ResourceThreadId=%lu\n", Bcb
, ResourceThreadId
);
586 if (iBcb
->PinCount
!= 0)
588 ExReleaseResourceForThreadLite(&iBcb
->Lock
, ResourceThreadId
);
592 CcpDereferenceBcb(iBcb
->Vacb
->SharedCacheMap
, iBcb
);
603 PINTERNAL_BCB iBcb
= CONTAINING_RECORD(Bcb
, INTERNAL_BCB
, PFCB
);
605 CCTRACE(CC_API_DEBUG
, "Bcb=%p\n", Bcb
);
617 IN BOOLEAN WriteThrough
,
618 IN PIO_STATUS_BLOCK IoStatus
)
620 PINTERNAL_BCB iBcb
= CONTAINING_RECORD(Bcb
, INTERNAL_BCB
, PFCB
);
622 PROS_SHARED_CACHE_MAP SharedCacheMap
;
624 CCTRACE(CC_API_DEBUG
, "Bcb=%p WriteThrough=%d\n", Bcb
, WriteThrough
);
626 SharedCacheMap
= iBcb
->Vacb
->SharedCacheMap
;
627 IoStatus
->Status
= STATUS_SUCCESS
;
631 CcFlushCache(iBcb
->Vacb
->SharedCacheMap
->FileObject
->SectionObjectPointer
,
632 &iBcb
->PFCB
.MappedFileOffset
,
633 iBcb
->PFCB
.MappedLength
,
638 IoStatus
->Status
= STATUS_SUCCESS
;
639 IoStatus
->Information
= 0;
642 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
643 if (--iBcb
->RefCount
== 0)
645 RemoveEntryList(&iBcb
->BcbEntry
);
646 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
648 if (iBcb
->PinCount
!= 0)
650 ExReleaseResourceLite(&iBcb
->Lock
);
652 ASSERT(iBcb
->PinCount
== 0);
656 * Don't mark dirty, if it was dirty,
657 * the VACB was already marked as such
658 * following the call to CcSetDirtyPinnedData
660 CcRosReleaseVacb(iBcb
->Vacb
->SharedCacheMap
,
665 ExDeleteResourceLite(&iBcb
->Lock
);
666 ExFreeToNPagedLookasideList(&iBcbLookasideList
, iBcb
);
670 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);