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