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
;
138 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
139 LARGE_MCB_MAPPING_ENTRY Node
, NeedleRun
;
140 PLARGE_MCB_MAPPING_ENTRY LowerRun
, HigherRun
;
143 DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, Lbn
, SectorCount
);
151 if (SectorCount
<= 0)
157 /* clean any possible previous entries in our range */
158 FsRtlRemoveBaseMcbEntry(OpaqueMcb
, Vbn
, SectorCount
);
160 // We need to map [Vbn, Vbn+SectorCount) to [Lbn, Lbn+SectorCount),
161 // taking in account the fact that we need to merge these runs if
162 // they are adjacent or overlap, but fail if new run fully fits into another run
164 /* initially we think we will be inserted as a separate run */
165 Node
.RunStartVbn
.QuadPart
= Vbn
;
166 Node
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
167 Node
.StartingLbn
.QuadPart
= Lbn
;
169 /* optionally merge with lower run */
170 NeedleRun
.RunStartVbn
.QuadPart
= Node
.RunStartVbn
.QuadPart
- 1;
171 NeedleRun
.RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
+ 1;
172 NeedleRun
.StartingLbn
.QuadPart
= ~0ULL;
173 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
174 if ((LowerRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)))
176 ASSERT(LowerRun
->RunEndVbn
.QuadPart
== Node
.RunStartVbn
.QuadPart
);
177 Node
.RunStartVbn
.QuadPart
= LowerRun
->RunStartVbn
.QuadPart
;
178 Node
.StartingLbn
.QuadPart
= LowerRun
->StartingLbn
.QuadPart
;
179 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
180 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, LowerRun
);
181 DPRINT("Intersecting lower run found (%I64d,%I64d) Lbn: %I64d\n", LowerRun
->RunStartVbn
.QuadPart
, LowerRun
->RunEndVbn
.QuadPart
, LowerRun
->StartingLbn
.QuadPart
);
184 /* optionally merge with higher run */
185 NeedleRun
.RunStartVbn
.QuadPart
= Node
.RunEndVbn
.QuadPart
;
186 NeedleRun
.RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
+ 1;
187 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
188 if ((HigherRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)))
190 ASSERT(HigherRun
->RunStartVbn
.QuadPart
== Node
.RunEndVbn
.QuadPart
);
191 Node
.RunEndVbn
.QuadPart
= HigherRun
->RunEndVbn
.QuadPart
;
192 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
193 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, HigherRun
);
194 DPRINT("Intersecting higher run found (%I64d,%I64d) Lbn: %I64d\n", HigherRun
->RunStartVbn
.QuadPart
, HigherRun
->RunEndVbn
.QuadPart
, HigherRun
->StartingLbn
.QuadPart
);
196 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
198 /* finally insert the resulting run */
199 RtlInsertElementGenericTable(&Mcb
->Mapping
->Table
, &Node
, sizeof(Node
), &NewElement
);
201 Node
.RunStartVbn
.QuadPart
= Vbn
;
202 Node
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
203 Node
.StartingLbn
.QuadPart
= Lbn
;
205 // NB: Two consecutive runs can only be merged, if actual LBNs also match!
208 Existing->RunStartVbn
216 Existing->RunStartVbn
224 Existing->RunStartVbn
232 Existing->RunStartVbn
240 Situation with holes:
241 1. Holes at both ends
242 2. Hole at the right, new run merged with the previous run
243 3. Hole at the right, new run is not merged with the previous run
244 4. Hole at the left, new run merged with the next run
245 5. Hole at the left, new run is not merged with the next run
246 6. No holes, exact fit to merge with both previous and next runs
247 7. No holes, merges only with the next run
248 8. No holes, merges only with the previous run
249 9. No holes, does not merge with next or prev runs
252 Overwriting existing mapping is not possible and results in FALSE being returned
256 DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Lbn
, SectorCount
, Result
);
265 FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb
,
268 IN LONGLONG SectorCount
)
272 DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, SectorCount
);
274 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
275 Result
= FsRtlAddBaseMcbEntry(&(Mcb
->BaseMcb
),
279 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
281 DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Lbn
, SectorCount
, Result
);
288 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
289 * %NULL value is forbidden.
290 * @RunIndex: Requested range index to retrieve.
291 * @Vbn: Returns the starting virtual block number of the wished range.
292 * %NULL pointer is forbidden.
293 * @Lbn: Returns the starting logical block number of the wished range (or -1 if it is a hole).
294 * %NULL pointer is forbidden.
295 * @SectorCount: Returns the length of the wished range.
296 * %NULL pointer is forbidden.
297 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
299 * Retrieves the parameters of the specified run with index @RunIndex.
301 * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping.
302 * libcaptive does not store 'hole' information to its #GTree.
303 * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1.
305 * Returns: %TRUE if successful.
309 FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
313 OUT PLONGLONG SectorCount
)
315 BOOLEAN Result
= FALSE
;
316 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
317 ULONG RunIndexRemaining
;
318 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
319 BOOLEAN First
= TRUE
;
321 DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p)\n", OpaqueMcb
, RunIndex
, Vbn
, Lbn
, SectorCount
);
323 RunIndexRemaining
= RunIndex
;
325 /* Traverse the tree */
326 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
328 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
332 /* Take care when we must emulate missing 'hole' run at start of our run list. */
333 if (Run
->RunStartVbn
.QuadPart
> 0)
335 if (RunIndexRemaining
== 0)
337 RunFoundLower
= &StaticRunBelow0
;
338 RunFoundHigher
= Run
;
340 /* stop the traversal */
343 /* If someone wants RunIndex #1 we are already on it. */
349 if (RunIndexRemaining
> 0)
351 /* FIXME: performance: non-linear direct seek to the requested RunIndex */
353 if (RunIndexRemaining
== 0)
358 /* continue the traversal */
363 RunFoundHigher
= Run
;
367 /* stop the traversal */
371 if (RunFound
) DPRINT("RunFound(%lu %lu %lu)\n", RunFound
->RunStartVbn
.LowPart
, RunFound
->RunEndVbn
.LowPart
, RunFound
->StartingLbn
.LowPart
);
372 if (RunFoundLower
) DPRINT("RunFoundLower(%lu %lu %lu)\n", RunFoundLower
->RunStartVbn
.LowPart
, RunFoundLower
->RunEndVbn
.LowPart
, RunFoundLower
->StartingLbn
.LowPart
);
373 if (RunFoundHigher
) DPRINT("RunFoundHigher(%lu %lu %lu)\n", RunFoundHigher
->RunStartVbn
.LowPart
, RunFoundHigher
->RunEndVbn
.LowPart
, RunFoundHigher
->StartingLbn
.LowPart
);
377 ASSERT(RunFoundLower
== NULL
);
378 ASSERT(RunFoundHigher
== NULL
);
381 *Vbn
= RunFound
->RunStartVbn
.QuadPart
;
383 *Lbn
= RunFound
->StartingLbn
.QuadPart
;
385 *SectorCount
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
391 if (RunFoundLower
&& RunFoundHigher
)
393 //ASSERT(RunFoundHigher != NULL);
396 *Vbn
= RunFoundLower
->RunEndVbn
.QuadPart
;
400 *SectorCount
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
406 ASSERT(RunFoundHigher
== NULL
);
409 DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
, Result
, *Vbn
, *Lbn
, *SectorCount
);
418 FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb
,
422 OUT PLONGLONG SectorCount
)
426 DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
);
428 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
429 Result
= FsRtlGetNextBaseMcbEntry(&(Mcb
->BaseMcb
),
434 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
436 DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
, Result
, *Vbn
, *Lbn
, *SectorCount
);
446 FsRtlInitializeBaseMcb(IN PBASE_MCB OpaqueMcb
,
447 IN POOL_TYPE PoolType
)
449 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
451 if (PoolType
== PagedPool
)
453 Mcb
->Mapping
= ExAllocateFromPagedLookasideList(&FsRtlFirstMappingLookasideList
);
457 Mcb
->Mapping
= ExAllocatePoolWithTag(PoolType
| POOL_RAISE_IF_ALLOCATION_FAILURE
,
458 sizeof(LARGE_MCB_MAPPING
),
462 Mcb
->PoolType
= PoolType
;
464 Mcb
->MaximumPairCount
= MAXIMUM_PAIR_COUNT
;
465 RtlInitializeGenericTable(&Mcb
->Mapping
->Table
,
477 FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb
,
478 IN POOL_TYPE PoolType
)
480 DPRINT("FsRtlInitializeLargeMcb(%p, %d)\n", Mcb
, PoolType
);
482 Mcb
->GuardedMutex
= ExAllocateFromNPagedLookasideList(&FsRtlFastMutexLookasideList
);
484 KeInitializeGuardedMutex(Mcb
->GuardedMutex
);
488 FsRtlInitializeBaseMcb(&(Mcb
->BaseMcb
), PoolType
);
490 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
492 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
494 Mcb
->GuardedMutex
= NULL
;
505 FsRtlInitializeLargeMcbs(VOID
)
507 /* Initialize the list for the MCB */
508 ExInitializePagedLookasideList(&FsRtlFirstMappingLookasideList
,
511 POOL_RAISE_IF_ALLOCATION_FAILURE
,
512 sizeof(LARGE_MCB_MAPPING
),
514 0); /* FIXME: Should be 4 */
516 /* Initialize the list for the guarded mutex */
517 ExInitializeNPagedLookasideList(&FsRtlFastMutexLookasideList
,
520 POOL_RAISE_IF_ALLOCATION_FAILURE
,
521 sizeof(KGUARDED_MUTEX
),
523 0); /* FIXME: Should be 32 */
531 FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
533 OUT PLONGLONG Lbn OPTIONAL
,
534 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
535 OUT PLONGLONG StartingLbn OPTIONAL
,
536 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
537 OUT PULONG Index OPTIONAL
)
539 BOOLEAN Result
= FALSE
;
540 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
543 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
544 BOOLEAN First
= TRUE
;
546 DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", OpaqueMcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
);
548 /* Traverse the tree */
549 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
551 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
555 /* Take care when we must emulate missing 'hole' run at start of our run list. */
556 if (Run
->RunStartVbn
.QuadPart
> 0)
559 RunFoundLower
= &StaticRunBelow0
;
564 if (Run
->RunStartVbn
.QuadPart
<= Vbn
&& Vbn
< Run
->RunEndVbn
.QuadPart
)
567 RunFoundLower
= NULL
;
568 /* stop the traversal; hit */
572 if (Run
->RunEndVbn
.QuadPart
<= Vbn
)
575 if (Run
->StartingLbn
.QuadPart
> 0)
579 /* continue the traversal; not yet crossed by the run */
583 if (Vbn
< Run
->RunStartVbn
.QuadPart
)
585 RunFoundHigher
= Run
;
587 /* stop the traversal; the run skipped us */
592 /* stop the traversal */
598 ASSERT(RunFoundLower
== NULL
);
599 ASSERT(RunFoundHigher
== NULL
);
602 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (Vbn
- RunFound
->RunStartVbn
.QuadPart
);
604 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
605 *SectorCountFromLbn
= RunFound
->RunEndVbn
.QuadPart
- Vbn
;
607 *StartingLbn
= RunFound
->StartingLbn
.QuadPart
;
608 if (SectorCountFromStartingLbn
)
609 *SectorCountFromStartingLbn
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
619 /* search for hole */
620 ASSERT(RunFoundLower
!= NULL
);
624 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
625 *SectorCountFromLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- Vbn
;
627 *StartingLbn
= ~0ull;
628 if (SectorCountFromStartingLbn
)
629 *SectorCountFromStartingLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
631 *Index
= RunIndex
- 2;
637 /* We may have some 'RunFoundLower'. */
640 DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
641 OpaqueMcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
, Result
,
642 (Lbn
? *Lbn
: (ULONGLONG
)-1), (SectorCountFromLbn
? *SectorCountFromLbn
: (ULONGLONG
)-1), (StartingLbn
? *StartingLbn
: (ULONGLONG
)-1),
643 (SectorCountFromStartingLbn
? *SectorCountFromStartingLbn
: (ULONGLONG
)-1), (Index
? *Index
: (ULONG
)-1));
653 FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb
,
655 OUT PLONGLONG Lbn OPTIONAL
,
656 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
657 OUT PLONGLONG StartingLbn OPTIONAL
,
658 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
659 OUT PULONG Index OPTIONAL
)
663 DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", Mcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
);
665 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
666 Result
= FsRtlLookupBaseMcbEntry(&(Mcb
->BaseMcb
),
671 SectorCountFromStartingLbn
,
673 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
675 DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
676 Mcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
, Result
,
677 (Lbn
? *Lbn
: (ULONGLONG
)-1), (SectorCountFromLbn
? *SectorCountFromLbn
: (ULONGLONG
)-1), (StartingLbn
? *StartingLbn
: (ULONGLONG
)-1),
678 (SectorCountFromStartingLbn
? *SectorCountFromStartingLbn
: (ULONGLONG
)-1), (Index
? *Index
: (ULONG
)-1));
685 FsRtlLookupLastLargeMcbEntryAndIndex_internal(IN PBASE_MCB_INTERNAL Mcb
,
688 OUT PULONG Index OPTIONAL
)
691 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
;
692 LONGLONG LastVbn
= 0;
694 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
696 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
698 /* Take care when we must emulate missing 'hole' runs. */
699 if (Run
->RunStartVbn
.QuadPart
> LastVbn
)
703 LastVbn
= Run
->RunEndVbn
.QuadPart
;
715 *Vbn
= RunFound
->RunEndVbn
.QuadPart
- 1;
721 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
) - 1;
730 *Index
= RunIndex
- 1;
742 FsRtlLookupLastBaseMcbEntryAndIndex(IN PBASE_MCB OpaqueMcb
,
743 IN OUT PLONGLONG LargeVbn
,
744 IN OUT PLONGLONG LargeLbn
,
748 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
750 DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
);
752 Result
= FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, LargeVbn
, LargeLbn
, Index
);
754 DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
, Result
, *LargeVbn
, *LargeLbn
, *Index
);
764 FsRtlLookupLastLargeMcbEntryAndIndex(IN PLARGE_MCB OpaqueMcb
,
765 OUT PLONGLONG LargeVbn
,
766 OUT PLONGLONG LargeLbn
,
771 DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
);
773 KeAcquireGuardedMutex(OpaqueMcb
->GuardedMutex
);
774 Result
= FsRtlLookupLastBaseMcbEntryAndIndex(&(OpaqueMcb
->BaseMcb
),
778 KeReleaseGuardedMutex(OpaqueMcb
->GuardedMutex
);
780 DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
, Result
, *LargeVbn
, *LargeLbn
, *Index
);
790 FsRtlLookupLastBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
795 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
797 DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p)\n", OpaqueMcb
, Vbn
, Lbn
);
799 Result
= FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, Vbn
, Lbn
, NULL
); /* Index */
801 DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, Result
, *Vbn
, *Lbn
);
811 FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb
,
817 DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p)\n", Mcb
, Vbn
, Lbn
);
819 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
820 Result
= FsRtlLookupLastBaseMcbEntry(&(Mcb
->BaseMcb
),
823 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
825 DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, Result
, *Vbn
, *Lbn
);
835 FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB OpaqueMcb
)
837 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
838 LONGLONG LbnAtVbn0
= -1;
839 ULONG Nodes
= RtlNumberGenericTableElements(&Mcb
->Mapping
->Table
);
840 ULONG NumberOfRuns
= 0;
842 DPRINT("FsRtlNumberOfRunsInBaseMcb(%p)\n", OpaqueMcb
);
844 if (Nodes
== 0) goto quit
;
846 FsRtlLookupBaseMcbEntry(OpaqueMcb
,
848 &LbnAtVbn0
, /* Lbn */
849 NULL
, NULL
, NULL
, NULL
); /* 4 output arguments - not interested in them */
852 /* Return the count */
853 //return Mcb->PairCount;
854 /* Return the number of 'real' and 'hole' runs.
855 * If we do not have sector 0 as 'real' emulate a 'hole' there.
857 NumberOfRuns
= Nodes
* 2 - (LbnAtVbn0
!= -1 ? 1 : 0); /* include holes as runs */
860 DPRINT("FsRtlNumberOfRunsInBaseMcb(%p) = %d\n", OpaqueMcb
, NumberOfRuns
);
869 FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb
)
873 DPRINT("FsRtlNumberOfRunsInLargeMcb(%p)\n", Mcb
);
875 /* Read the number of runs while holding the MCB lock */
876 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
877 NumberOfRuns
= FsRtlNumberOfRunsInBaseMcb(&(Mcb
->BaseMcb
));
878 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
880 DPRINT("FsRtlNumberOfRunsInLargeMcb(%p) = %d\n", Mcb
, NumberOfRuns
);
882 /* Return the count */
888 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
889 * %NULL value is forbidden.
890 * @Vbn: Starting virtual block number to specify the range to delete.
891 * @SectorCount: Length of the range to delete.
892 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
894 * Deletes any possible @Mcb mappings in the given range @Vbn ... @Vbn+@SectorCount-1.
895 * This call has no problems if no mappings exist there yet.
899 FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
901 IN LONGLONG SectorCount
)
903 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
904 LARGE_MCB_MAPPING_ENTRY NeedleRun
;
905 PLARGE_MCB_MAPPING_ENTRY HaystackRun
;
906 BOOLEAN Result
= TRUE
;
908 DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, SectorCount
);
910 if (Vbn
< 0 || SectorCount
<= 0)
916 if (Vbn
+ SectorCount
<= Vbn
)
922 NeedleRun
.RunStartVbn
.QuadPart
= Vbn
;
923 NeedleRun
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
924 NeedleRun
.StartingLbn
.QuadPart
= ~0ULL;
926 /* adjust/destroy all intersecting ranges */
927 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
928 while ((HaystackRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)))
930 if (HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunStartVbn
.QuadPart
)
932 ASSERT(HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunStartVbn
.QuadPart
);
933 HaystackRun
->RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
;
935 else if (HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunEndVbn
.QuadPart
)
937 ASSERT(HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunEndVbn
.QuadPart
);
938 HaystackRun
->RunStartVbn
.QuadPart
= NeedleRun
.RunEndVbn
.QuadPart
;
942 //ASSERT(NeedleRun.RunStartVbn.QuadPart >= HaystackRun->RunStartVbn.QuadPart);
943 //ASSERT(NeedleRun.RunEndVbn.QuadPart <= HaystackRun->RunEndVbn.QuadPart);
944 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
945 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, HaystackRun
);
946 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
949 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
952 DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d) = %d\n", OpaqueMcb
, Vbn
, SectorCount
, Result
);
961 FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb
,
963 IN LONGLONG SectorCount
)
965 DPRINT("FsRtlRemoveLargeMcbEntry(%p, %I64d, %I64d)\n", Mcb
, Vbn
, SectorCount
);
967 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
968 FsRtlRemoveBaseMcbEntry(&(Mcb
->BaseMcb
), Vbn
, SectorCount
);
969 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
977 FsRtlResetBaseMcb(IN PBASE_MCB OpaqueMcb
)
979 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
980 PLARGE_MCB_MAPPING_ENTRY Element
;
982 DPRINT("FsRtlResetBaseMcb(%p)\n", OpaqueMcb
);
984 while (RtlNumberGenericTableElements(&Mcb
->Mapping
->Table
) &&
985 (Element
= (PLARGE_MCB_MAPPING_ENTRY
)RtlGetElementGenericTable(&Mcb
->Mapping
->Table
, 0)))
987 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, Element
);
991 Mcb
->MaximumPairCount
= 0;
999 FsRtlResetLargeMcb(IN PLARGE_MCB Mcb
,
1000 IN BOOLEAN SelfSynchronized
)
1002 DPRINT("FsRtlResetLargeMcb(%p, %d)\n", Mcb
, SelfSynchronized
);
1004 if (!SelfSynchronized
)
1005 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1007 FsRtlResetBaseMcb(&Mcb
->BaseMcb
);
1009 if (!SelfSynchronized
)
1010 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1018 FsRtlSplitBaseMcb(IN PBASE_MCB OpaqueMcb
,
1022 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
1023 PLARGE_MCB_MAPPING_ENTRY Run
, InsertLowerRun
= NULL
, ExistingRun
= NULL
;
1026 DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, Amount
);
1028 /* Traverse the tree */
1029 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
1031 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
1033 /* unaffected run? */
1034 /* FIXME: performance: effective skip of all 'lower' runs without traversing them */
1035 if (Vbn
>= Run
->RunEndVbn
.QuadPart
) { DPRINT("Skipping it\n"); continue; }
1037 /* crossing run to be split?
1038 * 'lower_run' is created on the original place; just shortened.
1039 * current 'run' is shifted up later
1041 if (Vbn
< Run
->RunEndVbn
.QuadPart
)
1043 /* FIXME: shift 'run->Lbn_start' ? */
1044 Run
->RunStartVbn
.QuadPart
= Vbn
;
1046 InsertLowerRun
= NULL
;
1049 /* Shift the current 'run'.
1050 * Ordering is not changed in Generic Tree so I hope I do not need to reinsert it.
1052 Run
->RunStartVbn
.QuadPart
+= Amount
;
1053 ASSERT(Run
->RunEndVbn
.QuadPart
+ Amount
> Run
->RunEndVbn
.QuadPart
); /* overflow? */
1054 Run
->RunEndVbn
.QuadPart
+= Amount
;
1055 /* FIXME: shift 'run->Lbn_start' ? */
1057 /* continue the traversal */
1061 ExistingRun
= RtlInsertElementGenericTable(&Mcb
->Mapping
->Table
, InsertLowerRun
, sizeof(*InsertLowerRun
), &NewElement
);
1063 ASSERT(ExistingRun
== NULL
);
1065 DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d) = %d\n", OpaqueMcb
, Vbn
, Amount
, TRUE
);
1075 FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb
,
1081 DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d)\n", Mcb
, Vbn
, Amount
);
1083 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1084 Result
= FsRtlSplitBaseMcb(&(Mcb
->BaseMcb
),
1087 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1089 DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Amount
, Result
);
1099 FsRtlTruncateBaseMcb(IN PBASE_MCB OpaqueMcb
,
1102 DPRINT("FsRtlTruncateBaseMcb(%p, %I64d)\n", OpaqueMcb
, Vbn
);
1104 FsRtlRemoveBaseMcbEntry(OpaqueMcb
, Vbn
, MAXLONG
- Vbn
+ 1);
1112 FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb
,
1115 DPRINT("FsRtlTruncateLargeMcb(%p, %I64d)\n", Mcb
, Vbn
);
1117 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1118 FsRtlTruncateBaseMcb(&(Mcb
->BaseMcb
), Vbn
);
1119 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1127 FsRtlUninitializeBaseMcb(IN PBASE_MCB Mcb
)
1129 DPRINT("FsRtlUninitializeBaseMcb(%p)\n", Mcb
);
1131 FsRtlResetBaseMcb(Mcb
);
1133 if ((Mcb
->PoolType
== PagedPool
)/* && (Mcb->MaximumPairCount == MAXIMUM_PAIR_COUNT)*/)
1135 ExFreeToPagedLookasideList(&FsRtlFirstMappingLookasideList
,
1140 ExFreePoolWithTag(Mcb
->Mapping
, 'FSBC');
1149 FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb
)
1151 DPRINT("FsRtlUninitializeLargeMcb(%p)\n", Mcb
);
1153 if (Mcb
->GuardedMutex
)
1155 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
1157 FsRtlUninitializeBaseMcb(&(Mcb
->BaseMcb
));