https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3d4cf8d2d8327c8392fdf…
commit 3d4cf8d2d8327c8392fdf4cf589508f58808de83
Author: Jérôme Gardou <jerome.gardou(a)reactos.org>
AuthorDate: Mon Nov 30 12:42:33 2020 +0100
Commit: Jérôme Gardou <jerome.gardou(a)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
{