mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[NTOSKRNL] Rewrite BCB handling to be more robust
We now handle race conditions when creating BCB to avoid having duplicated BCB per shared maps. Also, we already specify whether the memory will be pinned when creating the BCB, to avoid potential duplications or BCB misuse.
This commit is contained in:
parent
8f4d8cb616
commit
cf8ba3bd9c
1 changed files with 113 additions and 38 deletions
|
@ -31,6 +31,40 @@ ULONG CcPinReadNoWait = 0;
|
|||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
static
|
||||
PINTERNAL_BCB
|
||||
NTAPI
|
||||
CcpFindBcb(
|
||||
IN PROS_SHARED_CACHE_MAP SharedCacheMap,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN Pinned)
|
||||
{
|
||||
PINTERNAL_BCB Bcb;
|
||||
BOOLEAN Found = FALSE;
|
||||
PLIST_ENTRY NextEntry;
|
||||
|
||||
for (NextEntry = SharedCacheMap->BcbList.Flink;
|
||||
NextEntry != &SharedCacheMap->BcbList;
|
||||
NextEntry = NextEntry->Flink)
|
||||
{
|
||||
Bcb = CONTAINING_RECORD(NextEntry, INTERNAL_BCB, BcbEntry);
|
||||
|
||||
if (Bcb->PFCB.MappedFileOffset.QuadPart <= FileOffset->QuadPart &&
|
||||
(Bcb->PFCB.MappedFileOffset.QuadPart + Bcb->PFCB.MappedLength) >=
|
||||
(FileOffset->QuadPart + Length))
|
||||
{
|
||||
if ((Pinned && Bcb->PinCount > 0) || (!Pinned && Bcb->PinCount == 0))
|
||||
{
|
||||
Found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (Found ? Bcb : NULL);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
|
@ -39,6 +73,7 @@ CcpMapData(
|
|||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN ULONG Flags,
|
||||
IN BOOLEAN ToPin,
|
||||
OUT PVOID *pBcb,
|
||||
OUT PVOID *pBuffer)
|
||||
{
|
||||
|
@ -46,7 +81,7 @@ CcpMapData(
|
|||
BOOLEAN Valid;
|
||||
PROS_VACB Vacb;
|
||||
NTSTATUS Status;
|
||||
PINTERNAL_BCB iBcb;
|
||||
PINTERNAL_BCB iBcb, DupBcb;
|
||||
LONGLONG ROffset;
|
||||
KIRQL OldIrql;
|
||||
|
||||
|
@ -133,45 +168,42 @@ CcpMapData(
|
|||
ExInitializeResourceLite(&iBcb->Lock);
|
||||
*pBcb = (PVOID)iBcb;
|
||||
|
||||
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
|
||||
InsertTailList(&SharedCacheMap->BcbList, &iBcb->BcbEntry);
|
||||
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
PINTERNAL_BCB
|
||||
NTAPI
|
||||
CcpFindBcb(
|
||||
IN PROS_SHARED_CACHE_MAP SharedCacheMap,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN Pinned)
|
||||
{
|
||||
PINTERNAL_BCB Bcb;
|
||||
BOOLEAN Found = FALSE;
|
||||
PLIST_ENTRY NextEntry;
|
||||
|
||||
for (NextEntry = SharedCacheMap->BcbList.Flink;
|
||||
NextEntry != &SharedCacheMap->BcbList;
|
||||
NextEntry = NextEntry->Flink)
|
||||
/* Only insert if we're not to pin data */
|
||||
if (!ToPin)
|
||||
{
|
||||
Bcb = CONTAINING_RECORD(NextEntry, INTERNAL_BCB, BcbEntry);
|
||||
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
|
||||
|
||||
if (Bcb->PFCB.MappedFileOffset.QuadPart <= FileOffset->QuadPart &&
|
||||
(Bcb->PFCB.MappedFileOffset.QuadPart + Bcb->PFCB.MappedLength) >=
|
||||
(FileOffset->QuadPart + Length))
|
||||
/* Check if we raced with another BCB creation */
|
||||
DupBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, FALSE);
|
||||
/* Yes, and we've lost */
|
||||
if (DupBcb != NULL)
|
||||
{
|
||||
if ((Pinned && Bcb->PinCount > 0) || (!Pinned && Bcb->PinCount == 0))
|
||||
{
|
||||
Found = TRUE;
|
||||
break;
|
||||
}
|
||||
/* We'll return that BCB */
|
||||
++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 */
|
||||
else
|
||||
{
|
||||
InsertTailList(&SharedCacheMap->BcbList, &iBcb->BcbEntry);
|
||||
}
|
||||
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeListHead(&iBcb->BcbEntry);
|
||||
}
|
||||
|
||||
return (Found ? Bcb : NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -218,7 +250,7 @@ CcMapData (
|
|||
|
||||
if (iBcb == NULL)
|
||||
{
|
||||
Ret = CcpMapData(SharedCacheMap, FileOffset, Length, Flags, pBcb, pBuffer);
|
||||
Ret = CcpMapData(SharedCacheMap, FileOffset, Length, Flags, FALSE, pBcb, pBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -336,7 +368,7 @@ CcPinRead (
|
|||
}
|
||||
|
||||
/* Map first */
|
||||
if (!CcpMapData(SharedCacheMap, FileOffset, Length, Flags, Bcb, Buffer))
|
||||
if (!CcpMapData(SharedCacheMap, FileOffset, Length, Flags, TRUE, Bcb, Buffer))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -347,6 +379,43 @@ CcPinRead (
|
|||
CcUnpinData(*Bcb);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Did we race for the BCB creation? */
|
||||
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
|
||||
iBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, TRUE);
|
||||
if (iBcb != NULL)
|
||||
{
|
||||
/* 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
|
||||
|
@ -469,7 +538,10 @@ CcUnpinDataForThread (
|
|||
FALSE);
|
||||
|
||||
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
|
||||
RemoveEntryList(&iBcb->BcbEntry);
|
||||
if (!IsListEmpty(&iBcb->BcbEntry))
|
||||
{
|
||||
RemoveEntryList(&iBcb->BcbEntry);
|
||||
}
|
||||
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
|
||||
|
||||
ExDeleteResourceLite(&iBcb->Lock);
|
||||
|
@ -543,7 +615,10 @@ CcUnpinRepinnedBcb (
|
|||
FALSE);
|
||||
|
||||
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
|
||||
RemoveEntryList(&iBcb->BcbEntry);
|
||||
if (!IsListEmpty(&iBcb->BcbEntry))
|
||||
{
|
||||
RemoveEntryList(&iBcb->BcbEntry);
|
||||
}
|
||||
KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
|
||||
|
||||
ExDeleteResourceLite(&iBcb->Lock);
|
||||
|
|
Loading…
Reference in a new issue