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
);
74 IN PROS_SHARED_CACHE_MAP SharedCacheMap
,
75 IN PLARGE_INTEGER FileOffset
,
81 LONGLONG ReadOffset
, BaseOffset
;
87 ReadOffset
= FileOffset
->QuadPart
;
89 DPRINT("SectionSize %I64x, FileSize %I64x\n",
90 SharedCacheMap
->SectionSize
.QuadPart
,
91 SharedCacheMap
->FileSize
.QuadPart
);
93 if (ReadOffset
% VACB_MAPPING_GRANULARITY
+ Length
> VACB_MAPPING_GRANULARITY
)
95 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
96 SharedCacheMap
->FileObject
, FileOffset
, Length
, Flags
);
100 if (!BooleanFlagOn(Flags
, MAP_NO_READ
))
102 static int Warned
= 0;
104 SetFlag(Flags
, MAP_NO_READ
);
107 DPRINT1("Mapping/pinning with no read not implemented. Forcing read, might fail if wait not allowed\n");
112 /* Properly round offset and call internal helper for getting a VACB */
113 ROffset
= ROUND_DOWN(ReadOffset
, VACB_MAPPING_GRANULARITY
);
114 Status
= CcRosGetVacb(SharedCacheMap
,
120 if (!NT_SUCCESS(Status
))
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
);
128 if (!Valid
&& BooleanFlagOn(Flags
, MAP_NO_READ
))
130 if (!BooleanFlagOn(Flags
, MAP_WAIT
))
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
);
138 Status
= CcReadVirtualAddress(Vacb
);
139 if (!NT_SUCCESS(Status
))
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
);
149 *pBuffer
= (PUCHAR
)*pBuffer
+ ReadOffset
% VACB_MAPPING_GRANULARITY
;
158 IN PROS_SHARED_CACHE_MAP SharedCacheMap
,
159 IN PINTERNAL_BCB Bcb
)
164 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
165 RefCount
= --Bcb
->RefCount
;
168 RemoveEntryList(&Bcb
->BcbEntry
);
169 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
171 ASSERT(Bcb
->PinCount
== 0);
172 CcRosReleaseVacb(SharedCacheMap
,
178 ExDeleteResourceLite(&Bcb
->Lock
);
179 ExFreeToNPagedLookasideList(&iBcbLookasideList
, Bcb
);
183 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
189 CcpGetAppropriateBcb(
190 IN PROS_SHARED_CACHE_MAP SharedCacheMap
,
192 IN PLARGE_INTEGER FileOffset
,
199 PINTERNAL_BCB iBcb
, DupBcb
;
201 iBcb
= ExAllocateFromNPagedLookasideList(&iBcbLookasideList
);
204 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
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
;
217 ExInitializeResourceLite(&iBcb
->Lock
);
219 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
221 /* Check if we raced with another BCB creation */
222 DupBcb
= CcpFindBcb(SharedCacheMap
, FileOffset
, Length
, ToPin
);
223 /* Yes, and we've lost */
226 /* We will return that BCB */
229 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
233 if (BooleanFlagOn(PinFlags
, PIN_EXCLUSIVE
))
235 Result
= ExAcquireResourceExclusiveLite(&iBcb
->Lock
, BooleanFlagOn(PinFlags
, PIN_WAIT
));
239 Result
= ExAcquireSharedStarveExclusive(&iBcb
->Lock
, BooleanFlagOn(PinFlags
, PIN_WAIT
));
248 CcpDereferenceBcb(SharedCacheMap
, DupBcb
);
255 /* Delete the loser */
256 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
257 ExDeleteResourceLite(&iBcb
->Lock
);
258 ExFreeToNPagedLookasideList(&iBcbLookasideList
, iBcb
);
261 /* Return the winner - no need to update buffer address, it's
262 * relative to the VACB, which is unchanged.
266 /* Nope, insert ourselves */
273 if (BooleanFlagOn(PinFlags
, PIN_EXCLUSIVE
))
275 Result
= ExAcquireResourceExclusiveLite(&iBcb
->Lock
, BooleanFlagOn(PinFlags
, PIN_WAIT
));
279 Result
= ExAcquireSharedStarveExclusive(&iBcb
->Lock
, BooleanFlagOn(PinFlags
, PIN_WAIT
));
285 InsertTailList(&SharedCacheMap
->BcbList
, &iBcb
->BcbEntry
);
286 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
295 IN PROS_SHARED_CACHE_MAP SharedCacheMap
,
296 IN PLARGE_INTEGER FileOffset
,
302 PINTERNAL_BCB NewBcb
;
308 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
309 NewBcb
= CcpFindBcb(SharedCacheMap
, FileOffset
, Length
, TRUE
);
314 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
316 if (BooleanFlagOn(Flags
, PIN_EXCLUSIVE
))
318 Result
= ExAcquireResourceExclusiveLite(&NewBcb
->Lock
, BooleanFlagOn(Flags
, PIN_WAIT
));
322 Result
= ExAcquireSharedStarveExclusive(&NewBcb
->Lock
, BooleanFlagOn(Flags
, PIN_WAIT
));
327 CcpDereferenceBcb(SharedCacheMap
, NewBcb
);
334 *Buffer
= (PUCHAR
)NewBcb
->Vacb
->BaseAddress
+ FileOffset
->QuadPart
% VACB_MAPPING_GRANULARITY
;
341 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
343 if (BooleanFlagOn(Flags
, PIN_IF_BCB
))
348 MapFlags
= Flags
& PIN_WAIT
;
349 if (BooleanFlagOn(Flags
, PIN_NO_READ
))
351 SetFlag(MapFlags
, MAP_NO_READ
);
354 Result
= CcpMapData(SharedCacheMap
, FileOffset
, Length
, MapFlags
, &Vacb
, Buffer
);
357 NewBcb
= CcpGetAppropriateBcb(SharedCacheMap
, Vacb
, FileOffset
, Length
, Flags
, TRUE
);
360 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
379 IN PFILE_OBJECT FileObject
,
380 IN PLARGE_INTEGER FileOffset
,
390 PROS_SHARED_CACHE_MAP SharedCacheMap
;
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
);
397 ASSERT(FileObject
->SectionObjectPointer
);
398 ASSERT(FileObject
->SectionObjectPointer
->SharedCacheMap
);
400 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
401 ASSERT(SharedCacheMap
);
403 if (Flags
& MAP_WAIT
)
412 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
413 iBcb
= CcpFindBcb(SharedCacheMap
, FileOffset
, Length
, FALSE
);
417 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
419 Ret
= CcpMapData(SharedCacheMap
, FileOffset
, Length
, Flags
, &Vacb
, pBuffer
);
422 iBcb
= CcpGetAppropriateBcb(SharedCacheMap
, Vacb
, FileOffset
, Length
, 0, FALSE
);
425 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, FALSE
, FALSE
);
437 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
440 *pBuffer
= (PUCHAR
)iBcb
->Vacb
->BaseAddress
+ FileOffset
->QuadPart
% VACB_MAPPING_GRANULARITY
;
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
);
455 IN PFILE_OBJECT FileObject
,
456 IN PLARGE_INTEGER FileOffset
,
464 PROS_SHARED_CACHE_MAP SharedCacheMap
;
466 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
467 FileObject
, FileOffset
, Length
, Flags
);
470 ASSERT(FileObject
->SectionObjectPointer
);
471 ASSERT(FileObject
->SectionObjectPointer
->SharedCacheMap
);
473 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
474 ASSERT(SharedCacheMap
);
475 if (!SharedCacheMap
->PinAccess
)
477 DPRINT1("FIXME: Pinning a file with no pin access!\n");
483 ++CcPinMappedDataCount
;
485 Result
= CcpPinData(SharedCacheMap
, FileOffset
, Length
, Flags
, Bcb
, &Buffer
);
500 IN PFILE_OBJECT FileObject
,
501 IN PLARGE_INTEGER FileOffset
,
507 PROS_SHARED_CACHE_MAP SharedCacheMap
;
509 CCTRACE(CC_API_DEBUG
, "FileOffset=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
510 FileObject
, FileOffset
, Length
, Flags
);
513 ASSERT(FileObject
->SectionObjectPointer
);
514 ASSERT(FileObject
->SectionObjectPointer
->SharedCacheMap
);
516 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
517 ASSERT(SharedCacheMap
);
518 if (!SharedCacheMap
->PinAccess
)
520 DPRINT1("FIXME: Pinning a file with no pin access!\n");
524 if (Flags
& PIN_WAIT
)
533 return CcpPinData(SharedCacheMap
, FileOffset
, Length
, Flags
, Bcb
, Buffer
);
542 IN PFILE_OBJECT FileObject
,
543 IN PLARGE_INTEGER FileOffset
,
550 CCTRACE(CC_API_DEBUG
, "FileOffset=%p FileOffset=%p Length=%lu Zero=%d Flags=0x%lx\n",
551 FileObject
, FileOffset
, Length
, Zero
, Flags
);
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.
558 * For now calling CcPinRead is better than returning error or
559 * just having UNIMPLEMENTED here.
561 return CcPinRead(FileObject
, FileOffset
, Length
, Flags
, Bcb
, Buffer
);
568 CcSetDirtyPinnedData (
570 IN PLARGE_INTEGER Lsn
)
572 PINTERNAL_BCB iBcb
= Bcb
;
574 CCTRACE(CC_API_DEBUG
, "Bcb=%p Lsn=%p\n",
578 if (!iBcb
->Vacb
->Dirty
)
580 CcRosMarkDirtyVacb(iBcb
->Vacb
);
592 CCTRACE(CC_API_DEBUG
, "Bcb=%p\n", Bcb
);
594 CcUnpinDataForThread(Bcb
, (ERESOURCE_THREAD
)PsGetCurrentThread());
602 CcUnpinDataForThread (
604 IN ERESOURCE_THREAD ResourceThreadId
)
606 PINTERNAL_BCB iBcb
= Bcb
;
607 PROS_SHARED_CACHE_MAP SharedCacheMap
;
609 CCTRACE(CC_API_DEBUG
, "Bcb=%p ResourceThreadId=%lu\n", Bcb
, ResourceThreadId
);
611 if (iBcb
->PinCount
!= 0)
613 ExReleaseResourceForThreadLite(&iBcb
->Lock
, ResourceThreadId
);
617 SharedCacheMap
= iBcb
->Vacb
->SharedCacheMap
;
618 CcpDereferenceBcb(SharedCacheMap
, iBcb
);
629 PINTERNAL_BCB iBcb
= Bcb
;
631 CCTRACE(CC_API_DEBUG
, "Bcb=%p\n", Bcb
);
643 IN BOOLEAN WriteThrough
,
644 IN PIO_STATUS_BLOCK IoStatus
)
646 PINTERNAL_BCB iBcb
= Bcb
;
648 PROS_SHARED_CACHE_MAP SharedCacheMap
;
650 CCTRACE(CC_API_DEBUG
, "Bcb=%p WriteThrough=%d\n", Bcb
, WriteThrough
);
652 SharedCacheMap
= iBcb
->Vacb
->SharedCacheMap
;
653 IoStatus
->Status
= STATUS_SUCCESS
;
655 KeAcquireSpinLock(&SharedCacheMap
->BcbSpinLock
, &OldIrql
);
656 if (--iBcb
->RefCount
== 0)
658 RemoveEntryList(&iBcb
->BcbEntry
);
659 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);
661 IoStatus
->Information
= 0;
664 if (iBcb
->Vacb
->Dirty
)
666 IoStatus
->Status
= CcRosFlushVacb(iBcb
->Vacb
);
670 IoStatus
->Status
= STATUS_SUCCESS
;
675 IoStatus
->Status
= STATUS_SUCCESS
;
678 if (iBcb
->PinCount
!= 0)
680 ExReleaseResourceLite(&iBcb
->Lock
);
682 ASSERT(iBcb
->PinCount
== 0);
685 CcRosReleaseVacb(iBcb
->Vacb
->SharedCacheMap
,
691 ExDeleteResourceLite(&iBcb
->Lock
);
692 ExFreeToNPagedLookasideList(&iBcbLookasideList
, iBcb
);
696 KeReleaseSpinLock(&SharedCacheMap
->BcbSpinLock
, OldIrql
);