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 BOOLEAN Result
= TRUE
;
139 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
140 LARGE_MCB_MAPPING_ENTRY Node
, NeedleRun
;
141 PLARGE_MCB_MAPPING_ENTRY LowerRun
, HigherRun
;
145 DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, Lbn
, SectorCount
);
153 if (SectorCount
<= 0)
159 IntResult
= FsRtlLookupBaseMcbEntry(OpaqueMcb
, Vbn
, &IntLbn
, NULL
, NULL
, NULL
, NULL
);
162 if (IntLbn
!= -1 && IntLbn
!= Lbn
)
169 /* clean any possible previous entries in our range */
170 FsRtlRemoveBaseMcbEntry(OpaqueMcb
, Vbn
, SectorCount
);
172 // We need to map [Vbn, Vbn+SectorCount) to [Lbn, Lbn+SectorCount),
173 // taking in account the fact that we need to merge these runs if
174 // they are adjacent or overlap, but fail if new run fully fits into another run
176 /* initially we think we will be inserted as a separate run */
177 Node
.RunStartVbn
.QuadPart
= Vbn
;
178 Node
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
179 Node
.StartingLbn
.QuadPart
= Lbn
;
181 /* optionally merge with lower run */
182 NeedleRun
.RunStartVbn
.QuadPart
= Node
.RunStartVbn
.QuadPart
- 1;
183 NeedleRun
.RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
+ 1;
184 NeedleRun
.StartingLbn
.QuadPart
= ~0ULL;
185 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
186 if ((LowerRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)) &&
187 (LowerRun
->StartingLbn
.QuadPart
+ (LowerRun
->RunEndVbn
.QuadPart
- LowerRun
->RunStartVbn
.QuadPart
) == Node
.StartingLbn
.QuadPart
))
189 ASSERT(LowerRun
->RunEndVbn
.QuadPart
== Node
.RunStartVbn
.QuadPart
);
190 Node
.RunStartVbn
.QuadPart
= LowerRun
->RunStartVbn
.QuadPart
;
191 Node
.StartingLbn
.QuadPart
= LowerRun
->StartingLbn
.QuadPart
;
192 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
193 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, LowerRun
);
194 DPRINT("Intersecting lower run found (%I64d,%I64d) Lbn: %I64d\n", LowerRun
->RunStartVbn
.QuadPart
, LowerRun
->RunEndVbn
.QuadPart
, LowerRun
->StartingLbn
.QuadPart
);
197 /* optionally merge with higher run */
198 NeedleRun
.RunStartVbn
.QuadPart
= Node
.RunEndVbn
.QuadPart
;
199 NeedleRun
.RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
+ 1;
200 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
201 if ((HigherRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)) &&
202 (Node
.StartingLbn
.QuadPart
<= HigherRun
->StartingLbn
.QuadPart
))
204 ASSERT(HigherRun
->RunStartVbn
.QuadPart
== Node
.RunEndVbn
.QuadPart
);
205 Node
.RunEndVbn
.QuadPart
= HigherRun
->RunEndVbn
.QuadPart
;
206 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
207 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, HigherRun
);
208 DPRINT("Intersecting higher run found (%I64d,%I64d) Lbn: %I64d\n", HigherRun
->RunStartVbn
.QuadPart
, HigherRun
->RunEndVbn
.QuadPart
, HigherRun
->StartingLbn
.QuadPart
);
210 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
212 /* finally insert the resulting run */
213 RtlInsertElementGenericTable(&Mcb
->Mapping
->Table
, &Node
, sizeof(Node
), &NewElement
);
216 // NB: Two consecutive runs can only be merged, if actual LBNs also match!
219 Existing->RunStartVbn
227 Existing->RunStartVbn
235 Existing->RunStartVbn
243 Existing->RunStartVbn
251 Situation with holes:
252 1. Holes at both ends
253 2. Hole at the right, new run merged with the previous run
254 3. Hole at the right, new run is not merged with the previous run
255 4. Hole at the left, new run merged with the next run
256 5. Hole at the left, new run is not merged with the next run
257 6. No holes, exact fit to merge with both previous and next runs
258 7. No holes, merges only with the next run
259 8. No holes, merges only with the previous run
260 9. No holes, does not merge with next or prev runs
263 Overwriting existing mapping is not possible and results in FALSE being returned
267 DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Lbn
, SectorCount
, Result
);
276 FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb
,
279 IN LONGLONG SectorCount
)
283 DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, SectorCount
);
285 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
286 Result
= FsRtlAddBaseMcbEntry(&(Mcb
->BaseMcb
),
290 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
292 DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Lbn
, SectorCount
, Result
);
299 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
300 * %NULL value is forbidden.
301 * @RunIndex: Requested range index to retrieve.
302 * @Vbn: Returns the starting virtual block number of the wished range.
303 * %NULL pointer is forbidden.
304 * @Lbn: Returns the starting logical block number of the wished range (or -1 if it is a hole).
305 * %NULL pointer is forbidden.
306 * @SectorCount: Returns the length of the wished range.
307 * %NULL pointer is forbidden.
308 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
310 * Retrieves the parameters of the specified run with index @RunIndex.
312 * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping.
313 * libcaptive does not store 'hole' information to its #GTree.
314 * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1.
316 * Returns: %TRUE if successful.
320 FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
324 OUT PLONGLONG SectorCount
)
326 BOOLEAN Result
= FALSE
;
327 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
328 ULONG RunIndexRemaining
;
329 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
330 BOOLEAN First
= TRUE
;
332 DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p)\n", OpaqueMcb
, RunIndex
, Vbn
, Lbn
, SectorCount
);
334 RunIndexRemaining
= RunIndex
;
336 /* Traverse the tree */
337 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
339 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
343 /* Take care when we must emulate missing 'hole' run at start of our run list. */
344 if (Run
->RunStartVbn
.QuadPart
> 0)
346 if (RunIndexRemaining
== 0)
348 RunFoundLower
= &StaticRunBelow0
;
349 RunFoundHigher
= Run
;
351 /* stop the traversal */
354 /* If someone wants RunIndex #1 we are already on it. */
360 if (RunIndexRemaining
> 0)
362 /* FIXME: performance: non-linear direct seek to the requested RunIndex */
364 if (RunIndexRemaining
== 0)
369 /* continue the traversal */
374 RunFoundHigher
= Run
;
378 /* stop the traversal */
382 if (RunFound
) DPRINT("RunFound(%lu %lu %lu)\n", RunFound
->RunStartVbn
.LowPart
, RunFound
->RunEndVbn
.LowPart
, RunFound
->StartingLbn
.LowPart
);
383 if (RunFoundLower
) DPRINT("RunFoundLower(%lu %lu %lu)\n", RunFoundLower
->RunStartVbn
.LowPart
, RunFoundLower
->RunEndVbn
.LowPart
, RunFoundLower
->StartingLbn
.LowPart
);
384 if (RunFoundHigher
) DPRINT("RunFoundHigher(%lu %lu %lu)\n", RunFoundHigher
->RunStartVbn
.LowPart
, RunFoundHigher
->RunEndVbn
.LowPart
, RunFoundHigher
->StartingLbn
.LowPart
);
388 ASSERT(RunFoundLower
== NULL
);
389 ASSERT(RunFoundHigher
== NULL
);
392 *Vbn
= RunFound
->RunStartVbn
.QuadPart
;
394 *Lbn
= RunFound
->StartingLbn
.QuadPart
;
396 *SectorCount
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
402 if (RunFoundLower
&& RunFoundHigher
)
404 //ASSERT(RunFoundHigher != NULL);
407 *Vbn
= RunFoundLower
->RunEndVbn
.QuadPart
;
411 *SectorCount
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
417 ASSERT(RunFoundHigher
== NULL
);
420 DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
, Result
, *Vbn
, *Lbn
, *SectorCount
);
429 FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb
,
433 OUT PLONGLONG SectorCount
)
437 DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
);
439 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
440 Result
= FsRtlGetNextBaseMcbEntry(&(Mcb
->BaseMcb
),
445 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
447 DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
, Result
, *Vbn
, *Lbn
, *SectorCount
);
457 FsRtlInitializeBaseMcb(IN PBASE_MCB OpaqueMcb
,
458 IN POOL_TYPE PoolType
)
460 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
462 if (PoolType
== PagedPool
)
464 Mcb
->Mapping
= ExAllocateFromPagedLookasideList(&FsRtlFirstMappingLookasideList
);
468 Mcb
->Mapping
= ExAllocatePoolWithTag(PoolType
| POOL_RAISE_IF_ALLOCATION_FAILURE
,
469 sizeof(LARGE_MCB_MAPPING
),
473 Mcb
->PoolType
= PoolType
;
475 Mcb
->MaximumPairCount
= MAXIMUM_PAIR_COUNT
;
476 RtlInitializeGenericTable(&Mcb
->Mapping
->Table
,
488 FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb
,
489 IN POOL_TYPE PoolType
)
491 DPRINT("FsRtlInitializeLargeMcb(%p, %d)\n", Mcb
, PoolType
);
493 Mcb
->GuardedMutex
= ExAllocateFromNPagedLookasideList(&FsRtlFastMutexLookasideList
);
495 KeInitializeGuardedMutex(Mcb
->GuardedMutex
);
499 FsRtlInitializeBaseMcb(&(Mcb
->BaseMcb
), PoolType
);
501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
503 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
505 Mcb
->GuardedMutex
= NULL
;
516 FsRtlInitializeLargeMcbs(VOID
)
518 /* Initialize the list for the MCB */
519 ExInitializePagedLookasideList(&FsRtlFirstMappingLookasideList
,
522 POOL_RAISE_IF_ALLOCATION_FAILURE
,
523 sizeof(LARGE_MCB_MAPPING
),
525 0); /* FIXME: Should be 4 */
527 /* Initialize the list for the guarded mutex */
528 ExInitializeNPagedLookasideList(&FsRtlFastMutexLookasideList
,
531 POOL_RAISE_IF_ALLOCATION_FAILURE
,
532 sizeof(KGUARDED_MUTEX
),
534 0); /* FIXME: Should be 32 */
542 FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
544 OUT PLONGLONG Lbn OPTIONAL
,
545 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
546 OUT PLONGLONG StartingLbn OPTIONAL
,
547 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
548 OUT PULONG Index OPTIONAL
)
550 BOOLEAN Result
= FALSE
;
551 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
554 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
555 BOOLEAN First
= TRUE
;
557 DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", OpaqueMcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
);
559 /* Traverse the tree */
560 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
562 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
566 /* Take care when we must emulate missing 'hole' run at start of our run list. */
567 if (Run
->RunStartVbn
.QuadPart
> 0)
570 RunFoundLower
= &StaticRunBelow0
;
575 if (Run
->RunStartVbn
.QuadPart
<= Vbn
&& Vbn
< Run
->RunEndVbn
.QuadPart
)
578 RunFoundLower
= NULL
;
579 /* stop the traversal; hit */
583 if (Run
->RunEndVbn
.QuadPart
<= Vbn
)
586 if (Run
->StartingLbn
.QuadPart
> 0)
590 /* continue the traversal; not yet crossed by the run */
594 if (Vbn
< Run
->RunStartVbn
.QuadPart
)
596 RunFoundHigher
= Run
;
598 /* stop the traversal; the run skipped us */
603 /* stop the traversal */
609 ASSERT(RunFoundLower
== NULL
);
610 ASSERT(RunFoundHigher
== NULL
);
613 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (Vbn
- RunFound
->RunStartVbn
.QuadPart
);
615 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
616 *SectorCountFromLbn
= RunFound
->RunEndVbn
.QuadPart
- Vbn
;
618 *StartingLbn
= RunFound
->StartingLbn
.QuadPart
;
619 if (SectorCountFromStartingLbn
)
620 *SectorCountFromStartingLbn
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
630 /* search for hole */
631 ASSERT(RunFoundLower
!= NULL
);
635 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
636 *SectorCountFromLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- Vbn
;
638 *StartingLbn
= ~0ull;
639 if (SectorCountFromStartingLbn
)
640 *SectorCountFromStartingLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
642 *Index
= RunIndex
- 2;
648 /* We may have some 'RunFoundLower'. */
651 DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
652 OpaqueMcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
, Result
,
653 (Lbn
? *Lbn
: (ULONGLONG
)-1), (SectorCountFromLbn
? *SectorCountFromLbn
: (ULONGLONG
)-1), (StartingLbn
? *StartingLbn
: (ULONGLONG
)-1),
654 (SectorCountFromStartingLbn
? *SectorCountFromStartingLbn
: (ULONGLONG
)-1), (Index
? *Index
: (ULONG
)-1));
664 FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb
,
666 OUT PLONGLONG Lbn OPTIONAL
,
667 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
668 OUT PLONGLONG StartingLbn OPTIONAL
,
669 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
670 OUT PULONG Index OPTIONAL
)
674 DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", Mcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
);
676 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
677 Result
= FsRtlLookupBaseMcbEntry(&(Mcb
->BaseMcb
),
682 SectorCountFromStartingLbn
,
684 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
686 DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
687 Mcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
, Result
,
688 (Lbn
? *Lbn
: (ULONGLONG
)-1), (SectorCountFromLbn
? *SectorCountFromLbn
: (ULONGLONG
)-1), (StartingLbn
? *StartingLbn
: (ULONGLONG
)-1),
689 (SectorCountFromStartingLbn
? *SectorCountFromStartingLbn
: (ULONGLONG
)-1), (Index
? *Index
: (ULONG
)-1));
696 FsRtlLookupLastLargeMcbEntryAndIndex_internal(IN PBASE_MCB_INTERNAL Mcb
,
699 OUT PULONG Index OPTIONAL
)
702 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
;
703 LONGLONG LastVbn
= 0;
705 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
707 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
709 /* Take care when we must emulate missing 'hole' runs. */
710 if (Run
->RunStartVbn
.QuadPart
> LastVbn
)
714 LastVbn
= Run
->RunEndVbn
.QuadPart
;
726 *Vbn
= RunFound
->RunEndVbn
.QuadPart
- 1;
732 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
) - 1;
741 *Index
= RunIndex
- 1;
753 FsRtlLookupLastBaseMcbEntryAndIndex(IN PBASE_MCB OpaqueMcb
,
754 IN OUT PLONGLONG LargeVbn
,
755 IN OUT PLONGLONG LargeLbn
,
759 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
761 DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
);
763 Result
= FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, LargeVbn
, LargeLbn
, Index
);
765 DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
, Result
, *LargeVbn
, *LargeLbn
, *Index
);
775 FsRtlLookupLastLargeMcbEntryAndIndex(IN PLARGE_MCB OpaqueMcb
,
776 OUT PLONGLONG LargeVbn
,
777 OUT PLONGLONG LargeLbn
,
782 DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
);
784 KeAcquireGuardedMutex(OpaqueMcb
->GuardedMutex
);
785 Result
= FsRtlLookupLastBaseMcbEntryAndIndex(&(OpaqueMcb
->BaseMcb
),
789 KeReleaseGuardedMutex(OpaqueMcb
->GuardedMutex
);
791 DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
, Result
, *LargeVbn
, *LargeLbn
, *Index
);
801 FsRtlLookupLastBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
806 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
808 DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p)\n", OpaqueMcb
, Vbn
, Lbn
);
810 Result
= FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, Vbn
, Lbn
, NULL
); /* Index */
812 DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, Result
, *Vbn
, *Lbn
);
822 FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb
,
828 DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p)\n", Mcb
, Vbn
, Lbn
);
830 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
831 Result
= FsRtlLookupLastBaseMcbEntry(&(Mcb
->BaseMcb
),
834 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
836 DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, Result
, *Vbn
, *Lbn
);
846 FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB OpaqueMcb
)
848 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
849 LONGLONG LbnAtVbn0
= -1;
850 ULONG Nodes
= RtlNumberGenericTableElements(&Mcb
->Mapping
->Table
);
851 ULONG NumberOfRuns
= 0;
853 DPRINT("FsRtlNumberOfRunsInBaseMcb(%p)\n", OpaqueMcb
);
855 if (Nodes
== 0) goto quit
;
857 FsRtlLookupBaseMcbEntry(OpaqueMcb
,
859 &LbnAtVbn0
, /* Lbn */
860 NULL
, NULL
, NULL
, NULL
); /* 4 output arguments - not interested in them */
863 /* Return the count */
864 //return Mcb->PairCount;
865 /* Return the number of 'real' and 'hole' runs.
866 * If we do not have sector 0 as 'real' emulate a 'hole' there.
868 NumberOfRuns
= Nodes
* 2 - (LbnAtVbn0
!= -1 ? 1 : 0); /* include holes as runs */
871 DPRINT("FsRtlNumberOfRunsInBaseMcb(%p) = %d\n", OpaqueMcb
, NumberOfRuns
);
880 FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb
)
884 DPRINT("FsRtlNumberOfRunsInLargeMcb(%p)\n", Mcb
);
886 /* Read the number of runs while holding the MCB lock */
887 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
888 NumberOfRuns
= FsRtlNumberOfRunsInBaseMcb(&(Mcb
->BaseMcb
));
889 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
891 DPRINT("FsRtlNumberOfRunsInLargeMcb(%p) = %d\n", Mcb
, NumberOfRuns
);
893 /* Return the count */
899 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
900 * %NULL value is forbidden.
901 * @Vbn: Starting virtual block number to specify the range to delete.
902 * @SectorCount: Length of the range to delete.
903 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
905 * Deletes any possible @Mcb mappings in the given range @Vbn ... @Vbn+@SectorCount-1.
906 * This call has no problems if no mappings exist there yet.
910 FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
912 IN LONGLONG SectorCount
)
914 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
915 LARGE_MCB_MAPPING_ENTRY NeedleRun
;
916 PLARGE_MCB_MAPPING_ENTRY HaystackRun
;
917 BOOLEAN Result
= TRUE
;
919 DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, SectorCount
);
921 if (Vbn
< 0 || SectorCount
<= 0)
927 if (Vbn
+ SectorCount
<= Vbn
)
933 NeedleRun
.RunStartVbn
.QuadPart
= Vbn
;
934 NeedleRun
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
935 NeedleRun
.StartingLbn
.QuadPart
= ~0ULL;
937 /* adjust/destroy all intersecting ranges */
938 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
939 while ((HaystackRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)))
941 if (HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunStartVbn
.QuadPart
)
943 ASSERT(HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunStartVbn
.QuadPart
);
944 HaystackRun
->RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
;
946 else if (HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunEndVbn
.QuadPart
)
948 ASSERT(HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunEndVbn
.QuadPart
);
949 HaystackRun
->RunStartVbn
.QuadPart
= NeedleRun
.RunEndVbn
.QuadPart
;
953 //ASSERT(NeedleRun.RunStartVbn.QuadPart >= HaystackRun->RunStartVbn.QuadPart);
954 //ASSERT(NeedleRun.RunEndVbn.QuadPart <= HaystackRun->RunEndVbn.QuadPart);
955 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
956 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, HaystackRun
);
957 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
960 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
963 DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d) = %d\n", OpaqueMcb
, Vbn
, SectorCount
, Result
);
972 FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb
,
974 IN LONGLONG SectorCount
)
976 DPRINT("FsRtlRemoveLargeMcbEntry(%p, %I64d, %I64d)\n", Mcb
, Vbn
, SectorCount
);
978 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
979 FsRtlRemoveBaseMcbEntry(&(Mcb
->BaseMcb
), Vbn
, SectorCount
);
980 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
988 FsRtlResetBaseMcb(IN PBASE_MCB OpaqueMcb
)
990 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
991 PLARGE_MCB_MAPPING_ENTRY Element
;
993 DPRINT("FsRtlResetBaseMcb(%p)\n", OpaqueMcb
);
995 while (RtlNumberGenericTableElements(&Mcb
->Mapping
->Table
) &&
996 (Element
= (PLARGE_MCB_MAPPING_ENTRY
)RtlGetElementGenericTable(&Mcb
->Mapping
->Table
, 0)))
998 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, Element
);
1002 Mcb
->MaximumPairCount
= 0;
1010 FsRtlResetLargeMcb(IN PLARGE_MCB Mcb
,
1011 IN BOOLEAN SelfSynchronized
)
1013 DPRINT("FsRtlResetLargeMcb(%p, %d)\n", Mcb
, SelfSynchronized
);
1015 if (!SelfSynchronized
)
1016 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1018 FsRtlResetBaseMcb(&Mcb
->BaseMcb
);
1020 if (!SelfSynchronized
)
1021 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1029 FsRtlSplitBaseMcb(IN PBASE_MCB OpaqueMcb
,
1033 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
1034 PLARGE_MCB_MAPPING_ENTRY Run
, InsertLowerRun
= NULL
, ExistingRun
= NULL
;
1037 DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, Amount
);
1039 /* Traverse the tree */
1040 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
1042 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
1044 /* unaffected run? */
1045 /* FIXME: performance: effective skip of all 'lower' runs without traversing them */
1046 if (Vbn
>= Run
->RunEndVbn
.QuadPart
) { DPRINT("Skipping it\n"); continue; }
1048 /* crossing run to be split?
1049 * 'lower_run' is created on the original place; just shortened.
1050 * current 'run' is shifted up later
1052 if (Vbn
< Run
->RunEndVbn
.QuadPart
)
1054 /* FIXME: shift 'run->Lbn_start' ? */
1055 Run
->RunStartVbn
.QuadPart
= Vbn
;
1057 InsertLowerRun
= NULL
;
1060 /* Shift the current 'run'.
1061 * Ordering is not changed in Generic Tree so I hope I do not need to reinsert it.
1063 Run
->RunStartVbn
.QuadPart
+= Amount
;
1064 ASSERT(Run
->RunEndVbn
.QuadPart
+ Amount
> Run
->RunEndVbn
.QuadPart
); /* overflow? */
1065 Run
->RunEndVbn
.QuadPart
+= Amount
;
1066 /* FIXME: shift 'run->Lbn_start' ? */
1068 /* continue the traversal */
1072 ExistingRun
= RtlInsertElementGenericTable(&Mcb
->Mapping
->Table
, InsertLowerRun
, sizeof(*InsertLowerRun
), &NewElement
);
1074 ASSERT(ExistingRun
== NULL
);
1076 DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d) = %d\n", OpaqueMcb
, Vbn
, Amount
, TRUE
);
1086 FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb
,
1092 DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d)\n", Mcb
, Vbn
, Amount
);
1094 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1095 Result
= FsRtlSplitBaseMcb(&(Mcb
->BaseMcb
),
1098 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1100 DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Amount
, Result
);
1110 FsRtlTruncateBaseMcb(IN PBASE_MCB OpaqueMcb
,
1113 DPRINT("FsRtlTruncateBaseMcb(%p, %I64d)\n", OpaqueMcb
, Vbn
);
1115 FsRtlRemoveBaseMcbEntry(OpaqueMcb
, Vbn
, MAXLONG
- Vbn
+ 1);
1123 FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb
,
1126 DPRINT("FsRtlTruncateLargeMcb(%p, %I64d)\n", Mcb
, Vbn
);
1128 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1129 FsRtlTruncateBaseMcb(&(Mcb
->BaseMcb
), Vbn
);
1130 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1138 FsRtlUninitializeBaseMcb(IN PBASE_MCB Mcb
)
1140 DPRINT("FsRtlUninitializeBaseMcb(%p)\n", Mcb
);
1142 FsRtlResetBaseMcb(Mcb
);
1144 if ((Mcb
->PoolType
== PagedPool
)/* && (Mcb->MaximumPairCount == MAXIMUM_PAIR_COUNT)*/)
1146 ExFreeToPagedLookasideList(&FsRtlFirstMappingLookasideList
,
1151 ExFreePoolWithTag(Mcb
->Mapping
, 'FSBC');
1160 FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb
)
1162 DPRINT("FsRtlUninitializeLargeMcb(%p)\n", Mcb
);
1164 if (Mcb
->GuardedMutex
)
1166 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
1168 FsRtlUninitializeBaseMcb(&(Mcb
->BaseMcb
));