2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL v2 - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/largemcb.c
5 * PURPOSE: Large Mapped Control Block (MCB) support for File System Drivers
6 * PROGRAMMERS: Aleksey Bragin <aleksey@reactos.org>
7 * Jan Kratochvil <project-captive@jankratochvil.net>
10 /* INCLUDES ******************************************************************/
16 #define MIN(x,y) (((x)<(y))?(x):(y))
17 #define MAX(x,y) (((x)>(y))?(x):(y))
19 /* GLOBALS *******************************************************************/
21 PAGED_LOOKASIDE_LIST FsRtlFirstMappingLookasideList
;
22 NPAGED_LOOKASIDE_LIST FsRtlFastMutexLookasideList
;
24 /* We use only real 'mapping' runs; we do not store 'holes' to our GTree. */
25 typedef struct _LARGE_MCB_MAPPING_ENTRY
// run
27 LARGE_INTEGER RunStartVbn
;
28 LARGE_INTEGER RunEndVbn
; /* RunStartVbn+SectorCount; that means +1 after the last sector */
29 LARGE_INTEGER StartingLbn
; /* Lbn of 'RunStartVbn' */
30 } LARGE_MCB_MAPPING_ENTRY
, *PLARGE_MCB_MAPPING_ENTRY
;
32 typedef struct _LARGE_MCB_MAPPING
// mcb_priv
34 RTL_GENERIC_TABLE Table
;
35 } LARGE_MCB_MAPPING
, *PLARGE_MCB_MAPPING
;
37 typedef struct _BASE_MCB_INTERNAL
{
38 ULONG MaximumPairCount
;
42 PLARGE_MCB_MAPPING Mapping
;
43 } BASE_MCB_INTERNAL
, *PBASE_MCB_INTERNAL
;
45 static LARGE_MCB_MAPPING_ENTRY StaticRunBelow0
= {
51 static PVOID NTAPI
McbMappingAllocate(PRTL_GENERIC_TABLE Table
, CLONG Bytes
)
54 PBASE_MCB Mcb
= (PBASE_MCB
)Table
->TableContext
;
55 Result
= ExAllocatePoolWithTag(Mcb
->PoolType
, Bytes
, 'LMCB');
56 DPRINT("McbMappingAllocate(%lu) => %p\n", Bytes
, Result
);
60 static VOID NTAPI
McbMappingFree(PRTL_GENERIC_TABLE Table
, PVOID Buffer
)
62 DPRINT("McbMappingFree(%p)\n", Buffer
);
63 ExFreePoolWithTag(Buffer
, 'LMCB');
67 RTL_GENERIC_COMPARE_RESULTS
69 McbMappingCompare(PRTL_GENERIC_TABLE Table
,
73 PLARGE_MCB_MAPPING_ENTRY A
= PtrA
, B
= PtrB
;
74 RTL_GENERIC_COMPARE_RESULTS Res
;
79 if (A
->RunStartVbn
.QuadPart
== B
->RunStartVbn
.QuadPart
&& A
->RunEndVbn
.QuadPart
== B
->RunEndVbn
.QuadPart
)
81 else if (A
->RunEndVbn
.QuadPart
<= B
->RunStartVbn
.QuadPart
)
82 Res
= GenericLessThan
;
83 else if (A
->RunEndVbn
.QuadPart
>= B
->RunStartVbn
.QuadPart
)
84 Res
= GenericGreaterThan
;
94 static RTL_GENERIC_COMPARE_RESULTS NTAPI
McbMappingIntersectCompare(PRTL_GENERIC_TABLE Table
, PVOID PtrA
, PVOID PtrB
)
96 PLARGE_MCB_MAPPING_ENTRY A
= PtrA
, B
= PtrB
;
97 RTL_GENERIC_COMPARE_RESULTS Res
;
99 if (A
->RunStartVbn
.QuadPart
<= B
->RunStartVbn
.QuadPart
&& A
->RunEndVbn
.QuadPart
> B
->RunStartVbn
.QuadPart
)
101 else if (A
->RunStartVbn
.QuadPart
>= B
->RunStartVbn
.QuadPart
&& B
->RunEndVbn
.QuadPart
> A
->RunStartVbn
.QuadPart
)
103 else if (A
->RunStartVbn
.QuadPart
< B
->RunStartVbn
.QuadPart
)
104 Res
= GenericLessThan
;
105 else if (A
->RunStartVbn
.QuadPart
> B
->RunStartVbn
.QuadPart
)
106 Res
= GenericGreaterThan
;
114 /* PUBLIC FUNCTIONS **********************************************************/
118 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
119 * %NULL value is forbidden.
120 * @Vbn: Starting virtual block number of the wished range.
121 * @Lbn: Starting logical block number of the wished range.
122 * @SectorCount: Length of the wished range.
123 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
125 * Adds the specified range @Vbn ... @Vbn+@SectorCount-1 to @Mcb.
126 * Any mappings previously in this range are deleted first.
128 * Returns: %TRUE if successful.
132 FsRtlAddBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
135 IN LONGLONG SectorCount
)
137 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
138 LARGE_MCB_MAPPING_ENTRY Node
, NeedleRun
;
139 PLARGE_MCB_MAPPING_ENTRY LowerRun
, HigherRun
;
142 if (Vbn
< 0) return FALSE
;
143 if (SectorCount
<= 0) return FALSE
;
145 /* clean any possible previous entries in our range */
146 FsRtlRemoveBaseMcbEntry(OpaqueMcb
, Vbn
, SectorCount
);
148 // We need to map [Vbn, Vbn+SectorCount) to [Lbn, Lbn+SectorCount),
149 // taking in account the fact that we need to merge these runs if
150 // they are adjacent or overlap, but fail if new run fully fits into another run
152 /* initially we think we will be inserted as a separate run */
153 Node
.RunStartVbn
.QuadPart
= Vbn
;
154 Node
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
155 Node
.StartingLbn
.QuadPart
= Lbn
;
157 /* optionally merge with lower run */
158 NeedleRun
.RunStartVbn
.QuadPart
= Node
.RunStartVbn
.QuadPart
- 1;
159 NeedleRun
.RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
+ 1;
160 NeedleRun
.StartingLbn
.QuadPart
= ~0ULL;
161 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
162 if ((LowerRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)))
164 ASSERT(LowerRun
->RunEndVbn
.QuadPart
== Node
.RunStartVbn
.QuadPart
);
165 Node
.RunStartVbn
.QuadPart
= LowerRun
->RunStartVbn
.QuadPart
;
166 Node
.StartingLbn
.QuadPart
= LowerRun
->StartingLbn
.QuadPart
;
167 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
168 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, LowerRun
);
169 DPRINT("Intersecting lower run found (%I64d,%I64d) Lbn: %I64d\n", LowerRun
->RunStartVbn
.QuadPart
, LowerRun
->RunEndVbn
.QuadPart
, LowerRun
->StartingLbn
.QuadPart
);
172 /* optionally merge with higher run */
173 NeedleRun
.RunStartVbn
.QuadPart
= Node
.RunEndVbn
.QuadPart
;
174 NeedleRun
.RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
+ 1;
175 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
176 if ((HigherRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)))
178 ASSERT(HigherRun
->RunStartVbn
.QuadPart
== Node
.RunEndVbn
.QuadPart
);
179 Node
.RunEndVbn
.QuadPart
= HigherRun
->RunEndVbn
.QuadPart
;
180 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
181 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, HigherRun
);
182 DPRINT("Intersecting higher run found (%I64d,%I64d) Lbn: %I64d\n", HigherRun
->RunStartVbn
.QuadPart
, HigherRun
->RunEndVbn
.QuadPart
, HigherRun
->StartingLbn
.QuadPart
);
184 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
186 /* finally insert the resulting run */
187 RtlInsertElementGenericTable(&Mcb
->Mapping
->Table
, &Node
, sizeof(Node
), &NewElement
);
189 Node
.RunStartVbn
.QuadPart
= Vbn
;
190 Node
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
191 Node
.StartingLbn
.QuadPart
= Lbn
;
193 // NB: Two consecutive runs can only be merged, if actual LBNs also match!
196 Existing->RunStartVbn
204 Existing->RunStartVbn
212 Existing->RunStartVbn
220 Existing->RunStartVbn
228 Situation with holes:
229 1. Holes at both ends
230 2. Hole at the right, new run merged with the previous run
231 3. Hole at the right, new run is not merged with the previous run
232 4. Hole at the left, new run merged with the next run
233 5. Hole at the left, new run is not merged with the next run
234 6. No holes, exact fit to merge with both previous and next runs
235 7. No holes, merges only with the next run
236 8. No holes, merges only with the previous run
237 9. No holes, does not merge with next or prev runs
240 Overwriting existing mapping is not possible and results in FALSE being returned
250 FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb
,
253 IN LONGLONG SectorCount
)
257 DPRINT("Mcb %p Vbn %I64d Lbn %I64d SectorCount %I64d\n", Mcb
, Vbn
, Lbn
, SectorCount
);
259 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
260 Result
= FsRtlAddBaseMcbEntry(&(Mcb
->BaseMcb
),
264 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
266 DPRINT("Done %u\n", Result
);
273 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
274 * %NULL value is forbidden.
275 * @RunIndex: Requested range index to retrieve.
276 * @Vbn: Returns the starting virtual block number of the wished range.
277 * %NULL pointer is forbidden.
278 * @Lbn: Returns the starting logical block number of the wished range (or -1 if it is a hole).
279 * %NULL pointer is forbidden.
280 * @SectorCount: Returns the length of the wished range.
281 * %NULL pointer is forbidden.
282 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
284 * Retrieves the parameters of the specified run with index @RunIndex.
286 * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping.
287 * libcaptive does not store 'hole' information to its #GTree.
288 * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1.
290 * Returns: %TRUE if successful.
294 FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
298 OUT PLONGLONG SectorCount
)
300 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
301 ULONG RunIndexRemaining
;
302 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
303 BOOLEAN First
= TRUE
;
305 RunIndexRemaining
= RunIndex
;
307 /* Traverse the tree */
308 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
310 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
314 /* Take care when we must emulate missing 'hole' run at start of our run list. */
315 if (Run
->RunStartVbn
.QuadPart
> 0)
317 if (RunIndexRemaining
== 0)
319 RunFoundLower
= &StaticRunBelow0
;
320 RunFoundHigher
= Run
;
322 /* stop the traversal */
325 /* If someone wants RunIndex #1 we are already on it. */
331 if (RunIndexRemaining
> 0)
333 /* FIXME: performance: non-linear direct seek to the requested RunIndex */
335 if (RunIndexRemaining
== 0)
340 /* continue the traversal */
345 RunFoundHigher
= Run
;
349 /* stop the traversal */
353 if (RunFound
) DPRINT("RunFound(%lu %lu %lu)\n", RunFound
->RunStartVbn
.LowPart
, RunFound
->RunEndVbn
.LowPart
, RunFound
->StartingLbn
.LowPart
);
354 if (RunFoundLower
) DPRINT("RunFoundLower(%lu %lu %lu)\n", RunFoundLower
->RunStartVbn
.LowPart
, RunFoundLower
->RunEndVbn
.LowPart
, RunFoundLower
->StartingLbn
.LowPart
);
355 if (RunFoundHigher
) DPRINT("RunFoundHigher(%lu %lu %lu)\n", RunFoundHigher
->RunStartVbn
.LowPart
, RunFoundHigher
->RunEndVbn
.LowPart
, RunFoundHigher
->StartingLbn
.LowPart
);
359 ASSERT(RunFoundLower
== NULL
);
360 ASSERT(RunFoundHigher
== NULL
);
363 *Vbn
= RunFound
->RunStartVbn
.QuadPart
;
365 *Lbn
= RunFound
->StartingLbn
.QuadPart
;
367 *SectorCount
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
372 if (RunFoundLower
&& RunFoundHigher
)
374 //ASSERT(RunFoundHigher != NULL);
377 *Vbn
= RunFoundLower
->RunEndVbn
.QuadPart
;
381 *SectorCount
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
386 ASSERT(RunFoundHigher
== NULL
);
395 FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb
,
399 OUT PLONGLONG SectorCount
)
403 DPRINT("FsRtlGetNextLargeMcbEntry Mcb %p RunIndex %lu\n", Mcb
, RunIndex
);
405 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
406 Result
= FsRtlGetNextBaseMcbEntry(&(Mcb
->BaseMcb
),
411 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
413 DPRINT("Done %u\n", Result
);
423 FsRtlInitializeBaseMcb(IN PBASE_MCB OpaqueMcb
,
424 IN POOL_TYPE PoolType
)
426 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
428 if (PoolType
== PagedPool
)
430 Mcb
->Mapping
= ExAllocateFromPagedLookasideList(&FsRtlFirstMappingLookasideList
);
434 Mcb
->Mapping
= ExAllocatePoolWithTag(PoolType
| POOL_RAISE_IF_ALLOCATION_FAILURE
,
435 sizeof(LARGE_MCB_MAPPING
),
439 Mcb
->PoolType
= PoolType
;
441 Mcb
->MaximumPairCount
= MAXIMUM_PAIR_COUNT
;
442 RtlInitializeGenericTable(&Mcb
->Mapping
->Table
,
454 FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb
,
455 IN POOL_TYPE PoolType
)
457 Mcb
->GuardedMutex
= ExAllocateFromNPagedLookasideList(&FsRtlFastMutexLookasideList
);
459 KeInitializeGuardedMutex(Mcb
->GuardedMutex
);
463 FsRtlInitializeBaseMcb(&(Mcb
->BaseMcb
), PoolType
);
465 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
467 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
469 Mcb
->GuardedMutex
= NULL
;
480 FsRtlInitializeLargeMcbs(VOID
)
482 /* Initialize the list for the MCB */
483 ExInitializePagedLookasideList(&FsRtlFirstMappingLookasideList
,
486 POOL_RAISE_IF_ALLOCATION_FAILURE
,
487 sizeof(LARGE_MCB_MAPPING
),
489 0); /* FIXME: Should be 4 */
491 /* Initialize the list for the guarded mutex */
492 ExInitializeNPagedLookasideList(&FsRtlFastMutexLookasideList
,
495 POOL_RAISE_IF_ALLOCATION_FAILURE
,
496 sizeof(KGUARDED_MUTEX
),
498 0); /* FIXME: Should be 32 */
506 FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
508 OUT PLONGLONG Lbn OPTIONAL
,
509 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
510 OUT PLONGLONG StartingLbn OPTIONAL
,
511 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
512 OUT PULONG Index OPTIONAL
)
514 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
518 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
519 BOOLEAN First
= TRUE
;
521 /* Traverse the tree */
522 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
524 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
528 /* Take care when we must emulate missing 'hole' run at start of our run list. */
529 if (Run
->RunStartVbn
.QuadPart
> 0)
532 RunFoundLower
= &StaticRunBelow0
;
537 if (Run
->RunStartVbn
.QuadPart
<= Vbn
&& Vbn
< Run
->RunEndVbn
.QuadPart
)
540 RunFoundLower
= NULL
;
541 /* stop the traversal; hit */
545 if (Run
->RunEndVbn
.QuadPart
<= Vbn
)
548 if (Run
->StartingLbn
.QuadPart
> 0)
552 /* continue the traversal; not yet crossed by the run */
556 if (Vbn
< Run
->RunStartVbn
.QuadPart
)
558 RunFoundHigher
= Run
;
560 /* stop the traversal; the run skipped us */
565 /* stop the traversal */
571 ASSERT(RunFoundLower
== NULL
);
572 ASSERT(RunFoundHigher
== NULL
);
575 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (Vbn
- RunFound
->RunStartVbn
.QuadPart
);
577 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
578 *SectorCountFromLbn
= RunFound
->RunEndVbn
.QuadPart
- Vbn
;
580 *StartingLbn
= RunFound
->StartingLbn
.QuadPart
;
581 if (SectorCountFromStartingLbn
)
582 *SectorCountFromStartingLbn
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
591 /* search for hole */
592 ASSERT(RunFoundLower
!= NULL
);
596 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
597 *SectorCountFromLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- Vbn
;
599 *StartingLbn
= ~0ull;
600 if (SectorCountFromStartingLbn
)
601 *SectorCountFromStartingLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
603 *Index
= RunIndex
- 2;
608 /* We may have some 'RunFoundLower'. */
617 FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb
,
619 OUT PLONGLONG Lbn OPTIONAL
,
620 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
621 OUT PLONGLONG StartingLbn OPTIONAL
,
622 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
623 OUT PULONG Index OPTIONAL
)
627 DPRINT("FsRtlLookupLargeMcbEntry Mcb %p Vbn %I64d\n", Mcb
, Vbn
);
629 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
630 Result
= FsRtlLookupBaseMcbEntry(&(Mcb
->BaseMcb
),
635 SectorCountFromStartingLbn
,
637 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
639 DPRINT("Done %u\n", Result
);
646 FsRtlLookupLastLargeMcbEntryAndIndex_internal(IN PBASE_MCB_INTERNAL Mcb
,
649 OUT PULONG Index OPTIONAL
)
652 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
;
653 LONGLONG LastVbn
= 0;
655 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
657 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
659 /* Take care when we must emulate missing 'hole' runs. */
660 if (Run
->RunStartVbn
.QuadPart
> LastVbn
)
664 LastVbn
= Run
->RunEndVbn
.QuadPart
;
676 *Vbn
= RunFound
->RunEndVbn
.QuadPart
- 1;
682 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
) - 1;
691 *Index
= RunIndex
- 1;
703 FsRtlLookupLastBaseMcbEntryAndIndex(IN PBASE_MCB OpaqueMcb
,
704 IN OUT PLONGLONG LargeVbn
,
705 IN OUT PLONGLONG LargeLbn
,
708 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
710 return FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, LargeVbn
, LargeLbn
, Index
);
718 FsRtlLookupLastLargeMcbEntryAndIndex(IN PLARGE_MCB OpaqueMcb
,
719 OUT PLONGLONG LargeVbn
,
720 OUT PLONGLONG LargeLbn
,
725 DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex %p\n", OpaqueMcb
);
727 KeAcquireGuardedMutex(OpaqueMcb
->GuardedMutex
);
728 Result
= FsRtlLookupLastBaseMcbEntryAndIndex(&(OpaqueMcb
->BaseMcb
),
732 KeReleaseGuardedMutex(OpaqueMcb
->GuardedMutex
);
734 DPRINT("Done %u\n", Result
);
744 FsRtlLookupLastBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
748 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
750 return FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, Vbn
, Lbn
, NULL
); /* Index */
758 FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb
,
764 DPRINT("FsRtlLookupLastLargeMcbEntry Mcb %p\n", Mcb
);
766 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
767 Result
= FsRtlLookupLastBaseMcbEntry(&(Mcb
->BaseMcb
),
770 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
772 DPRINT("Done %u\n", Result
);
782 FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB OpaqueMcb
)
784 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
785 LONGLONG LbnAtVbn0
= -1;
786 ULONG Nodes
= RtlNumberGenericTableElements(&Mcb
->Mapping
->Table
);
788 if (Nodes
== 0) return 0;
790 FsRtlLookupBaseMcbEntry(OpaqueMcb
,
792 &LbnAtVbn0
, /* Lbn */
793 NULL
, NULL
, NULL
, NULL
); /* 4 output arguments - not interested in them */
796 /* Return the count */
797 //return Mcb->PairCount;
798 /* Return the number of 'real' and 'hole' runs.
799 * If we do not have sector 0 as 'real' emulate a 'hole' there.
801 return Nodes
* 2 - (LbnAtVbn0
!= -1 ? 1 : 0); /* include holes as runs */
809 FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb
)
813 DPRINT("FsRtlNumberOfRunsInLargeMcb Mcb %p\n", Mcb
);
815 /* Read the number of runs while holding the MCB lock */
816 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
817 NumberOfRuns
= FsRtlNumberOfRunsInBaseMcb(&(Mcb
->BaseMcb
));
818 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
820 DPRINT("Done %lu\n", NumberOfRuns
);
822 /* Return the count */
828 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
829 * %NULL value is forbidden.
830 * @Vbn: Starting virtual block number to specify the range to delete.
831 * @SectorCount: Length of the range to delete.
832 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
834 * Deletes any possible @Mcb mappings in the given range @Vbn ... @Vbn+@SectorCount-1.
835 * This call has no problems if no mappings exist there yet.
839 FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
841 IN LONGLONG SectorCount
)
843 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
844 LARGE_MCB_MAPPING_ENTRY NeedleRun
;
845 PLARGE_MCB_MAPPING_ENTRY HaystackRun
;
847 if (Vbn
< 0 || SectorCount
<= 0) return FALSE
;
848 if (Vbn
+ SectorCount
<= Vbn
) return FALSE
;
850 NeedleRun
.RunStartVbn
.QuadPart
= Vbn
;
851 NeedleRun
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
852 NeedleRun
.StartingLbn
.QuadPart
= ~0ULL;
854 /* adjust/destroy all intersecting ranges */
855 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
856 while ((HaystackRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)))
858 if (HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunStartVbn
.QuadPart
)
860 ASSERT(HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunStartVbn
.QuadPart
);
861 HaystackRun
->RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
;
863 else if (HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunEndVbn
.QuadPart
)
865 ASSERT(HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunEndVbn
.QuadPart
);
866 HaystackRun
->RunStartVbn
.QuadPart
= NeedleRun
.RunEndVbn
.QuadPart
;
870 ASSERT(NeedleRun
.RunStartVbn
.QuadPart
>= HaystackRun
->RunStartVbn
.QuadPart
);
871 //ASSERT(NeedleRun.RunEndVbn.QuadPart <= HaystackRun->RunEndVbn.QuadPart);
872 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
873 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, HaystackRun
);
874 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
877 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
887 FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb
,
889 IN LONGLONG SectorCount
)
891 DPRINT("FsRtlRemoveLargeMcbEntry Mcb %p, Vbn %I64d, SectorCount %I64d\n", Mcb
, Vbn
, SectorCount
);
893 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
894 FsRtlRemoveBaseMcbEntry(&(Mcb
->BaseMcb
), Vbn
, SectorCount
);
895 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
905 FsRtlResetBaseMcb(IN PBASE_MCB OpaqueMcb
)
907 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
908 PLARGE_MCB_MAPPING_ENTRY Element
;
910 while (RtlNumberGenericTableElements(&Mcb
->Mapping
->Table
) &&
911 (Element
= (PLARGE_MCB_MAPPING_ENTRY
)RtlGetElementGenericTable(&Mcb
->Mapping
->Table
, 0)))
913 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, Element
);
917 Mcb
->MaximumPairCount
= 0;
925 FsRtlResetLargeMcb(IN PLARGE_MCB Mcb
,
926 IN BOOLEAN SelfSynchronized
)
928 if (!SelfSynchronized
)
929 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
931 FsRtlResetBaseMcb(&Mcb
->BaseMcb
);
933 if (!SelfSynchronized
)
934 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
942 FsRtlSplitBaseMcb(IN PBASE_MCB OpaqueMcb
,
946 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
947 PLARGE_MCB_MAPPING_ENTRY Run
, InsertLowerRun
= NULL
, ExistingRun
= NULL
;
950 /* Traverse the tree */
951 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
953 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
955 /* unaffected run? */
956 /* FIXME: performance: effective skip of all 'lower' runs without traversing them */
957 if (Vbn
>= Run
->RunEndVbn
.QuadPart
) { DPRINT("Skipping it\n"); continue; }
959 /* crossing run to be split?
960 * 'lower_run' is created on the original place; just shortened.
961 * current 'run' is shifted up later
963 if (Vbn
< Run
->RunEndVbn
.QuadPart
)
965 /* FIXME: shift 'run->Lbn_start' ? */
966 Run
->RunStartVbn
.QuadPart
= Vbn
;
968 InsertLowerRun
= NULL
;
971 /* Shift the current 'run'.
972 * Ordering is not changed in Generic Tree so I hope I do not need to reinsert it.
974 Run
->RunStartVbn
.QuadPart
+= Amount
;
975 ASSERT(Run
->RunEndVbn
.QuadPart
+ Amount
> Run
->RunEndVbn
.QuadPart
); /* overflow? */
976 Run
->RunEndVbn
.QuadPart
+= Amount
;
977 /* FIXME: shift 'run->Lbn_start' ? */
979 /* continue the traversal */
983 ExistingRun
= RtlInsertElementGenericTable(&Mcb
->Mapping
->Table
, InsertLowerRun
, sizeof(*InsertLowerRun
), &NewElement
);
985 ASSERT(ExistingRun
== NULL
);
995 FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb
,
1001 DPRINT("FsRtlSplitLargeMcb %p, Vbn %I64d, Amount %I64d\n", Mcb
, Vbn
, Amount
);
1003 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1004 Result
= FsRtlSplitBaseMcb(&(Mcb
->BaseMcb
),
1007 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1009 DPRINT("Done %u\n", Result
);
1019 FsRtlTruncateBaseMcb(IN PBASE_MCB OpaqueMcb
,
1022 DPRINT("Mcb=%p, Vbn=%I64d\n", OpaqueMcb
, Vbn
);
1023 FsRtlRemoveBaseMcbEntry(OpaqueMcb
, Vbn
, MAXLONG
- Vbn
+ 1);
1031 FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb
,
1034 DPRINT("FsRtlTruncateLargeMcb %p Vbn %I64d\n", Mcb
, Vbn
);
1035 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1036 FsRtlTruncateBaseMcb(&(Mcb
->BaseMcb
), Vbn
);
1037 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1046 FsRtlUninitializeBaseMcb(IN PBASE_MCB Mcb
)
1048 FsRtlResetBaseMcb(Mcb
);
1050 if ((Mcb
->PoolType
== PagedPool
)/* && (Mcb->MaximumPairCount == MAXIMUM_PAIR_COUNT)*/)
1052 ExFreeToPagedLookasideList(&FsRtlFirstMappingLookasideList
,
1057 ExFreePoolWithTag(Mcb
->Mapping
, 'FSBC');
1066 FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb
)
1068 if (Mcb
->GuardedMutex
)
1070 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
1072 FsRtlUninitializeBaseMcb(&(Mcb
->BaseMcb
));