xref: /reactos/ntoskrnl/fsrtl/largemcb.c (revision 3d4cf8d2)
1 /*
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>
8  *                  Trevor Thompson
9  */
10 
11 /* INCLUDES ******************************************************************/
12 
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 #define MIN(x,y) (((x)<(y))?(x):(y))
18 #define MAX(x,y) (((x)>(y))?(x):(y))
19 
20 /* GLOBALS *******************************************************************/
21 
22 PAGED_LOOKASIDE_LIST FsRtlFirstMappingLookasideList;
23 NPAGED_LOOKASIDE_LIST FsRtlFastMutexLookasideList;
24 
25 /* We use only real 'mapping' runs; we do not store 'holes' to our GTree. */
26 typedef struct _LARGE_MCB_MAPPING_ENTRY // run
27 {
28     LARGE_INTEGER RunStartVbn;
29     LARGE_INTEGER RunEndVbn;   /* RunStartVbn+SectorCount; that means +1 after the last sector */
30     LARGE_INTEGER StartingLbn; /* Lbn of 'RunStartVbn' */
31 } LARGE_MCB_MAPPING_ENTRY, *PLARGE_MCB_MAPPING_ENTRY;
32 
33 typedef struct _LARGE_MCB_MAPPING // mcb_priv
34 {
35     RTL_GENERIC_TABLE Table;
36 } LARGE_MCB_MAPPING, *PLARGE_MCB_MAPPING;
37 
38 typedef struct _BASE_MCB_INTERNAL {
39     ULONG MaximumPairCount;
40     ULONG PairCount;
41     USHORT PoolType;
42     USHORT Flags;
43     PLARGE_MCB_MAPPING Mapping;
44 } BASE_MCB_INTERNAL, *PBASE_MCB_INTERNAL;
45 
46 /*
47 static LARGE_MCB_MAPPING_ENTRY StaticRunBelow0 = {
48     {{-1}}, // ignored
49     {{0}},
50     {{-1}}, // ignored
51 };
52 */
53 
McbMappingAllocate(PRTL_GENERIC_TABLE Table,CLONG Bytes)54 static PVOID NTAPI McbMappingAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
55 {
56     PVOID Result;
57     PBASE_MCB Mcb = (PBASE_MCB)Table->TableContext;
58     Result = ExAllocatePoolWithTag(Mcb->PoolType, Bytes, 'BCML');
59     DPRINT("McbMappingAllocate(%lu) => %p\n", Bytes, Result);
60     return Result;
61 }
62 
McbMappingFree(PRTL_GENERIC_TABLE Table,PVOID Buffer)63 static VOID NTAPI McbMappingFree(PRTL_GENERIC_TABLE Table, PVOID Buffer)
64 {
65     DPRINT("McbMappingFree(%p)\n", Buffer);
66     ExFreePoolWithTag(Buffer, 'BCML');
67 }
68 
69 static
70 RTL_GENERIC_COMPARE_RESULTS
71 NTAPI
McbMappingCompare(PRTL_GENERIC_TABLE Table,PVOID PtrA,PVOID PtrB)72 McbMappingCompare(PRTL_GENERIC_TABLE Table,
73                   PVOID PtrA,
74                   PVOID PtrB)
75 {
76     PLARGE_MCB_MAPPING_ENTRY A = PtrA, B = PtrB;
77     RTL_GENERIC_COMPARE_RESULTS Res;
78 
79     ASSERT(A);
80     ASSERT(B);
81 
82     if (A->RunStartVbn.QuadPart == B->RunStartVbn.QuadPart && A->RunEndVbn.QuadPart == B->RunEndVbn.QuadPart)
83         Res = GenericEqual;
84     else if (A->RunEndVbn.QuadPart <= B->RunStartVbn.QuadPart)
85         Res = GenericLessThan;
86     else if (A->RunEndVbn.QuadPart >= B->RunStartVbn.QuadPart)
87         Res = GenericGreaterThan;
88     else
89     {
90         ASSERT(FALSE);
91         Res = GenericEqual;
92     }
93 
94     return Res;
95 }
96 
McbMappingIntersectCompare(PRTL_GENERIC_TABLE Table,PVOID PtrA,PVOID PtrB)97 static RTL_GENERIC_COMPARE_RESULTS NTAPI McbMappingIntersectCompare(PRTL_GENERIC_TABLE Table, PVOID PtrA, PVOID PtrB)
98 {
99     PLARGE_MCB_MAPPING_ENTRY A = PtrA, B = PtrB;
100     RTL_GENERIC_COMPARE_RESULTS Res;
101 
102     if (A->RunStartVbn.QuadPart <= B->RunStartVbn.QuadPart && A->RunEndVbn.QuadPart > B->RunStartVbn.QuadPart)
103         Res = GenericEqual;
104     else if (A->RunStartVbn.QuadPart >= B->RunStartVbn.QuadPart && B->RunEndVbn.QuadPart > A->RunStartVbn.QuadPart)
105         Res = GenericEqual;
106     else if (A->RunStartVbn.QuadPart < B->RunStartVbn.QuadPart)
107         Res = GenericLessThan;
108     else if (A->RunStartVbn.QuadPart > B->RunStartVbn.QuadPart)
109         Res = GenericGreaterThan;
110     else
111         Res = GenericEqual;
112 
113     return Res;
114 }
115 
116 
117 /* PUBLIC FUNCTIONS **********************************************************/
118 
119 /*
120  * @implemented
121  * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
122  * %NULL value is forbidden.
123  * @Vbn: Starting virtual block number of the wished range.
124  * @Lbn: Starting logical block number of the wished range.
125  * @SectorCount: Length of the wished range.
126  * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
127  *
128  * Adds the specified range @Vbn ... @Vbn+@SectorCount-1 to @Mcb.
129  * Any mappings previously in this range are deleted first.
130  *
131  * Returns: %TRUE if successful.
132  */
133 BOOLEAN
134 NTAPI
FsRtlAddBaseMcbEntry(IN PBASE_MCB OpaqueMcb,IN LONGLONG Vbn,IN LONGLONG Lbn,IN LONGLONG SectorCount)135 FsRtlAddBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
136                      IN LONGLONG Vbn,
137                      IN LONGLONG Lbn,
138                      IN LONGLONG SectorCount)
139 {
140     BOOLEAN Result = TRUE;
141     BOOLEAN IntResult;
142     PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
143     LARGE_MCB_MAPPING_ENTRY Node, NeedleRun;
144     PLARGE_MCB_MAPPING_ENTRY LowerRun, HigherRun;
145     BOOLEAN NewElement;
146     LONGLONG IntLbn, IntSectorCount;
147 
148     DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d)\n", OpaqueMcb, Vbn, Lbn, SectorCount);
149 
150     if (Vbn < 0)
151     {
152         Result = FALSE;
153         goto quit;
154     }
155 
156     if (SectorCount <= 0)
157     {
158         Result = FALSE;
159         goto quit;
160     }
161 
162     IntResult = FsRtlLookupBaseMcbEntry(OpaqueMcb, Vbn, &IntLbn, &IntSectorCount, NULL, NULL, NULL);
163     if (IntResult)
164     {
165         if (IntLbn != -1 && IntLbn != Lbn)
166         {
167             Result = FALSE;
168             goto quit;
169         }
170 
171         if ((IntLbn != -1) && (IntSectorCount >= SectorCount))
172         {
173             /* This is a no-op */
174             goto quit;
175         }
176     }
177 
178     /* clean any possible previous entries in our range */
179     FsRtlRemoveBaseMcbEntry(OpaqueMcb, Vbn, SectorCount);
180 
181     // We need to map [Vbn, Vbn+SectorCount) to [Lbn, Lbn+SectorCount),
182     // taking in account the fact that we need to merge these runs if
183     // they are adjacent or overlap, but fail if new run fully fits into another run
184 
185     /* initially we think we will be inserted as a separate run */
186     Node.RunStartVbn.QuadPart = Vbn;
187     Node.RunEndVbn.QuadPart = Vbn + SectorCount;
188     Node.StartingLbn.QuadPart = Lbn;
189 
190     /* optionally merge with lower run */
191     NeedleRun.RunStartVbn.QuadPart = Node.RunStartVbn.QuadPart - 1;
192     NeedleRun.RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart + 1;
193     NeedleRun.StartingLbn.QuadPart = ~0ULL;
194     Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
195     if ((LowerRun = RtlLookupElementGenericTable(&Mcb->Mapping->Table, &NeedleRun)) &&
196         (LowerRun->StartingLbn.QuadPart + (LowerRun->RunEndVbn.QuadPart - LowerRun->RunStartVbn.QuadPart) == Node.StartingLbn.QuadPart))
197     {
198         ASSERT(LowerRun->RunEndVbn.QuadPart == Node.RunStartVbn.QuadPart);
199         Node.RunStartVbn.QuadPart = LowerRun->RunStartVbn.QuadPart;
200         Node.StartingLbn.QuadPart = LowerRun->StartingLbn.QuadPart;
201         Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
202         RtlDeleteElementGenericTable(&Mcb->Mapping->Table, LowerRun);
203         --Mcb->PairCount;
204         DPRINT("Intersecting lower run found (%I64d,%I64d) Lbn: %I64d\n", LowerRun->RunStartVbn.QuadPart, LowerRun->RunEndVbn.QuadPart, LowerRun->StartingLbn.QuadPart);
205     }
206 
207     /* optionally merge with higher run */
208     NeedleRun.RunStartVbn.QuadPart = Node.RunEndVbn.QuadPart;
209     NeedleRun.RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart + 1;
210     Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
211     if ((HigherRun = RtlLookupElementGenericTable(&Mcb->Mapping->Table, &NeedleRun)) &&
212         (Node.StartingLbn.QuadPart <= HigherRun->StartingLbn.QuadPart))
213     {
214         ASSERT(HigherRun->RunStartVbn.QuadPart == Node.RunEndVbn.QuadPart);
215         Node.RunEndVbn.QuadPart = HigherRun->RunEndVbn.QuadPart;
216         Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
217         RtlDeleteElementGenericTable(&Mcb->Mapping->Table, HigherRun);
218         --Mcb->PairCount;
219         DPRINT("Intersecting higher run found (%I64d,%I64d) Lbn: %I64d\n", HigherRun->RunStartVbn.QuadPart, HigherRun->RunEndVbn.QuadPart, HigherRun->StartingLbn.QuadPart);
220     }
221     Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
222 
223     /* finally insert the resulting run */
224     RtlInsertElementGenericTable(&Mcb->Mapping->Table, &Node, sizeof(Node), &NewElement);
225     ++Mcb->PairCount;
226     ASSERT(NewElement);
227 
228     // NB: Two consecutive runs can only be merged, if actual LBNs also match!
229 
230     /* 1.
231             Existing->RunStartVbn
232             |
233             |///////|
234                 |/////////////|
235                 |
236                 Node->RunStartVbn
237 
238         2.
239             Existing->RunStartVbn
240             |
241             |///////|
242         |//////|
243         |
244         Node->RunStartVbn
245 
246         3.
247             Existing->RunStartVbn
248             |
249             |///////|
250                 |///|
251                 |
252                 Node->RunStartVbn
253 
254         4.
255             Existing->RunStartVbn
256             |
257             |///////|
258         |///////////////|
259         |
260         Node->RunStartVbn
261 
262 
263     Situation with holes:
264     1. Holes at both ends
265     2. Hole at the right, new run merged with the previous run
266     3. Hole at the right, new run is not merged with the previous run
267     4. Hole at the left, new run merged with the next run
268     5. Hole at the left, new run is not merged with the next run
269     6. No holes, exact fit to merge with both previous and next runs
270     7. No holes, merges only with the next run
271     8. No holes, merges only with the previous run
272     9. No holes, does not merge with next or prev runs
273 
274 
275     Overwriting existing mapping is not possible and results in FALSE being returned
276     */
277 
278 quit:
279     DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb, Vbn, Lbn, SectorCount, Result);
280     return Result;
281 }
282 
283 /*
284  * @implemented
285  */
286 BOOLEAN
287 NTAPI
FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb,IN LONGLONG Vbn,IN LONGLONG Lbn,IN LONGLONG SectorCount)288 FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb,
289                       IN LONGLONG Vbn,
290                       IN LONGLONG Lbn,
291                       IN LONGLONG SectorCount)
292 {
293     BOOLEAN Result;
294 
295     DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d)\n", Mcb, Vbn, Lbn, SectorCount);
296 
297     KeAcquireGuardedMutex(Mcb->GuardedMutex);
298     Result = FsRtlAddBaseMcbEntry(&(Mcb->BaseMcb),
299                                   Vbn,
300                                   Lbn,
301                                   SectorCount);
302     KeReleaseGuardedMutex(Mcb->GuardedMutex);
303 
304     DPRINT("FsRtlAddLargeMcbEntry(%p, %I64d, %I64d, %I64d) = %d\n", Mcb, Vbn, Lbn, SectorCount, Result);
305 
306     return Result;
307 }
308 
309 /*
310  * @implemented
311  * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
312  * %NULL value is forbidden.
313  * @RunIndex: Requested range index to retrieve.
314  * @Vbn: Returns the starting virtual block number of the wished range.
315  * %NULL pointer is forbidden.
316  * @Lbn: Returns the starting logical block number of the wished range (or -1 if it is a hole).
317  * %NULL pointer is forbidden.
318  * @SectorCount: Returns the length of the wished range.
319  * %NULL pointer is forbidden.
320  * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
321  *
322  * Retrieves the parameters of the specified run with index @RunIndex.
323  *
324  * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping.
325  * libcaptive does not store 'hole' information to its #GTree.
326  * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1.
327  *
328  * Returns: %TRUE if successful.
329  */
330 BOOLEAN
331 NTAPI
FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb,IN ULONG RunIndex,OUT PLONGLONG Vbn,OUT PLONGLONG Lbn,OUT PLONGLONG SectorCount)332 FsRtlGetNextBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
333     IN ULONG RunIndex,
334     OUT PLONGLONG Vbn,
335     OUT PLONGLONG Lbn,
336     OUT PLONGLONG SectorCount)
337 {
338     BOOLEAN Result = FALSE;
339     PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
340     PLARGE_MCB_MAPPING_ENTRY Run = NULL;
341     ULONG CurrentIndex = 0;
342     ULONGLONG LastVbn = 0;
343     ULONGLONG LastSectorCount = 0;
344 
345     // Traverse the tree
346     for (Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, TRUE);
347     Run;
348         Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, FALSE))
349     {
350         // is the current index a hole?
351         if (Run->RunStartVbn.QuadPart > (LastVbn + LastSectorCount))
352         {
353             // Is this the index we're looking for?
354             if (RunIndex == CurrentIndex)
355             {
356                 *Vbn = LastVbn + LastSectorCount;
357                 *Lbn = -1;
358                 *SectorCount = Run->RunStartVbn.QuadPart - *Vbn;
359 
360                 Result = TRUE;
361                 goto quit;
362             }
363 
364             CurrentIndex++;
365         }
366 
367         if (RunIndex == CurrentIndex)
368         {
369             *Vbn = Run->RunStartVbn.QuadPart;
370             *Lbn = Run->StartingLbn.QuadPart;
371             *SectorCount = Run->RunEndVbn.QuadPart - Run->RunStartVbn.QuadPart;
372 
373             Result = TRUE;
374             goto quit;
375         }
376 
377         CurrentIndex++;
378         LastVbn = Run->RunStartVbn.QuadPart;
379         LastSectorCount = Run->RunEndVbn.QuadPart - Run->RunStartVbn.QuadPart;
380     }
381 
382 quit:
383     DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb, RunIndex, Vbn, Lbn, SectorCount, Result, *Vbn, *Lbn, *SectorCount);
384     return Result;
385 }
386 
387 /*
388  * @implemented
389  */
390 BOOLEAN
391 NTAPI
FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb,IN ULONG RunIndex,OUT PLONGLONG Vbn,OUT PLONGLONG Lbn,OUT PLONGLONG SectorCount)392 FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb,
393                           IN ULONG RunIndex,
394                           OUT PLONGLONG Vbn,
395                           OUT PLONGLONG Lbn,
396                           OUT PLONGLONG SectorCount)
397 {
398     BOOLEAN Result;
399 
400     DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p)\n", Mcb, RunIndex, Vbn, Lbn, SectorCount);
401 
402     KeAcquireGuardedMutex(Mcb->GuardedMutex);
403     Result = FsRtlGetNextBaseMcbEntry(&(Mcb->BaseMcb),
404                                       RunIndex,
405                                       Vbn,
406                                       Lbn,
407                                       SectorCount);
408     KeReleaseGuardedMutex(Mcb->GuardedMutex);
409 
410     DPRINT("FsRtlGetNextLargeMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb, RunIndex, Vbn, Lbn, SectorCount, Result, *Vbn, *Lbn, *SectorCount);
411 
412     return Result;
413 }
414 
415 /*
416  * @implemented
417  */
418 VOID
419 NTAPI
FsRtlInitializeBaseMcb(IN PBASE_MCB OpaqueMcb,IN POOL_TYPE PoolType)420 FsRtlInitializeBaseMcb(IN PBASE_MCB OpaqueMcb,
421                        IN POOL_TYPE PoolType)
422 {
423     PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
424 
425     if (PoolType == PagedPool)
426     {
427         Mcb->Mapping = ExAllocateFromPagedLookasideList(&FsRtlFirstMappingLookasideList);
428     }
429     else
430     {
431         Mcb->Mapping = ExAllocatePoolWithTag(PoolType | POOL_RAISE_IF_ALLOCATION_FAILURE,
432                                              sizeof(LARGE_MCB_MAPPING),
433                                              'CBSF');
434     }
435 
436     Mcb->PoolType = PoolType;
437     Mcb->PairCount = 0;
438     Mcb->MaximumPairCount = MAXIMUM_PAIR_COUNT;
439     RtlInitializeGenericTable(&Mcb->Mapping->Table,
440                               McbMappingCompare,
441                               McbMappingAllocate,
442                               McbMappingFree,
443                               Mcb);
444 }
445 
446 /*
447  * @implemented
448  */
449 VOID
450 NTAPI
FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb,IN POOL_TYPE PoolType)451 FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb,
452                         IN POOL_TYPE PoolType)
453 {
454     DPRINT("FsRtlInitializeLargeMcb(%p, %d)\n", Mcb, PoolType);
455 
456     Mcb->GuardedMutex = ExAllocateFromNPagedLookasideList(&FsRtlFastMutexLookasideList);
457 
458     KeInitializeGuardedMutex(Mcb->GuardedMutex);
459 
460     _SEH2_TRY
461     {
462         FsRtlInitializeBaseMcb(&(Mcb->BaseMcb), PoolType);
463     }
464     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
465     {
466         ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList,
467                                     Mcb->GuardedMutex);
468         Mcb->GuardedMutex = NULL;
469     }
470     _SEH2_END;
471 }
472 
473 /*
474  * @implemented
475  */
476 CODE_SEG("INIT")
477 VOID
478 NTAPI
FsRtlInitializeLargeMcbs(VOID)479 FsRtlInitializeLargeMcbs(VOID)
480 {
481     /* Initialize the list for the MCB */
482     ExInitializePagedLookasideList(&FsRtlFirstMappingLookasideList,
483                                    NULL,
484                                    NULL,
485                                    POOL_RAISE_IF_ALLOCATION_FAILURE,
486                                    sizeof(LARGE_MCB_MAPPING),
487                                    IFS_POOL_TAG,
488                                    0); /* FIXME: Should be 4 */
489 
490     /* Initialize the list for the guarded mutex */
491     ExInitializeNPagedLookasideList(&FsRtlFastMutexLookasideList,
492                                     NULL,
493                                     NULL,
494                                     POOL_RAISE_IF_ALLOCATION_FAILURE,
495                                     sizeof(KGUARDED_MUTEX),
496                                     IFS_POOL_TAG,
497                                     0); /* FIXME: Should be 32 */
498 }
499 
500 /*
501  * @implemented
502  */
503 BOOLEAN
504 NTAPI
FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb,IN LONGLONG Vbn,OUT PLONGLONG Lbn OPTIONAL,OUT PLONGLONG SectorCountFromLbn OPTIONAL,OUT PLONGLONG StartingLbn OPTIONAL,OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,OUT PULONG Index OPTIONAL)505 FsRtlLookupBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
506     IN LONGLONG Vbn,
507     OUT PLONGLONG Lbn OPTIONAL,
508     OUT PLONGLONG SectorCountFromLbn OPTIONAL,
509     OUT PLONGLONG StartingLbn OPTIONAL,
510     OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
511     OUT PULONG Index OPTIONAL)
512 {
513     BOOLEAN Result = FALSE;
514     ULONG i;
515     LONGLONG LastVbn = 0, LastLbn = 0, Count = 0;   // the last values we've found during traversal
516 
517     DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", OpaqueMcb, Vbn, Lbn, SectorCountFromLbn, StartingLbn, SectorCountFromStartingLbn, Index);
518 
519     for (i = 0; FsRtlGetNextBaseMcbEntry(OpaqueMcb, i, &LastVbn, &LastLbn, &Count); i++)
520     {
521         // have we reached the target mapping?
522         if (Vbn < LastVbn + Count)
523         {
524             if (Lbn)
525             {
526                 if (LastLbn == -1)
527                     *Lbn = -1;
528                 else
529                     *Lbn = LastLbn + (Vbn - LastVbn);
530             }
531 
532             if (SectorCountFromLbn)
533                 *SectorCountFromLbn = LastVbn + Count - Vbn;
534             if (StartingLbn)
535                 *StartingLbn = LastLbn;
536             if (SectorCountFromStartingLbn)
537                 *SectorCountFromStartingLbn = LastVbn + Count - LastVbn;
538             if (Index)
539                 *Index = i;
540 
541             Result = TRUE;
542             goto quit;
543         }
544     }
545 
546 quit:
547     DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
548            OpaqueMcb, Vbn, Lbn, SectorCountFromLbn, StartingLbn, SectorCountFromStartingLbn, Index, Result,
549            (Lbn ? *Lbn : (ULONGLONG)-1), (SectorCountFromLbn ? *SectorCountFromLbn : (ULONGLONG)-1), (StartingLbn ? *StartingLbn : (ULONGLONG)-1),
550            (SectorCountFromStartingLbn ? *SectorCountFromStartingLbn : (ULONGLONG)-1), (Index ? *Index : (ULONG)-1));
551 
552     return Result;
553 }
554 
555 /*
556  * @implemented
557  */
558 BOOLEAN
559 NTAPI
FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb,IN LONGLONG Vbn,OUT PLONGLONG Lbn OPTIONAL,OUT PLONGLONG SectorCountFromLbn OPTIONAL,OUT PLONGLONG StartingLbn OPTIONAL,OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,OUT PULONG Index OPTIONAL)560 FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb,
561                          IN LONGLONG Vbn,
562                          OUT PLONGLONG Lbn OPTIONAL,
563                          OUT PLONGLONG SectorCountFromLbn OPTIONAL,
564                          OUT PLONGLONG StartingLbn OPTIONAL,
565                          OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
566                          OUT PULONG Index OPTIONAL)
567 {
568     BOOLEAN Result;
569 
570     DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p)\n", Mcb, Vbn, Lbn, SectorCountFromLbn, StartingLbn, SectorCountFromStartingLbn, Index);
571 
572     KeAcquireGuardedMutex(Mcb->GuardedMutex);
573     Result = FsRtlLookupBaseMcbEntry(&(Mcb->BaseMcb),
574                                      Vbn,
575                                      Lbn,
576                                      SectorCountFromLbn,
577                                      StartingLbn,
578                                      SectorCountFromStartingLbn,
579                                      Index);
580     KeReleaseGuardedMutex(Mcb->GuardedMutex);
581 
582     DPRINT("FsRtlLookupLargeMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n",
583            Mcb, Vbn, Lbn, SectorCountFromLbn, StartingLbn, SectorCountFromStartingLbn, Index, Result,
584            (Lbn ? *Lbn : (ULONGLONG)-1), (SectorCountFromLbn ? *SectorCountFromLbn : (ULONGLONG)-1), (StartingLbn ? *StartingLbn : (ULONGLONG)-1),
585            (SectorCountFromStartingLbn ? *SectorCountFromStartingLbn : (ULONGLONG)-1), (Index ? *Index : (ULONG)-1));
586 
587     return Result;
588 }
589 
590 static BOOLEAN
591 NTAPI
FsRtlLookupLastLargeMcbEntryAndIndex_internal(IN PBASE_MCB_INTERNAL Mcb,OUT PLONGLONG Vbn,OUT PLONGLONG Lbn,OUT PULONG Index OPTIONAL)592 FsRtlLookupLastLargeMcbEntryAndIndex_internal(IN PBASE_MCB_INTERNAL Mcb,
593                                               OUT PLONGLONG Vbn,
594                                               OUT PLONGLONG Lbn,
595                                               OUT PULONG Index OPTIONAL)
596 {
597     ULONG RunIndex = 0;
598     PLARGE_MCB_MAPPING_ENTRY Run, RunFound = NULL;
599     LONGLONG LastVbn = 0;
600 
601     for (Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, TRUE);
602         Run;
603         Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, FALSE))
604     {
605         /* Take care when we must emulate missing 'hole' runs. */
606         if (Run->RunStartVbn.QuadPart > LastVbn)
607         {
608             RunIndex++;
609         }
610         LastVbn = Run->RunEndVbn.QuadPart;
611         RunIndex++;
612         RunFound = Run;
613     }
614 
615     if (!RunFound)
616     {
617         return FALSE;
618     }
619 
620     if (Vbn)
621     {
622         *Vbn = RunFound->RunEndVbn.QuadPart - 1;
623     }
624     if (Lbn)
625     {
626         if (1)
627         {
628             *Lbn = RunFound->StartingLbn.QuadPart + (RunFound->RunEndVbn.QuadPart - RunFound->RunStartVbn.QuadPart) - 1;
629         }
630         else
631         {
632             *Lbn = ~0ULL;
633         }
634     }
635     if (Index)
636     {
637         *Index = RunIndex - 1;
638     }
639 
640     return TRUE;
641 }
642 
643 
644 /*
645  * @implemented
646  */
647 BOOLEAN
648 NTAPI
FsRtlLookupLastBaseMcbEntryAndIndex(IN PBASE_MCB OpaqueMcb,IN OUT PLONGLONG LargeVbn,IN OUT PLONGLONG LargeLbn,IN OUT PULONG Index)649 FsRtlLookupLastBaseMcbEntryAndIndex(IN PBASE_MCB OpaqueMcb,
650                                     IN OUT PLONGLONG LargeVbn,
651                                     IN OUT PLONGLONG LargeLbn,
652                                     IN OUT PULONG Index)
653 {
654     BOOLEAN Result;
655     PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
656 
657     DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb, LargeVbn, LargeLbn, Index);
658 
659     Result = FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb, LargeVbn, LargeLbn, Index);
660 
661     DPRINT("FsRtlLookupLastBaseMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb, LargeVbn, LargeLbn, Index, Result, *LargeVbn, *LargeLbn, *Index);
662 
663     return Result;
664 }
665 
666 /*
667  * @implemented
668  */
669 BOOLEAN
670 NTAPI
FsRtlLookupLastLargeMcbEntryAndIndex(IN PLARGE_MCB OpaqueMcb,OUT PLONGLONG LargeVbn,OUT PLONGLONG LargeLbn,OUT PULONG Index)671 FsRtlLookupLastLargeMcbEntryAndIndex(IN PLARGE_MCB OpaqueMcb,
672                                      OUT PLONGLONG LargeVbn,
673                                      OUT PLONGLONG LargeLbn,
674                                      OUT PULONG Index)
675 {
676     BOOLEAN Result;
677 
678     DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p)\n", OpaqueMcb, LargeVbn, LargeLbn, Index);
679 
680     KeAcquireGuardedMutex(OpaqueMcb->GuardedMutex);
681     Result = FsRtlLookupLastBaseMcbEntryAndIndex(&(OpaqueMcb->BaseMcb),
682                                                  LargeVbn,
683                                                  LargeLbn,
684                                                  Index);
685     KeReleaseGuardedMutex(OpaqueMcb->GuardedMutex);
686 
687     DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex(%p, %p, %p, %p) = %d (%I64d, %I64d, %d)\n", OpaqueMcb, LargeVbn, LargeLbn, Index, Result, *LargeVbn, *LargeLbn, *Index);
688 
689     return Result;
690 }
691 
692 /*
693  * @unimplemented
694  */
695 BOOLEAN
696 NTAPI
FsRtlLookupLastBaseMcbEntry(IN PBASE_MCB OpaqueMcb,OUT PLONGLONG Vbn,OUT PLONGLONG Lbn)697 FsRtlLookupLastBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
698                             OUT PLONGLONG Vbn,
699                             OUT PLONGLONG Lbn)
700 {
701     BOOLEAN Result;
702     PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
703 
704     DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p)\n", OpaqueMcb, Vbn, Lbn);
705 
706     Result = FsRtlLookupLastLargeMcbEntryAndIndex_internal(Mcb, Vbn, Lbn, NULL); /* Index */
707 
708     DPRINT("FsRtlLookupLastBaseMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb, Vbn, Lbn, Result, *Vbn, *Lbn);
709 
710     return Result;
711 }
712 
713 /*
714  * @implemented
715  */
716 BOOLEAN
717 NTAPI
FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb,OUT PLONGLONG Vbn,OUT PLONGLONG Lbn)718 FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb,
719                              OUT PLONGLONG Vbn,
720                              OUT PLONGLONG Lbn)
721 {
722     BOOLEAN Result;
723 
724     DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p)\n", Mcb, Vbn, Lbn);
725 
726     KeAcquireGuardedMutex(Mcb->GuardedMutex);
727     Result = FsRtlLookupLastBaseMcbEntry(&(Mcb->BaseMcb),
728                                          Vbn,
729                                          Lbn);
730     KeReleaseGuardedMutex(Mcb->GuardedMutex);
731 
732     DPRINT("FsRtlLookupLastLargeMcbEntry(%p, %p, %p) = %d (%I64d, %I64d)\n", Mcb, Vbn, Lbn, Result, *Vbn, *Lbn);
733 
734     return Result;
735 }
736 
737 /*
738  * @implemented
739  */
740 ULONG
741 NTAPI
FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB OpaqueMcb)742 FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB OpaqueMcb)
743 {
744     ULONG NumberOfRuns = 0;
745     LONGLONG Vbn, Lbn, Count;
746     int i;
747 
748     DPRINT("FsRtlNumberOfRunsInBaseMcb(%p)\n", OpaqueMcb);
749 
750     // Count how many Mcb entries there are
751     for (i = 0; FsRtlGetNextBaseMcbEntry(OpaqueMcb, i, &Vbn, &Lbn, &Count); i++)
752     {
753         NumberOfRuns++;
754     }
755 
756     DPRINT("FsRtlNumberOfRunsInBaseMcb(%p) = %d\n", OpaqueMcb, NumberOfRuns);
757     return NumberOfRuns;
758 }
759 
760 /*
761  * @implemented
762  */
763 ULONG
764 NTAPI
FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)765 FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
766 {
767     ULONG NumberOfRuns;
768 
769     DPRINT("FsRtlNumberOfRunsInLargeMcb(%p)\n", Mcb);
770 
771     /* Read the number of runs while holding the MCB lock */
772     KeAcquireGuardedMutex(Mcb->GuardedMutex);
773     NumberOfRuns = FsRtlNumberOfRunsInBaseMcb(&(Mcb->BaseMcb));
774     KeReleaseGuardedMutex(Mcb->GuardedMutex);
775 
776     DPRINT("FsRtlNumberOfRunsInLargeMcb(%p) = %d\n", Mcb, NumberOfRuns);
777 
778     /* Return the count */
779     return NumberOfRuns;
780 }
781 
782 /*
783  * @implemented
784  * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
785  * %NULL value is forbidden.
786  * @Vbn: Starting virtual block number to specify the range to delete.
787  * @SectorCount: Length of the range to delete.
788  * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
789  *
790  * Deletes any possible @Mcb mappings in the given range @Vbn ... @Vbn+@SectorCount-1.
791  * This call has no problems if no mappings exist there yet.
792  */
793 BOOLEAN
794 NTAPI
FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb,IN LONGLONG Vbn,IN LONGLONG SectorCount)795 FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
796                         IN LONGLONG Vbn,
797                         IN LONGLONG SectorCount)
798 {
799     PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
800     LARGE_MCB_MAPPING_ENTRY NeedleRun;
801     PLARGE_MCB_MAPPING_ENTRY HaystackRun;
802     BOOLEAN Result = TRUE;
803 
804     DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d)\n", OpaqueMcb, Vbn, SectorCount);
805 
806     if (Vbn < 0 || SectorCount <= 0)
807     {
808         Result = FALSE;
809         goto quit;
810     }
811 
812     if (Vbn + SectorCount <= Vbn)
813     {
814         Result = FALSE;
815         goto quit;
816     }
817 
818     NeedleRun.RunStartVbn.QuadPart = Vbn;
819     NeedleRun.RunEndVbn.QuadPart = Vbn + SectorCount;
820     NeedleRun.StartingLbn.QuadPart = -1;
821 
822     /* adjust/destroy all intersecting ranges */
823     Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
824     while ((HaystackRun = RtlLookupElementGenericTable(&Mcb->Mapping->Table, &NeedleRun)))
825     {
826         if (HaystackRun->RunStartVbn.QuadPart < NeedleRun.RunStartVbn.QuadPart)
827         {
828             LONGLONG HaystackRunEnd = HaystackRun->RunEndVbn.QuadPart;
829             ASSERT(HaystackRun->RunEndVbn.QuadPart > NeedleRun.RunStartVbn.QuadPart);
830 
831             HaystackRun->RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart;
832 
833             if (HaystackRunEnd > NeedleRun.RunEndVbn.QuadPart)
834             {
835                 /* The run we are deleting is included in the run we just truncated.
836                  * Add the tail back. */
837                 LARGE_MCB_MAPPING_ENTRY TailRun;
838                 BOOLEAN NewElement;
839 
840                 TailRun.RunStartVbn.QuadPart = NeedleRun.RunEndVbn.QuadPart;
841                 TailRun.RunEndVbn.QuadPart = HaystackRunEnd;
842                 TailRun.StartingLbn.QuadPart = HaystackRun->StartingLbn.QuadPart + (NeedleRun.RunEndVbn.QuadPart - HaystackRun->RunStartVbn.QuadPart);
843 
844                 Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
845 
846                 RtlInsertElementGenericTable(&Mcb->Mapping->Table, &TailRun, sizeof(TailRun), &NewElement);
847                 ++Mcb->PairCount;
848                 ASSERT(NewElement);
849 
850                 Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
851             }
852         }
853         else if (HaystackRun->RunEndVbn.QuadPart > NeedleRun.RunEndVbn.QuadPart)
854         {
855             LONGLONG HaystackRunStart = HaystackRun->RunStartVbn.QuadPart;
856             LONGLONG HaystackStartingLbn = HaystackRun->StartingLbn.QuadPart;
857 
858             ASSERT(HaystackRun->RunStartVbn.QuadPart < NeedleRun.RunEndVbn.QuadPart);
859             HaystackRun->RunStartVbn.QuadPart = NeedleRun.RunEndVbn.QuadPart;
860             /* Adjust the starting LBN */
861             HaystackRun->StartingLbn.QuadPart += NeedleRun.RunEndVbn.QuadPart - HaystackRunStart;
862 
863             if (HaystackRunStart < NeedleRun.RunStartVbn.QuadPart)
864             {
865                 /* The run we are deleting is included in the run we just truncated.
866                  * Add the head back. */
867                 LARGE_MCB_MAPPING_ENTRY HeadRun;
868                 BOOLEAN NewElement;
869 
870                 HeadRun.RunStartVbn.QuadPart = HaystackRunStart;
871                 HeadRun.RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart;
872                 HeadRun.StartingLbn.QuadPart = HaystackStartingLbn;
873 
874                 Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
875 
876                 RtlInsertElementGenericTable(&Mcb->Mapping->Table, &HeadRun, sizeof(HeadRun), &NewElement);
877                 ++Mcb->PairCount;
878                 ASSERT(NewElement);
879 
880                 Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
881             }
882         }
883         else
884         {
885             //ASSERT(NeedleRun.RunStartVbn.QuadPart >= HaystackRun->RunStartVbn.QuadPart);
886             //ASSERT(NeedleRun.RunEndVbn.QuadPart <= HaystackRun->RunEndVbn.QuadPart);
887             Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
888             RtlDeleteElementGenericTable(&Mcb->Mapping->Table, HaystackRun);
889             --Mcb->PairCount;
890             Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
891         }
892     }
893     Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
894 
895 quit:
896     DPRINT("FsRtlRemoveBaseMcbEntry(%p, %I64d, %I64d) = %d\n", OpaqueMcb, Vbn, SectorCount, Result);
897     return Result;
898 }
899 
900 /*
901  * @implemented
902  */
903 VOID
904 NTAPI
FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb,IN LONGLONG Vbn,IN LONGLONG SectorCount)905 FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb,
906                          IN LONGLONG Vbn,
907                          IN LONGLONG SectorCount)
908 {
909     DPRINT("FsRtlRemoveLargeMcbEntry(%p, %I64d, %I64d)\n", Mcb, Vbn, SectorCount);
910 
911     KeAcquireGuardedMutex(Mcb->GuardedMutex);
912     FsRtlRemoveBaseMcbEntry(&(Mcb->BaseMcb), Vbn, SectorCount);
913     KeReleaseGuardedMutex(Mcb->GuardedMutex);
914 }
915 
916 /*
917  * @implemented
918  */
919 VOID
920 NTAPI
FsRtlResetBaseMcb(IN PBASE_MCB OpaqueMcb)921 FsRtlResetBaseMcb(IN PBASE_MCB OpaqueMcb)
922 {
923     PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
924     PLARGE_MCB_MAPPING_ENTRY Element;
925 
926     DPRINT("FsRtlResetBaseMcb(%p)\n", OpaqueMcb);
927 
928     while (RtlNumberGenericTableElements(&Mcb->Mapping->Table) &&
929            (Element = (PLARGE_MCB_MAPPING_ENTRY)RtlGetElementGenericTable(&Mcb->Mapping->Table, 0)))
930     {
931         RtlDeleteElementGenericTable(&Mcb->Mapping->Table, Element);
932     }
933 
934     Mcb->PairCount = 0;
935     Mcb->MaximumPairCount = 0;
936 }
937 
938 /*
939  * @implemented
940  */
941 VOID
942 NTAPI
FsRtlResetLargeMcb(IN PLARGE_MCB Mcb,IN BOOLEAN SelfSynchronized)943 FsRtlResetLargeMcb(IN PLARGE_MCB Mcb,
944                    IN BOOLEAN SelfSynchronized)
945 {
946     DPRINT("FsRtlResetLargeMcb(%p, %d)\n", Mcb, SelfSynchronized);
947 
948     if (!SelfSynchronized)
949         KeAcquireGuardedMutex(Mcb->GuardedMutex);
950 
951     FsRtlResetBaseMcb(&Mcb->BaseMcb);
952 
953     if (!SelfSynchronized)
954         KeReleaseGuardedMutex(Mcb->GuardedMutex);
955 }
956 
957 /*
958  * @unimplemented
959  */
960 BOOLEAN
961 NTAPI
FsRtlSplitBaseMcb(IN PBASE_MCB OpaqueMcb,IN LONGLONG Vbn,IN LONGLONG Amount)962 FsRtlSplitBaseMcb(IN PBASE_MCB OpaqueMcb,
963                   IN LONGLONG Vbn,
964                   IN LONGLONG Amount)
965 {
966     PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
967     PLARGE_MCB_MAPPING_ENTRY Run, InsertLowerRun = NULL, ExistingRun = NULL;
968     BOOLEAN NewElement;
969 
970     DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d)\n", OpaqueMcb, Vbn, Amount);
971 
972     /* Traverse the tree */
973     for (Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, TRUE);
974         Run;
975         Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, FALSE))
976     {
977         /* unaffected run? */
978         /* FIXME: performance: effective skip of all 'lower' runs without traversing them */
979         if (Vbn >= Run->RunEndVbn.QuadPart) { DPRINT("Skipping it\n"); continue; }
980 
981         /* crossing run to be split?
982         * 'lower_run' is created on the original place; just shortened.
983         * current 'run' is shifted up later
984         */
985         if (Vbn < Run->RunEndVbn.QuadPart)
986         {
987             /* FIXME: shift 'run->Lbn_start' ? */
988             Run->RunStartVbn.QuadPart = Vbn;
989 
990             InsertLowerRun = NULL;
991         }
992 
993         /* Shift the current 'run'.
994         * Ordering is not changed in Generic Tree so I hope I do not need to reinsert it.
995         */
996         Run->RunStartVbn.QuadPart += Amount;
997         ASSERT(Run->RunEndVbn.QuadPart + Amount > Run->RunEndVbn.QuadPart); /* overflow? */
998         Run->RunEndVbn.QuadPart += Amount;
999         /* FIXME: shift 'run->Lbn_start' ? */
1000 
1001         /* continue the traversal */
1002     }
1003 
1004     if (InsertLowerRun)
1005     {
1006         ExistingRun = RtlInsertElementGenericTable(&Mcb->Mapping->Table, InsertLowerRun, sizeof(*InsertLowerRun), &NewElement);
1007         ++Mcb->PairCount;
1008     }
1009 
1010     ASSERT(ExistingRun == NULL);
1011 
1012     DPRINT("FsRtlSplitBaseMcb(%p, %I64d, %I64d) = %d\n", OpaqueMcb, Vbn, Amount, TRUE);
1013 
1014     return TRUE;
1015 }
1016 
1017 /*
1018  * @implemented
1019  */
1020 BOOLEAN
1021 NTAPI
FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb,IN LONGLONG Vbn,IN LONGLONG Amount)1022 FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb,
1023                    IN LONGLONG Vbn,
1024                    IN LONGLONG Amount)
1025 {
1026     BOOLEAN Result;
1027 
1028     DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d)\n", Mcb, Vbn, Amount);
1029 
1030     KeAcquireGuardedMutex(Mcb->GuardedMutex);
1031     Result = FsRtlSplitBaseMcb(&(Mcb->BaseMcb),
1032                                Vbn,
1033                                Amount);
1034     KeReleaseGuardedMutex(Mcb->GuardedMutex);
1035 
1036     DPRINT("FsRtlSplitLargeMcb(%p, %I64d, %I64d) = %d\n", Mcb, Vbn, Amount, Result);
1037 
1038     return Result;
1039 }
1040 
1041 /*
1042  * @unimplemented
1043  */
1044 VOID
1045 NTAPI
FsRtlTruncateBaseMcb(IN PBASE_MCB OpaqueMcb,IN LONGLONG Vbn)1046 FsRtlTruncateBaseMcb(IN PBASE_MCB OpaqueMcb,
1047                      IN LONGLONG Vbn)
1048 {
1049     DPRINT("FsRtlTruncateBaseMcb(%p, %I64d)\n", OpaqueMcb, Vbn);
1050 
1051     FsRtlRemoveBaseMcbEntry(OpaqueMcb, Vbn, MAXLONG - Vbn + 1);
1052 }
1053 
1054 /*
1055  * @implemented
1056  */
1057 VOID
1058 NTAPI
FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb,IN LONGLONG Vbn)1059 FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb,
1060                       IN LONGLONG Vbn)
1061 {
1062     DPRINT("FsRtlTruncateLargeMcb(%p, %I64d)\n", Mcb, Vbn);
1063 
1064     KeAcquireGuardedMutex(Mcb->GuardedMutex);
1065     FsRtlTruncateBaseMcb(&(Mcb->BaseMcb), Vbn);
1066     KeReleaseGuardedMutex(Mcb->GuardedMutex);
1067 }
1068 
1069 /*
1070  * @implemented
1071  */
1072 VOID
1073 NTAPI
FsRtlUninitializeBaseMcb(IN PBASE_MCB Mcb)1074 FsRtlUninitializeBaseMcb(IN PBASE_MCB Mcb)
1075 {
1076     DPRINT("FsRtlUninitializeBaseMcb(%p)\n", Mcb);
1077 
1078     FsRtlResetBaseMcb(Mcb);
1079 
1080     if ((Mcb->PoolType == PagedPool)/* && (Mcb->MaximumPairCount == MAXIMUM_PAIR_COUNT)*/)
1081     {
1082         ExFreeToPagedLookasideList(&FsRtlFirstMappingLookasideList,
1083                                    Mcb->Mapping);
1084     }
1085     else
1086     {
1087         ExFreePoolWithTag(Mcb->Mapping, 'CBSF');
1088     }
1089 }
1090 
1091 /*
1092  * @implemented
1093  */
1094 VOID
1095 NTAPI
FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)1096 FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
1097 {
1098     DPRINT("FsRtlUninitializeLargeMcb(%p)\n", Mcb);
1099 
1100     if (Mcb->GuardedMutex)
1101     {
1102         ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList,
1103                                     Mcb->GuardedMutex);
1104         FsRtlUninitializeBaseMcb(&(Mcb->BaseMcb));
1105     }
1106 }
1107