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
);
202 // NB: Two consecutive runs can only be merged, if actual LBNs also match!
205 Existing->RunStartVbn
213 Existing->RunStartVbn
221 Existing->RunStartVbn
229 Existing->RunStartVbn
237 Situation with holes:
238 1. Holes at both ends
239 2. Hole at the right, new run merged with the previous run
240 3. Hole at the right, new run is not merged with the previous run
241 4. Hole at the left, new run merged with the next run
242 5. Hole at the left, new run is not merged with the next run
243 6. No holes, exact fit to merge with both previous and next runs
244 7. No holes, merges only with the next run
245 8. No holes, merges only with the previous run
246 9. No holes, does not merge with next or prev runs
249 Overwriting existing mapping is not possible and results in FALSE being returned
253 DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Lbn
, SectorCount
, Result
);
262 FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb
,
265 IN LONGLONG SectorCount
)
269 DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, SectorCount
);
271 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
272 Result
= FsRtlAddBaseMcbEntry(&(Mcb
->BaseMcb
),
276 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
278 DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Lbn
, SectorCount
, Result
);
285 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
286 * %NULL value is forbidden.
287 * @RunIndex: Requested range index to retrieve.
288 * @Vbn: Returns the starting virtual block number of the wished range.
289 * %NULL pointer is forbidden.
290 * @Lbn: Returns the starting logical block number of the wished range (or -1 if it is a hole).
291 * %NULL pointer is forbidden.
292 * @SectorCount: Returns the length of the wished range.
293 * %NULL pointer is forbidden.
294 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
296 * Retrieves the parameters of the specified run with index @RunIndex.
298 * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping.
299 * libcaptive does not store 'hole' information to its #GTree.
300 * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1.
302 * Returns: %TRUE if successful.
306 FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
310 OUT PLONGLONG SectorCount
)
312 BOOLEAN Result
= FALSE
;
313 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
314 ULONG RunIndexRemaining
;
315 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
316 BOOLEAN First
= TRUE
;
318 DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p)\n", OpaqueMcb
, RunIndex
, Vbn
, Lbn
, SectorCount
);
320 RunIndexRemaining
= RunIndex
;
322 /* Traverse the tree */
323 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
325 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
329 /* Take care when we must emulate missing 'hole' run at start of our run list. */
330 if (Run
->RunStartVbn
.QuadPart
> 0)
332 if (RunIndexRemaining
== 0)
334 RunFoundLower
= &StaticRunBelow0
;
335 RunFoundHigher
= Run
;
337 /* stop the traversal */
340 /* If someone wants RunIndex #1 we are already on it. */
346 if (RunIndexRemaining
> 0)
348 /* FIXME: performance: non-linear direct seek to the requested RunIndex */
350 if (RunIndexRemaining
== 0)
355 /* continue the traversal */
360 RunFoundHigher
= Run
;
364 /* stop the traversal */
368 if (RunFound
) DPRINT("RunFound(%lu %lu %lu)\n", RunFound
->RunStartVbn
.LowPart
, RunFound
->RunEndVbn
.LowPart
, RunFound
->StartingLbn
.LowPart
);
369 if (RunFoundLower
) DPRINT("RunFoundLower(%lu %lu %lu)\n", RunFoundLower
->RunStartVbn
.LowPart
, RunFoundLower
->RunEndVbn
.LowPart
, RunFoundLower
->StartingLbn
.LowPart
);
370 if (RunFoundHigher
) DPRINT("RunFoundHigher(%lu %lu %lu)\n", RunFoundHigher
->RunStartVbn
.LowPart
, RunFoundHigher
->RunEndVbn
.LowPart
, RunFoundHigher
->StartingLbn
.LowPart
);
374 ASSERT(RunFoundLower
== NULL
);
375 ASSERT(RunFoundHigher
== NULL
);
378 *Vbn
= RunFound
->RunStartVbn
.QuadPart
;
380 *Lbn
= RunFound
->StartingLbn
.QuadPart
;
382 *SectorCount
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
388 if (RunFoundLower
&& RunFoundHigher
)
390 //ASSERT(RunFoundHigher != NULL);
393 *Vbn
= RunFoundLower
->RunEndVbn
.QuadPart
;
397 *SectorCount
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
403 ASSERT(RunFoundHigher
== NULL
);
406 DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
, Result
, *Vbn
, *Lbn
, *SectorCount
);
415 FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb
,
419 OUT PLONGLONG SectorCount
)
423 DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
);
425 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
426 Result
= FsRtlGetNextBaseMcbEntry(&(Mcb
->BaseMcb
),
431 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
433 DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb
, RunIndex
, Vbn
, Lbn
, SectorCount
, Result
, *Vbn
, *Lbn
, *SectorCount
);
443 FsRtlInitializeBaseMcb(IN PBASE_MCB OpaqueMcb
,
444 IN POOL_TYPE PoolType
)
446 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
448 if (PoolType
== PagedPool
)
450 Mcb
->Mapping
= ExAllocateFromPagedLookasideList(&FsRtlFirstMappingLookasideList
);
454 Mcb
->Mapping
= ExAllocatePoolWithTag(PoolType
| POOL_RAISE_IF_ALLOCATION_FAILURE
,
455 sizeof(LARGE_MCB_MAPPING
),
459 Mcb
->PoolType
= PoolType
;
461 Mcb
->MaximumPairCount
= MAXIMUM_PAIR_COUNT
;
462 RtlInitializeGenericTable(&Mcb
->Mapping
->Table
,
474 FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb
,
475 IN POOL_TYPE PoolType
)
477 DPRINT("FsRtlInitializeLargeMcb(%p, %d)\n", Mcb
, PoolType
);
479 Mcb
->GuardedMutex
= ExAllocateFromNPagedLookasideList(&FsRtlFastMutexLookasideList
);
481 KeInitializeGuardedMutex(Mcb
->GuardedMutex
);
485 FsRtlInitializeBaseMcb(&(Mcb
->BaseMcb
), PoolType
);
487 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
489 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
491 Mcb
->GuardedMutex
= NULL
;
502 FsRtlInitializeLargeMcbs(VOID
)
504 /* Initialize the list for the MCB */
505 ExInitializePagedLookasideList(&FsRtlFirstMappingLookasideList
,
508 POOL_RAISE_IF_ALLOCATION_FAILURE
,
509 sizeof(LARGE_MCB_MAPPING
),
511 0); /* FIXME: Should be 4 */
513 /* Initialize the list for the guarded mutex */
514 ExInitializeNPagedLookasideList(&FsRtlFastMutexLookasideList
,
517 POOL_RAISE_IF_ALLOCATION_FAILURE
,
518 sizeof(KGUARDED_MUTEX
),
520 0); /* FIXME: Should be 32 */
528 FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
530 OUT PLONGLONG Lbn OPTIONAL
,
531 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
532 OUT PLONGLONG StartingLbn OPTIONAL
,
533 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
534 OUT PULONG Index OPTIONAL
)
536 BOOLEAN Result
= FALSE
;
537 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
540 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
, RunFoundLower
= NULL
, RunFoundHigher
= NULL
;
541 BOOLEAN First
= TRUE
;
543 DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", OpaqueMcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
);
545 /* Traverse the tree */
546 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
548 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
552 /* Take care when we must emulate missing 'hole' run at start of our run list. */
553 if (Run
->RunStartVbn
.QuadPart
> 0)
556 RunFoundLower
= &StaticRunBelow0
;
561 if (Run
->RunStartVbn
.QuadPart
<= Vbn
&& Vbn
< Run
->RunEndVbn
.QuadPart
)
564 RunFoundLower
= NULL
;
565 /* stop the traversal; hit */
569 if (Run
->RunEndVbn
.QuadPart
<= Vbn
)
572 if (Run
->StartingLbn
.QuadPart
> 0)
576 /* continue the traversal; not yet crossed by the run */
580 if (Vbn
< Run
->RunStartVbn
.QuadPart
)
582 RunFoundHigher
= Run
;
584 /* stop the traversal; the run skipped us */
589 /* stop the traversal */
595 ASSERT(RunFoundLower
== NULL
);
596 ASSERT(RunFoundHigher
== NULL
);
599 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (Vbn
- RunFound
->RunStartVbn
.QuadPart
);
601 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
602 *SectorCountFromLbn
= RunFound
->RunEndVbn
.QuadPart
- Vbn
;
604 *StartingLbn
= RunFound
->StartingLbn
.QuadPart
;
605 if (SectorCountFromStartingLbn
)
606 *SectorCountFromStartingLbn
= RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
;
616 /* search for hole */
617 ASSERT(RunFoundLower
!= NULL
);
621 if (SectorCountFromLbn
) /* FIXME: 'after' means including current 'Lbn' or without it? */
622 *SectorCountFromLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- Vbn
;
624 *StartingLbn
= ~0ull;
625 if (SectorCountFromStartingLbn
)
626 *SectorCountFromStartingLbn
= RunFoundHigher
->RunStartVbn
.QuadPart
- RunFoundLower
->RunEndVbn
.QuadPart
;
628 *Index
= RunIndex
- 2;
634 /* We may have some 'RunFoundLower'. */
637 DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
638 OpaqueMcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
, Result
,
639 (Lbn
? *Lbn
: (ULONGLONG
)-1), (SectorCountFromLbn
? *SectorCountFromLbn
: (ULONGLONG
)-1), (StartingLbn
? *StartingLbn
: (ULONGLONG
)-1),
640 (SectorCountFromStartingLbn
? *SectorCountFromStartingLbn
: (ULONGLONG
)-1), (Index
? *Index
: (ULONG
)-1));
650 FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb
,
652 OUT PLONGLONG Lbn OPTIONAL
,
653 OUT PLONGLONG SectorCountFromLbn OPTIONAL
,
654 OUT PLONGLONG StartingLbn OPTIONAL
,
655 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL
,
656 OUT PULONG Index OPTIONAL
)
660 DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", Mcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
);
662 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
663 Result
= FsRtlLookupBaseMcbEntry(&(Mcb
->BaseMcb
),
668 SectorCountFromStartingLbn
,
670 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
672 DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
673 Mcb
, Vbn
, Lbn
, SectorCountFromLbn
, StartingLbn
, SectorCountFromStartingLbn
, Index
, Result
,
674 (Lbn
? *Lbn
: (ULONGLONG
)-1), (SectorCountFromLbn
? *SectorCountFromLbn
: (ULONGLONG
)-1), (StartingLbn
? *StartingLbn
: (ULONGLONG
)-1),
675 (SectorCountFromStartingLbn
? *SectorCountFromStartingLbn
: (ULONGLONG
)-1), (Index
? *Index
: (ULONG
)-1));
682 FsRtlLookupLastLargeMcbEntryAndIndex_internal(IN PBASE_MCB_INTERNAL Mcb
,
685 OUT PULONG Index OPTIONAL
)
688 PLARGE_MCB_MAPPING_ENTRY Run
, RunFound
= NULL
;
689 LONGLONG LastVbn
= 0;
691 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
693 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
695 /* Take care when we must emulate missing 'hole' runs. */
696 if (Run
->RunStartVbn
.QuadPart
> LastVbn
)
700 LastVbn
= Run
->RunEndVbn
.QuadPart
;
712 *Vbn
= RunFound
->RunEndVbn
.QuadPart
- 1;
718 *Lbn
= RunFound
->StartingLbn
.QuadPart
+ (RunFound
->RunEndVbn
.QuadPart
- RunFound
->RunStartVbn
.QuadPart
) - 1;
727 *Index
= RunIndex
- 1;
739 FsRtlLookupLastBaseMcbEntryAndIndex(IN PBASE_MCB OpaqueMcb
,
740 IN OUT PLONGLONG LargeVbn
,
741 IN OUT PLONGLONG LargeLbn
,
745 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
747 DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
);
749 Result
= FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, LargeVbn
, LargeLbn
, Index
);
751 DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
, Result
, *LargeVbn
, *LargeLbn
, *Index
);
761 FsRtlLookupLastLargeMcbEntryAndIndex(IN PLARGE_MCB OpaqueMcb
,
762 OUT PLONGLONG LargeVbn
,
763 OUT PLONGLONG LargeLbn
,
768 DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
);
770 KeAcquireGuardedMutex(OpaqueMcb
->GuardedMutex
);
771 Result
= FsRtlLookupLastBaseMcbEntryAndIndex(&(OpaqueMcb
->BaseMcb
),
775 KeReleaseGuardedMutex(OpaqueMcb
->GuardedMutex
);
777 DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb
, LargeVbn
, LargeLbn
, Index
, Result
, *LargeVbn
, *LargeLbn
, *Index
);
787 FsRtlLookupLastBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
792 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
794 DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p)\n", OpaqueMcb
, Vbn
, Lbn
);
796 Result
= FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb
, Vbn
, Lbn
, NULL
); /* Index */
798 DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, Result
, *Vbn
, *Lbn
);
808 FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb
,
814 DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p)\n", Mcb
, Vbn
, Lbn
);
816 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
817 Result
= FsRtlLookupLastBaseMcbEntry(&(Mcb
->BaseMcb
),
820 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
822 DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb
, Vbn
, Lbn
, Result
, *Vbn
, *Lbn
);
832 FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB OpaqueMcb
)
834 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
835 LONGLONG LbnAtVbn0
= -1;
836 ULONG Nodes
= RtlNumberGenericTableElements(&Mcb
->Mapping
->Table
);
837 ULONG NumberOfRuns
= 0;
839 DPRINT("FsRtlNumberOfRunsInBaseMcb(%p)\n", OpaqueMcb
);
841 if (Nodes
== 0) goto quit
;
843 FsRtlLookupBaseMcbEntry(OpaqueMcb
,
845 &LbnAtVbn0
, /* Lbn */
846 NULL
, NULL
, NULL
, NULL
); /* 4 output arguments - not interested in them */
849 /* Return the count */
850 //return Mcb->PairCount;
851 /* Return the number of 'real' and 'hole' runs.
852 * If we do not have sector 0 as 'real' emulate a 'hole' there.
854 NumberOfRuns
= Nodes
* 2 - (LbnAtVbn0
!= -1 ? 1 : 0); /* include holes as runs */
857 DPRINT("FsRtlNumberOfRunsInBaseMcb(%p) = %d\n", OpaqueMcb
, NumberOfRuns
);
866 FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb
)
870 DPRINT("FsRtlNumberOfRunsInLargeMcb(%p)\n", Mcb
);
872 /* Read the number of runs while holding the MCB lock */
873 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
874 NumberOfRuns
= FsRtlNumberOfRunsInBaseMcb(&(Mcb
->BaseMcb
));
875 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
877 DPRINT("FsRtlNumberOfRunsInLargeMcb(%p) = %d\n", Mcb
, NumberOfRuns
);
879 /* Return the count */
885 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
886 * %NULL value is forbidden.
887 * @Vbn: Starting virtual block number to specify the range to delete.
888 * @SectorCount: Length of the range to delete.
889 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
891 * Deletes any possible @Mcb mappings in the given range @Vbn ... @Vbn+@SectorCount-1.
892 * This call has no problems if no mappings exist there yet.
896 FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb
,
898 IN LONGLONG SectorCount
)
900 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
901 LARGE_MCB_MAPPING_ENTRY NeedleRun
;
902 PLARGE_MCB_MAPPING_ENTRY HaystackRun
;
903 BOOLEAN Result
= TRUE
;
905 DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, SectorCount
);
907 if (Vbn
< 0 || SectorCount
<= 0)
913 if (Vbn
+ SectorCount
<= Vbn
)
919 NeedleRun
.RunStartVbn
.QuadPart
= Vbn
;
920 NeedleRun
.RunEndVbn
.QuadPart
= Vbn
+ SectorCount
;
921 NeedleRun
.StartingLbn
.QuadPart
= ~0ULL;
923 /* adjust/destroy all intersecting ranges */
924 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
925 while ((HaystackRun
= RtlLookupElementGenericTable(&Mcb
->Mapping
->Table
, &NeedleRun
)))
927 if (HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunStartVbn
.QuadPart
)
929 ASSERT(HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunStartVbn
.QuadPart
);
930 HaystackRun
->RunEndVbn
.QuadPart
= NeedleRun
.RunStartVbn
.QuadPart
;
932 else if (HaystackRun
->RunEndVbn
.QuadPart
> NeedleRun
.RunEndVbn
.QuadPart
)
934 ASSERT(HaystackRun
->RunStartVbn
.QuadPart
< NeedleRun
.RunEndVbn
.QuadPart
);
935 HaystackRun
->RunStartVbn
.QuadPart
= NeedleRun
.RunEndVbn
.QuadPart
;
939 //ASSERT(NeedleRun.RunStartVbn.QuadPart >= HaystackRun->RunStartVbn.QuadPart);
940 //ASSERT(NeedleRun.RunEndVbn.QuadPart <= HaystackRun->RunEndVbn.QuadPart);
941 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
942 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, HaystackRun
);
943 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingIntersectCompare
;
946 Mcb
->Mapping
->Table
.CompareRoutine
= McbMappingCompare
;
949 DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d) = %d\n", OpaqueMcb
, Vbn
, SectorCount
, Result
);
958 FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb
,
960 IN LONGLONG SectorCount
)
962 DPRINT("FsRtlRemoveLargeMcbEntry(%p, %I64d, %I64d)\n", Mcb
, Vbn
, SectorCount
);
964 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
965 FsRtlRemoveBaseMcbEntry(&(Mcb
->BaseMcb
), Vbn
, SectorCount
);
966 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
974 FsRtlResetBaseMcb(IN PBASE_MCB OpaqueMcb
)
976 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
977 PLARGE_MCB_MAPPING_ENTRY Element
;
979 DPRINT("FsRtlResetBaseMcb(%p)\n", OpaqueMcb
);
981 while (RtlNumberGenericTableElements(&Mcb
->Mapping
->Table
) &&
982 (Element
= (PLARGE_MCB_MAPPING_ENTRY
)RtlGetElementGenericTable(&Mcb
->Mapping
->Table
, 0)))
984 RtlDeleteElementGenericTable(&Mcb
->Mapping
->Table
, Element
);
988 Mcb
->MaximumPairCount
= 0;
996 FsRtlResetLargeMcb(IN PLARGE_MCB Mcb
,
997 IN BOOLEAN SelfSynchronized
)
999 DPRINT("FsRtlResetLargeMcb(%p, %d)\n", Mcb
, SelfSynchronized
);
1001 if (!SelfSynchronized
)
1002 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1004 FsRtlResetBaseMcb(&Mcb
->BaseMcb
);
1006 if (!SelfSynchronized
)
1007 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1015 FsRtlSplitBaseMcb(IN PBASE_MCB OpaqueMcb
,
1019 PBASE_MCB_INTERNAL Mcb
= (PBASE_MCB_INTERNAL
)OpaqueMcb
;
1020 PLARGE_MCB_MAPPING_ENTRY Run
, InsertLowerRun
= NULL
, ExistingRun
= NULL
;
1023 DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d)\n", OpaqueMcb
, Vbn
, Amount
);
1025 /* Traverse the tree */
1026 for (Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, TRUE
);
1028 Run
= (PLARGE_MCB_MAPPING_ENTRY
)RtlEnumerateGenericTable(&Mcb
->Mapping
->Table
, FALSE
))
1030 /* unaffected run? */
1031 /* FIXME: performance: effective skip of all 'lower' runs without traversing them */
1032 if (Vbn
>= Run
->RunEndVbn
.QuadPart
) { DPRINT("Skipping it\n"); continue; }
1034 /* crossing run to be split?
1035 * 'lower_run' is created on the original place; just shortened.
1036 * current 'run' is shifted up later
1038 if (Vbn
< Run
->RunEndVbn
.QuadPart
)
1040 /* FIXME: shift 'run->Lbn_start' ? */
1041 Run
->RunStartVbn
.QuadPart
= Vbn
;
1043 InsertLowerRun
= NULL
;
1046 /* Shift the current 'run'.
1047 * Ordering is not changed in Generic Tree so I hope I do not need to reinsert it.
1049 Run
->RunStartVbn
.QuadPart
+= Amount
;
1050 ASSERT(Run
->RunEndVbn
.QuadPart
+ Amount
> Run
->RunEndVbn
.QuadPart
); /* overflow? */
1051 Run
->RunEndVbn
.QuadPart
+= Amount
;
1052 /* FIXME: shift 'run->Lbn_start' ? */
1054 /* continue the traversal */
1058 ExistingRun
= RtlInsertElementGenericTable(&Mcb
->Mapping
->Table
, InsertLowerRun
, sizeof(*InsertLowerRun
), &NewElement
);
1060 ASSERT(ExistingRun
== NULL
);
1062 DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d) = %d\n", OpaqueMcb
, Vbn
, Amount
, TRUE
);
1072 FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb
,
1078 DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d)\n", Mcb
, Vbn
, Amount
);
1080 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1081 Result
= FsRtlSplitBaseMcb(&(Mcb
->BaseMcb
),
1084 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1086 DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d) = %d\n", Mcb
, Vbn
, Amount
, Result
);
1096 FsRtlTruncateBaseMcb(IN PBASE_MCB OpaqueMcb
,
1099 DPRINT("FsRtlTruncateBaseMcb(%p, %I64d)\n", OpaqueMcb
, Vbn
);
1101 FsRtlRemoveBaseMcbEntry(OpaqueMcb
, Vbn
, MAXLONG
- Vbn
+ 1);
1109 FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb
,
1112 DPRINT("FsRtlTruncateLargeMcb(%p, %I64d)\n", Mcb
, Vbn
);
1114 KeAcquireGuardedMutex(Mcb
->GuardedMutex
);
1115 FsRtlTruncateBaseMcb(&(Mcb
->BaseMcb
), Vbn
);
1116 KeReleaseGuardedMutex(Mcb
->GuardedMutex
);
1124 FsRtlUninitializeBaseMcb(IN PBASE_MCB Mcb
)
1126 DPRINT("FsRtlUninitializeBaseMcb(%p)\n", Mcb
);
1128 FsRtlResetBaseMcb(Mcb
);
1130 if ((Mcb
->PoolType
== PagedPool
)/* && (Mcb->MaximumPairCount == MAXIMUM_PAIR_COUNT)*/)
1132 ExFreeToPagedLookasideList(&FsRtlFirstMappingLookasideList
,
1137 ExFreePoolWithTag(Mcb
->Mapping
, 'FSBC');
1146 FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb
)
1148 DPRINT("FsRtlUninitializeLargeMcb(%p)\n", Mcb
);
1150 if (Mcb
->GuardedMutex
)
1152 ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList
,
1154 FsRtlUninitializeBaseMcb(&(Mcb
->BaseMcb
));