[NTOSKRNL] Rewrite the way we create BCB for pinning

We won't reuse a BCB created for mapping, we will now have
our own dedicated BCB.
This allows having a bit more cleaner implementation of CcPinMappedData()
This commit is contained in:
Pierre Schweitzer 2018-10-13 22:46:10 +02:00
parent 2d47c3be29
commit 1afcbbd125
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B

View file

@ -73,17 +73,14 @@ CcpMapData(
IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER FileOffset,
IN ULONG Length, IN ULONG Length,
IN ULONG Flags, IN ULONG Flags,
IN BOOLEAN ToPin, OUT PROS_VACB *pVacb,
OUT PVOID *pBcb,
OUT PVOID *pBuffer) OUT PVOID *pBuffer)
{ {
LONGLONG ReadOffset; LONGLONG ReadOffset;
BOOLEAN Valid; BOOLEAN Valid;
PROS_VACB Vacb; PROS_VACB Vacb;
NTSTATUS Status; NTSTATUS Status;
PINTERNAL_BCB iBcb, DupBcb;
LONGLONG ROffset; LONGLONG ROffset;
KIRQL OldIrql;
ReadOffset = FileOffset->QuadPart; ReadOffset = FileOffset->QuadPart;
@ -146,14 +143,30 @@ CcpMapData(
} }
*pBuffer = (PUCHAR)*pBuffer + ReadOffset % VACB_MAPPING_GRANULARITY; *pBuffer = (PUCHAR)*pBuffer + ReadOffset % VACB_MAPPING_GRANULARITY;
*pVacb = Vacb;
return TRUE;
}
static
PVOID
CcpGetAppropriateBcb(
IN PROS_SHARED_CACHE_MAP SharedCacheMap,
IN PROS_VACB Vacb,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG PinFlags,
IN BOOLEAN ToPin)
{
KIRQL OldIrql;
BOOLEAN Result;
PINTERNAL_BCB iBcb, DupBcb;
iBcb = ExAllocateFromNPagedLookasideList(&iBcbLookasideList); iBcb = ExAllocateFromNPagedLookasideList(&iBcbLookasideList);
if (iBcb == NULL) if (iBcb == NULL)
{ {
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", return NULL;
SharedCacheMap->FileObject, FileOffset, Length, Flags);
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
return FALSE;
} }
RtlZeroMemory(iBcb, sizeof(*iBcb)); RtlZeroMemory(iBcb, sizeof(*iBcb));
@ -166,44 +179,147 @@ CcpMapData(
iBcb->PinCount = 0; iBcb->PinCount = 0;
iBcb->RefCount = 1; iBcb->RefCount = 1;
ExInitializeResourceLite(&iBcb->Lock); ExInitializeResourceLite(&iBcb->Lock);
*pBcb = (PVOID)iBcb;
/* Only insert if we're not to pin data */ KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
if (!ToPin)
/* Check if we raced with another BCB creation */
DupBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, ToPin);
/* Yes, and we've lost */
if (DupBcb != NULL)
{ {
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); Result = TRUE;
/* Check if we raced with another BCB creation */ if (ToPin)
DupBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, FALSE); {
/* Yes, and we've lost */ DupBcb->PinCount++;
if (DupBcb != NULL)
if (BooleanFlagOn(PinFlags, PIN_EXCLUSIVE))
{
Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(PinFlags, PIN_WAIT));
}
else
{
Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(PinFlags, PIN_WAIT));
}
if (!Result)
{
DupBcb->PinCount--;
DupBcb = NULL;
}
}
if (Result)
{ {
/* We'll return that BCB */ /* We'll return that BCB */
++DupBcb->RefCount; ++DupBcb->RefCount;
/* Delete the loser */
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
ExDeleteResourceLite(&iBcb->Lock);
ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb);
/* Return the winner - no need to update buffer address, it's
* relative to the VACB, which is unchanged.
*/
*pBcb = DupBcb;
} }
/* Nope, insert ourselves */
/* Delete the loser */
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
ExDeleteResourceLite(&iBcb->Lock);
ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb);
/* Return the winner - no need to update buffer address, it's
* relative to the VACB, which is unchanged.
*/
iBcb = DupBcb;
}
/* Nope, insert ourselves */
else
{
if (ToPin)
{
iBcb->PinCount++;
if (BooleanFlagOn(PinFlags, PIN_EXCLUSIVE))
{
Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(PinFlags, PIN_WAIT));
}
else
{
Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(PinFlags, PIN_WAIT));
}
ASSERT(Result);
}
InsertTailList(&SharedCacheMap->BcbList, &iBcb->BcbEntry);
}
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
return iBcb;
}
static
BOOLEAN
CcpPinData(
IN PROS_SHARED_CACHE_MAP SharedCacheMap,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG Flags,
OUT PVOID * Bcb,
OUT PVOID * Buffer)
{
PINTERNAL_BCB NewBcb;
BOOLEAN Result;
PROS_VACB Vacb;
KIRQL OldIrql;
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
NewBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, TRUE);
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
if (NewBcb != NULL)
{
NewBcb->PinCount++;
if (BooleanFlagOn(Flags, PIN_EXCLUSIVE))
{
Result = ExAcquireResourceExclusiveLite(&NewBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
}
else else
{ {
InsertTailList(&SharedCacheMap->BcbList, &iBcb->BcbEntry); Result = ExAcquireSharedStarveExclusive(&NewBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
} }
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
if (!Result)
{
NewBcb->PinCount--;
}
else
{
NewBcb->RefCount++;
*Bcb = NewBcb;
*Buffer = (PUCHAR)NewBcb->Vacb->BaseAddress + FileOffset->QuadPart % VACB_MAPPING_GRANULARITY;
}
return Result;
} }
else else
{ {
InitializeListHead(&iBcb->BcbEntry); if (BooleanFlagOn(Flags, PIN_IF_BCB))
{
return FALSE;
}
Result = CcpMapData(SharedCacheMap, FileOffset, Length, Flags, &Vacb, Buffer);
if (Result)
{
NewBcb = CcpGetAppropriateBcb(SharedCacheMap, Vacb, FileOffset, Length, Flags, TRUE);
if (NewBcb == NULL)
{
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
Result = FALSE;
}
else
{
*Bcb = NewBcb;
}
}
} }
return TRUE; return Result;
} }
/* /*
@ -222,6 +338,7 @@ CcMapData (
BOOLEAN Ret; BOOLEAN Ret;
KIRQL OldIrql; KIRQL OldIrql;
PINTERNAL_BCB iBcb; PINTERNAL_BCB iBcb;
PROS_VACB Vacb;
PROS_SHARED_CACHE_MAP SharedCacheMap; PROS_SHARED_CACHE_MAP SharedCacheMap;
DPRINT("CcMapData(FileObject 0x%p, FileOffset %I64x, Length %lu, Flags 0x%lx," DPRINT("CcMapData(FileObject 0x%p, FileOffset %I64x, Length %lu, Flags 0x%lx,"
@ -250,7 +367,20 @@ CcMapData (
if (iBcb == NULL) if (iBcb == NULL)
{ {
Ret = CcpMapData(SharedCacheMap, FileOffset, Length, Flags, FALSE, pBcb, pBuffer); Ret = CcpMapData(SharedCacheMap, FileOffset, Length, Flags, &Vacb, pBuffer);
if (Ret)
{
iBcb = CcpGetAppropriateBcb(SharedCacheMap, Vacb, FileOffset, Length, 0, FALSE);
if (iBcb == NULL)
{
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
Ret = FALSE;
}
else
{
*pBcb = iBcb;
}
}
} }
else else
{ {
@ -278,6 +408,7 @@ CcPinMappedData (
OUT PVOID * Bcb) OUT PVOID * Bcb)
{ {
BOOLEAN Result; BOOLEAN Result;
PVOID Buffer;
PINTERNAL_BCB iBcb; PINTERNAL_BCB iBcb;
PROS_SHARED_CACHE_MAP SharedCacheMap; PROS_SHARED_CACHE_MAP SharedCacheMap;
@ -297,22 +428,11 @@ CcPinMappedData (
} }
iBcb = *Bcb; iBcb = *Bcb;
ASSERT(iBcb->PinCount == 0);
iBcb->PinCount++; Result = CcpPinData(SharedCacheMap, FileOffset, Length, Flags, Bcb, &Buffer);
if (Result)
if (BooleanFlagOn(Flags, PIN_EXCLUSIVE))
{ {
Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT)); CcUnpinData(iBcb);
}
else
{
Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
}
if (!Result)
{
iBcb->PinCount--;
} }
return Result; return Result;
@ -331,9 +451,6 @@ CcPinRead (
OUT PVOID * Bcb, OUT PVOID * Bcb,
OUT PVOID * Buffer) OUT PVOID * Buffer)
{ {
KIRQL OldIrql;
BOOLEAN Result;
PINTERNAL_BCB iBcb;
PROS_SHARED_CACHE_MAP SharedCacheMap; PROS_SHARED_CACHE_MAP SharedCacheMap;
CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Flags=0x%lx\n", CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
@ -345,6 +462,11 @@ CcPinRead (
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
ASSERT(SharedCacheMap); ASSERT(SharedCacheMap);
if (!SharedCacheMap->PinAccess)
{
DPRINT1("FIXME: Pinning a file with no pin access!\n");
return FALSE;
}
if (Flags & PIN_WAIT) if (Flags & PIN_WAIT)
{ {
@ -355,95 +477,7 @@ CcPinRead (
++CcPinReadNoWait; ++CcPinReadNoWait;
} }
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); return CcpPinData(SharedCacheMap, FileOffset, Length, Flags, Bcb, Buffer);
iBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, TRUE);
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
if (iBcb == NULL)
{
/* We failed to find an already existing BCB */
if (BooleanFlagOn(Flags, PIN_IF_BCB))
{
return FALSE;
}
/* Map first */
if (!CcpMapData(SharedCacheMap, FileOffset, Length, Flags, TRUE, Bcb, Buffer))
{
return FALSE;
}
/* Pin then */
if (!CcPinMappedData(FileObject, FileOffset, Length, Flags, Bcb))
{
CcUnpinData(*Bcb);
return FALSE;
}
/* Did we race for the BCB creation? */
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
iBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, TRUE);
if (iBcb != NULL)
{
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
/* Free our now unused BCB */
CcUnpinData(*Bcb);
/* Lock the found BCB and return it */
if (BooleanFlagOn(Flags, PIN_EXCLUSIVE))
{
Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
}
else
{
Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
}
if (!Result)
{
return FALSE;
}
++iBcb->PinCount;
++iBcb->RefCount;
*Bcb = iBcb;
}
else
{
iBcb = *Bcb;
/* Insert ourselves in the linked list */
InsertTailList(&SharedCacheMap->BcbList, &iBcb->BcbEntry);
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
}
}
/* We found a BCB, lock it and return it */
else
{
if (BooleanFlagOn(Flags, PIN_EXCLUSIVE))
{
Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
}
else
{
Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
}
if (!Result)
{
return FALSE;
}
++iBcb->PinCount;
++iBcb->RefCount;
*Bcb = iBcb;
*Buffer = (PUCHAR)iBcb->Vacb->BaseAddress + FileOffset->QuadPart % VACB_MAPPING_GRANULARITY;
}
return TRUE;
} }
/* /*