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.

1018 lines
26 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. VmcbSup.c
  5. Abstract:
  6. Historical note: this package was originally written for HPFS (pinball)
  7. and is now resurrected for UDFS. Since UDFS is readonly in initial
  8. versions we will snip by #ifdef the write support, leaving it visible
  9. for the future - this code has not been changed (nearly) whatsoever and
  10. is left named as Pb (pinball) code.
  11. The VMCB routines provide support for maintaining a mapping between
  12. LBNs and VBNs for a virtual volume file. The volume file is all
  13. of the sectors that make up the on-disk structures. A file system
  14. uses this package to map LBNs for on-disk structure to VBNs in a volume
  15. file. This when used in conjunction with Memory Management and the
  16. Cache Manager will treat the volume file as a simple mapped file. A
  17. variable of type VMCB is used to store the mapping information and one
  18. is needed for every mounted volume.
  19. The main idea behind this package is to allow the user to dynamically
  20. read in new disk structure sectors (e.g., File Entries). The user assigns
  21. the new sector a VBN in the Volume file and has memory management fault
  22. the page containing the sector into memory. To do this Memory management
  23. will call back into the file system to read the page from the volume file
  24. passing in the appropriate VBN. Now the file system takes the VBN and
  25. maps it back to its LBN and does the read.
  26. The granularity of mapping is one a per page basis. That is if
  27. a mapping for LBN 8 is added to the VMCB structure and the page size
  28. is 8 sectors then the VMCB routines will actually assign a mapping for
  29. LBNS 8 through 15, and they will be assigned to a page aligned set of
  30. VBNS. This function is needed to allow us to work efficiently with
  31. memory management. This means that some sectors in some pages might
  32. actually contain regular file data and not volume information, and so
  33. when writing the page out we must only write the sectors that are really
  34. in use by the volume file. To help with this we provide a set
  35. of routines to keep track of dirty volume file sectors.
  36. That way, when the file system is called to write a page to the volume
  37. file, it will only write the sectors that are dirty.
  38. Concurrent access the VMCB structure is control by this package.
  39. The functions provided in this package are as follows:
  40. o UdfInitializeVmcb - Initialize a new VMCB structure.
  41. o UdfUninitializeVmcb - Uninitialize an existing VMCB structure.
  42. o UdfSetMaximumLbnVmcb - Sets/Resets the maximum allowed LBN
  43. for the specified VMCB structure.
  44. o UdfAddVmcbMapping - This routine takes an LBN and assigns to it
  45. a VBN. If the LBN already was assigned to an VBN it simply returns
  46. the old VBN and does not do a new assignemnt.
  47. o UdfRemoveVmcbMapping - This routine takes an LBN and removes its
  48. mapping from the VMCB structure.
  49. o UdfVmcbVbnToLbn - This routine takes a VBN and returns the
  50. LBN it maps to.
  51. o UdfVmcbLbnToVbn - This routine takes an LBN and returns the
  52. VBN its maps to.
  53. Authors:
  54. Gary Kimura [GaryKi] 4-Apr-1990
  55. Dan Lovinger [DanLo] 10-Sep-1996
  56. Revision History:
  57. Tom Jolly [tomjolly] 21-Jan-2000 CcPurge and extend at end of stream
  58. Tom Jolly [TomJolly] 1-March-2000 UDF 2.01 support
  59. --*/
  60. #include "UdfProcs.h"
  61. //
  62. // The Bug check file id for this module
  63. //
  64. #define BugCheckFileId (UDFS_BUG_CHECK_VMCBSUP)
  65. //
  66. // The local debug trace level
  67. //
  68. #define Dbg (UDFS_DEBUG_LEVEL_VMCBSUP)
  69. //
  70. // The following macro is used to calculate the number of pages (in terms of
  71. // sectors) needed to contain a given sector count. For example (assuming
  72. // 1kb sector size, 8kb page size)
  73. //
  74. // PadSectorCountToPage( 0 Sectors ) = 0 Pages = 0 Sectors
  75. // PadSectorCountToPage( 1 Sectors ) = 1 Page = 8 Sectors
  76. // PadSectorCountToPage( 2 Sectors ) = 1 Page = 8 Sectors
  77. // PadSectorCountToPage( 8 .. ) = 2 Pages = 16 sectors
  78. //
  79. // Evaluates to the number of
  80. //
  81. #define PadSectorCountToPage(V, L) ( ( ((L)+((PAGE_SIZE/(V)->SectorSize)-1)) / (PAGE_SIZE/(V)->SectorSize) ) * (PAGE_SIZE/(V)->SectorSize) )
  82. //
  83. // Evaluates to first page aligned LBN <= Supplied LBN
  84. //
  85. #define AlignToPageBase( V, L) ((L) & ~((PAGE_SIZE / (V)->SectorSize)-1))
  86. //
  87. // Evaluates to TRUE if the LBN is page aligned, FALSE otherwise
  88. //
  89. #define IsPageAligned( V, L) (0 == ((L) & ((PAGE_SIZE / (V)->SectorSize)-1)) )
  90. //
  91. // Macros for VMCB synchronisation
  92. //
  93. #define VmcbLockForRead( V) (VOID)ExAcquireResourceSharedLite( &((V)->Resource), TRUE )
  94. #define VmcbLockForModify( V) (VOID)ExAcquireResourceExclusiveLite( &((V)->Resource), TRUE )
  95. #define VmcbRelease( V) ExReleaseResourceLite( &((V)->Resource))
  96. //
  97. // Local Routines.
  98. //
  99. BOOLEAN
  100. UdfVmcbLookupMcbEntry (
  101. IN PMCB Mcb,
  102. IN VBN Vbn,
  103. OUT PLBN Lbn,
  104. OUT PULONG SectorCount OPTIONAL,
  105. OUT PULONG Index OPTIONAL
  106. );
  107. #ifdef ALLOC_PRAGMA
  108. #pragma alloc_text(PAGE, UdfAddVmcbMapping)
  109. #pragma alloc_text(PAGE, UdfInitializeVmcb)
  110. #pragma alloc_text(PAGE, UdfRemoveVmcbMapping)
  111. #pragma alloc_text(PAGE, UdfResetVmcb)
  112. #pragma alloc_text(PAGE, UdfSetMaximumLbnVmcb)
  113. #pragma alloc_text(PAGE, UdfUninitializeVmcb)
  114. #pragma alloc_text(PAGE, UdfVmcbLbnToVbn)
  115. #pragma alloc_text(PAGE, UdfVmcbLookupMcbEntry)
  116. #pragma alloc_text(PAGE, UdfVmcbVbnToLbn)
  117. #endif
  118. VOID
  119. UdfInitializeVmcb (
  120. IN PVMCB Vmcb,
  121. IN POOL_TYPE PoolType,
  122. IN ULONG MaximumLbn,
  123. IN ULONG SectorSize
  124. )
  125. /*++
  126. Routine Description:
  127. This routine initializes a new Vmcb Structure. The caller must
  128. supply the memory for the structure. This must precede all other calls
  129. that set/query the volume file mapping.
  130. If pool is not available this routine will raise a status value
  131. indicating insufficient resources.
  132. Arguments:
  133. Vmcb - Supplies a pointer to the volume file structure to initialize.
  134. PoolType - Supplies the pool type to use when allocating additional
  135. internal structures.
  136. MaximumLbn - Supplies the maximum Lbn value that is valid for this
  137. volume.
  138. LbSize - Size of a sector on this volume
  139. Return Value:
  140. None
  141. --*/
  142. {
  143. BOOLEAN VbnInitialized;
  144. BOOLEAN LbnInitialized;
  145. PAGED_CODE();
  146. DebugTrace(( +1, Dbg, "UdfInitializeVmcb, Vmcb = %08x\n", Vmcb ));
  147. VbnInitialized = FALSE;
  148. LbnInitialized = FALSE;
  149. try {
  150. //
  151. // Initialize the fields in the vmcb structure
  152. //
  153. FsRtlInitializeMcb( &Vmcb->VbnIndexed, PoolType );
  154. VbnInitialized = TRUE;
  155. FsRtlInitializeMcb( &Vmcb->LbnIndexed, PoolType );
  156. LbnInitialized = TRUE;
  157. Vmcb->MaximumLbn = MaximumLbn;
  158. Vmcb->SectorSize = SectorSize;
  159. Vmcb->NodeTypeCode = UDFS_NTC_VMCB;
  160. Vmcb->NodeByteSize = sizeof( VMCB);
  161. ExInitializeResourceLite( &Vmcb->Resource );
  162. } finally {
  163. //
  164. // If this is an abnormal termination then check if we need to
  165. // uninitialize the mcb structures
  166. //
  167. if (AbnormalTermination()) {
  168. if (VbnInitialized) { FsRtlUninitializeMcb( &Vmcb->VbnIndexed ); }
  169. if (LbnInitialized) { FsRtlUninitializeMcb( &Vmcb->LbnIndexed ); }
  170. }
  171. DebugUnwind("UdfInitializeVmcb");
  172. DebugTrace(( -1, Dbg, "UdfInitializeVmcb -> VOID\n" ));
  173. }
  174. }
  175. VOID
  176. UdfUninitializeVmcb (
  177. IN PVMCB Vmcb
  178. )
  179. /*++
  180. Routine Description:
  181. This routine uninitializes an existing VMCB structure. After calling
  182. this routine the input VMCB structure must be re-initialized before
  183. being used again.
  184. Arguments:
  185. Vmcb - Supplies a pointer to the VMCB structure to uninitialize.
  186. Return Value:
  187. None.
  188. --*/
  189. {
  190. PAGED_CODE();
  191. DebugTrace(( +1, Dbg, "UdfUninitializeVmcb, Vmcb = %08x\n", Vmcb ));
  192. //
  193. // Unitialize the fields in the Vmcb structure
  194. //
  195. FsRtlUninitializeMcb( &Vmcb->VbnIndexed );
  196. FsRtlUninitializeMcb( &Vmcb->LbnIndexed );
  197. ExDeleteResourceLite( &Vmcb->Resource);
  198. //
  199. // And return to our caller
  200. //
  201. DebugTrace(( -1, Dbg, "UdfUninitializeVmcb -> VOID\n" ));
  202. return;
  203. }
  204. VOID
  205. UdfResetVmcb (
  206. IN PVMCB Vmcb
  207. )
  208. /*++
  209. Routine Description:
  210. This routine resets the mappings in an existing VMCB structure.
  211. Arguments:
  212. Vmcb - Supplies a pointer to the VMCB structure to reset.
  213. Return Value:
  214. None.
  215. --*/
  216. {
  217. PAGED_CODE();
  218. DebugTrace(( +1, Dbg, "UdfResetVmcb, Vmcb = %08x\n", Vmcb ));
  219. //
  220. // Unitialize the fields in the Vmcb structure
  221. //
  222. FsRtlResetLargeMcb( (PLARGE_MCB) &Vmcb->VbnIndexed, TRUE );
  223. FsRtlResetLargeMcb( (PLARGE_MCB) &Vmcb->LbnIndexed, TRUE );
  224. //
  225. // And return to our caller
  226. //
  227. DebugTrace(( -1, Dbg, "UdfResetVmcb -> VOID\n" ));
  228. return;
  229. }
  230. VOID
  231. UdfSetMaximumLbnVmcb (
  232. IN PVMCB Vmcb,
  233. IN ULONG MaximumLbn
  234. )
  235. /*++
  236. Routine Description:
  237. This routine sets/resets the maximum allowed LBN for the specified
  238. Vmcb structure. The Vmcb structure must already have been initialized
  239. by calling UdfInitializeVmcb.
  240. Arguments:
  241. Vmcb - Supplies a pointer to the volume file structure to initialize.
  242. MaximumLbn - Supplies the maximum Lbn value that is valid for this
  243. volume.
  244. Return Value:
  245. None
  246. --*/
  247. {
  248. PAGED_CODE();
  249. DebugTrace(( +1, Dbg, "UdfSetMaximumLbnVmcb, Vmcb = %08x\n", Vmcb ));
  250. //
  251. // Set the field
  252. //
  253. Vmcb->MaximumLbn = MaximumLbn;
  254. //
  255. // And return to our caller
  256. //
  257. DebugTrace(( -1, Dbg, "UdfSetMaximumLbnVmcb -> VOID\n" ));
  258. return;
  259. }
  260. BOOLEAN
  261. UdfVmcbVbnToLbn (
  262. IN PVMCB Vmcb,
  263. IN VBN Vbn,
  264. IN PLBN Lbn,
  265. OUT PULONG SectorCount OPTIONAL
  266. )
  267. /*++
  268. Routine Description:
  269. This routine translates a VBN to an LBN.
  270. Arguments:
  271. Vmcb - Supplies the VMCB structure being queried.
  272. Vbn - Supplies the VBN to translate from.
  273. Lbn - Receives the LBN mapped by the input Vbn. This value is only valid
  274. if the function result is TRUE.
  275. SectorCount - Optionally receives the number of sectors corresponding
  276. to the run.
  277. Return Value:
  278. BOOLEAN - TRUE if he Vbn has a valid mapping and FALSE otherwise.
  279. --*/
  280. {
  281. BOOLEAN Result;
  282. DebugTrace(( +1, Dbg, "UdfVmcbVbnToLbn, Vbn = %08x\n", Vbn ));
  283. //
  284. // Now grab the resource
  285. //
  286. VmcbLockForRead( Vmcb);
  287. try {
  288. Result = UdfVmcbLookupMcbEntry( &Vmcb->VbnIndexed,
  289. Vbn,
  290. Lbn,
  291. SectorCount,
  292. NULL );
  293. DebugTrace(( 0, Dbg, "*Lbn = %08x\n", *Lbn ));
  294. //
  295. // If the returned Lbn is greater than the maximum allowed Lbn
  296. // then return FALSE
  297. //
  298. if (Result && (*Lbn > Vmcb->MaximumLbn)) {
  299. try_leave( Result = FALSE );
  300. }
  301. //
  302. // If the last returned Lbn is greater than the maximum allowed Lbn
  303. // then bring in the sector count
  304. //
  305. if (Result &&
  306. ARGUMENT_PRESENT(SectorCount) &&
  307. (*Lbn+*SectorCount-1 > Vmcb->MaximumLbn)) {
  308. *SectorCount = (Vmcb->MaximumLbn - *Lbn + 1);
  309. }
  310. } finally {
  311. VmcbRelease( Vmcb);
  312. DebugUnwind("UdfVmcbVbnToLbn");
  313. DebugTrace(( -1, Dbg, "UdfVmcbVbnToLbn -> Result = %08x\n", Result ));
  314. }
  315. return Result;
  316. }
  317. BOOLEAN
  318. UdfVmcbLbnToVbn (
  319. IN PVMCB Vmcb,
  320. IN LBN Lbn,
  321. OUT PVBN Vbn,
  322. OUT PULONG SectorCount OPTIONAL
  323. )
  324. /*++
  325. Routine Description:
  326. This routine translates an LBN to a VBN.
  327. Arguments:
  328. Vmcb - Supplies the VMCB structure being queried.
  329. Lbn - Supplies the LBN to translate from.
  330. Vbn - Recieves the VBN mapped by the input LBN. This value is
  331. only valid if the function result is TRUE.
  332. SectorCount - Optionally receives the number of sectors corresponding
  333. to the run.
  334. Return Value:
  335. BOOLEAN - TRUE if the mapping is valid and FALSE otherwise.
  336. --*/
  337. {
  338. BOOLEAN Result;
  339. PAGED_CODE();
  340. DebugTrace(( +1, Dbg, "UdfVmcbLbnToVbn, Lbn = %08x\n", Lbn ));
  341. //
  342. // If the requested Lbn is greater than the maximum allowed Lbn
  343. // then the result is FALSE
  344. //
  345. if (Lbn > Vmcb->MaximumLbn) {
  346. DebugTrace(( -1, Dbg, "Lbn too large, UdfVmcbLbnToVbn -> FALSE\n" ));
  347. return FALSE;
  348. }
  349. //
  350. // Now grab the resource
  351. //
  352. VmcbLockForRead( Vmcb);
  353. try {
  354. Result = UdfVmcbLookupMcbEntry( &Vmcb->LbnIndexed,
  355. Lbn,
  356. Vbn,
  357. SectorCount,
  358. NULL );
  359. if (Result) {
  360. DebugTrace(( 0, Dbg, "*Vbn = %08x\n", *Vbn ));
  361. }
  362. } finally {
  363. VmcbRelease( Vmcb);
  364. DebugUnwind("UdfVmcbLbnToVbn");
  365. DebugTrace(( -1, Dbg, "UdfVmcbLbnToVbn -> Result = %08x\n", Result ));
  366. }
  367. return Result;
  368. }
  369. BOOLEAN
  370. UdfAddVmcbMapping (
  371. IN PIRP_CONTEXT IrpContext,
  372. IN PVMCB Vmcb,
  373. IN LBN Lbn,
  374. IN ULONG SectorCount,
  375. IN BOOLEAN ExactEnd,
  376. OUT PVBN Vbn,
  377. OUT PULONG AlignedSectorCount
  378. )
  379. /*++
  380. Routine Description:
  381. This routine adds a new LBN to VBN mapping to the VMCB structure. When
  382. a new LBN is added to the structure it does it only on page aligned
  383. boundaries.
  384. If pool is not available to store the information this routine will
  385. raise a status value indicating insufficient resources.
  386. May acquire Vcb->VmcbMappingResource EXCLUSIVE if an existing mapping can
  387. be extended (and hence a purge is necessary), released before return.
  388. Caller must have NO active mappings through Vmcb stream before calling this
  389. function.
  390. Arguments:
  391. Vmcb - Supplies the VMCB being updated.
  392. Lbn - Supplies the starting LBN to add to VMCB.
  393. SectorCount - Supplies the number of Sectors in the run. We're only currently expecting
  394. single sector mappings.
  395. ExactEnd - Indicates that instead of aligning to map sectors beyond
  396. the end of the request, use a hole. Implies trying to look at
  397. these sectors could be undesireable.
  398. Vbn - Receives the assigned VBN
  399. AlignedSectorCount - Receives the actual sector count created in the
  400. Vmcb for page alignment purposes. Vbn+AlignedSectorCount-1 == LastVbn.
  401. Return Value:
  402. BOOLEAN - TRUE if this is a new mapping and FALSE if the mapping
  403. for the LBN already exists. If it already exists then the
  404. sector count for this new addition must already be in the
  405. VMCB structure
  406. --*/
  407. {
  408. BOOLEAN Result;
  409. BOOLEAN VbnMcbAdded = FALSE;
  410. BOOLEAN LbnMcbAdded = FALSE;
  411. BOOLEAN AllowRoundToPage;
  412. LBN LocalLbn;
  413. VBN LocalVbn;
  414. ULONG LocalCount;
  415. LARGE_INTEGER Offset;
  416. PVCB Vcb;
  417. PAGED_CODE();
  418. DebugTrace(( +1, Dbg, "UdfAddVmcbMapping, Lbn = %08x\n", Lbn ));
  419. DebugTrace(( 0, Dbg, " SectorCount = %08x\n", SectorCount ));
  420. ASSERT( SectorCount == 1 );
  421. ASSERT_IRP_CONTEXT( IrpContext);
  422. Vcb = IrpContext->Vcb;
  423. //
  424. // Now grab the resource exclusive
  425. //
  426. VmcbLockForModify( Vmcb);
  427. try {
  428. //
  429. // Check if the Lbn is already mapped, which means we find an entry
  430. // with a non zero mapping Vbn value.
  431. //
  432. if (UdfVmcbLookupMcbEntry( &Vmcb->LbnIndexed,
  433. Lbn,
  434. Vbn,
  435. &LocalCount,
  436. NULL )) {
  437. //
  438. // It is already mapped so now the sector count must not exceed
  439. // the count already in the run
  440. //
  441. if (SectorCount <= LocalCount) {
  442. DebugTrace(( 0, Dbg, "Already mapped (Vbn == 0x%08x)\n", *Vbn));
  443. *AlignedSectorCount = LocalCount;
  444. try_leave( Result = FALSE );
  445. }
  446. //
  447. // Trying to add overlapping extents indicates overlapping structures...
  448. //
  449. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR);
  450. }
  451. //
  452. // If there is a VAT in use, then we treat the media as CDR style, and don't
  453. // round/align extents to page boundries, since this could include (unreadable)
  454. // packet leadin/out sectors.
  455. //
  456. AllowRoundToPage = (NULL == Vcb->VatFcb);
  457. //
  458. // At this point, we did not find a full existing mapping for the
  459. // Lbn and count. But there might be some overlapping runs that we'll
  460. // need to now remove from the vmcb structure. So for each Lbn in
  461. // the range we're after, check to see if it is mapped and remove the
  462. // mapping. We only need to do this test if the sector count is less
  463. // than or equal to a page size. Because those are the only
  464. // structures that we know we'll try an remove/overwrite.
  465. //
  466. if (SectorCount <= PadSectorCountToPage(Vmcb, 1)) {
  467. if (UdfVmcbLookupMcbEntry( &Vmcb->LbnIndexed,
  468. Lbn,
  469. Vbn,
  470. &LocalCount,
  471. NULL )) {
  472. UdfRemoveVmcbMapping( Vmcb, *Vbn, PadSectorCountToPage(Vmcb, 1) );
  473. }
  474. }
  475. //
  476. // We need to add this new run at the end of the Vbns
  477. //
  478. if (!FsRtlLookupLastMcbEntry( &Vmcb->VbnIndexed, &LocalVbn, &LocalLbn )) {
  479. //
  480. // Vmcb is currently empty.
  481. //
  482. LocalVbn = -1;
  483. }
  484. if (!AllowRoundToPage) {
  485. //
  486. // So this volume may have unreadable sectors on it (eg CDR packet written)
  487. // and so we extend the vmcb one sector at a time, only including sectors
  488. // which we're specifically asked for, and hence know that we should be
  489. // able to read.
  490. //
  491. // We simply use the next available VSN, purging the last vmcb page if
  492. // neccessary (we're adding sectors to it), and don't page align the lbn
  493. // or sectorcount.
  494. //
  495. ASSERT( 1 == SectorCount);
  496. LocalVbn += 1;
  497. LocalLbn = Lbn;
  498. LocalCount = SectorCount;
  499. if (!IsPageAligned( Vmcb, LocalVbn)) {
  500. //
  501. // The next VSN is not at the beginning of a page (ie: the last page
  502. // in the vmcb has space in it for more sectors), so purge this
  503. // page in the metadata stream before updating the mapping information.
  504. //
  505. ASSERT( Vcb && Vcb->MetadataFcb );
  506. Offset.QuadPart = (ULONGLONG) BytesFromSectors( IrpContext->Vcb, AlignToPageBase( Vmcb, LocalVbn) );
  507. //
  508. // Block until all mappings through the vmcb stream have been dropped
  509. // before attempting the purge
  510. //
  511. UdfAcquireVmcbForCcPurge( IrpContext, IrpContext->Vcb);
  512. CcPurgeCacheSection( IrpContext->Vcb->MetadataFcb->FileObject->SectionObjectPointer,
  513. &Offset,
  514. PAGE_SIZE,
  515. FALSE );
  516. UdfReleaseVmcb( IrpContext, IrpContext->Vcb);
  517. }
  518. }
  519. else {
  520. //
  521. // All sectors on this volume should be readable, so we always extend the
  522. // vmcb a page at a time, hoping that metadata will be packed sensibly.
  523. // Because we always extend in page chunks, LocalVbn will be the last VSN
  524. // in a page aligned block, so +1 lands on the next page (aligned VSN) in
  525. // the VMCB stream.
  526. //
  527. LocalVbn += 1;
  528. LocalLbn = AlignToPageBase( Vmcb, Lbn);
  529. LocalCount = PadSectorCountToPage( Vmcb, SectorCount + (Lbn - LocalLbn));
  530. ASSERT( IsPageAligned( Vmcb, LocalVbn));
  531. }
  532. //
  533. // Add the double mapping
  534. //
  535. if (!FsRtlAddMcbEntry( &Vmcb->VbnIndexed,
  536. LocalVbn,
  537. LocalLbn,
  538. LocalCount )) {
  539. UdfRaiseStatus( IrpContext, STATUS_INTERNAL_ERROR);
  540. }
  541. VbnMcbAdded = TRUE;
  542. if (!FsRtlAddMcbEntry( &Vmcb->LbnIndexed,
  543. LocalLbn,
  544. LocalVbn,
  545. LocalCount )) {
  546. UdfRaiseStatus( IrpContext, STATUS_INTERNAL_ERROR);
  547. }
  548. LbnMcbAdded = TRUE;
  549. *Vbn = LocalVbn + (Lbn - LocalLbn);
  550. *AlignedSectorCount = LocalCount - (Lbn - LocalLbn);
  551. Result = TRUE;
  552. } finally {
  553. //
  554. // If this is an abnormal termination then clean up any mcb's that we
  555. // might have modified.
  556. //
  557. if (AbnormalTermination()) {
  558. if (VbnMcbAdded) { FsRtlRemoveMcbEntry( &Vmcb->VbnIndexed, LocalVbn, LocalCount ); }
  559. if (LbnMcbAdded) { FsRtlRemoveMcbEntry( &Vmcb->LbnIndexed, LocalLbn, LocalCount ); }
  560. }
  561. VmcbRelease( Vmcb);
  562. DebugUnwind("UdfAddVmcbMapping");
  563. if (Result) {
  564. DebugTrace(( 0, Dbg, " LocalVbn = %08x\n", LocalVbn ));
  565. DebugTrace(( 0, Dbg, " LocalLbn = %08x\n", LocalLbn ));
  566. DebugTrace(( 0, Dbg, " LocalCount = %08x\n", LocalCount ));
  567. DebugTrace(( 0, Dbg, " *Vbn = %08x\n", *Vbn ));
  568. DebugTrace(( 0, Dbg, " *AlignedSectorCount = %08x\n", *AlignedSectorCount ));
  569. }
  570. DebugTrace((-1, Dbg, "UdfAddVmcbMapping -> %08x\n", Result ));
  571. }
  572. return Result;
  573. }
  574. VOID
  575. UdfRemoveVmcbMapping (
  576. IN PVMCB Vmcb,
  577. IN VBN Vbn,
  578. IN ULONG SectorCount
  579. )
  580. /*++
  581. Routine Description:
  582. This routine removes a Vmcb mapping.
  583. If pool is not available to store the information this routine will
  584. raise a status value indicating insufficient resources.
  585. Arguments:
  586. Vmcb - Supplies the Vmcb being updated.
  587. Vbn - Supplies the VBN to remove
  588. SectorCount - Supplies the number of sectors to remove.
  589. Return Value:
  590. None.
  591. --*/
  592. {
  593. LBN Lbn;
  594. ULONG LocalCount;
  595. ULONG i;
  596. PAGED_CODE();
  597. DebugTrace((+1, Dbg, "UdfRemoveVmcbMapping, Vbn = %08x\n", Vbn ));
  598. DebugTrace(( 0, Dbg, " SectorCount = %08x\n", SectorCount ));
  599. //
  600. // Now grab the resource exclusive
  601. //
  602. VmcbLockForModify( Vmcb);
  603. try {
  604. for (i = 0; i < SectorCount; i += 1) {
  605. //
  606. // Lookup the Vbn so we can get its current Lbn mapping
  607. //
  608. if (!UdfVmcbLookupMcbEntry( &Vmcb->VbnIndexed,
  609. Vbn + i,
  610. &Lbn,
  611. &LocalCount,
  612. NULL )) {
  613. UdfBugCheck( 0, 0, 0 );
  614. }
  615. FsRtlRemoveMcbEntry( &Vmcb->VbnIndexed,
  616. Vbn + i,
  617. 1 );
  618. FsRtlRemoveMcbEntry( &Vmcb->LbnIndexed,
  619. Lbn,
  620. 1 );
  621. }
  622. {
  623. DebugTrace(( 0, Dbg, "VbnIndex:\n", 0 ));
  624. DebugTrace(( 0, Dbg, "LbnIndex:\n", 0 ));
  625. }
  626. } finally {
  627. VmcbRelease( Vmcb);
  628. DebugUnwind( "UdfRemoveVmcbMapping" );
  629. DebugTrace(( -1, Dbg, "UdfRemoveVmcbMapping -> VOID\n" ));
  630. }
  631. return;
  632. }
  633. //
  634. // Local support routine
  635. //
  636. BOOLEAN
  637. UdfVmcbLookupMcbEntry (
  638. IN PMCB Mcb,
  639. IN VBN Vbn,
  640. OUT PLBN Lbn,
  641. OUT PULONG SectorCount OPTIONAL,
  642. OUT PULONG Index OPTIONAL
  643. )
  644. /*++
  645. Routine Description:
  646. This routine retrieves the mapping of a Vbn to an Lbn from an Mcb.
  647. It indicates if the mapping exists and the size of the run.
  648. The only difference betweent this and the regular FsRtlLookupMcbEntry
  649. is that we undo the behavior of returning TRUE in holes in the allocation.
  650. This is because we don't want to avoid mapping at Lbn 0, which is how the
  651. emulated behavior of the small Mcb package tells callers that there is no
  652. mapping at that location in a hole. We have holes all over our Vbn space
  653. in the VbnIndexed map.
  654. The small Mcb package was able to get away with this because Lbn 0 was the
  655. boot sector (or similar magic location) on the disc. In our metadata stream,
  656. we wish to use Vbn 0 (remember this is a double map).
  657. Arguments:
  658. Mcb - Supplies the Mcb being examined.
  659. Vbn - Supplies the Vbn to lookup.
  660. Lbn - Receives the Lbn corresponding to the Vbn. A value of -1 is
  661. returned if the Vbn does not have a corresponding Lbn.
  662. SectorCount - Receives the number of sectors that map from the Vbn to
  663. contiguous Lbn values beginning with the input Vbn.
  664. Index - Receives the index of the run found.
  665. Return Value:
  666. BOOLEAN - TRUE if the Vbn is within the range of VBNs mapped by the
  667. MCB (not if it corresponds to a hole in the mapping), and FALSE
  668. if the Vbn is beyond the range of the MCB's mapping.
  669. For example, if an MCB has a mapping for VBNs 5 and 7 but not for
  670. 6, then a lookup on Vbn 5 or 7 will yield a non zero Lbn and a sector
  671. count of 1. A lookup for Vbn 6 will return FALSE with an Lbn value of
  672. 0, and lookup for Vbn 8 or above will return FALSE.
  673. --*/
  674. {
  675. BOOLEAN Results;
  676. LONGLONG LiLbn = 0;
  677. LONGLONG LiSectorCount = 0;
  678. Results = FsRtlLookupLargeMcbEntry( (PLARGE_MCB)Mcb,
  679. (LONGLONG)(Vbn),
  680. &LiLbn,
  681. ARGUMENT_PRESENT(SectorCount) ? &LiSectorCount : NULL,
  682. NULL,
  683. NULL,
  684. Index );
  685. if ((ULONG)LiLbn == -1) {
  686. *Lbn = 0;
  687. Results = FALSE;
  688. } else {
  689. *Lbn = (ULONG)LiLbn;
  690. }
  691. if (ARGUMENT_PRESENT(SectorCount)) { *SectorCount = ((ULONG)LiSectorCount); }
  692. return Results;
  693. }