[NTOSKRNL]

Cherry pick r71407 by Trevor Thompson:
- Rewrote FsRtlGetNextBaseMcbEntry(), FsRtlLookupBaseMcbEntry(), and FsRtlNumberOfRunsInBaseMcb() using simpler logic.

This finally fixes broken MCB handling in ReactOS and allows FSDs relying on MCB to properly work in ReactOS!

CORE-11002 #resolve #comment Fixed in r71409

svn path=/trunk/; revision=71409
This commit is contained in:
Pierre Schweitzer 2016-05-26 16:35:45 +00:00
parent a5a8ffb511
commit e6b12e4774

View file

@ -5,6 +5,7 @@
* PURPOSE: Large Mapped Control Block (MCB) support for File System Drivers * PURPOSE: Large Mapped Control Block (MCB) support for File System Drivers
* PROGRAMMERS: Aleksey Bragin <aleksey@reactos.org> * PROGRAMMERS: Aleksey Bragin <aleksey@reactos.org>
* Jan Kratochvil <project-captive@jankratochvil.net> * Jan Kratochvil <project-captive@jankratochvil.net>
* Trevor Thompson
*/ */
/* INCLUDES ******************************************************************/ /* INCLUDES ******************************************************************/
@ -42,11 +43,13 @@ typedef struct _BASE_MCB_INTERNAL {
PLARGE_MCB_MAPPING Mapping; PLARGE_MCB_MAPPING Mapping;
} BASE_MCB_INTERNAL, *PBASE_MCB_INTERNAL; } BASE_MCB_INTERNAL, *PBASE_MCB_INTERNAL;
/*
static LARGE_MCB_MAPPING_ENTRY StaticRunBelow0 = { static LARGE_MCB_MAPPING_ENTRY StaticRunBelow0 = {
{{-1}}, /* ignored */ {{-1}}, // ignored
{{0}}, {{0}},
{{-1}}, /* ignored */ {{-1}}, // ignored
}; };
*/
static PVOID NTAPI McbMappingAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes) static PVOID NTAPI McbMappingAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
{ {
@ -321,103 +324,59 @@ FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb,
BOOLEAN BOOLEAN
NTAPI NTAPI
FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb, FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
IN ULONG RunIndex, IN ULONG RunIndex,
OUT PLONGLONG Vbn, OUT PLONGLONG Vbn,
OUT PLONGLONG Lbn, OUT PLONGLONG Lbn,
OUT PLONGLONG SectorCount) OUT PLONGLONG SectorCount)
{ {
BOOLEAN Result = FALSE; BOOLEAN Result = FALSE;
PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb; PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
ULONG RunIndexRemaining; PLARGE_MCB_MAPPING_ENTRY Run = NULL;
PLARGE_MCB_MAPPING_ENTRY Run, RunFound = NULL, RunFoundLower = NULL, RunFoundHigher = NULL; ULONG CurrentIndex = 0;
BOOLEAN First = TRUE; ULONGLONG LastVbn = 0;
ULONGLONG LastSectorCount = 0;
DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p)\n", OpaqueMcb, RunIndex, Vbn, Lbn, SectorCount); // Traverse the tree
RunIndexRemaining = RunIndex;
/* Traverse the tree */
for (Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, TRUE); for (Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, TRUE);
Run; Run;
Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, FALSE)) Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, FALSE))
{ {
if (First) // is the current index a hole?
if (Run->RunStartVbn.QuadPart > (LastVbn + LastSectorCount))
{ {
/* Take care when we must emulate missing 'hole' run at start of our run list. */ // Is this the index we're looking for?
if (Run->RunStartVbn.QuadPart > 0) if (RunIndex == CurrentIndex)
{ {
if (RunIndexRemaining == 0) *Vbn = LastVbn + LastSectorCount;
{ *Lbn = -1;
RunFoundLower = &StaticRunBelow0; *SectorCount = Run->RunStartVbn.QuadPart - *Vbn;
RunFoundHigher = Run;
/* stop the traversal */ Result = TRUE;
break; goto quit;
}
/* If someone wants RunIndex #1 we are already on it. */
RunIndexRemaining--;
} }
First = FALSE;
CurrentIndex++;
} }
if (RunIndexRemaining > 0) if (RunIndex == CurrentIndex)
{ {
/* FIXME: performance: non-linear direct seek to the requested RunIndex */ *Vbn = Run->RunStartVbn.QuadPart;
RunIndexRemaining--; *Lbn = Run->StartingLbn.QuadPart;
if (RunIndexRemaining == 0) *SectorCount = Run->RunEndVbn.QuadPart - Run->RunStartVbn.QuadPart;
RunFoundLower = Run;
else
RunIndexRemaining--;
/* continue the traversal */ Result = TRUE;
continue; goto quit;
} }
if (RunFoundLower) CurrentIndex++;
RunFoundHigher = Run; LastVbn = Run->RunStartVbn.QuadPart;
else LastSectorCount = Run->RunEndVbn.QuadPart - Run->RunStartVbn.QuadPart;
RunFound = Run;
/* stop the traversal */
break;
} }
if (RunFound) DPRINT("RunFound(%lu %lu %lu)\n", RunFound->RunStartVbn.LowPart, RunFound->RunEndVbn.LowPart, RunFound->StartingLbn.LowPart); // these values are meaningless when returning false (but setting them can be helpful for debugging purposes)
if (RunFoundLower) DPRINT("RunFoundLower(%lu %lu %lu)\n", RunFoundLower->RunStartVbn.LowPart, RunFoundLower->RunEndVbn.LowPart, RunFoundLower->StartingLbn.LowPart); *Vbn = 0xdeadbeef;
if (RunFoundHigher) DPRINT("RunFoundHigher(%lu %lu %lu)\n", RunFoundHigher->RunStartVbn.LowPart, RunFoundHigher->RunEndVbn.LowPart, RunFoundHigher->StartingLbn.LowPart); *Lbn = 0xdeadbeef;
*SectorCount = 0xdeadbeef;
if (RunFound)
{
ASSERT(RunFoundLower == NULL);
ASSERT(RunFoundHigher == NULL);
if (Vbn)
*Vbn = RunFound->RunStartVbn.QuadPart;
if (Lbn)
*Lbn = RunFound->StartingLbn.QuadPart;
if (SectorCount)
*SectorCount = RunFound->RunEndVbn.QuadPart - RunFound->RunStartVbn.QuadPart;
Result = TRUE;
goto quit;
}
if (RunFoundLower && RunFoundHigher)
{
//ASSERT(RunFoundHigher != NULL);
if (Vbn)
*Vbn = RunFoundLower->RunEndVbn.QuadPart;
if (Lbn)
*Lbn = -1;
if (SectorCount)
*SectorCount = RunFoundHigher->RunStartVbn.QuadPart - RunFoundLower->RunEndVbn.QuadPart;
Result = TRUE;
goto quit;
}
ASSERT(RunFoundHigher == NULL);
quit: quit:
DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb, RunIndex, Vbn, Lbn, SectorCount, Result, *Vbn, *Lbn, *SectorCount); DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb, RunIndex, Vbn, Lbn, SectorCount, Result, *Vbn, *Lbn, *SectorCount);
@ -538,117 +497,55 @@ FsRtlInitializeLargeMcbs(VOID)
} }
/* /*
* @unimplemented * @implemented
*/ */
BOOLEAN BOOLEAN
NTAPI NTAPI
FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb, FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
IN LONGLONG Vbn, IN LONGLONG Vbn,
OUT PLONGLONG Lbn OPTIONAL, OUT PLONGLONG Lbn OPTIONAL,
OUT PLONGLONG SectorCountFromLbn OPTIONAL, OUT PLONGLONG SectorCountFromLbn OPTIONAL,
OUT PLONGLONG StartingLbn OPTIONAL, OUT PLONGLONG StartingLbn OPTIONAL,
OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL, OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
OUT PULONG Index OPTIONAL) OUT PULONG Index OPTIONAL)
{ {
BOOLEAN Result = FALSE; BOOLEAN Result = FALSE;
PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb; ULONG i;
LONGLONG LastVbn = 0, LastLbn = 0, Count = 0; // the last values we've found during traversal
ULONG RunIndex = 0;
PLARGE_MCB_MAPPING_ENTRY Run, RunFound = NULL, RunFoundLower = NULL, RunFoundHigher = NULL;
BOOLEAN First = TRUE;
DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", OpaqueMcb, Vbn, Lbn, SectorCountFromLbn, StartingLbn, SectorCountFromStartingLbn, Index); DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", OpaqueMcb, Vbn, Lbn, SectorCountFromLbn, StartingLbn, SectorCountFromStartingLbn, Index);
/* Traverse the tree */ for (i = 0; FsRtlGetNextBaseMcbEntry(OpaqueMcb, i, &LastVbn, &LastLbn, &Count); i++)
for (Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, TRUE);
Run;
Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, FALSE))
{ {
if (First) // have we reached the target mapping?
if (Vbn < LastVbn + Count)
{ {
/* Take care when we must emulate missing 'hole' run at start of our run list. */ if (Lbn)
if (Run->RunStartVbn.QuadPart > 0)
{ {
RunIndex++; if (LastLbn == -1)
RunFoundLower = &StaticRunBelow0; *Lbn = -1;
else
*Lbn = LastLbn + (Vbn - LastVbn);
} }
First = FALSE;
}
if (Run->RunStartVbn.QuadPart <= Vbn && Vbn < Run->RunEndVbn.QuadPart) if (SectorCountFromLbn)
{ *SectorCountFromLbn = LastVbn + Count - Vbn;
RunFound = Run; if (StartingLbn)
RunFoundLower = NULL; *StartingLbn = LastLbn;
/* stop the traversal; hit */ if (SectorCountFromStartingLbn)
break; *SectorCountFromStartingLbn = LastVbn + Count - LastVbn;
} if (Index)
*Index = i;
if (Run->RunEndVbn.QuadPart <= Vbn) Result = TRUE;
{ goto quit;
RunFoundLower = Run;
if (Run->StartingLbn.QuadPart > 0)
{
RunIndex += 2;
}
/* continue the traversal; not yet crossed by the run */
continue;
} }
if (Vbn < Run->RunStartVbn.QuadPart)
{
RunFoundHigher = Run;
RunIndex++;
/* stop the traversal; the run skipped us */
break;
}
ASSERT(FALSE);
/* stop the traversal */
break;
} }
if (RunFound) if (Lbn)
{ *Lbn = -1;
ASSERT(RunFoundLower == NULL); if (StartingLbn)
ASSERT(RunFoundHigher == NULL); *StartingLbn = -1;
if (Lbn)
*Lbn = RunFound->StartingLbn.QuadPart + (Vbn - RunFound->RunStartVbn.QuadPart);
if (SectorCountFromLbn) /* FIXME: 'after' means including current 'Lbn' or without it? */
*SectorCountFromLbn = RunFound->RunEndVbn.QuadPart - Vbn;
if (StartingLbn)
*StartingLbn = RunFound->StartingLbn.QuadPart;
if (SectorCountFromStartingLbn)
*SectorCountFromStartingLbn = RunFound->RunEndVbn.QuadPart - RunFound->RunStartVbn.QuadPart;
if (Index)
*Index = RunIndex;
Result = TRUE;
goto quit;
}
if (RunFoundHigher)
{
/* search for hole */
ASSERT(RunFoundLower != NULL);
if (Lbn)
*Lbn = ~0ull;
if (SectorCountFromLbn) /* FIXME: 'after' means including current 'Lbn' or without it? */
*SectorCountFromLbn = RunFoundHigher->RunStartVbn.QuadPart - Vbn;
if (StartingLbn)
*StartingLbn = ~0ull;
if (SectorCountFromStartingLbn)
*SectorCountFromStartingLbn = RunFoundHigher->RunStartVbn.QuadPart - RunFoundLower->RunEndVbn.QuadPart;
if (Index)
*Index = RunIndex - 2;
Result = TRUE;
goto quit;
}
/* We may have some 'RunFoundLower'. */
quit: quit:
DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n", DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
@ -848,28 +745,18 @@ ULONG
NTAPI NTAPI
FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB OpaqueMcb) FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB OpaqueMcb)
{ {
PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
LONGLONG LbnAtVbn0 = -1;
ULONG NumberOfRuns = 0; ULONG NumberOfRuns = 0;
LONGLONG Vbn, Lbn, Count;
int i;
DPRINT("FsRtlNumberOfRunsInBaseMcb(%p)\n", OpaqueMcb); DPRINT("FsRtlNumberOfRunsInBaseMcb(%p)\n", OpaqueMcb);
if (Mcb->PairCount == 0) goto quit; // Count how many Mcb entries there are
for (i = 0; FsRtlGetNextBaseMcbEntry(OpaqueMcb, i, &Vbn, &Lbn, &Count); i++)
{
NumberOfRuns++;
}
FsRtlLookupBaseMcbEntry(OpaqueMcb,
0, /* Vbn */
&LbnAtVbn0, /* Lbn */
NULL, NULL, NULL, NULL); /* 4 output arguments - not interested in them */
/* Return the count */
//return Mcb->PairCount;
/* Return the number of 'real' and 'hole' runs.
* If we do not have sector 0 as 'real' emulate a 'hole' there.
*/
NumberOfRuns = Mcb->PairCount * 2 - (LbnAtVbn0 != -1 ? 1 : 0); /* include holes as runs */
quit:
DPRINT("FsRtlNumberOfRunsInBaseMcb(%p) = %d\n", OpaqueMcb, NumberOfRuns); DPRINT("FsRtlNumberOfRunsInBaseMcb(%p) = %d\n", OpaqueMcb, NumberOfRuns);
return NumberOfRuns; return NumberOfRuns;
} }