https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3d4cf8d2d8327c8392fdf4...
commit 3d4cf8d2d8327c8392fdf4cf589508f58808de83 Author: Jérôme Gardou jerome.gardou@reactos.org AuthorDate: Mon Nov 30 12:42:33 2020 +0100 Commit: Jérôme Gardou jerome.gardou@reactos.org CommitDate: Tue Dec 8 11:48:00 2020 +0100
[NTOS/FSRTL] Fix MCB tests
- Fix behaviour when adding or removing entries in the middle of an existing run - Do not touch output parameters when failing, caller might rely on this. --- ntoskrnl/fsrtl/largemcb.c | 73 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 15 deletions(-)
diff --git a/ntoskrnl/fsrtl/largemcb.c b/ntoskrnl/fsrtl/largemcb.c index 0ce7949e5ff..7c2749ea810 100644 --- a/ntoskrnl/fsrtl/largemcb.c +++ b/ntoskrnl/fsrtl/largemcb.c @@ -143,7 +143,7 @@ FsRtlAddBaseMcbEntry(IN PBASE_MCB OpaqueMcb, LARGE_MCB_MAPPING_ENTRY Node, NeedleRun; PLARGE_MCB_MAPPING_ENTRY LowerRun, HigherRun; BOOLEAN NewElement; - LONGLONG IntLbn; + LONGLONG IntLbn, IntSectorCount;
DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d)\n", OpaqueMcb, Vbn, Lbn, SectorCount);
@@ -159,7 +159,7 @@ FsRtlAddBaseMcbEntry(IN PBASE_MCB OpaqueMcb, goto quit; }
- IntResult = FsRtlLookupBaseMcbEntry(OpaqueMcb, Vbn, &IntLbn, NULL, NULL, NULL, NULL); + IntResult = FsRtlLookupBaseMcbEntry(OpaqueMcb, Vbn, &IntLbn, &IntSectorCount, NULL, NULL, NULL); if (IntResult) { if (IntLbn != -1 && IntLbn != Lbn) @@ -167,6 +167,12 @@ FsRtlAddBaseMcbEntry(IN PBASE_MCB OpaqueMcb, Result = FALSE; goto quit; } + + if ((IntLbn != -1) && (IntSectorCount >= SectorCount)) + { + /* This is a no-op */ + goto quit; + } }
/* clean any possible previous entries in our range */ @@ -314,7 +320,7 @@ FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb, * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant? * * Retrieves the parameters of the specified run with index @RunIndex. - * + * * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping. * libcaptive does not store 'hole' information to its #GTree. * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1. @@ -336,7 +342,7 @@ FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb, ULONGLONG LastVbn = 0; ULONGLONG LastSectorCount = 0;
- // Traverse the tree + // Traverse the tree for (Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, TRUE); Run; Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, FALSE)) @@ -373,11 +379,6 @@ FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb, LastSectorCount = Run->RunEndVbn.QuadPart - Run->RunStartVbn.QuadPart; }
- // these values are meaningless when returning false (but setting them can be helpful for debugging purposes) - *Vbn = 0xdeadbeef; - *Lbn = 0xdeadbeef; - *SectorCount = 0xdeadbeef; - quit: DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb, RunIndex, Vbn, Lbn, SectorCount, Result, *Vbn, *Lbn, *SectorCount); return Result; @@ -542,11 +543,6 @@ FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb, } }
- if (Lbn) - *Lbn = -1; - if (StartingLbn) - *StartingLbn = -1; - quit: DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n", OpaqueMcb, Vbn, Lbn, SectorCountFromLbn, StartingLbn, SectorCountFromStartingLbn, Index, Result, @@ -821,7 +817,7 @@ FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
NeedleRun.RunStartVbn.QuadPart = Vbn; NeedleRun.RunEndVbn.QuadPart = Vbn + SectorCount; - NeedleRun.StartingLbn.QuadPart = ~0ULL; + NeedleRun.StartingLbn.QuadPart = -1;
/* adjust/destroy all intersecting ranges */ Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare; @@ -829,13 +825,60 @@ FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb, { if (HaystackRun->RunStartVbn.QuadPart < NeedleRun.RunStartVbn.QuadPart) { + LONGLONG HaystackRunEnd = HaystackRun->RunEndVbn.QuadPart; ASSERT(HaystackRun->RunEndVbn.QuadPart > NeedleRun.RunStartVbn.QuadPart); + HaystackRun->RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart; + + if (HaystackRunEnd > NeedleRun.RunEndVbn.QuadPart) + { + /* The run we are deleting is included in the run we just truncated. + * Add the tail back. */ + LARGE_MCB_MAPPING_ENTRY TailRun; + BOOLEAN NewElement; + + TailRun.RunStartVbn.QuadPart = NeedleRun.RunEndVbn.QuadPart; + TailRun.RunEndVbn.QuadPart = HaystackRunEnd; + TailRun.StartingLbn.QuadPart = HaystackRun->StartingLbn.QuadPart + (NeedleRun.RunEndVbn.QuadPart - HaystackRun->RunStartVbn.QuadPart); + + Mcb->Mapping->Table.CompareRoutine = McbMappingCompare; + + RtlInsertElementGenericTable(&Mcb->Mapping->Table, &TailRun, sizeof(TailRun), &NewElement); + ++Mcb->PairCount; + ASSERT(NewElement); + + Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare; + } } else if (HaystackRun->RunEndVbn.QuadPart > NeedleRun.RunEndVbn.QuadPart) { + LONGLONG HaystackRunStart = HaystackRun->RunStartVbn.QuadPart; + LONGLONG HaystackStartingLbn = HaystackRun->StartingLbn.QuadPart; + ASSERT(HaystackRun->RunStartVbn.QuadPart < NeedleRun.RunEndVbn.QuadPart); HaystackRun->RunStartVbn.QuadPart = NeedleRun.RunEndVbn.QuadPart; + /* Adjust the starting LBN */ + HaystackRun->StartingLbn.QuadPart += NeedleRun.RunEndVbn.QuadPart - HaystackRunStart; + + if (HaystackRunStart < NeedleRun.RunStartVbn.QuadPart) + { + /* The run we are deleting is included in the run we just truncated. + * Add the head back. */ + LARGE_MCB_MAPPING_ENTRY HeadRun; + BOOLEAN NewElement; + + HeadRun.RunStartVbn.QuadPart = HaystackRunStart; + HeadRun.RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart; + HeadRun.StartingLbn.QuadPart = HaystackStartingLbn; + + Mcb->Mapping->Table.CompareRoutine = McbMappingCompare; + + RtlInsertElementGenericTable(&Mcb->Mapping->Table, &HeadRun, sizeof(HeadRun), &NewElement); + ++Mcb->PairCount; + ASSERT(NewElement); + + Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare; + } } else {