Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3033 lines
78 KiB

  1. //depot/Lab01_N/Base/ntos/fsrtl/largemcb.c#5 - edit change 5743 (text)
  2. /*++
  3. Copyright (c) 1989 Microsoft Corporation
  4. Module Name:
  5. LargeMcb.c
  6. Abstract:
  7. The MCB routines provide support for maintaining an in-memory copy of
  8. the retrieval mapping information for a file. The general idea is to
  9. have the file system lookup the retrieval mapping for a VBN once from
  10. the disk, add the mapping to the MCB structure, and then utilize the
  11. MCB to retrieve the mapping for subsequent accesses to the file. A
  12. variable of type MCB is used to store the mapping information.
  13. The routines provided here allow the user to incrementally store some
  14. or all of the retrieval mapping for a file and to do so in any order.
  15. That is, the mapping can be inserted to the MCB structure all at once
  16. starting from the beginning and working to the end of the file, or it
  17. can be randomly scattered throughout the file.
  18. The package identifies each contiguous run of sectors mapping VBNs
  19. and LBNs indenpendent of the order they are added to the MCB
  20. structure. For example a user can define a mapping between VBN
  21. sector 0 and LBN sector 107, and between VBN sector 2 and LBN sector
  22. 109. The mapping now contains two runs each one sector in length.
  23. Now if the user adds an additional mapping between VBN sector 1 and
  24. LBN sector 106 the MCB structure will contain only one run 3 sectors
  25. in length.
  26. Concurrent access to the MCB structure is control by this package.
  27. The following routines are provided by this package:
  28. o FsRtlInitializeMcb - Initialize a new MCB structure. There
  29. should be one MCB for every opened file. Each MCB structure
  30. must be initialized before it can be used by the system.
  31. o FsRtlUninitializeMcb - Uninitialize an MCB structure. This call
  32. is used to cleanup any anciallary structures allocated and
  33. maintained by the MCB. After being uninitialized the MCB must
  34. again be initialized before it can be used by the system.
  35. o FsRtlAddMcbEntry - This routine adds a new range of mappings
  36. between LBNs and VBNs to the MCB structure.
  37. o FsRtlRemoveMcbEntry - This routines removes an existing range of
  38. mappings between LBNs and VBNs from the MCB structure.
  39. o FsRtlLookupMcbEntry - This routine returns the LBN mapped to by
  40. a VBN, and indicates, in sectors, the length of the run.
  41. o FsRtlLookupLastMcbEntry - This routine returns the mapping for
  42. the largest VBN stored in the structure.
  43. o FsRtlLookupLastMcbEntryAndIndex - This routine returns the mapping
  44. for the largest VBN stored in the structure as well as its index
  45. Note that calling LookupLastMcbEntry and NumberOfRunsInMcb cannot
  46. be synchronized except by the caller.
  47. o FsRtlNumberOfRunsInMcb - This routine tells the caller total
  48. number of discontiguous sectors runs stored in the MCB
  49. structure.
  50. o FsRtlGetNextMcbEntry - This routine returns the the caller the
  51. starting VBN and LBN of a given run stored in the MCB structure.
  52. Author:
  53. Gary Kimura [GaryKi] 5-Feb-1990
  54. Revision History:
  55. --*/
  56. #include "FsRtlP.h"
  57. //
  58. // Trace level for the module
  59. //
  60. #define Dbg (0x80000000)
  61. //
  62. // Retrieval mapping data structures. The following two structure together
  63. // are used to map a Vbn to an Lbn. It is layed out as follows:
  64. //
  65. //
  66. // MCB:
  67. // +----------------+----------------+
  68. // | PairCount |MaximumPairCount|
  69. // +----------------+----------------+
  70. // | Mapping | PoolType |
  71. // +----------------+----------------+
  72. //
  73. //
  74. // MAPPING:
  75. // +----------------+----------------+
  76. // | Lbn | NextVbn | : 0
  77. // +----------------+----------------+
  78. // | |
  79. // / /
  80. // / /
  81. // | |
  82. // +----------------+----------------+
  83. // | Lbn | NextVbn | : PairCount
  84. // +----------------+----------------+
  85. // | |
  86. // / /
  87. // / /
  88. // | |
  89. // +----------------+----------------+
  90. // | Lbn | NextVbn |
  91. // +----------------+----------------+
  92. //
  93. // : MaximumPairCount
  94. //
  95. // The pairs from 0 to PairCount - 1 are valid. Given an index between
  96. // 0 and PairCount - 1 (inclusive) it represents the following Vbn
  97. // to Lbn mapping information
  98. //
  99. //
  100. // { if Index == 0 then 0
  101. // StartingVbn {
  102. // { if Index <> 0 then NextVbn[i-1]
  103. //
  104. //
  105. // EndingVbn = NextVbn[i] - 1
  106. //
  107. //
  108. // StartingLbn = Lbn[i]
  109. //
  110. //
  111. // To compute the mapping of a Vbn to an Lbn the following algorithm
  112. // is used
  113. //
  114. // 1. search through the pairs until we find the slot "i" that contains
  115. // the Vbn we after. Report an error if none if found.
  116. //
  117. // 2. Lbn = StartingLbn + (Vbn - StartingVbn);
  118. //
  119. // A hole in the allocation (i.e., a sparse allocation) is represented by
  120. // an Lbn value of -1 (note that is is different than Mcb.c).
  121. //
  122. #define UNUSED_LBN (-1)
  123. typedef struct _MAPPING {
  124. VBN NextVbn;
  125. LBN Lbn;
  126. } MAPPING;
  127. typedef MAPPING *PMAPPING;
  128. typedef struct _NONOPAQUE_MCB {
  129. PFAST_MUTEX FastMutex;
  130. ULONG MaximumPairCount;
  131. ULONG PairCount;
  132. POOL_TYPE PoolType;
  133. PMAPPING Mapping;
  134. } NONOPAQUE_MCB;
  135. typedef NONOPAQUE_MCB *PNONOPAQUE_MCB;
  136. //
  137. // A macro to return the size, in bytes, of a retrieval mapping structure
  138. //
  139. #define SizeOfMapping(MCB) ((sizeof(MAPPING) * (MCB)->MaximumPairCount))
  140. //
  141. // The parts of a run can be computed as follows:
  142. //
  143. //
  144. // StartingVbn(MCB,I) Mapping[I].NextVbn
  145. // | |
  146. // V V
  147. //
  148. // Run-(I-1)---+ +---------Run-(I)-----------+ +---Run-(I+1)
  149. //
  150. // A A
  151. // | |
  152. // Mapping[I].Lbn EndingLbn(MCB,I)
  153. //
  154. #define PreviousEndingVbn(MCB,I) ( \
  155. (VBN)((I) == 0 ? 0xffffffff : EndingVbn(MCB,(I)-1)) \
  156. )
  157. #define StartingVbn(MCB,I) ( \
  158. (VBN)((I) == 0 ? 0 : (((MCB)->Mapping))[(I)-1].NextVbn) \
  159. )
  160. #define EndingVbn(MCB,I) ( \
  161. (VBN)((((MCB)->Mapping)[(I)].NextVbn) - 1) \
  162. )
  163. #define NextStartingVbn(MCB,I) ( \
  164. (VBN)((I) >= (MCB)->PairCount ? 0 : StartingVbn(MCB,(I)+1)) \
  165. )
  166. #define PreviousEndingLbn(MCB,I) ( \
  167. (LBN)((I) == 0 ? UNUSED_LBN : EndingLbn(MCB,(I)-1)) \
  168. )
  169. #define StartingLbn(MCB,I) ( \
  170. (LBN)(((MCB)->Mapping)[(I)].Lbn) \
  171. )
  172. #define EndingLbn(MCB,I) ( \
  173. (LBN)(StartingLbn(MCB,I) == UNUSED_LBN ? \
  174. UNUSED_LBN : \
  175. ((MCB)->Mapping[(I)].Lbn + \
  176. (MCB)->Mapping[(I)].NextVbn - StartingVbn(MCB,I) - 1) \
  177. ) \
  178. )
  179. #define NextStartingLbn(MCB,I) ( \
  180. (LBN)((I) >= (MCB)->PairCount - 1 ? UNUSED_LBN : StartingLbn(MCB,(I)+1)) \
  181. )
  182. #if 0
  183. LBN
  184. NextStartingLbn(
  185. PNONOPAQUE_MCB Mcb,
  186. ULONG I
  187. )
  188. {
  189. if ( I >= Mcb->PairCount - 1 ) {
  190. return (LBN)UNUSED_LBN;
  191. }
  192. else {
  193. return StartingLbn(Mcb,I+1);
  194. }
  195. }
  196. #endif
  197. #define SectorsWithinRun(MCB,I) ( \
  198. (ULONG)(EndingVbn(MCB,I) - StartingVbn(MCB,I) + 1) \
  199. )
  200. //
  201. // Define a tag for general pool allocations from this module
  202. //
  203. #undef MODULE_POOL_TAG
  204. #define MODULE_POOL_TAG ('mrSF')
  205. VOID
  206. FsRtlRemoveMcbEntryPrivate (
  207. IN PNONOPAQUE_MCB OpaqueMcb,
  208. IN ULONG Vbn,
  209. IN ULONG SectorCount
  210. );
  211. //
  212. // A private routine to search a mapping structure for a Vbn
  213. //
  214. BOOLEAN
  215. FsRtlFindLargeIndex (
  216. IN PNONOPAQUE_MCB Mcb,
  217. IN VBN Vbn,
  218. OUT PULONG Index
  219. );
  220. VOID
  221. FsRtlAddLargeEntry (
  222. IN PNONOPAQUE_MCB Mcb,
  223. IN ULONG WhereToAddIndex,
  224. IN ULONG AmountToAdd
  225. );
  226. VOID
  227. FsRtlRemoveLargeEntry (
  228. IN PNONOPAQUE_MCB Mcb,
  229. IN ULONG WhereToRemoveIndex,
  230. IN ULONG AmountToRemove
  231. );
  232. //
  233. // Some private routines to handle common allocations.
  234. //
  235. #define FsRtlAllocateFirstMapping() \
  236. (PVOID)ExAllocateFromPagedLookasideList( &FsRtlFirstMappingLookasideList )
  237. #define FsRtlFreeFirstMapping(Mapping) \
  238. ExFreeToPagedLookasideList( &FsRtlFirstMappingLookasideList, (Mapping) )
  239. #define FsRtlAllocateFastMutex() \
  240. (PFAST_MUTEX)ExAllocateFromNPagedLookasideList( &FsRtlFastMutexLookasideList )
  241. #define FsRtlFreeFastMutex(FastMutex) \
  242. ExFreeToNPagedLookasideList( &FsRtlFastMutexLookasideList, (FastMutex) )
  243. #ifdef ALLOC_PRAGMA
  244. #pragma alloc_text(INIT, FsRtlInitializeLargeMcbs)
  245. #pragma alloc_text(PAGE, FsRtlInitializeMcb)
  246. #pragma alloc_text(PAGE, FsRtlUninitializeMcb)
  247. #endif
  248. //
  249. // Define a small cache of free mapping pairs structures and also the
  250. // initial size of the mapping pair
  251. //
  252. #define INITIAL_MAXIMUM_PAIR_COUNT (15)
  253. PAGED_LOOKASIDE_LIST FsRtlFirstMappingLookasideList;
  254. //
  255. // The following lookaside is used to keep all the Fast Mutexes we will need to
  256. // boot contiguous.
  257. //
  258. NPAGED_LOOKASIDE_LIST FsRtlFastMutexLookasideList;
  259. //
  260. // The following few routines define the small mcb package which is
  261. // implemented behind everyones back as large mcbs. The only funny
  262. // thing we really need to do here is to make sure that unused Lbns
  263. // get returned as 0 and not -1. This is the result of an historical
  264. // difference between the original Mcb and LargeMcb packages.
  265. //
  266. VOID
  267. FsRtlInitializeMcb (
  268. IN PMCB Mcb,
  269. IN POOL_TYPE PoolType
  270. )
  271. {
  272. PAGED_CODE();
  273. FsRtlInitializeLargeMcb( (PLARGE_MCB)Mcb,
  274. PoolType );
  275. return;
  276. }
  277. VOID
  278. FsRtlUninitializeMcb (
  279. IN PMCB Mcb
  280. )
  281. {
  282. PAGED_CODE();
  283. FsRtlUninitializeLargeMcb( (PLARGE_MCB)Mcb );
  284. return;
  285. }
  286. VOID
  287. FsRtlTruncateMcb (
  288. IN PMCB Mcb,
  289. IN VBN Vbn
  290. )
  291. {
  292. PAGED_CODE();
  293. FsRtlTruncateLargeMcb( (PLARGE_MCB)Mcb,
  294. (LONGLONG)(Vbn) );
  295. return;
  296. }
  297. BOOLEAN
  298. FsRtlAddMcbEntry (
  299. IN PMCB Mcb,
  300. IN VBN Vbn,
  301. IN LBN Lbn,
  302. IN ULONG SectorCount
  303. )
  304. {
  305. PAGED_CODE();
  306. return FsRtlAddLargeMcbEntry( (PLARGE_MCB)Mcb,
  307. (LONGLONG)(Vbn),
  308. (LONGLONG)(Lbn),
  309. (LONGLONG)(SectorCount) );
  310. }
  311. VOID
  312. FsRtlRemoveMcbEntry (
  313. IN PMCB OpaqueMcb,
  314. IN VBN Vbn,
  315. IN ULONG SectorCount
  316. )
  317. {
  318. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  319. PAGED_CODE();
  320. DebugTrace(+1, Dbg, "FsRtlRemoveMcbEntry, Mcb = %08lx\n", Mcb );
  321. DebugTrace( 0, Dbg, " Vbn = %08lx\n", Vbn );
  322. DebugTrace( 0, Dbg, " SectorCount = %08lx\n", SectorCount );
  323. ExAcquireFastMutex( Mcb->FastMutex );
  324. try {
  325. FsRtlRemoveMcbEntryPrivate( Mcb,
  326. Vbn,
  327. SectorCount );
  328. } finally {
  329. ExReleaseFastMutex( Mcb->FastMutex );
  330. DebugTrace(-1, Dbg, "FsRtlRemoveMcbEntry -> VOID\n", 0 );
  331. }
  332. return;
  333. }
  334. BOOLEAN
  335. FsRtlLookupMcbEntry (
  336. IN PMCB Mcb,
  337. IN VBN Vbn,
  338. OUT PLBN Lbn,
  339. OUT PULONG SectorCount OPTIONAL,
  340. OUT PULONG Index OPTIONAL
  341. )
  342. {
  343. BOOLEAN Result;
  344. LONGLONG LiLbn;
  345. LONGLONG LiSectorCount;
  346. Result = FsRtlLookupLargeMcbEntry( (PLARGE_MCB)Mcb,
  347. (LONGLONG)(Vbn),
  348. &LiLbn,
  349. ARGUMENT_PRESENT(SectorCount) ? &LiSectorCount : NULL,
  350. NULL,
  351. NULL,
  352. Index );
  353. if (Result) {
  354. *Lbn = (((ULONG)LiLbn) == -1 ? 0 : ((ULONG)LiLbn));
  355. if (ARGUMENT_PRESENT(SectorCount)) {
  356. *SectorCount = ((ULONG)LiSectorCount);
  357. }
  358. }
  359. return Result;
  360. }
  361. BOOLEAN
  362. FsRtlLookupLastMcbEntry (
  363. IN PMCB Mcb,
  364. OUT PVBN Vbn,
  365. OUT PLBN Lbn
  366. )
  367. {
  368. BOOLEAN Result;
  369. LONGLONG LiVbn;
  370. LONGLONG LiLbn;
  371. PAGED_CODE();
  372. Result = FsRtlLookupLastLargeMcbEntry( (PLARGE_MCB)Mcb,
  373. &LiVbn,
  374. &LiLbn );
  375. if (Result) {
  376. *Vbn = ((ULONG)LiVbn);
  377. *Lbn = (((ULONG)LiLbn) == -1 ? 0 : ((ULONG)LiLbn));
  378. }
  379. return Result;
  380. }
  381. ULONG
  382. FsRtlNumberOfRunsInMcb (
  383. IN PMCB Mcb
  384. )
  385. {
  386. PAGED_CODE();
  387. return FsRtlNumberOfRunsInLargeMcb( (PLARGE_MCB)Mcb );
  388. }
  389. BOOLEAN
  390. FsRtlGetNextMcbEntry (
  391. IN PMCB Mcb,
  392. IN ULONG RunIndex,
  393. OUT PVBN Vbn,
  394. OUT PLBN Lbn,
  395. OUT PULONG SectorCount
  396. )
  397. {
  398. BOOLEAN Result;
  399. LONGLONG LiVbn;
  400. LONGLONG LiLbn;
  401. LONGLONG LiSectorCount;
  402. PAGED_CODE();
  403. Result = FsRtlGetNextLargeMcbEntry( (PLARGE_MCB)Mcb,
  404. RunIndex,
  405. &LiVbn,
  406. &LiLbn,
  407. &LiSectorCount );
  408. if (Result) {
  409. *Vbn = ((ULONG)LiVbn);
  410. *Lbn = (((ULONG)LiLbn) == -1 ? 0 : ((ULONG)LiLbn));
  411. *SectorCount = ((ULONG)LiSectorCount);
  412. }
  413. return Result;
  414. }
  415. VOID
  416. FsRtlInitializeLargeMcbs (
  417. VOID
  418. )
  419. /*++
  420. Routine Description:
  421. This routine initializes the global portion of the large mcb package
  422. at system initialization time.
  423. Arguments:
  424. None.
  425. Return Value:
  426. None.
  427. --*/
  428. {
  429. //
  430. // Initialize the lookaside of paged initial mapping arrays.
  431. //
  432. ExInitializePagedLookasideList( &FsRtlFirstMappingLookasideList,
  433. NULL,
  434. NULL,
  435. POOL_RAISE_IF_ALLOCATION_FAILURE,
  436. sizeof( MAPPING ) * INITIAL_MAXIMUM_PAIR_COUNT,
  437. 'miSF',
  438. 4 );
  439. //
  440. // Initialize the Fast Mutex lookaside list.
  441. //
  442. ExInitializeNPagedLookasideList( &FsRtlFastMutexLookasideList,
  443. NULL,
  444. NULL,
  445. POOL_RAISE_IF_ALLOCATION_FAILURE,
  446. sizeof( FAST_MUTEX),
  447. 'mfSF',
  448. 32 );
  449. }
  450. VOID
  451. FsRtlInitializeLargeMcb (
  452. IN PLARGE_MCB OpaqueMcb,
  453. IN POOL_TYPE PoolType
  454. )
  455. /*++
  456. Routine Description:
  457. This routine initializes a new Mcb structure. The caller must
  458. supply the memory for the Mcb structure. This call must precede all
  459. other calls that set/query the Mcb structure.
  460. If pool is not available this routine will raise a status value
  461. indicating insufficient resources.
  462. Arguments:
  463. OpaqueMcb - Supplies a pointer to the Mcb structure to initialize.
  464. PoolType - Supplies the pool type to use when allocating additional
  465. internal Mcb memory.
  466. Return Value:
  467. None.
  468. --*/
  469. {
  470. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  471. DebugTrace(+1, Dbg, "FsRtlInitializeLargeMcb, Mcb = %08lx\n", Mcb );
  472. //
  473. // Preset the following fields to null so we know to deallocate them
  474. // during an abnormal termination
  475. //
  476. Mcb->FastMutex = NULL;
  477. Mcb->Mapping = NULL;
  478. try {
  479. //
  480. // Initialize the fields in the Mcb
  481. //
  482. Mcb->FastMutex = FsRtlAllocateFastMutex();
  483. ExInitializeFastMutex( Mcb->FastMutex );
  484. Mcb->PairCount = 0;
  485. Mcb->PoolType = PoolType;
  486. //
  487. // Allocate a new buffer an initial size is one that will hold
  488. // 16 runs
  489. //
  490. if (PoolType == PagedPool) {
  491. Mcb->Mapping = FsRtlAllocateFirstMapping();
  492. } else {
  493. Mcb->Mapping = FsRtlpAllocatePool( Mcb->PoolType, sizeof(MAPPING) * INITIAL_MAXIMUM_PAIR_COUNT );
  494. }
  495. //**** RtlZeroMemory( Mcb->Mapping, sizeof(MAPPING) * INITIAL_MAXIMUM_PAIR_COUNT );
  496. Mcb->MaximumPairCount = INITIAL_MAXIMUM_PAIR_COUNT;
  497. } finally {
  498. //
  499. // If this is an abnormal termination then we need to deallocate
  500. // the FastMutex and/or mapping (but once the mapping is allocated,
  501. // we can't raise).
  502. //
  503. if (AbnormalTermination()) {
  504. if (Mcb->FastMutex != NULL) { FsRtlFreeFastMutex( Mcb->FastMutex ); }
  505. }
  506. DebugTrace(-1, Dbg, "FsRtlInitializeLargeMcb -> VOID\n", 0 );
  507. }
  508. //
  509. // And return to our caller
  510. //
  511. return;
  512. }
  513. VOID
  514. FsRtlUninitializeLargeMcb (
  515. IN PLARGE_MCB OpaqueMcb
  516. )
  517. /*++
  518. Routine Description:
  519. This routine uninitializes an Mcb structure. After calling this routine
  520. the input Mcb structure must be re-initialized before being used again.
  521. Arguments:
  522. OpaqueMcb - Supplies a pointer to the Mcb structure to uninitialize.
  523. Return Value:
  524. None.
  525. --*/
  526. {
  527. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  528. DebugTrace(+1, Dbg, "FsRtlUninitializeLargeMcb, Mcb = %08lx\n", Mcb );
  529. //
  530. // Protect against some user calling us to uninitialize an mcb twice
  531. //
  532. if (Mcb->FastMutex == NULL) {
  533. // ASSERTMSG("Being called to uninitialize an Mcb that is already Uninitialized ", FALSE);
  534. return;
  535. }
  536. //
  537. // Deallocate the FastMutex and mapping buffer
  538. //
  539. FsRtlFreeFastMutex( Mcb->FastMutex );
  540. Mcb->FastMutex = NULL;
  541. if ((Mcb->PoolType == PagedPool) && (Mcb->MaximumPairCount == INITIAL_MAXIMUM_PAIR_COUNT)) {
  542. FsRtlFreeFirstMapping( Mcb->Mapping );
  543. } else {
  544. ExFreePool( Mcb->Mapping );
  545. }
  546. //
  547. // Now zero our all of the fields in the Mcb
  548. //
  549. //**** Mcb->MaximumPairCount = 0;
  550. //**** Mcb->PairCount = 0;
  551. //**** Mcb->Mapping = NULL;
  552. //
  553. // And return to our caller
  554. //
  555. DebugTrace(-1, Dbg, "FsRtlUninitializeLargeMcb -> VOID\n", 0 );
  556. return;
  557. }
  558. VOID
  559. FsRtlTruncateLargeMcb (
  560. IN PLARGE_MCB OpaqueMcb,
  561. IN LONGLONG LargeVbn
  562. )
  563. /*++
  564. Routine Description:
  565. This routine truncates an Mcb structure to the specified Vbn.
  566. After calling this routine the Mcb will only contain mappings
  567. up to and not including the input vbn.
  568. Arguments:
  569. OpaqueMcb - Supplies a pointer to the Mcb structure to truncate.
  570. LargeVbn - Specifies the last Vbn at which is no longer to be
  571. mapped.
  572. Return Value:
  573. None.
  574. --*/
  575. {
  576. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  577. VBN Vbn = ((ULONG)LargeVbn);
  578. ULONG Index;
  579. PAGED_CODE();
  580. DebugTrace(+1, Dbg, "FsRtlTruncateLargeMcb, Mcb = %08lx\n", Mcb );
  581. ExAcquireFastMutex( Mcb->FastMutex );
  582. ASSERTMSG("LargeInteger not supported yet ", ((((PLARGE_INTEGER)&LargeVbn)->HighPart == 0) ||
  583. (Mcb->PairCount == 0) ||
  584. ((((PLARGE_INTEGER)&LargeVbn)->HighPart == 0x7FFFFFFF) &&
  585. (((ULONG)LargeVbn) == 0xFFFFFFFF))));
  586. try {
  587. //
  588. // Do a quick test to see if we are truncating the entire Mcb.
  589. //
  590. if (Vbn == 0) {
  591. Mcb->PairCount = 0;
  592. } else if (Mcb->PairCount > 0) {
  593. //
  594. // Find the index for the entry with the last Vcn we want to keep.
  595. // There is nothing to do if the Mcb already ends prior to
  596. // this point.
  597. //
  598. if (FsRtlFindLargeIndex(Mcb, Vbn - 1, &Index)) {
  599. //
  600. // If this entry currently describes a hole then
  601. // truncate to the previous entry.
  602. //
  603. if (StartingLbn(Mcb, Index) == UNUSED_LBN) {
  604. Mcb->PairCount = Index;
  605. //
  606. // Otherwise we will truncate the Mcb to this point. Truncate
  607. // the number of Vbns of this run if necessary.
  608. //
  609. } else {
  610. Mcb->PairCount = Index + 1;
  611. if (NextStartingVbn(Mcb, Index) > Vbn) {
  612. (Mcb->Mapping)[Index].NextVbn = Vbn;
  613. }
  614. }
  615. }
  616. }
  617. //
  618. // Now see if we can shrink the allocation for the mapping pairs.
  619. // We'll shrink the mapping pair buffer if the new pair count will
  620. // fit within a quarter of the current maximum pair count and the
  621. // current maximum is greater than the initial pair count.
  622. //
  623. if ((Mcb->PairCount < (Mcb->MaximumPairCount / 4)) &&
  624. (Mcb->MaximumPairCount > INITIAL_MAXIMUM_PAIR_COUNT)) {
  625. ULONG NewMax;
  626. PMAPPING Mapping;
  627. //
  628. // We need to allocate a new mapping so compute a new maximum pair
  629. // count. We'll allocate double the current pair count, but never
  630. // less than the initial pair count.
  631. //
  632. NewMax = Mcb->PairCount * 2;
  633. if (NewMax < INITIAL_MAXIMUM_PAIR_COUNT) {
  634. NewMax = INITIAL_MAXIMUM_PAIR_COUNT;
  635. }
  636. //
  637. // Be careful to trap failures due to resource exhaustion.
  638. //
  639. try {
  640. if (NewMax == INITIAL_MAXIMUM_PAIR_COUNT && Mcb->PoolType == PagedPool) {
  641. Mapping = FsRtlAllocateFirstMapping();
  642. } else {
  643. Mapping = FsRtlpAllocatePool( Mcb->PoolType, sizeof(MAPPING) * NewMax );
  644. }
  645. } except (EXCEPTION_EXECUTE_HANDLER) {
  646. Mapping = NULL;
  647. }
  648. //
  649. // Now check if we really got a new buffer
  650. //
  651. if (Mapping != NULL) {
  652. //
  653. // Now copy over the old mapping to the new buffer
  654. //
  655. RtlCopyMemory( Mapping, Mcb->Mapping, sizeof(MAPPING) * Mcb->PairCount );
  656. //
  657. // Deallocate the old buffer. This should never be the size of an
  658. // initial mapping ...
  659. //
  660. ExFreePool( Mcb->Mapping );
  661. //
  662. // And set up the new buffer in the Mcb
  663. //
  664. Mcb->Mapping = Mapping;
  665. Mcb->MaximumPairCount = NewMax;
  666. }
  667. }
  668. } finally {
  669. ExReleaseFastMutex( Mcb->FastMutex );
  670. }
  671. //
  672. // And return to our caller
  673. //
  674. DebugTrace(-1, Dbg, "FsRtlTruncateLargeMcb -> VOID\n", 0 );
  675. return;
  676. }
  677. NTKERNELAPI
  678. VOID
  679. FsRtlResetLargeMcb (
  680. IN PLARGE_MCB OpaqueMcb,
  681. IN BOOLEAN SelfSynchronized
  682. )
  683. /*++
  684. Routine Description:
  685. This routine truncates an Mcb structure to contain zero mapping
  686. pairs. It does not shrink the mapping pairs array.
  687. Arguments:
  688. OpaqueMcb - Supplies a pointer to the Mcb structure to truncate.
  689. SelfSynchronized - Indicates whether the caller is already synchronized
  690. with respect to the Mcb.
  691. Return Value:
  692. None.
  693. --*/
  694. {
  695. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  696. if (SelfSynchronized) {
  697. //
  698. // If we are self-synchronized, then all we do is clear out the
  699. // current mapping pair count.
  700. //
  701. Mcb->PairCount = 0;
  702. } else {
  703. //
  704. // Since we are not self-synchronized, we must serialize access to
  705. // the Mcb before clearing the pair count
  706. //
  707. ExAcquireFastMutex( Mcb->FastMutex );
  708. Mcb->PairCount = 0;
  709. ExReleaseFastMutex( Mcb->FastMutex );
  710. }
  711. return;
  712. }
  713. BOOLEAN
  714. FsRtlAddLargeMcbEntry (
  715. IN PLARGE_MCB OpaqueMcb,
  716. IN LONGLONG LargeVbn,
  717. IN LONGLONG LargeLbn,
  718. IN LONGLONG LargeSectorCount
  719. )
  720. /*++
  721. Routine Description:
  722. This routine is used to add a new mapping of VBNs to LBNs to an existing
  723. Mcb. The information added will map
  724. Vbn to Lbn,
  725. Vbn+1 to Lbn+1,...
  726. Vbn+(SectorCount-1) to Lbn+(SectorCount-1).
  727. The mapping for the VBNs must not already exist in the Mcb. If the
  728. mapping continues a previous run, then this routine will actually coalesce
  729. them into 1 run.
  730. If pool is not available to store the information this routine will raise a
  731. status value indicating insufficient resources.
  732. An input Lbn value of zero is illegal (i.e., the Mcb structure will never
  733. map a Vbn to a zero Lbn value).
  734. Arguments:
  735. OpaqueMcb - Supplies the Mcb in which to add the new mapping.
  736. Vbn - Supplies the starting Vbn of the new mapping run to add to the Mcb.
  737. Lbn - Supplies the starting Lbn of the new mapping run to add to the Mcb.
  738. SectorCount - Supplies the size of the new mapping run (in sectors).
  739. Return Value:
  740. BOOLEAN - TRUE if the mapping was added successfully (i.e., the new
  741. Vbns did not collide with existing Vbns), and FALSE otherwise. If
  742. FALSE is returned then the Mcb is not changed.
  743. --*/
  744. {
  745. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  746. VBN Vbn = ((ULONG)LargeVbn);
  747. LBN Lbn = ((ULONG)LargeLbn);
  748. ULONG SectorCount = ((ULONG)LargeSectorCount);
  749. ULONG Index;
  750. VBN LastVbn;
  751. BOOLEAN Result;
  752. ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeVbn)->HighPart == 0);
  753. ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeLbn)->HighPart == 0);
  754. ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeSectorCount)->HighPart == 0);
  755. PAGED_CODE();
  756. DebugTrace(+1, Dbg, "FsRtlAddLargeMcbEntry, Mcb = %08lx\n", Mcb );
  757. DebugTrace( 0, Dbg, " Vbn = %08lx\n", Vbn );
  758. DebugTrace( 0, Dbg, " Lbn = %08lx\n", Lbn );
  759. DebugTrace( 0, Dbg, " SectorCount = %08lx\n", SectorCount );
  760. ExAcquireFastMutex( Mcb->FastMutex );
  761. try {
  762. if (FsRtlFindLargeIndex(Mcb, Vbn, &Index)) {
  763. ULONG EndVbn = Vbn + SectorCount - 1;
  764. ULONG EndIndex;
  765. //
  766. // First check the case where we are adding to an existing mcb run
  767. // and if so then we will modify the insertion to complete the run
  768. //
  769. // --ExistingRun--| ==becomes==> --ExistingRun--|
  770. // |--NewRun--| |---|
  771. //
  772. // --ExistingRun----| ==becomes==> a noop
  773. // |--NewRun--|
  774. //
  775. if (StartingLbn(Mcb, Index) != UNUSED_LBN) {
  776. //
  777. // Check that the Lbn's line up between the new and existing run
  778. //
  779. if (Lbn != (StartingLbn(Mcb, Index) + (Vbn - StartingVbn(Mcb, Index)))) {
  780. //
  781. // Let our caller know we couldn't insert the run.
  782. //
  783. try_return(Result = FALSE);
  784. }
  785. //
  786. // Check if the new run is contained in the existing run
  787. //
  788. if (EndVbn <= EndingVbn(Mcb, Index)) {
  789. //
  790. // Do nothing because the run is contained within the existing run
  791. //
  792. try_return(Result = TRUE);
  793. }
  794. //
  795. // Otherwise we will simply trim off the request for the new run
  796. // to not overlap with the existing run
  797. //
  798. Vbn = NextStartingVbn(Mcb, Index);
  799. Lbn = EndingLbn(Mcb, Index) + 1;
  800. ASSERT(EndVbn >= Vbn);
  801. SectorCount = EndVbn - Vbn + 1;
  802. //
  803. // At this point the new run start in a hole, now check that if
  804. // crosses into a non hole and if so then adjust new run to fit
  805. // in the hole
  806. //
  807. //
  808. // |--ExistingRun-- ==becomes==> |--ExistingRun--
  809. // |--NewRun--| |--New|
  810. //
  811. } else if (FsRtlFindLargeIndex(Mcb, EndVbn, &EndIndex) && (Index == (EndIndex-1))) {
  812. //
  813. // Check that the Lbn's line up in the overlap
  814. //
  815. if (StartingLbn(Mcb, EndIndex) != Lbn + (StartingVbn(Mcb, EndIndex) - Vbn)) {
  816. //
  817. // Let our caller know we couldn't insert the run.
  818. //
  819. try_return(Result = FALSE);
  820. }
  821. //
  822. // Truncate the sector count to go up to but not include
  823. // the existing run
  824. //
  825. SectorCount = StartingVbn(Mcb, EndIndex) - Vbn;
  826. }
  827. }
  828. //
  829. // Find the index for the starting Vbn of our new run, if there isn't
  830. // a hole found then index will be set to paircount.
  831. //
  832. if (((Index = Mcb->PairCount) == 0) ||
  833. (PreviousEndingVbn(Mcb,Index)+1 <= Vbn) ||
  834. !FsRtlFindLargeIndex(Mcb, Vbn, &Index)) {
  835. //
  836. // We didn't find a mapping, therefore this new mapping must
  837. // go on at the end of the current mapping.
  838. //
  839. // See if we can just grow the last mapping in the current mcb.
  840. // We can grow the last entry if (1) the Vbns follow on, and (2)
  841. // the Lbns follow on. We can only grow the last mapping if the
  842. // index is not 0.
  843. //
  844. if ((Index != 0) &&
  845. (PreviousEndingVbn(Mcb,Index) + 1 == Vbn) &&
  846. (PreviousEndingLbn(Mcb,Index) + 1 == Lbn)) {
  847. //
  848. // --LastRun--|---NewRun--|
  849. //
  850. //
  851. // Extend the last run in the mcb
  852. //
  853. DebugTrace( 0, Dbg, "Continuing last run\n", 0);
  854. (Mcb->Mapping)[Mcb->PairCount-1].NextVbn += SectorCount;
  855. try_return (Result = TRUE);
  856. }
  857. //
  858. // We couldn't grow the last mapping, now check to see if
  859. // this is a continuation of the last Vbn (i.e., there isn't
  860. // going to be a hole in the mapping). Or if this is the first
  861. // run in the mapping
  862. //
  863. if ((Vbn == 0) ||
  864. (PreviousEndingVbn(Mcb,Index) + 1 == Vbn)) {
  865. //
  866. // --LastRun--||---NewRun--|
  867. //
  868. // 0:|--NewRun--|
  869. //
  870. //
  871. // We only need to add one more run to the mcb, so make sure
  872. // there is enough room for one.
  873. //
  874. DebugTrace( 0, Dbg, "Adding new contiguous last run\n", 0);
  875. FsRtlAddLargeEntry( Mcb, Index, 1 );
  876. //
  877. // Add the new mapping
  878. //
  879. (Mcb->Mapping)[Index].Lbn = Lbn;
  880. (Mcb->Mapping)[Index].NextVbn = Vbn + SectorCount;
  881. try_return (Result = TRUE);
  882. }
  883. //
  884. // If we reach this point then there is going to be a hole in the
  885. // mapping. and the mapping gets appended to the end of the current
  886. // allocation. So need to make room for two more runs in the mcb.
  887. //
  888. //
  889. // --LastRun--| hole |---NewRun--|
  890. //
  891. // 0: hole |--NewRun--|
  892. //
  893. DebugTrace( 0, Dbg, "Adding new noncontiguous last run\n", 0);
  894. FsRtlAddLargeEntry( Mcb, Index, 2 );
  895. //
  896. // Add the hole
  897. //
  898. (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
  899. (Mcb->Mapping)[Index].NextVbn = Vbn;
  900. //
  901. // Add the new mapping
  902. //
  903. (Mcb->Mapping)[Index+1].Lbn = Lbn;
  904. (Mcb->Mapping)[Index+1].NextVbn = Vbn + SectorCount;
  905. try_return (Result = TRUE);
  906. }
  907. //
  908. // We found an index for the Vbn therefore we must be trying
  909. // to fill up a hole in the mcb. So first we need to check to make
  910. // sure there really is a hole to be filled
  911. //
  912. LastVbn = Vbn + SectorCount - 1;
  913. if ((StartingLbn(Mcb,Index) == UNUSED_LBN) &&
  914. (StartingVbn(Mcb,Index) <= Vbn) && (LastVbn <= EndingVbn(Mcb,Index))) {
  915. //
  916. // The mapping fits in this hole, but now here are the following
  917. // cases we must consider for the new mapping
  918. //
  919. if ((StartingVbn(Mcb,Index) < Vbn) && (LastVbn < EndingVbn(Mcb,Index))) {
  920. // Leaves a hole are both ends
  921. //
  922. // --PreviousRun--| hole |--NewRun--| hole |--FollowingRun--
  923. //
  924. // 0: hole |--NewRun--| hole |--FollowingRun--
  925. //
  926. DebugTrace( 0, Dbg, "Hole at both ends\n", 0);
  927. //
  928. // Make room for two more entries. The NextVbn field of the
  929. // one we're shifting remains valid.
  930. //
  931. FsRtlAddLargeEntry( Mcb, Index, 2 );
  932. //
  933. // Add the first hole
  934. //
  935. (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
  936. (Mcb->Mapping)[Index].NextVbn = Vbn;
  937. //
  938. // Add the new mapping
  939. //
  940. (Mcb->Mapping)[Index+1].Lbn = Lbn;
  941. (Mcb->Mapping)[Index+1].NextVbn = Vbn + SectorCount;
  942. //
  943. // The second hole is already set up by the add entry call, because
  944. // that call just shift over the original hole to that slot
  945. //
  946. try_return (Result = TRUE);
  947. }
  948. if ((StartingVbn(Mcb,Index) == Vbn) && (LastVbn < EndingVbn(Mcb,Index))) {
  949. if (PreviousEndingLbn(Mcb,Index) + 1 == Lbn) {
  950. //
  951. // Leaves a hole at the rear, and continues the earlier run
  952. //
  953. // --PreviousRun--|--NewRun--| hole |--FollowingRun--
  954. //
  955. DebugTrace( 0, Dbg, "Hole at rear and continue\n", 0);
  956. //
  957. // We just need to extend the previous run
  958. //
  959. (Mcb->Mapping)[Index-1].NextVbn += SectorCount;
  960. try_return (Result = TRUE);
  961. } else {
  962. //
  963. // Leaves a hole at the rear, and does not continue the
  964. // earlier run. As occurs if index is zero.
  965. //
  966. // --PreviousRun--||--NewRun--| hole |--FollowingRun--
  967. //
  968. // 0:|--NewRun--| hole |--FollowingRun--
  969. //
  970. DebugTrace( 0, Dbg, "Hole at rear and not continue\n", 0);
  971. //
  972. // Make room for one more entry. The NextVbn field of the
  973. // one we're shifting remains valid.
  974. //
  975. FsRtlAddLargeEntry( Mcb, Index, 1 );
  976. //
  977. // Add the new mapping
  978. //
  979. (Mcb->Mapping)[Index].Lbn = Lbn;
  980. (Mcb->Mapping)[Index].NextVbn = Vbn + SectorCount;
  981. //
  982. // The hole is already set up by the add entry call, because
  983. // that call just shift over the original hole to that slot
  984. //
  985. try_return (Result = TRUE);
  986. }
  987. }
  988. if ((StartingVbn(Mcb,Index) < Vbn) && (LastVbn == EndingVbn(Mcb,Index))) {
  989. if (NextStartingLbn(Mcb,Index) == Lbn + SectorCount) {
  990. //
  991. // Leaves a hole at the front, and continues the following run
  992. //
  993. // --PreviousRun--| hole |--NewRun--|--FollowingRun--
  994. //
  995. // 0: hole |--NewRun--|--FollowingRun--
  996. //
  997. DebugTrace( 0, Dbg, "Hole at front and continue\n", 0);
  998. //
  999. // We just need to extend the following run
  1000. //
  1001. (Mcb->Mapping)[Index].NextVbn = Vbn;
  1002. (Mcb->Mapping)[Index+1].Lbn = Lbn;
  1003. try_return (Result = TRUE);
  1004. } else {
  1005. //
  1006. // Leaves a hole at the front, and does not continue the following
  1007. // run
  1008. //
  1009. // --PreviousRun--| hole |--NewRun--||--FollowingRun--
  1010. //
  1011. // 0: hole |--NewRun--||--FollowingRun--
  1012. //
  1013. DebugTrace( 0, Dbg, "Hole at front and not continue\n", 0);
  1014. //
  1015. // Make room for one more entry. The NextVbn field of the
  1016. // one we're shifting remains valid.
  1017. //
  1018. FsRtlAddLargeEntry( Mcb, Index, 1 );
  1019. //
  1020. // Add the hole
  1021. //
  1022. (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
  1023. (Mcb->Mapping)[Index].NextVbn = Vbn;
  1024. //
  1025. // Add the new mapping
  1026. //
  1027. (Mcb->Mapping)[Index+1].Lbn = Lbn;
  1028. try_return (Result = TRUE);
  1029. }
  1030. }
  1031. if ((PreviousEndingLbn(Mcb,Index) + 1 == Lbn) &&
  1032. (NextStartingLbn(Mcb,Index) == Lbn + SectorCount)) {
  1033. //
  1034. // Leaves no holes, and continues both runs
  1035. //
  1036. // --PreviousRun--|--NewRun--|--FollowingRun--
  1037. //
  1038. DebugTrace( 0, Dbg, "No holes, and continues both runs\n", 0);
  1039. //
  1040. // We need to collapse the current index and the following index
  1041. // but first we copy the NextVbn of the follwing run into
  1042. // the NextVbn field of the previous run to so it all becomes
  1043. // one run
  1044. //
  1045. (Mcb->Mapping)[Index-1].NextVbn = (Mcb->Mapping)[Index+1].NextVbn;
  1046. FsRtlRemoveLargeEntry( Mcb, Index, 2 );
  1047. try_return (Result = TRUE);
  1048. }
  1049. if (NextStartingLbn(Mcb,Index) == Lbn + SectorCount) {
  1050. //
  1051. // Leaves no holes, and continues only following run
  1052. //
  1053. // --PreviousRun--||--NewRun--|--FollowingRun--
  1054. //
  1055. // 0:|--NewRun--|--FollowingRun--
  1056. //
  1057. DebugTrace( 0, Dbg, "No holes, and continues following\n", 0);
  1058. //
  1059. // This index is going away so we need to stretch the
  1060. // following run to meet up with the previous run
  1061. //
  1062. (Mcb->Mapping)[Index+1].Lbn = Lbn;
  1063. FsRtlRemoveLargeEntry( Mcb, Index, 1 );
  1064. try_return (Result = TRUE);
  1065. }
  1066. if (PreviousEndingLbn(Mcb,Index) + 1 == Lbn) {
  1067. //
  1068. // Leaves no holes, and continues only earlier run
  1069. //
  1070. // --PreviousRun--|--NewRun--||--FollowingRun--
  1071. //
  1072. DebugTrace( 0, Dbg, "No holes, and continues earlier\n", 0);
  1073. //
  1074. // This index is going away so we need to stretch the
  1075. // previous run to meet up with the following run
  1076. //
  1077. (Mcb->Mapping)[Index-1].NextVbn = (Mcb->Mapping)[Index].NextVbn;
  1078. FsRtlRemoveLargeEntry( Mcb, Index, 1 );
  1079. try_return (Result = TRUE);
  1080. }
  1081. //
  1082. // Leaves no holes, and continues neither run
  1083. //
  1084. // --PreviousRun--||--NewRun--||--FollowingRun--
  1085. //
  1086. // 0:|--NewRun--||--FollowingRun--
  1087. //
  1088. DebugTrace( 0, Dbg, "No holes, and continues none\n", 0);
  1089. (Mcb->Mapping)[Index].Lbn = Lbn;
  1090. try_return (Result = TRUE);
  1091. }
  1092. //
  1093. // We tried to overwrite an existing mapping so we'll have to
  1094. // tell our caller that it's not possible
  1095. //
  1096. Result = FALSE;
  1097. try_exit: NOTHING;
  1098. } finally {
  1099. ExReleaseFastMutex( Mcb->FastMutex );
  1100. DebugTrace(-1, Dbg, "FsRtlAddLargeMcbEntry -> %08lx\n", Result );
  1101. }
  1102. return Result;
  1103. }
  1104. VOID
  1105. FsRtlRemoveLargeMcbEntry (
  1106. IN PLARGE_MCB OpaqueMcb,
  1107. IN LONGLONG LargeVbn,
  1108. IN LONGLONG LargeSectorCount
  1109. )
  1110. /*++
  1111. Routine Description:
  1112. This routine removes a mapping of VBNs to LBNs from an Mcb. The mappings
  1113. removed are for
  1114. Vbn,
  1115. Vbn+1, to
  1116. Vbn+(SectorCount-1).
  1117. The operation works even if the mapping for a Vbn in the specified range
  1118. does not already exist in the Mcb. If the specified range of Vbn includes
  1119. the last mapped Vbn in the Mcb then the Mcb mapping shrinks accordingly.
  1120. If pool is not available to store the information this routine will raise
  1121. a status value indicating insufficient resources.
  1122. Arguments:
  1123. OpaqueMcb - Supplies the Mcb from which to remove the mapping.
  1124. Vbn - Supplies the starting Vbn of the mappings to remove.
  1125. SectorCount - Supplies the size of the mappings to remove (in sectors).
  1126. Return Value:
  1127. None.
  1128. --*/
  1129. {
  1130. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  1131. VBN Vbn = ((ULONG)LargeVbn);
  1132. ULONG SectorCount = ((ULONG)LargeSectorCount);
  1133. PAGED_CODE();
  1134. ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeVbn)->HighPart == 0);
  1135. DebugTrace(+1, Dbg, "FsRtlRemoveLargeMcbEntry, Mcb = %08lx\n", Mcb );
  1136. DebugTrace( 0, Dbg, " Vbn = %08lx\n", Vbn );
  1137. DebugTrace( 0, Dbg, " SectorCount = %08lx\n", SectorCount );
  1138. ExAcquireFastMutex( Mcb->FastMutex );
  1139. try {
  1140. FsRtlRemoveMcbEntryPrivate( Mcb, Vbn, SectorCount );
  1141. } finally {
  1142. ExReleaseFastMutex( Mcb->FastMutex );
  1143. DebugTrace(-1, Dbg, "FsRtlRemoveLargeMcbEntry -> VOID\n", 0 );
  1144. }
  1145. return;
  1146. }
  1147. BOOLEAN
  1148. FsRtlLookupLargeMcbEntry (
  1149. IN PLARGE_MCB OpaqueMcb,
  1150. IN LONGLONG LargeVbn,
  1151. OUT PLONGLONG LargeLbn OPTIONAL,
  1152. OUT PLONGLONG LargeSectorCount OPTIONAL,
  1153. OUT PLONGLONG LargeStartingLbn OPTIONAL,
  1154. OUT PLONGLONG LargeCountFromStartingLbn OPTIONAL,
  1155. OUT PULONG Index OPTIONAL
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. This routine retrieves the mapping of a Vbn to an Lbn from an Mcb.
  1160. It indicates if the mapping exists and the size of the run.
  1161. Arguments:
  1162. OpaqueMcb - Supplies the Mcb being examined.
  1163. Vbn - Supplies the Vbn to lookup.
  1164. Lbn - Receives the Lbn corresponding to the Vbn. A value of -1 is
  1165. returned if the Vbn does not have a corresponding Lbn.
  1166. SectorCount - Receives the number of sectors that map from the Vbn to
  1167. contiguous Lbn values beginning with the input Vbn.
  1168. Index - Receives the index of the run found.
  1169. Return Value:
  1170. BOOLEAN - TRUE if the Vbn is within the range of VBNs mapped by the
  1171. MCB (even if it corresponds to a hole in the mapping), and FALSE
  1172. if the Vbn is beyond the range of the MCB's mapping.
  1173. For example, if an MCB has a mapping for VBNs 5 and 7 but not for
  1174. 6, then a lookup on Vbn 5 or 7 will yield a non zero Lbn and a sector
  1175. count of 1. A lookup for Vbn 6 will return TRUE with an Lbn value of
  1176. 0, and lookup for Vbn 8 or above will return FALSE.
  1177. --*/
  1178. {
  1179. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  1180. BOOLEAN Result;
  1181. ULONG LocalIndex;
  1182. DebugTrace(+1, Dbg, "FsRtlLookupLargeMcbEntry, Mcb = %08lx\n", Mcb );
  1183. DebugTrace( 0, Dbg, " LargeVbn.LowPart = %08lx\n", LargeVbn.LowPart );
  1184. ExAcquireFastMutex( Mcb->FastMutex );
  1185. ASSERTMSG("LargeInteger not supported yet ", ((((PLARGE_INTEGER)&LargeVbn)->HighPart == 0) ||
  1186. (Mcb->PairCount == 0) ||
  1187. ((((PLARGE_INTEGER)&LargeVbn)->HighPart == 0x7FFFFFFF) &&
  1188. (((ULONG)LargeVbn) == 0xFFFFFFFF))));
  1189. try {
  1190. if (!FsRtlFindLargeIndex(Mcb, ((ULONG)LargeVbn), &LocalIndex)) {
  1191. try_return (Result = FALSE);
  1192. }
  1193. //
  1194. // Compute the lbn for corresponding to the vbn, the value is the
  1195. // starting lbn of the run plus the number of sectors offset into the
  1196. // run. But if it's a hole then the sector Lbn is zero.
  1197. //
  1198. if (ARGUMENT_PRESENT(LargeLbn)) {
  1199. if (StartingLbn(Mcb,LocalIndex) == UNUSED_LBN) {
  1200. *LargeLbn = UNUSED_LBN;
  1201. } else {
  1202. *LargeLbn = StartingLbn(Mcb,LocalIndex) + (((ULONG)LargeVbn) - StartingVbn(Mcb,LocalIndex));
  1203. }
  1204. }
  1205. //
  1206. // If there sector count argument is present then we'll return the number
  1207. // of sectors remaing in the run.
  1208. //
  1209. if (ARGUMENT_PRESENT(LargeSectorCount)) {
  1210. *LargeSectorCount = EndingVbn(Mcb,LocalIndex) - ((ULONG)LargeVbn) + 1;
  1211. }
  1212. //
  1213. // Compute the starting lbn for corresponding to the start of the run, the value is the
  1214. // starting lbn of the run. But if it's a hole then the sector Lbn is zero.
  1215. //
  1216. if (ARGUMENT_PRESENT(LargeStartingLbn)) {
  1217. if (StartingLbn(Mcb,LocalIndex) == UNUSED_LBN) {
  1218. *LargeStartingLbn = UNUSED_LBN;
  1219. } else {
  1220. *LargeStartingLbn = StartingLbn(Mcb,LocalIndex);
  1221. }
  1222. }
  1223. //
  1224. // If there sector count argument is present then we'll return the number
  1225. // of sectors in the run.
  1226. //
  1227. if (ARGUMENT_PRESENT(LargeCountFromStartingLbn)) {
  1228. *LargeCountFromStartingLbn = EndingVbn(Mcb,LocalIndex) - StartingVbn(Mcb,LocalIndex) + 1;
  1229. }
  1230. //
  1231. // If the caller want to know the Index number, fill it in.
  1232. //
  1233. if (ARGUMENT_PRESENT(Index)) {
  1234. *Index = LocalIndex;
  1235. }
  1236. Result = TRUE;
  1237. try_exit: NOTHING;
  1238. } finally {
  1239. ExReleaseFastMutex( Mcb->FastMutex );
  1240. DebugTrace(-1, Dbg, "FsRtlLookupLargeMcbEntry -> %08lx\n", Result );
  1241. }
  1242. return Result;
  1243. }
  1244. BOOLEAN
  1245. FsRtlLookupLastLargeMcbEntry (
  1246. IN PLARGE_MCB OpaqueMcb,
  1247. OUT PLONGLONG LargeVbn,
  1248. OUT PLONGLONG LargeLbn
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. This routine retrieves the last Vbn to Lbn mapping stored in the Mcb.
  1253. It returns the mapping for the last sector or the last run in the
  1254. Mcb. The results of this function is useful when extending an existing
  1255. file and needing to a hint on where to try and allocate sectors on the
  1256. disk.
  1257. Arguments:
  1258. OpaqueMcb - Supplies the Mcb being examined.
  1259. Vbn - Receives the last Vbn value mapped.
  1260. Lbn - Receives the Lbn corresponding to the Vbn.
  1261. Return Value:
  1262. BOOLEAN - TRUE if there is a mapping within the Mcb and FALSE otherwise
  1263. (i.e., the Mcb does not contain any mapping).
  1264. --*/
  1265. {
  1266. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  1267. BOOLEAN Result;
  1268. PAGED_CODE();
  1269. DebugTrace(+1, Dbg, "FsRtlLookupLastLargeMcbEntry, Mcb = %08lx\n", Mcb );
  1270. ExAcquireFastMutex( Mcb->FastMutex );
  1271. try {
  1272. //
  1273. // Check to make sure there is at least one run in the mcb
  1274. //
  1275. if (Mcb->PairCount <= 0) {
  1276. try_return (Result = FALSE);
  1277. }
  1278. //
  1279. // Return the last mapping of the last run
  1280. //
  1281. *LargeLbn = EndingLbn(Mcb,Mcb->PairCount-1);
  1282. *LargeVbn = EndingVbn(Mcb,Mcb->PairCount-1);
  1283. Result = TRUE;
  1284. try_exit: NOTHING;
  1285. } finally {
  1286. ExReleaseFastMutex( Mcb->FastMutex );
  1287. DebugTrace(-1, Dbg, "FsRtlLookupLastLargeMcbEntry -> %08lx\n", Result );
  1288. }
  1289. return Result;
  1290. }
  1291. BOOLEAN
  1292. FsRtlLookupLastLargeMcbEntryAndIndex (
  1293. IN PLARGE_MCB OpaqueMcb,
  1294. OUT PLONGLONG LargeVbn,
  1295. OUT PLONGLONG LargeLbn,
  1296. OUT PULONG Index
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. This routine retrieves the last Vbn to Lbn mapping stored in the Mcb.
  1301. It returns the mapping for the last sector or the last run in the
  1302. Mcb. The results of this function is useful when extending an existing
  1303. file and needing to a hint on where to try and allocate sectors on the
  1304. disk.
  1305. Arguments:
  1306. OpaqueMcb - Supplies the Mcb being examined.
  1307. Vbn - Receives the last Vbn value mapped.
  1308. Lbn - Receives the Lbn corresponding to the Vbn.
  1309. Index - Receives the index of the last run.
  1310. Return Value:
  1311. BOOLEAN - TRUE if there is a mapping within the Mcb and FALSE otherwise
  1312. (i.e., the Mcb does not contain any mapping).
  1313. --*/
  1314. {
  1315. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  1316. BOOLEAN Result;
  1317. PAGED_CODE();
  1318. DebugTrace(+1, Dbg, "FsRtlLookupLastLargeMcbEntryAndIndex, Mcb = %08lx\n", Mcb );
  1319. ExAcquireFastMutex( Mcb->FastMutex );
  1320. try {
  1321. //
  1322. // Check to make sure there is at least one run in the mcb
  1323. //
  1324. if (Mcb->PairCount <= 0) {
  1325. try_return (Result = FALSE);
  1326. }
  1327. //
  1328. // Return the last mapping of the last run
  1329. //
  1330. *((PULONG)LargeLbn) = EndingLbn(Mcb,Mcb->PairCount-1);
  1331. *((PULONG)LargeVbn) = EndingVbn(Mcb,Mcb->PairCount-1);
  1332. *Index = Mcb->PairCount - 1;
  1333. Result = TRUE;
  1334. try_exit: NOTHING;
  1335. } finally {
  1336. ExReleaseFastMutex( Mcb->FastMutex );
  1337. DebugTrace(-1, Dbg, "FsRtlLookupLastLargeMcbEntryAndIndex -> %08lx\n", Result );
  1338. }
  1339. ((PLARGE_INTEGER)LargeVbn)->HighPart = (*((PULONG)LargeVbn) == UNUSED_LBN ? UNUSED_LBN : 0);
  1340. ((PLARGE_INTEGER)LargeLbn)->HighPart = (*((PULONG)LargeLbn) == UNUSED_LBN ? UNUSED_LBN : 0);
  1341. return Result;
  1342. }
  1343. ULONG
  1344. FsRtlNumberOfRunsInLargeMcb (
  1345. IN PLARGE_MCB OpaqueMcb
  1346. )
  1347. /*++
  1348. Routine Description:
  1349. This routine returns to the its caller the number of distinct runs
  1350. mapped by an Mcb. Holes (i.e., Vbns that map to Lbn=UNUSED_LBN) are counted
  1351. as runs. For example, an Mcb containing a mapping for only Vbns 0 and 3
  1352. will have 3 runs, one for the first mapped sector, a second for the
  1353. hole covering Vbns 1 and 2, and a third for Vbn 3.
  1354. Arguments:
  1355. OpaqueMcb - Supplies the Mcb being examined.
  1356. Return Value:
  1357. ULONG - Returns the number of distinct runs mapped by the input Mcb.
  1358. --*/
  1359. {
  1360. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  1361. ULONG Count;
  1362. PAGED_CODE();
  1363. DebugTrace(+1, Dbg, "FsRtlNumberOfRunsInLargeMcb, Mcb = %08lx\n", Mcb );
  1364. ExAcquireFastMutex( Mcb->FastMutex );
  1365. Count = Mcb->PairCount;
  1366. ExReleaseFastMutex( Mcb->FastMutex );
  1367. DebugTrace(-1, Dbg, "FsRtlNumberOfRunsInLargeMcb -> %08lx\n", Count );
  1368. return Count;
  1369. }
  1370. BOOLEAN
  1371. FsRtlGetNextLargeMcbEntry (
  1372. IN PLARGE_MCB OpaqueMcb,
  1373. IN ULONG RunIndex,
  1374. OUT PLONGLONG LargeVbn,
  1375. OUT PLONGLONG LargeLbn,
  1376. OUT PLONGLONG LargeSectorCount
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. This routine returns to its caller the Vbn, Lbn, and SectorCount for
  1381. distinct runs mapped by an Mcb. Holes are counted as runs. For example,
  1382. to construct to print out all of the runs in a a file is:
  1383. //. . for (i = 0; FsRtlGetNextLargeMcbEntry(Mcb,i,&Vbn,&Lbn,&Count); i++) {
  1384. //
  1385. //. . // print out vbn, lbn, and count
  1386. //
  1387. //. . }
  1388. Arguments:
  1389. OpaqueMcb - Supplies the Mcb being examined.
  1390. RunIndex - Supplies the index of the run (zero based) to return to the
  1391. caller.
  1392. Vbn - Receives the starting Vbn of the returned run, or zero if the
  1393. run does not exist.
  1394. Lbn - Recieves the starting Lbn of the returned run, or zero if the
  1395. run does not exist.
  1396. SectorCount - Receives the number of sectors within the returned run,
  1397. or zero if the run does not exist.
  1398. Return Value:
  1399. BOOLEAN - TRUE if the specified run (i.e., RunIndex) exists in the Mcb,
  1400. and FALSE otherwise. If FALSE is returned then the Vbn, Lbn, and
  1401. SectorCount parameters receive zero.
  1402. --*/
  1403. {
  1404. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  1405. BOOLEAN Result;
  1406. PAGED_CODE();
  1407. DebugTrace(+1, Dbg, "FsRtlGetNextLargeMcbEntry, Mcb = %08lx\n", Mcb );
  1408. DebugTrace( 0, Dbg, " RunIndex = %08lx\n", RunIndex );
  1409. ExAcquireFastMutex( Mcb->FastMutex );
  1410. try {
  1411. //
  1412. // Make sure the run index is within range
  1413. //
  1414. if (RunIndex >= Mcb->PairCount) {
  1415. try_return (Result = FALSE);
  1416. }
  1417. //
  1418. // Set the return variables
  1419. //
  1420. *((PULONG)LargeVbn) = StartingVbn(Mcb,RunIndex);
  1421. ((PLARGE_INTEGER)LargeVbn)->HighPart = (*((PULONG)LargeVbn) == UNUSED_LBN ? UNUSED_LBN : 0);
  1422. *((PULONG)LargeLbn) = StartingLbn(Mcb,RunIndex);
  1423. ((PLARGE_INTEGER)LargeLbn)->HighPart = (*((PULONG)LargeLbn) == UNUSED_LBN ? UNUSED_LBN : 0);
  1424. *LargeSectorCount = SectorsWithinRun(Mcb,RunIndex);
  1425. Result = TRUE;
  1426. try_exit: NOTHING;
  1427. } finally {
  1428. ExReleaseFastMutex( Mcb->FastMutex );
  1429. DebugTrace(-1, Dbg, "FsRtlGetNextLargeMcbEntry -> %08lx\n", Result );
  1430. }
  1431. return Result;
  1432. }
  1433. BOOLEAN
  1434. FsRtlSplitLargeMcb (
  1435. IN PLARGE_MCB OpaqueMcb,
  1436. IN LONGLONG LargeVbn,
  1437. IN LONGLONG LargeAmount
  1438. )
  1439. /*++
  1440. Routine Description:
  1441. This routine is used to create a hole within an MCB, by shifting the
  1442. mapping of Vbns. All mappings above the input vbn are shifted by the
  1443. amount specified and while keeping their current lbn value. Pictorially
  1444. we have as input the following MCB
  1445. VBN : LargeVbn-1 LargeVbn N
  1446. +-----------------+------------------+
  1447. LBN : X Y
  1448. And after the split we have
  1449. VBN : LargeVbn-1 LargeVbn+Amount N+Amount
  1450. +-----------------+.............+---------------------------+
  1451. LBN : X UnusedLbn Y
  1452. When doing the split we have a few cases to consider. They are:
  1453. 1. The input Vbn is beyond the last run. In this case this operation
  1454. is a noop.
  1455. 2. The input Vbn is within or adjacent to a existing run of unused Lbns.
  1456. In this case we simply need to extend the size of the existing hole
  1457. and shift succeeding runs.
  1458. 3. The input Vbn is between two existing runs, including the an input vbn
  1459. value of zero. In this case we need to add a new entry for the hole
  1460. and shift succeeding runs.
  1461. 4. The input Vbn is within an existing run. In this case we need to add
  1462. two new entries to contain the split run and the hole.
  1463. If pool is not available to store the information this routine will raise a
  1464. status value indicating insufficient resources.
  1465. Arguments:
  1466. OpaqueMcb - Supplies the Mcb in which to add the new mapping.
  1467. Vbn - Supplies the starting Vbn that is to be shifted.
  1468. Amount - Supplies the amount to shift by.
  1469. Return Value:
  1470. BOOLEAN - TRUE if the mapping was successfully shifted, and FALSE otherwise.
  1471. If FALSE is returned then the Mcb is not changed.
  1472. --*/
  1473. {
  1474. PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
  1475. VBN Vbn = ((ULONG)LargeVbn);
  1476. ULONG Amount = ((ULONG)LargeAmount);
  1477. ULONG Index;
  1478. BOOLEAN Result;
  1479. ULONG i;
  1480. PAGED_CODE();
  1481. DebugTrace(+1, Dbg, "FsRtlSplitLargeMcb, Mcb = %08lx\n", Mcb );
  1482. DebugTrace( 0, Dbg, " Vbn = %08lx\n", Vbn );
  1483. DebugTrace( 0, Dbg, " Amount = %08lx\n", Amount );
  1484. ExAcquireFastMutex( Mcb->FastMutex );
  1485. ASSERTMSG("LargeInteger not supported yet ", ((((PLARGE_INTEGER)&LargeVbn)->HighPart == 0) ||
  1486. (Mcb->PairCount == 0)));
  1487. ASSERTMSG("LargeInteger not supported yet ", ((((PLARGE_INTEGER)&LargeAmount)->HighPart == 0) ||
  1488. (Mcb->PairCount == 0)));
  1489. try {
  1490. //
  1491. // First lookup the index for the entry that we are going to split.
  1492. // If we can't find the entry then there is nothing to split. This
  1493. // takes care of the case where the input vbn is beyond the last run
  1494. // in the mcb
  1495. //
  1496. if (!FsRtlFindLargeIndex( Mcb, Vbn, &Index)) {
  1497. try_return(Result = FALSE);
  1498. }
  1499. //
  1500. // Now check if the input Vbn is within a hole
  1501. //
  1502. if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
  1503. //
  1504. // Before: --PreviousRun--||--IndexHole--||--FollowingRun--
  1505. // After: --PreviousRun--||----IndexHole----||--FollowingRun--
  1506. //
  1507. // In this case the vbn is somewhere within the hole and we
  1508. // simply need to added the amount of each existing run
  1509. // beyond the hole.
  1510. //
  1511. //
  1512. // In this case there is really nothing to do here because the
  1513. // ending code will already shift the runs by proper amount
  1514. // starting at index
  1515. //
  1516. NOTHING;
  1517. //
  1518. // Now check if the input vbn is between a hole and an existing run.
  1519. //
  1520. } else if ((StartingVbn(Mcb,Index) == Vbn) && (Index != 0) && (PreviousEndingLbn(Mcb,Index) == UNUSED_LBN)) {
  1521. //
  1522. // Before: --Hole--||--IndexRun--
  1523. // After: --Hole------||--IndexRun--
  1524. //
  1525. // In this case the vbn points to the start of the existing
  1526. // run and we need to do the split between the hole and the
  1527. // existing run by simply adding the amount to each existing
  1528. // run beyond the hole.
  1529. //
  1530. //
  1531. // In this case we need to decement the index by 1 and then
  1532. // fall to the bottom code which will do the shifting for us
  1533. //
  1534. Index -= 1;
  1535. //
  1536. // Now check if the input vbn is between two existing runs
  1537. //
  1538. } else if (StartingVbn(Mcb,Index) == Vbn) {
  1539. //
  1540. // Before: --PreviousRun--||--IndexRun--
  1541. // After: --PreviousRun--||--NewHole--||--IndexRun--
  1542. //
  1543. // Before: 0:|--IndexRun--
  1544. // After: 0:|--NewHole--||--IndexRun--
  1545. //
  1546. // In this case the vbn points to the start of an existing
  1547. // run and the preceeding is either a real run or the start
  1548. // of mapping pairs We simply add a new entry for the hole
  1549. // and shift succeeding runs.
  1550. //
  1551. FsRtlAddLargeEntry( Mcb, Index, 1 );
  1552. (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
  1553. (Mcb->Mapping)[Index].NextVbn = Vbn + Amount;
  1554. Index += 1;
  1555. //
  1556. // Otherwise the input vbn is inside an existing run
  1557. //
  1558. } else {
  1559. //
  1560. // Before: --IndexRun--
  1561. // After: --SplitRun--||--NewHole--||--SplitRun--
  1562. //
  1563. // In this case the vbn points within an existing run
  1564. // we need to add two new extries for hole and split
  1565. // run and shift succeeding runs
  1566. //
  1567. FsRtlAddLargeEntry( Mcb, Index, 2 );
  1568. (Mcb->Mapping)[Index].Lbn = (Mcb->Mapping)[Index+2].Lbn;
  1569. (Mcb->Mapping)[Index].NextVbn = Vbn;
  1570. (Mcb->Mapping)[Index+1].Lbn = (LBN)UNUSED_LBN;
  1571. (Mcb->Mapping)[Index+1].NextVbn = Vbn + Amount;
  1572. (Mcb->Mapping)[Index+2].Lbn = (Mcb->Mapping)[Index+2].Lbn +
  1573. StartingVbn(Mcb, Index+1) -
  1574. StartingVbn(Mcb, Index);
  1575. Index += 2;
  1576. }
  1577. //
  1578. // At this point we have completed most of the work we now need to
  1579. // shift existing runs from the index to the end of the mappings
  1580. // by the specified amount
  1581. //
  1582. for (i = Index; i < Mcb->PairCount; i += 1) {
  1583. (Mcb->Mapping)[i].NextVbn += Amount;
  1584. }
  1585. Result = TRUE;
  1586. try_exit: NOTHING;
  1587. } finally {
  1588. ExReleaseFastMutex( Mcb->FastMutex );
  1589. DebugTrace(-1, Dbg, "FsRtlSplitLargeMcb -> %08lx\n", Result );
  1590. }
  1591. return Result;
  1592. }
  1593. //
  1594. // Private support routine
  1595. //
  1596. VOID
  1597. FsRtlRemoveMcbEntryPrivate (
  1598. IN PNONOPAQUE_MCB Mcb,
  1599. IN ULONG Vbn,
  1600. IN ULONG SectorCount
  1601. )
  1602. /*++
  1603. Routine Description:
  1604. This is the work routine for remove large mcb entry. It does the work
  1605. without taking out the mcb FastMutex.
  1606. Arguments:
  1607. Mcb - Supplies the Mcb from which to remove the mapping.
  1608. Vbn - Supplies the starting Vbn of the mappings to remove.
  1609. SectorCount - Supplies the size of the mappings to remove (in sectors).
  1610. Return Value:
  1611. None.
  1612. --*/
  1613. {
  1614. ULONG Index;
  1615. PAGED_CODE();
  1616. //
  1617. // Do a quick test to see if we are wiping out the entire MCB.
  1618. //
  1619. if ((Vbn == 0) && (Mcb->PairCount > 0) && (SectorCount >= Mcb->Mapping[Mcb->PairCount-1].NextVbn)) {
  1620. Mcb->PairCount = 0;
  1621. return;
  1622. }
  1623. //
  1624. // While there is some more mapping to remove we'll continue
  1625. // with our main loop
  1626. //
  1627. while (SectorCount > 0) {
  1628. //
  1629. // Locate the mapping for the vbn
  1630. //
  1631. if (!FsRtlFindLargeIndex(Mcb, Vbn, &Index)) {
  1632. DebugTrace( 0, Dbg, "FsRtlRemoveLargeMcbEntry, Cannot remove an unmapped Vbn = %08lx\n", Vbn );
  1633. return;
  1634. }
  1635. //
  1636. // Now that we some something to remove the following cases must
  1637. // be considered
  1638. //
  1639. if ((StartingVbn(Mcb,Index) == Vbn) &&
  1640. (EndingVbn(Mcb,Index) < Vbn + SectorCount)) {
  1641. ULONG i;
  1642. //
  1643. // Removes the entire run
  1644. //
  1645. //
  1646. // Update the amount to remove
  1647. //
  1648. i = SectorsWithinRun(Mcb,Index);
  1649. Vbn += i;
  1650. SectorCount -= i;
  1651. //
  1652. // If already a hole then leave it alone
  1653. //
  1654. if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
  1655. NOTHING;
  1656. //
  1657. // Test for last run
  1658. //
  1659. } else if (Index == Mcb->PairCount - 1) {
  1660. if ((PreviousEndingLbn(Mcb,Index) != UNUSED_LBN) ||
  1661. (Index == 0)) {
  1662. //
  1663. // Previous is not hole, index is last run
  1664. //
  1665. // --Previous--| Hole
  1666. //
  1667. // 0: Hole
  1668. //
  1669. DebugTrace( 0, Dbg, "Entire run, Previous not hole, index is last run\n", 0);
  1670. //
  1671. // Just remove this entry
  1672. //
  1673. FsRtlRemoveLargeEntry( Mcb, Index, 1);
  1674. } else {
  1675. //
  1676. // Previous is hole, index is last run
  1677. //
  1678. // --Hole--| Hole
  1679. //
  1680. DebugTrace( 0, Dbg, "Entire run, Previous hole, index is last run\n", 0);
  1681. //
  1682. // Just remove this entry, and preceding entry
  1683. //
  1684. FsRtlRemoveLargeEntry( Mcb, Index-1, 2);
  1685. }
  1686. } else if (((PreviousEndingLbn(Mcb,Index) != UNUSED_LBN) || (Index == 0)) &&
  1687. (NextStartingLbn(Mcb,Index) != UNUSED_LBN)) {
  1688. //
  1689. // Previous and following are not holes
  1690. //
  1691. // --Previous--| Hole |--Following--
  1692. //
  1693. // 0: Hole |--Following--
  1694. //
  1695. DebugTrace( 0, Dbg, "Entire run, Previous & Following not holes\n", 0);
  1696. //
  1697. // Make this index a hole
  1698. //
  1699. (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
  1700. } else if (((PreviousEndingLbn(Mcb,Index) != UNUSED_LBN) || (Index == 0)) &&
  1701. (NextStartingLbn(Mcb,Index) == UNUSED_LBN)) {
  1702. //
  1703. // Following is hole
  1704. //
  1705. // --Previous--| Hole |--Hole--
  1706. //
  1707. // 0: Hole |--Hole--
  1708. //
  1709. DebugTrace( 0, Dbg, "Entire run, Following is hole\n", 0);
  1710. //
  1711. // Simply remove this entry
  1712. //
  1713. FsRtlRemoveLargeEntry( Mcb, Index, 1 );
  1714. } else if ((PreviousEndingLbn(Mcb,Index) == UNUSED_LBN) &&
  1715. (NextStartingLbn(Mcb,Index) != UNUSED_LBN)) {
  1716. //
  1717. // Previous is hole
  1718. //
  1719. // --Hole--| Hole |--Following--
  1720. //
  1721. DebugTrace( 0, Dbg, "Entire run, Previous is hole\n", 0);
  1722. //
  1723. // Mark current entry a hole
  1724. //
  1725. (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
  1726. //
  1727. // Remove previous entry
  1728. //
  1729. FsRtlRemoveLargeEntry( Mcb, Index - 1, 1 );
  1730. } else {
  1731. //
  1732. // Previous and following are holes
  1733. //
  1734. // --Hole--| Hole |--Hole--
  1735. //
  1736. DebugTrace( 0, Dbg, "Entire run, Previous & following are holes\n", 0);
  1737. //
  1738. // Remove previous and this entry
  1739. //
  1740. FsRtlRemoveLargeEntry( Mcb, Index - 1, 2 );
  1741. }
  1742. } else if (StartingVbn(Mcb,Index) == Vbn) {
  1743. //
  1744. // Removes first part of run
  1745. //
  1746. //
  1747. // If already a hole then leave it alone
  1748. //
  1749. if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
  1750. NOTHING;
  1751. } else if ((PreviousEndingLbn(Mcb,Index) != UNUSED_LBN) || (Index == 0)) {
  1752. //
  1753. // Previous is not hole
  1754. //
  1755. // --Previous--| Hole |--Index--||--Following--
  1756. //
  1757. // 0: Hole |--Index--||--Following--
  1758. //
  1759. DebugTrace( 0, Dbg, "1st part, Previous is not hole\n", 0);
  1760. //
  1761. // Make room for one more entry. The NextVbn field of the
  1762. // one we're shifting remains valid.
  1763. //
  1764. FsRtlAddLargeEntry( Mcb, Index, 1 );
  1765. //
  1766. // Set the hole
  1767. //
  1768. (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
  1769. (Mcb->Mapping)[Index].NextVbn = Vbn + SectorCount;
  1770. //
  1771. // Set the new Lbn for the remaining run
  1772. //
  1773. (Mcb->Mapping)[Index+1].Lbn += SectorCount;
  1774. } else {
  1775. //
  1776. // Previous is hole
  1777. //
  1778. // --Hole--| Hole |--Index--||--Following--
  1779. //
  1780. DebugTrace( 0, Dbg, "1st part, Previous is hole\n", 0);
  1781. //
  1782. // Expand the preceding hole
  1783. //
  1784. (Mcb->Mapping)[Index-1].NextVbn += SectorCount;
  1785. //
  1786. // Set the new Lbn for the remaining run
  1787. //
  1788. (Mcb->Mapping)[Index].Lbn += SectorCount;
  1789. }
  1790. //
  1791. // Update the amount to remove
  1792. //
  1793. Vbn += SectorCount;
  1794. SectorCount = 0;
  1795. } else if (EndingVbn(Mcb,Index) < Vbn + SectorCount) {
  1796. ULONG AmountToRemove;
  1797. AmountToRemove = EndingVbn(Mcb,Index) - Vbn + 1;
  1798. //
  1799. // Removes last part of run
  1800. //
  1801. //
  1802. // If already a hole then leave it alone
  1803. //
  1804. if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
  1805. NOTHING;
  1806. } else if (Index == Mcb->PairCount - 1) {
  1807. //
  1808. // Index is last run
  1809. //
  1810. // --Previous--||--Index--| Hole
  1811. //
  1812. // 0:|--Index--| Hole
  1813. //
  1814. DebugTrace( 0, Dbg, "last part, Index is last run\n", 0);
  1815. //
  1816. // Shrink back the size of the current index
  1817. //
  1818. (Mcb->Mapping)[Index].NextVbn -= AmountToRemove;
  1819. } else if (NextStartingLbn(Mcb,Index) == UNUSED_LBN) {
  1820. //
  1821. // Following is hole
  1822. //
  1823. // --Previous--||--Index--| Hole |--Hole--
  1824. //
  1825. // 0:|--Index--| Hole |--Hole--
  1826. //
  1827. DebugTrace( 0, Dbg, "last part, Following is hole\n", 0);
  1828. //
  1829. // Shrink back the size of the current index
  1830. //
  1831. (Mcb->Mapping)[Index].NextVbn -= AmountToRemove;
  1832. } else {
  1833. //
  1834. // Following is not hole
  1835. //
  1836. // --Previous--||--Index--| Hole |--Following--
  1837. //
  1838. //
  1839. // 0:|--Index--| Hole |--Following--
  1840. //
  1841. DebugTrace( 0, Dbg, "last part, Following is not hole\n", 0);
  1842. //
  1843. // Make room for one more entry. The NextVbn field of the
  1844. // one we're shifting remains valid.
  1845. //
  1846. FsRtlAddLargeEntry( Mcb, Index+1, 1 );
  1847. //
  1848. // Set the new hole
  1849. //
  1850. (Mcb->Mapping)[Index+1].Lbn = (LBN)UNUSED_LBN;
  1851. (Mcb->Mapping)[Index+1].NextVbn = (Mcb->Mapping)[Index].NextVbn;
  1852. //
  1853. // Shrink back the size of the current index
  1854. //
  1855. (Mcb->Mapping)[Index].NextVbn -= AmountToRemove;
  1856. }
  1857. //
  1858. // Update amount to remove
  1859. //
  1860. Vbn += AmountToRemove;
  1861. SectorCount -= AmountToRemove;
  1862. } else {
  1863. //
  1864. // If already a hole then leave it alone
  1865. //
  1866. if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
  1867. NOTHING;
  1868. } else {
  1869. //
  1870. // Remove middle of run
  1871. //
  1872. // --Previous--||--Index--| Hole |--Index--||--Following--
  1873. //
  1874. // 0:|--Index--| Hole |--Index--||--Following--
  1875. //
  1876. DebugTrace( 0, Dbg, "Middle of run\n", 0);
  1877. //
  1878. // Make room for two more entries. The NextVbn field of the
  1879. // one we're shifting remains valid.
  1880. //
  1881. FsRtlAddLargeEntry( Mcb, Index, 2 );
  1882. //
  1883. // Set up the first remaining run
  1884. //
  1885. (Mcb->Mapping)[Index].Lbn = (Mcb->Mapping)[Index+2].Lbn;
  1886. (Mcb->Mapping)[Index].NextVbn = Vbn;
  1887. //
  1888. // Set up the hole
  1889. //
  1890. (Mcb->Mapping)[Index+1].Lbn = (LBN)UNUSED_LBN;
  1891. (Mcb->Mapping)[Index+1].NextVbn = Vbn + SectorCount;
  1892. //
  1893. // Set up the second remaining run
  1894. //
  1895. (Mcb->Mapping)[Index+2].Lbn += SectorsWithinRun(Mcb,Index) +
  1896. SectorsWithinRun(Mcb,Index+1);
  1897. }
  1898. //
  1899. // Update amount to remove
  1900. //
  1901. Vbn += SectorCount;
  1902. SectorCount = 0;
  1903. }
  1904. }
  1905. return;
  1906. }
  1907. //
  1908. // Private routine
  1909. //
  1910. BOOLEAN
  1911. FsRtlFindLargeIndex (
  1912. IN PNONOPAQUE_MCB Mcb,
  1913. IN VBN Vbn,
  1914. OUT PULONG Index
  1915. )
  1916. /*++
  1917. Routine Description:
  1918. This is a private routine that locates a mapping for a Vbn
  1919. in a given mapping array
  1920. Arguments:
  1921. Mcb - Supplies the mapping array to examine
  1922. Vbn - Supplies the Vbn to look up
  1923. Index - Receives the index within the mapping array of the mapping
  1924. containing the Vbn. If none if found then the index is set to
  1925. PairCount.
  1926. Return Value:
  1927. BOOLEAN - TRUE if Vbn is found and FALSE otherwise
  1928. --*/
  1929. {
  1930. LONG MinIndex;
  1931. LONG MaxIndex;
  1932. LONG MidIndex;
  1933. //
  1934. // We'll just do a binary search for the mapping entry. Min and max
  1935. // are our search boundaries
  1936. //
  1937. MinIndex = 0;
  1938. MaxIndex = Mcb->PairCount - 1;
  1939. while (MinIndex <= MaxIndex) {
  1940. //
  1941. // Compute the middle index to look at
  1942. //
  1943. MidIndex = ((MaxIndex + MinIndex) / 2);
  1944. //
  1945. // check if the Vbn is less than the mapping at the mid index
  1946. //
  1947. if (Vbn < StartingVbn(Mcb, MidIndex)) {
  1948. //
  1949. // Vbn is less than the middle index so we need to drop
  1950. // the max down
  1951. //
  1952. MaxIndex = MidIndex - 1;
  1953. //
  1954. // check if the Vbn is greater than the mapping at the mid index
  1955. //
  1956. } else if (Vbn > EndingVbn(Mcb, MidIndex)) {
  1957. //
  1958. // Vbn is greater than the middle index so we need to bring
  1959. // up the min
  1960. //
  1961. MinIndex = MidIndex + 1;
  1962. //
  1963. // Otherwise we've found the index containing the Vbn so set the
  1964. // index and return TRUE.
  1965. //
  1966. } else {
  1967. *Index = MidIndex;
  1968. return TRUE;
  1969. }
  1970. }
  1971. //
  1972. // A match wasn't found so set index to PairCount and return FALSE
  1973. //
  1974. *Index = Mcb->PairCount;
  1975. return FALSE;
  1976. }
  1977. //
  1978. // Private Routine
  1979. //
  1980. VOID
  1981. FsRtlAddLargeEntry (
  1982. IN PNONOPAQUE_MCB Mcb,
  1983. IN ULONG WhereToAddIndex,
  1984. IN ULONG AmountToAdd
  1985. )
  1986. /*++
  1987. Routine Description:
  1988. This routine takes a current Mcb and detemines if there is enough
  1989. room to add the new mapping entries. If there is not enough room
  1990. it reallocates a new mcb buffer and copies over the current mapping.
  1991. If also will spread out the current mappings to leave the specified
  1992. index slots in the mapping unfilled. For example, if WhereToAddIndex
  1993. is equal to the current pair count then we don't need to make a hole
  1994. in the mapping, but if the index is less than the current pair count
  1995. then we'll need to slide some of the mappings down to make room
  1996. at the specified index.
  1997. Arguments:
  1998. Mcb - Supplies the mcb being checked and modified
  1999. WhereToAddIndex - Supplies the index of where the additional entries
  2000. need to be made
  2001. AmountToAdd - Supplies the number of additional entries needed in the
  2002. mcb
  2003. Return Value:
  2004. None.
  2005. --*/
  2006. {
  2007. PAGED_CODE();
  2008. //
  2009. // Check to see if the current buffer is large enough to hold
  2010. // the additional entries
  2011. //
  2012. if (Mcb->PairCount + AmountToAdd > Mcb->MaximumPairCount) {
  2013. ULONG NewMax;
  2014. PMAPPING Mapping;
  2015. //
  2016. // We need to allocate a new mapping so compute a new maximum pair
  2017. // count. We'll only be asked to grow by at most 2 at a time, so
  2018. // doubling will definitely make us large enough for the new amount.
  2019. // But we won't double without bounds we'll stop doubling if the
  2020. // pair count gets too high.
  2021. //
  2022. if (Mcb->MaximumPairCount < 2048) {
  2023. NewMax = Mcb->MaximumPairCount * 2;
  2024. } else {
  2025. NewMax = Mcb->MaximumPairCount + 2048;
  2026. }
  2027. Mapping = FsRtlpAllocatePool( Mcb->PoolType, sizeof(MAPPING) * NewMax );
  2028. //**** RtlZeroMemory( Mapping, sizeof(MAPPING) * NewMax );
  2029. //
  2030. // Now copy over the old mapping to the new buffer
  2031. //
  2032. RtlCopyMemory( Mapping, Mcb->Mapping, sizeof(MAPPING) * Mcb->PairCount );
  2033. //
  2034. // Deallocate the old buffer
  2035. //
  2036. if ((Mcb->PoolType == PagedPool) && (Mcb->MaximumPairCount == INITIAL_MAXIMUM_PAIR_COUNT)) {
  2037. FsRtlFreeFirstMapping( Mcb->Mapping );
  2038. } else {
  2039. ExFreePool( Mcb->Mapping );
  2040. }
  2041. //
  2042. // And set up the new buffer in the Mcb
  2043. //
  2044. Mcb->Mapping = Mapping;
  2045. Mcb->MaximumPairCount = NewMax;
  2046. }
  2047. //
  2048. // Now see if we need to shift some entries over according to the
  2049. // WhereToAddIndex value
  2050. //
  2051. if (WhereToAddIndex < Mcb->PairCount) {
  2052. RtlMoveMemory( &((Mcb->Mapping)[WhereToAddIndex + AmountToAdd]),
  2053. &((Mcb->Mapping)[WhereToAddIndex]),
  2054. (Mcb->PairCount - WhereToAddIndex) * sizeof(MAPPING) );
  2055. }
  2056. //
  2057. // Now zero out the new additions
  2058. //
  2059. //**** RtlZeroMemory( &((Mcb->Mapping)[WhereToAddIndex]), sizeof(MAPPING) * AmountToAdd );
  2060. //
  2061. // Now increment the PairCount
  2062. //
  2063. Mcb->PairCount += AmountToAdd;
  2064. //
  2065. // And return to our caller
  2066. //
  2067. return;
  2068. }
  2069. //
  2070. // Private Routine
  2071. //
  2072. VOID
  2073. FsRtlRemoveLargeEntry (
  2074. IN PNONOPAQUE_MCB Mcb,
  2075. IN ULONG WhereToRemoveIndex,
  2076. IN ULONG AmountToRemove
  2077. )
  2078. /*++
  2079. Routine Description:
  2080. This routine takes a current Mcb and removes one or more entries.
  2081. Arguments:
  2082. Mcb - Supplies the mcb being checked and modified
  2083. WhereToRemoveIndex - Supplies the index of the entries to remove
  2084. AmountToRemove - Supplies the number of entries to remove
  2085. Return Value:
  2086. None.
  2087. --*/
  2088. {
  2089. PAGED_CODE();
  2090. //
  2091. // Check to see if we need to shift everything down because the
  2092. // entries to remove do not include the last entry in the mcb
  2093. //
  2094. if (WhereToRemoveIndex + AmountToRemove < Mcb->PairCount) {
  2095. RtlMoveMemory( &((Mcb->Mapping)[WhereToRemoveIndex]),
  2096. &((Mcb->Mapping)[WhereToRemoveIndex + AmountToRemove]),
  2097. (Mcb->PairCount - (WhereToRemoveIndex + AmountToRemove))
  2098. * sizeof(MAPPING) );
  2099. }
  2100. //
  2101. // Now zero out the entries beyond the part we just shifted down
  2102. //
  2103. //**** RtlZeroMemory( &((Mcb->Mapping)[Mcb->PairCount - AmountToRemove]), AmountToRemove * sizeof(MAPPING) );
  2104. //
  2105. // Now decrement the PairCount
  2106. //
  2107. Mcb->PairCount -= AmountToRemove;
  2108. //
  2109. // And return to our caller
  2110. //
  2111. return;
  2112. }