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
);
195 DPRINT("Intersecting lower run found (%I64d,%I64d) Lbn: %I64d\n", LowerRun
->RunStartVbn
.QuadPart
, LowerRun
->RunEndVbn
.QuadPart
, LowerRun
->StartingLbn
.QuadPart
);
198 /* optionally merge with higher run */
199 NeedleRun
.RunStartVbn
.QuadPart
= Node
.RunEndVbn
.QuadPart
;
200 NeedleRun
.RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
+ 1;
201 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
202 if ((HigherRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)) &&
203 (Node
.StartingLbn
.QuadPart
<= HigherRun
->StartingLbn
.QuadPart
))
205 ASSERT(HigherRun
->RunStartVbn
.QuadPart
== Node
.RunEndVbn
.QuadPart
);
206 Node
.RunEndVbn
.QuadPart
= HigherRun
->RunEndVbn
.QuadPart
;
207 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
208 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, HigherRun
);
210 DPRINT("Intersecting higher run found (%I64d,%I64d) Lbn: %I64d\n", HigherRun
->RunStartVbn
.QuadPart
, HigherRun
->RunEndVbn
.QuadPart
, HigherRun
->StartingLbn
.QuadPart
);
212 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
214 /* finally insert the resulting run */
215 RtlInsertElementGenericTable(&Mcb
->Mapping
->Table
, &Node
, sizeof(Node
), &NewElement
);
219 // NB: Two consecutive runs can only be merged, if actual LBNs also match!
222 Existing->RunStartVbn
230 Existing->RunStartVbn
238 Existing->RunStartVbn
246 Existing->RunStartVbn
254 Situation with holes:
255 1. Holes at both ends
256 2. Hole at the right, new run merged with the previous run
257 3. Hole at the right, new run is not merged with the previous run
258 4. Hole at the left, new run merged with the next run
259 5. Hole at the left, new run is not merged with the next run
260 6. No holes, exact fit to merge with both previous and next runs
261 7. No holes, merges only with the next run
262 8. No holes, merges only with the previous run
263 9. No holes, does not merge with next or prev runs
266 Overwriting existing mapping is not possible and results in FALSE being returned
270 DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Lbn
, SectorCount
, Result
);
279 FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb
,
282 IN LONGLONG SectorCount
)
286 DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, SectorCount
);
288 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
289 Result
= FsRtlAddBaseMcbEntry(&(Mcb
->BaseMcb
),
293 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
295 DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Lbn
, SectorCount
, Result
);
302 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
303 * %NULL value is forbidden.
304 * @RunIndex: Requested range index to retrieve.
305 * @Vbn: Returns the starting virtual block number of the wished range.
306 * %NULL pointer is forbidden.
307 * @Lbn: Returns the starting logical block number of the wished range (or -1 if it is a hole).
308 * %NULL pointer is forbidden.
309 * @SectorCount: Returns the length of the wished range.
310 * %NULL pointer is forbidden.
311 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
313 * Retrieves the parameters of the specified run with index @RunIndex.
315 * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping.
316 * libcaptive does not store 'hole' information to its #GTree.
317 * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1.
319 * Returns: %TRUE if successful.
323 FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
327 OUT PLONGLONG SectorCount
)
329 BOOLEAN Result
= FALSE
;
330 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
331 ULONG RunIndexRemaining
;
332 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
333 BOOLEAN First
= TRUE
;
335 DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p)\n", OpaqueMcb
, RunIndex
, Vbn
, Lbn
, SectorCount
);
337 RunIndexRemaining
= RunIndex
;
339 /* Traverse the tree */
340 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
342 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
346 /* Take care when we must emulate missing 'hole' run at start of our run list. */
347 if (Run
->RunStartVbn
.QuadPart
> 0)
349 if (RunIndexRemaining
== 0)
351 RunFoundLower
= &StaticRunBelow0
;
352 RunFoundHigher
= Run
;
354 /* stop the traversal */
357 /* If someone wants RunIndex #1 we are already on it. */
363 if (RunIndexRemaining
> 0)
365 /* FIXME: performance: non-linear direct seek to the requested RunIndex */
367 if (RunIndexRemaining
== 0)
372 /* continue the traversal */
377 RunFoundHigher
= Run
;
381 /* stop the traversal */
385 if (RunFound
) DPRINT("RunFound(%lu %lu %lu)\n", RunFound
->RunStartVbn
.LowPart
, RunFound
->RunEndVbn
.LowPart
, RunFound
->StartingLbn
.LowPart
);
386 if (RunFoundLower
) DPRINT("RunFoundLower(%lu %lu %lu)\n", RunFoundLower
->RunStartVbn
.LowPart
, RunFoundLower
->RunEndVbn
.LowPart
, RunFoundLower
->StartingLbn
.LowPart
);
387 if (RunFoundHigher
) DPRINT("RunFoundHigher(%lu %lu %lu)\n", RunFoundHigher
->RunStartVbn
.LowPart
, RunFoundHigher
->RunEndVbn
.LowPart
, RunFoundHigher
->StartingLbn
.LowPart
);
391 ASSERT(RunFoundLower
== NULL
);
392 ASSERT(RunFoundHigher
== NULL
);
395 *Vbn
= RunFound
->RunStartVbn
.QuadPart
;
397 *Lbn
= RunFound
->StartingLbn
.QuadPart
;
399 *SectorCount
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
405 if (RunFoundLower
&& RunFoundHigher
)
407 //ASSERT(RunFoundHigher != NULL);
410 *Vbn
= RunFoundLower
->RunEndVbn
.QuadPart
;
414 *SectorCount
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
420 ASSERT(RunFoundHigher
== NULL
);
423 DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
, Result
, *Vbn
, *Lbn
, *SectorCount
);
432 FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb
,
436 OUT PLONGLONG SectorCount
)
440 DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
);
442 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
443 Result
= FsRtlGetNextBaseMcbEntry(&(Mcb
->BaseMcb
),
448 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
450 DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
, Result
, *Vbn
, *Lbn
, *SectorCount
);
460 FsRtlInitializeBaseMcb(IN PBASE_MCB OpaqueMcb
,
461 IN POOL_TYPE PoolType
)
463 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
465 if (PoolType
== PagedPool
)
467 Mcb
->Mapping
= ExAllocateFromPagedLookasideList(&FsRtlFirstMappingLookasideList
);
471 Mcb
->Mapping
= ExAllocatePoolWithTag(PoolType
| POOL_RAISE_IF_ALLOCATION_FAILURE
,
472 sizeof(LARGE_MCB_MAPPING
),
476 Mcb
->PoolType
= PoolType
;
478 Mcb
->MaximumPairCount
= MAXIMUM_PAIR_COUNT
;
479 RtlInitializeGenericTable(&Mcb
->Mapping
->Table
,
491 FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb
,
492 IN POOL_TYPE PoolType
)
494 DPRINT("FsRtlInitializeLargeMcb(%p, %d)\n", Mcb
, PoolType
);
496 Mcb
->GuardedMutex
= ExAllocateFromNPagedLookasideList(&FsRtlFastMutexLookasideList
);
498 KeInitializeGuardedMutex(Mcb
->GuardedMutex
);
502 FsRtlInitializeBaseMcb(&(Mcb
->BaseMcb
), PoolType
);
504 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
506 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
508 Mcb
->GuardedMutex
= NULL
;
519 FsRtlInitializeLargeMcbs(VOID
)
521 /* Initialize the list for the MCB */
522 ExInitializePagedLookasideList(&FsRtlFirstMappingLookasideList
,
525 POOL_RAISE_IF_ALLOCATION_FAILURE
,
526 sizeof(LARGE_MCB_MAPPING
),
528 0); /* FIXME: Should be 4 */
530 /* Initialize the list for the guarded mutex */
531 ExInitializeNPagedLookasideList(&FsRtlFastMutexLookasideList
,
534 POOL_RAISE_IF_ALLOCATION_FAILURE
,
535 sizeof(KGUARDED_MUTEX
),
537 0); /* FIXME: Should be 32 */
545 FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
547 OUT PLONGLONG Lbn OPTIONAL
,
548 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
549 OUT PLONGLONG StartingLbn OPTIONAL
,
550 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
551 OUT PULONG Index OPTIONAL
)
553 BOOLEAN Result
= FALSE
;
554 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
557 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
558 BOOLEAN First
= TRUE
;
560 DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", OpaqueMcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
);
562 /* Traverse the tree */
563 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
565 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
569 /* Take care when we must emulate missing 'hole' run at start of our run list. */
570 if (Run
->RunStartVbn
.QuadPart
> 0)
573 RunFoundLower
= &StaticRunBelow0
;
578 if (Run
->RunStartVbn
.QuadPart
<= Vbn
&& Vbn
< Run
->RunEndVbn
.QuadPart
)
581 RunFoundLower
= NULL
;
582 /* stop the traversal; hit */
586 if (Run
->RunEndVbn
.QuadPart
<= Vbn
)
589 if (Run
->StartingLbn
.QuadPart
> 0)
593 /* continue the traversal; not yet crossed by the run */
597 if (Vbn
< Run
->RunStartVbn
.QuadPart
)
599 RunFoundHigher
= Run
;
601 /* stop the traversal; the run skipped us */
606 /* stop the traversal */
612 ASSERT(RunFoundLower
== NULL
);
613 ASSERT(RunFoundHigher
== NULL
);
616 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (Vbn
- RunFound
->RunStartVbn
.QuadPart
);
618 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
619 *SectorCountFromLbn
= RunFound
->RunEndVbn
.QuadPart
- Vbn
;
621 *StartingLbn
= RunFound
->StartingLbn
.QuadPart
;
622 if (SectorCountFromStartingLbn
)
623 *SectorCountFromStartingLbn
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
633 /* search for hole */
634 ASSERT(RunFoundLower
!= NULL
);
638 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
639 *SectorCountFromLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- Vbn
;
641 *StartingLbn
= ~0ull;
642 if (SectorCountFromStartingLbn
)
643 *SectorCountFromStartingLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
645 *Index
= RunIndex
- 2;
651 /* We may have some 'RunFoundLower'. */
654 DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
655 OpaqueMcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
, Result
,
656 (Lbn
? *Lbn
: (ULONGLONG
)-1), (SectorCountFromLbn
? *SectorCountFromLbn
: (ULONGLONG
)-1), (StartingLbn
? *StartingLbn
: (ULONGLONG
)-1),
657 (SectorCountFromStartingLbn
? *SectorCountFromStartingLbn
: (ULONGLONG
)-1), (Index
? *Index
: (ULONG
)-1));
667 FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb
,
669 OUT PLONGLONG Lbn OPTIONAL
,
670 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
671 OUT PLONGLONG StartingLbn OPTIONAL
,
672 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
673 OUT PULONG Index OPTIONAL
)
677 DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", Mcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
);
679 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
680 Result
= FsRtlLookupBaseMcbEntry(&(Mcb
->BaseMcb
),
685 SectorCountFromStartingLbn
,
687 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
689 DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
690 Mcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
, Result
,
691 (Lbn
? *Lbn
: (ULONGLONG
)-1), (SectorCountFromLbn
? *SectorCountFromLbn
: (ULONGLONG
)-1), (StartingLbn
? *StartingLbn
: (ULONGLONG
)-1),
692 (SectorCountFromStartingLbn
? *SectorCountFromStartingLbn
: (ULONGLONG
)-1), (Index
? *Index
: (ULONG
)-1));
699 FsRtlLookupLastLargeMcbEntryAndIndex_internal(IN PBASE_MCB_INTERNAL Mcb
,
702 OUT PULONG Index OPTIONAL
)
705 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
;
706 LONGLONG LastVbn
= 0;
708 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
710 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
712 /* Take care when we must emulate missing 'hole' runs. */
713 if (Run
->RunStartVbn
.QuadPart
> LastVbn
)
717 LastVbn
= Run
->RunEndVbn
.QuadPart
;
729 *Vbn
= RunFound
->RunEndVbn
.QuadPart
- 1;
735 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
) - 1;
744 *Index
= RunIndex
- 1;
756 FsRtlLookupLastBaseMcbEntryAndIndex(IN PBASE_MCB OpaqueMcb
,
757 IN OUT PLONGLONG LargeVbn
,
758 IN OUT PLONGLONG LargeLbn
,
762 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
764 DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
);
766 Result
= FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, LargeVbn
, LargeLbn
, Index
);
768 DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
, Result
, *LargeVbn
, *LargeLbn
, *Index
);
778 FsRtlLookupLastLargeMcbEntryAndIndex(IN PLARGE_MCB OpaqueMcb
,
779 OUT PLONGLONG LargeVbn
,
780 OUT PLONGLONG LargeLbn
,
785 DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
);
787 KeAcquireGuardedMutex(OpaqueMcb
->GuardedMutex
);
788 Result
= FsRtlLookupLastBaseMcbEntryAndIndex(&(OpaqueMcb
->BaseMcb
),
792 KeReleaseGuardedMutex(OpaqueMcb
->GuardedMutex
);
794 DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
, Result
, *LargeVbn
, *LargeLbn
, *Index
);
804 FsRtlLookupLastBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
809 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
811 DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p)\n", OpaqueMcb
, Vbn
, Lbn
);
813 Result
= FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, Vbn
, Lbn
, NULL
); /* Index */
815 DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, Result
, *Vbn
, *Lbn
);
825 FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb
,
831 DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p)\n", Mcb
, Vbn
, Lbn
);
833 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
834 Result
= FsRtlLookupLastBaseMcbEntry(&(Mcb
->BaseMcb
),
837 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
839 DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, Result
, *Vbn
, *Lbn
);
849 FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB OpaqueMcb
)
851 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
852 LONGLONG LbnAtVbn0
= -1;
853 ULONG NumberOfRuns
= 0;
855 DPRINT("FsRtlNumberOfRunsInBaseMcb(%p)\n", OpaqueMcb
);
857 if (Mcb
->PairCount
== 0) goto quit
;
859 FsRtlLookupBaseMcbEntry(OpaqueMcb
,
861 &LbnAtVbn0
, /* Lbn */
862 NULL
, NULL
, NULL
, NULL
); /* 4 output arguments - not interested in them */
865 /* Return the count */
866 //return Mcb->PairCount;
867 /* Return the number of 'real' and 'hole' runs.
868 * If we do not have sector 0 as 'real' emulate a 'hole' there.
870 NumberOfRuns
= Mcb
->PairCount
* 2 - (LbnAtVbn0
!= -1 ? 1 : 0); /* include holes as runs */
873 DPRINT("FsRtlNumberOfRunsInBaseMcb(%p) = %d\n", OpaqueMcb
, NumberOfRuns
);
882 FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb
)
886 DPRINT("FsRtlNumberOfRunsInLargeMcb(%p)\n", Mcb
);
888 /* Read the number of runs while holding the MCB lock */
889 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
890 NumberOfRuns
= FsRtlNumberOfRunsInBaseMcb(&(Mcb
->BaseMcb
));
891 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
893 DPRINT("FsRtlNumberOfRunsInLargeMcb(%p) = %d\n", Mcb
, NumberOfRuns
);
895 /* Return the count */
901 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
902 * %NULL value is forbidden.
903 * @Vbn: Starting virtual block number to specify the range to delete.
904 * @SectorCount: Length of the range to delete.
905 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
907 * Deletes any possible @Mcb mappings in the given range @Vbn ... @Vbn+@SectorCount-1.
908 * This call has no problems if no mappings exist there yet.
912 FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
914 IN LONGLONG SectorCount
)
916 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
917 LARGE_MCB_MAPPING_ENTRY NeedleRun
;
918 PLARGE_MCB_MAPPING_ENTRY HaystackRun
;
919 BOOLEAN Result
= TRUE
;
921 DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, SectorCount
);
923 if (Vbn
< 0 || SectorCount
<= 0)
929 if (Vbn
+ SectorCount
<= Vbn
)
935 NeedleRun
.RunStartVbn
.QuadPart
= Vbn
;
936 NeedleRun
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
937 NeedleRun
.StartingLbn
.QuadPart
= ~0ULL;
939 /* adjust/destroy all intersecting ranges */
940 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
941 while ((HaystackRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)))
943 if (HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunStartVbn
.QuadPart
)
945 ASSERT(HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunStartVbn
.QuadPart
);
946 HaystackRun
->RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
;
948 else if (HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunEndVbn
.QuadPart
)
950 ASSERT(HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunEndVbn
.QuadPart
);
951 HaystackRun
->RunStartVbn
.QuadPart
= NeedleRun
.RunEndVbn
.QuadPart
;
955 //ASSERT(NeedleRun.RunStartVbn.QuadPart >= HaystackRun->RunStartVbn.QuadPart);
956 //ASSERT(NeedleRun.RunEndVbn.QuadPart <= HaystackRun->RunEndVbn.QuadPart);
957 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
958 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, HaystackRun
);
960 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
963 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
966 DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d) = %d\n", OpaqueMcb
, Vbn
, SectorCount
, Result
);
975 FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb
,
977 IN LONGLONG SectorCount
)
979 DPRINT("FsRtlRemoveLargeMcbEntry(%p, %I64d, %I64d)\n", Mcb
, Vbn
, SectorCount
);
981 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
982 FsRtlRemoveBaseMcbEntry(&(Mcb
->BaseMcb
), Vbn
, SectorCount
);
983 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
991 FsRtlResetBaseMcb(IN PBASE_MCB OpaqueMcb
)
993 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
994 PLARGE_MCB_MAPPING_ENTRY Element
;
996 DPRINT("FsRtlResetBaseMcb(%p)\n", OpaqueMcb
);
998 while (RtlNumberGenericTableElements(&Mcb
->Mapping
->Table
) &&
999 (Element
= (PLARGE_MCB_MAPPING_ENTRY
)RtlGetElementGenericTable(&Mcb
->Mapping
->Table
, 0)))
1001 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, Element
);
1005 Mcb
->MaximumPairCount
= 0;
1013 FsRtlResetLargeMcb(IN PLARGE_MCB Mcb
,
1014 IN BOOLEAN SelfSynchronized
)
1016 DPRINT("FsRtlResetLargeMcb(%p, %d)\n", Mcb
, SelfSynchronized
);
1018 if (!SelfSynchronized
)
1019 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1021 FsRtlResetBaseMcb(&Mcb
->BaseMcb
);
1023 if (!SelfSynchronized
)
1024 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1032 FsRtlSplitBaseMcb(IN PBASE_MCB OpaqueMcb
,
1036 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
1037 PLARGE_MCB_MAPPING_ENTRY Run
, InsertLowerRun
= NULL
, ExistingRun
= NULL
;
1040 DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, Amount
);
1042 /* Traverse the tree */
1043 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
1045 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
1047 /* unaffected run? */
1048 /* FIXME: performance: effective skip of all 'lower' runs without traversing them */
1049 if (Vbn
>= Run
->RunEndVbn
.QuadPart
) { DPRINT("Skipping it\n"); continue; }
1051 /* crossing run to be split?
1052 * 'lower_run' is created on the original place; just shortened.
1053 * current 'run' is shifted up later
1055 if (Vbn
< Run
->RunEndVbn
.QuadPart
)
1057 /* FIXME: shift 'run->Lbn_start' ? */
1058 Run
->RunStartVbn
.QuadPart
= Vbn
;
1060 InsertLowerRun
= NULL
;
1063 /* Shift the current 'run'.
1064 * Ordering is not changed in Generic Tree so I hope I do not need to reinsert it.
1066 Run
->RunStartVbn
.QuadPart
+= Amount
;
1067 ASSERT(Run
->RunEndVbn
.QuadPart
+ Amount
> Run
->RunEndVbn
.QuadPart
); /* overflow? */
1068 Run
->RunEndVbn
.QuadPart
+= Amount
;
1069 /* FIXME: shift 'run->Lbn_start' ? */
1071 /* continue the traversal */
1076 ExistingRun
= RtlInsertElementGenericTable(&Mcb
->Mapping
->Table
, InsertLowerRun
, sizeof(*InsertLowerRun
), &NewElement
);
1080 ASSERT(ExistingRun
== NULL
);
1082 DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d) = %d\n", OpaqueMcb
, Vbn
, Amount
, TRUE
);
1092 FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb
,
1098 DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d)\n", Mcb
, Vbn
, Amount
);
1100 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1101 Result
= FsRtlSplitBaseMcb(&(Mcb
->BaseMcb
),
1104 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1106 DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Amount
, Result
);
1116 FsRtlTruncateBaseMcb(IN PBASE_MCB OpaqueMcb
,
1119 DPRINT("FsRtlTruncateBaseMcb(%p, %I64d)\n", OpaqueMcb
, Vbn
);
1121 FsRtlRemoveBaseMcbEntry(OpaqueMcb
, Vbn
, MAXLONG
- Vbn
+ 1);
1129 FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb
,
1132 DPRINT("FsRtlTruncateLargeMcb(%p, %I64d)\n", Mcb
, Vbn
);
1134 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1135 FsRtlTruncateBaseMcb(&(Mcb
->BaseMcb
), Vbn
);
1136 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1144 FsRtlUninitializeBaseMcb(IN PBASE_MCB Mcb
)
1146 DPRINT("FsRtlUninitializeBaseMcb(%p)\n", Mcb
);
1148 FsRtlResetBaseMcb(Mcb
);
1150 if ((Mcb
->PoolType
== PagedPool
)/* && (Mcb->MaximumPairCount == MAXIMUM_PAIR_COUNT)*/)
1152 ExFreeToPagedLookasideList(&FsRtlFirstMappingLookasideList
,
1157 ExFreePoolWithTag(Mcb
->Mapping
, 'FSBC');
1166 FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb
)
1168 DPRINT("FsRtlUninitializeLargeMcb(%p)\n", Mcb
);
1170 if (Mcb
->GuardedMutex
)
1172 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
1174 FsRtlUninitializeBaseMcb(&(Mcb
->BaseMcb
));