Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

vmcbsup.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 VmcbSup.c 00008 00009 Abstract: 00010 00011 Historical note: this package was originally written for HPFS (pinball) 00012 and is now resurrected for UDFS. Since UDFS is readonly in initial 00013 versions we will snip by #ifdef the write support, leaving it visible 00014 for the future - this code has not been changed (nearly) whatsoever and 00015 is left named as Pb (pinball) code. 00016 00017 The VMCB routines provide support for maintaining a mapping between 00018 LBNs and VBNs for a virtual volume file. The volume file is all 00019 of the sectors that make up the on-disk structures. A file system 00020 uses this package to map LBNs for on-disk structure to VBNs in a volume 00021 file. This when used in conjunction with Memory Management and the 00022 Cache Manager will treat the volume file as a simple mapped file. A 00023 variable of type VMCB is used to store the mapping information and one 00024 is needed for every mounted volume. 00025 00026 The main idea behind this package is to allow the user to dynamically 00027 read in new disk structure sectors (e.g., File Entries). The user assigns 00028 the new sector a VBN in the Volume file and has memory management fault 00029 the page containing the sector into memory. To do this Memory management 00030 will call back into the file system to read the page from the volume file 00031 passing in the appropriate VBN. Now the file system takes the VBN and 00032 maps it back to its LBN and does the read. 00033 00034 The granularity of mapping is one a per page basis. That is if 00035 a mapping for LBN 8 is added to the VMCB structure and the page size 00036 is 8 sectors then the VMCB routines will actually assign a mapping for 00037 LBNS 8 through 15, and they will be assigned to a page aligned set of 00038 VBNS. This function is needed to allow us to work efficiently with 00039 memory management. This means that some sectors in some pages might 00040 actually contain regular file data and not volume information, and so 00041 when writing the page out we must only write the sectors that are really 00042 in use by the volume file. To help with this we provide a set 00043 of routines to keep track of dirty volume file sectors. 00044 That way, when the file system is called to write a page to the volume 00045 file, it will only write the sectors that are dirty. 00046 00047 Concurrent access the VMCB structure is control by this package. 00048 00049 The functions provided in this package are as follows: 00050 00051 o UdfInitializeVmcb - Initialize a new VMCB structure. 00052 00053 o UdfUninitializeVmcb - Uninitialize an existing VMCB structure. 00054 00055 o UdfSetMaximumLbnVmcb - Sets/Resets the maximum allowed LBN 00056 for the specified VMCB structure. 00057 00058 o UdfAddVmcbMapping - This routine takes an LBN and assigns to it 00059 a VBN. If the LBN already was assigned to an VBN it simply returns 00060 the old VBN and does not do a new assignemnt. 00061 00062 o UdfRemoveVmcbMapping - This routine takes an LBN and removes its 00063 mapping from the VMCB structure. 00064 00065 o UdfVmcbVbnToLbn - This routine takes a VBN and returns the 00066 LBN it maps to. 00067 00068 o UdfVmcbLbnToVbn - This routine takes an LBN and returns the 00069 VBN its maps to. 00070 00071 #if VMCB_WRITE_SUPPORT 00072 00073 o PbSetDirtyVmcb - This routine is used to mark sectors dirty 00074 in the volume file. 00075 00076 o PbSetCleanVmcb - This routine is used to mark sectors clean 00077 in the volume file. 00078 00079 o PbGetDirtySectorsVmcb - This routine is used to retrieve the 00080 dirty sectors for a page in the volume file. 00081 00082 o PbGetAndCleanDirtyVmcb - This routine is used to retrieve the 00083 dirty sectors for a page in the volume file and atomically clear 00084 the dirty sectors. 00085 00086 #endif // VMCB_WRITE_SUPPORT 00087 00088 Authors: 00089 00090 Gary Kimura [GaryKi] 4-Apr-1990 00091 Dan Lovinger [DanLo] 10-Sep-1996 00092 00093 Revision History: 00094 00095 --*/ 00096 00097 #include "UdfProcs.h" 00098 00099 // 00100 // The Bug check file id for this module 00101 // 00102 00103 #define BugCheckFileId (UDFS_BUG_CHECK_VMCBSUP) 00104 00105 // 00106 // The local debug trace level 00107 // 00108 00109 #define Dbg (UDFS_DEBUG_LEVEL_VMCBSUP) 00110 00111 // 00112 // Turn off write/dirty/clean sector support 00113 // 00114 00115 #define VMCB_WRITE_SUPPORT 0 00116 00117 00118 // 00119 // The following macro is used to calculate the number of pages (in terms of 00120 // sectors) needed to contain a given sector count. For example, 00121 // 00122 // PageAlign( 0 Sectors ) = 0 Pages = 0 Sectors 00123 // PageAlign( 1 Sectors ) = 1 Page = 8 Sectors 00124 // PageAlign( 2 Sectors ) = 1 Page = 8 Sectors 00125 // 00126 00127 #define PageAlign(V, L) ((((L)+((PAGE_SIZE/(V)->SectorSize)-1))/(PAGE_SIZE/(V)->SectorSize))*(PAGE_SIZE/(V)->SectorSize)) 00128 00129 00130 #if VMCB_WRITE_SUPPORT 00131 00132 // 00133 // The following constant is a bit mask, with one bit set for each sector 00134 // that'll fit in a page (4K page, 8 bits; 8K page, 16 bits, etc) 00135 // 00136 00137 #define SECTOR_MASK ((1 << (PAGE_SIZE / sizeof (SECTOR))) - 1) 00138 00139 // 00140 // The Dirty Page structure are elements in the dirty table generic table. 00141 // This is followed by the procedure prototypes for the local generic table 00142 // routines 00143 // 00144 00145 typedef struct _DIRTY_PAGE { 00146 ULONG LbnPageNumber; 00147 ULONG DirtyMask; 00148 } DIRTY_PAGE; 00149 typedef DIRTY_PAGE *PDIRTY_PAGE; 00150 00151 RTL_GENERIC_COMPARE_RESULTS 00152 PbCompareDirtyVmcb ( 00153 IN PRTL_GENERIC_TABLE DirtyTable, 00154 IN PVOID FirstStruct, 00155 IN PVOID SecondStruct 00156 ); 00157 00158 PVOID 00159 PbAllocateDirtyVmcb ( 00160 IN PRTL_GENERIC_TABLE DirtyTable, 00161 IN CLONG ByteSize 00162 ); 00163 00164 VOID 00165 PbDeallocateDirtyVmcb ( 00166 IN PRTL_GENERIC_TABLE DirtyTable, 00167 IN PVOID Buffer 00168 ); 00169 00170 ULONG 00171 PbDumpDirtyVmcb ( 00172 IN PVMCB Vmcb 00173 ); 00174 00175 #endif // VMCB_WRITE_SUPPORT 00176 00177 // 00178 // Local Routines. 00179 // 00180 00181 BOOLEAN 00182 UdfVmcbLookupMcbEntry ( 00183 IN PMCB Mcb, 00184 IN VBN Vbn, 00185 OUT PLBN Lbn, 00186 OUT PULONG SectorCount OPTIONAL, 00187 OUT PULONG Index OPTIONAL 00188 ); 00189 00190 00191 #ifdef ALLOC_PRAGMA 00192 #pragma alloc_text(PAGE, UdfAddVmcbMapping) 00193 00194 #if VMCB_WRITE_SUPPORT 00195 #pragma alloc_text(PAGE, PbAllocateDirtyVmcb) 00196 #pragma alloc_text(PAGE, PbDeallocateDirtyVmcb) 00197 #pragma alloc_text(PAGE, PbDumpDirtyVmcb) 00198 #pragma alloc_text(PAGE, PbGetAndCleanDirtyVmcb) 00199 #endif // VMCB_WRITE_SUPPORT 00200 00201 #pragma alloc_text(PAGE, UdfInitializeVmcb) 00202 #pragma alloc_text(PAGE, UdfRemoveVmcbMapping) 00203 #pragma alloc_text(PAGE, UdfResetVmcb) 00204 00205 #if VMCB_WRITE_SUPPORT 00206 #pragma alloc_text(PAGE, PbSetCleanVmcb) 00207 #pragma alloc_text(PAGE, PbSetDirtyVmcb) 00208 #endif // VMCB_WRITE_SUPPORT 00209 00210 #pragma alloc_text(PAGE, UdfSetMaximumLbnVmcb) 00211 #pragma alloc_text(PAGE, UdfUninitializeVmcb) 00212 #pragma alloc_text(PAGE, UdfVmcbLbnToVbn) 00213 #pragma alloc_text(PAGE, UdfVmcbLookupMcbEntry) 00214 #pragma alloc_text(PAGE, UdfVmcbVbnToLbn) 00215 #endif 00216 00217 00218 VOID 00219 UdfInitializeVmcb ( 00220 IN PVMCB Vmcb, 00221 IN POOL_TYPE PoolType, 00222 IN ULONG MaximumLbn, 00223 IN ULONG SectorSize 00224 ) 00225 00226 /*++ 00227 00228 Routine Description: 00229 00230 This routine initializes a new Vmcb Structure. The caller must 00231 supply the memory for the structure. This must precede all other calls 00232 that set/query the volume file mapping. 00233 00234 If pool is not available this routine will raise a status value 00235 indicating insufficient resources. 00236 00237 Arguments: 00238 00239 Vmcb - Supplies a pointer to the volume file structure to initialize. 00240 00241 PoolType - Supplies the pool type to use when allocating additional 00242 internal structures. 00243 00244 MaximumLbn - Supplies the maximum Lbn value that is valid for this 00245 volume. 00246 00247 LbSize - Size of a sector on this volume 00248 00249 Return Value: 00250 00251 None 00252 00253 --*/ 00254 00255 { 00256 BOOLEAN VbnInitialized; 00257 BOOLEAN LbnInitialized; 00258 00259 PAGED_CODE(); 00260 00261 DebugTrace(( +1, Dbg, "UdfInitializeVmcb, Vmcb = %08x\n", Vmcb )); 00262 00263 VbnInitialized = FALSE; 00264 LbnInitialized = FALSE; 00265 00266 try { 00267 00268 // 00269 // Initialize the fields in the vmcb structure 00270 // 00271 00272 KeInitializeMutex( &Vmcb->Mutex, 0 ); 00273 00274 FsRtlInitializeMcb( &Vmcb->VbnIndexed, PoolType ); 00275 VbnInitialized = TRUE; 00276 00277 FsRtlInitializeMcb( &Vmcb->LbnIndexed, PoolType ); 00278 LbnInitialized = TRUE; 00279 00280 Vmcb->MaximumLbn = MaximumLbn; 00281 00282 Vmcb->SectorSize = SectorSize; 00283 00284 #if VMCB_WRITE_SUPPORT 00285 00286 // 00287 // For the dirty table we store in the table context field the pool 00288 // type to use for allocating additional structures 00289 // 00290 00291 RtlInitializeGenericTable( &Vmcb->DirtyTable, 00292 PbCompareDirtyVmcb, 00293 PbAllocateDirtyVmcb, 00294 PbDeallocateDirtyVmcb, 00295 (PVOID)PoolType ); 00296 00297 #endif // VMCB_WRITE_SUPPORT 00298 00299 } finally { 00300 00301 // 00302 // If this is an abnormal termination then check if we need to 00303 // uninitialize the mcb structures 00304 // 00305 00306 if (AbnormalTermination()) { 00307 00308 if (VbnInitialized) { FsRtlUninitializeMcb( &Vmcb->VbnIndexed ); } 00309 if (LbnInitialized) { FsRtlUninitializeMcb( &Vmcb->LbnIndexed ); } 00310 } 00311 00312 DebugUnwind("UdfInitializeVmcb"); 00313 DebugTrace(( -1, Dbg, "UdfInitializeVmcb -> VOID\n" )); 00314 } 00315 00316 // 00317 // And return to our caller 00318 // 00319 00320 return; 00321 } 00322 00323 00324 VOID 00325 UdfUninitializeVmcb ( 00326 IN PVMCB Vmcb 00327 ) 00328 00329 /*++ 00330 00331 Routine Description: 00332 00333 This routine uninitializes an existing VMCB structure. After calling 00334 this routine the input VMCB structure must be re-initialized before 00335 being used again. 00336 00337 Arguments: 00338 00339 Vmcb - Supplies a pointer to the VMCB structure to uninitialize. 00340 00341 Return Value: 00342 00343 None. 00344 00345 --*/ 00346 00347 { 00348 PAGED_CODE(); 00349 00350 DebugTrace(( +1, Dbg, "UdfUninitializeVmcb, Vmcb = %08x\n", Vmcb )); 00351 00352 // 00353 // Unitialize the fields in the Vmcb structure 00354 // 00355 00356 FsRtlUninitializeMcb( &Vmcb->VbnIndexed ); 00357 FsRtlUninitializeMcb( &Vmcb->LbnIndexed ); 00358 00359 // 00360 // And return to our caller 00361 // 00362 00363 DebugTrace(( -1, Dbg, "UdfUninitializeVmcb -> VOID\n" )); 00364 00365 return; 00366 } 00367 00368 00369 VOID 00370 UdfResetVmcb ( 00371 IN PVMCB Vmcb 00372 ) 00373 00374 /*++ 00375 00376 Routine Description: 00377 00378 This routine resets the mappings in an existing VMCB structure. 00379 00380 Arguments: 00381 00382 Vmcb - Supplies a pointer to the VMCB structure to reset. 00383 00384 Return Value: 00385 00386 None. 00387 00388 --*/ 00389 00390 { 00391 PAGED_CODE(); 00392 00393 DebugTrace(( +1, Dbg, "UdfResetVmcb, Vmcb = %08x\n", Vmcb )); 00394 00395 // 00396 // Unitialize the fields in the Vmcb structure 00397 // 00398 00399 FsRtlResetLargeMcb( (PLARGE_MCB) &Vmcb->VbnIndexed, TRUE ); 00400 FsRtlResetLargeMcb( (PLARGE_MCB) &Vmcb->LbnIndexed, TRUE ); 00401 00402 // 00403 // And return to our caller 00404 // 00405 00406 DebugTrace(( -1, Dbg, "UdfResetVmcb -> VOID\n" )); 00407 00408 return; 00409 } 00410 00411 00412 VOID 00413 UdfSetMaximumLbnVmcb ( 00414 IN PVMCB Vmcb, 00415 IN ULONG MaximumLbn 00416 ) 00417 00418 /*++ 00419 00420 Routine Description: 00421 00422 This routine sets/resets the maximum allowed LBN for the specified 00423 Vmcb structure. The Vmcb structure must already have been initialized 00424 by calling UdfInitializeVmcb. 00425 00426 Arguments: 00427 00428 Vmcb - Supplies a pointer to the volume file structure to initialize. 00429 00430 MaximumLbn - Supplies the maximum Lbn value that is valid for this 00431 volume. 00432 00433 Return Value: 00434 00435 None 00436 00437 --*/ 00438 00439 { 00440 PAGED_CODE(); 00441 00442 DebugTrace(( +1, Dbg, "UdfSetMaximumLbnVmcb, Vmcb = %08x\n", Vmcb )); 00443 00444 // 00445 // Set the field 00446 // 00447 00448 Vmcb->MaximumLbn = MaximumLbn; 00449 00450 // 00451 // And return to our caller 00452 // 00453 00454 DebugTrace(( -1, Dbg, "UdfSetMaximumLbnVmcb -> VOID\n" )); 00455 00456 return; 00457 } 00458 00459 00460 BOOLEAN 00461 UdfVmcbVbnToLbn ( 00462 IN PVMCB Vmcb, 00463 IN VBN Vbn, 00464 IN PLBN Lbn, 00465 OUT PULONG SectorCount OPTIONAL 00466 ) 00467 00468 /*++ 00469 00470 Routine Description: 00471 00472 This routine translates a VBN to an LBN. 00473 00474 Arguments: 00475 00476 Vmcb - Supplies the VMCB structure being queried. 00477 00478 Vbn - Supplies the VBN to translate from. 00479 00480 Lbn - Receives the LBN mapped by the input Vbn. This value is only valid 00481 if the function result is TRUE. 00482 00483 SectorCount - Optionally receives the number of sectors corresponding 00484 to the run. 00485 00486 Return Value: 00487 00488 BOOLEAN - TRUE if he Vbn has a valid mapping and FALSE otherwise. 00489 00490 --*/ 00491 00492 { 00493 BOOLEAN Result; 00494 00495 DebugTrace(( +1, Dbg, "UdfVmcbVbnToLbn, Vbn = %08x\n", Vbn )); 00496 00497 // 00498 // Now grab the mutex for the vmcb 00499 // 00500 00501 (VOID)KeWaitForSingleObject( &Vmcb->Mutex, 00502 Executive, 00503 KernelMode, 00504 FALSE, 00505 (PLARGE_INTEGER) NULL ); 00506 00507 try { 00508 00509 Result = UdfVmcbLookupMcbEntry( &Vmcb->VbnIndexed, 00510 Vbn, 00511 Lbn, 00512 SectorCount, 00513 NULL ); 00514 00515 DebugTrace(( 0, Dbg, "*Lbn = %08x\n", *Lbn )); 00516 00517 // 00518 // If the returned Lbn is greater than the maximum allowed Lbn 00519 // then return FALSE 00520 // 00521 00522 if (Result && (*Lbn > Vmcb->MaximumLbn)) { 00523 00524 try_leave( Result = FALSE ); 00525 } 00526 00527 // 00528 // If the last returned Lbn is greater than the maximum allowed Lbn 00529 // then bring in the sector count 00530 // 00531 00532 if (Result && 00533 ARGUMENT_PRESENT(SectorCount) && 00534 (*Lbn+*SectorCount-1 > Vmcb->MaximumLbn)) { 00535 00536 *SectorCount = (Vmcb->MaximumLbn - *Lbn + 1); 00537 } 00538 00539 } finally { 00540 00541 (VOID) KeReleaseMutex( &Vmcb->Mutex, FALSE ); 00542 00543 DebugUnwind("UdfVmcbVbnToLbn"); 00544 DebugTrace(( -1, Dbg, "UdfVmcbVbnToLbn -> Result = %08x\n", Result )); 00545 } 00546 00547 00548 return Result; 00549 } 00550 00551 00552 BOOLEAN 00553 UdfVmcbLbnToVbn ( 00554 IN PVMCB Vmcb, 00555 IN LBN Lbn, 00556 OUT PVBN Vbn, 00557 OUT PULONG SectorCount OPTIONAL 00558 ) 00559 00560 /*++ 00561 00562 Routine Description: 00563 00564 This routine translates an LBN to a VBN. 00565 00566 Arguments: 00567 00568 Vmcb - Supplies the VMCB structure being queried. 00569 00570 Lbn - Supplies the LBN to translate from. 00571 00572 Vbn - Recieves the VBN mapped by the input LBN. This value is 00573 only valid if the function result is TRUE. 00574 00575 SectorCount - Optionally receives the number of sectors corresponding 00576 to the run. 00577 00578 Return Value: 00579 00580 BOOLEAN - TRUE if the mapping is valid and FALSE otherwise. 00581 00582 --*/ 00583 00584 { 00585 BOOLEAN Result; 00586 00587 PAGED_CODE(); 00588 00589 DebugTrace(( +1, Dbg, "UdfVmcbLbnToVbn, Lbn = %08x\n", Lbn )); 00590 00591 // 00592 // If the requested Lbn is greater than the maximum allowed Lbn 00593 // then the result is FALSE 00594 // 00595 00596 if (Lbn > Vmcb->MaximumLbn) { 00597 00598 DebugTrace(( -1, Dbg, "Lbn too large, UdfVmcbLbnToVbn -> FALSE\n" )); 00599 00600 return FALSE; 00601 } 00602 00603 // 00604 // Now grab the mutex for the vmcb 00605 // 00606 00607 (VOID)KeWaitForSingleObject( &Vmcb->Mutex, 00608 Executive, 00609 KernelMode, 00610 FALSE, 00611 (PLARGE_INTEGER) NULL ); 00612 00613 try { 00614 00615 Result = UdfVmcbLookupMcbEntry( &Vmcb->LbnIndexed, 00616 Lbn, 00617 Vbn, 00618 SectorCount, 00619 NULL ); 00620 00621 DebugTrace(( 0, Dbg, "*Vbn = %08x\n", *Vbn )); 00622 00623 } finally { 00624 00625 (VOID) KeReleaseMutex( &Vmcb->Mutex, FALSE ); 00626 00627 00628 DebugUnwind("UdfVmcbLbnToVbn"); 00629 DebugTrace(( -1, Dbg, "UdfVmcbLbnToVbn -> Result = %08x\n", Result )); 00630 } 00631 00632 return Result; 00633 } 00634 00635 00636 BOOLEAN 00637 UdfAddVmcbMapping ( 00638 IN PVMCB Vmcb, 00639 IN LBN Lbn, 00640 IN ULONG SectorCount, 00641 IN BOOLEAN ExactEnd, 00642 OUT PVBN Vbn, 00643 OUT PULONG AlignedSectorCount 00644 ) 00645 00646 /*++ 00647 00648 Routine Description: 00649 00650 This routine adds a new LBN to VBN mapping to the VMCB structure. When 00651 a new LBN is added to the structure it does it only on page aligned 00652 boundaries. 00653 00654 If pool is not available to store the information this routine will 00655 raise a status value indicating insufficient resources. 00656 00657 Arguments: 00658 00659 Vmcb - Supplies the VMCB being updated. 00660 00661 Lbn - Supplies the starting LBN to add to VMCB. 00662 00663 SectorCount - Supplies the number of Sectors in the run 00664 00665 ExactEnd - Indicates that instead of aligning to map sectors beyond 00666 the end of the request, use a hole. Implies trying to look at 00667 these sectors could be undesireable. 00668 00669 Vbn - Receives the assigned VBN 00670 00671 AlignedSectorCount - Receives the actual sector count created in the 00672 Vmcb for page alignment purposes. Vbn+AlignedSectorCount-1 == LastVbn. 00673 00674 Return Value: 00675 00676 BOOLEAN - TRUE if this is a new mapping and FALSE if the mapping 00677 for the LBN already exists. If it already exists then the 00678 sector count for this new addition must already be in the 00679 VMCB structure 00680 00681 --*/ 00682 00683 { 00684 00685 BOOLEAN Result; 00686 00687 BOOLEAN VbnMcbAdded; 00688 BOOLEAN LbnMcbAdded; 00689 00690 LBN LocalLbn; 00691 VBN LocalVbn; 00692 ULONG LocalCount; 00693 00694 PAGED_CODE(); 00695 00696 DebugTrace(( +1, Dbg, "UdfAddVmcbMapping, Lbn = %08x\n", Lbn )); 00697 DebugTrace(( 0, Dbg, " SectorCount = %08x\n", SectorCount )); 00698 00699 ASSERT( SectorCount != 0 ); 00700 00701 VbnMcbAdded = FALSE; 00702 LbnMcbAdded = FALSE; 00703 00704 // 00705 // Now grab the mutex for the vmcb 00706 // 00707 00708 (VOID)KeWaitForSingleObject( &Vmcb->Mutex, 00709 Executive, 00710 KernelMode, 00711 FALSE, 00712 (PLARGE_INTEGER) NULL ); 00713 00714 try { 00715 00716 // 00717 // Check if the Lbn is already mapped, which means we find an entry 00718 // with a non zero mapping Vbn value. 00719 // 00720 00721 if (UdfVmcbLookupMcbEntry( &Vmcb->LbnIndexed, 00722 Lbn, 00723 Vbn, 00724 &LocalCount, 00725 NULL )) { 00726 00727 // 00728 // It is already mapped so now the sector count must not exceed 00729 // the count already in the run 00730 // 00731 00732 if (SectorCount <= LocalCount) { 00733 00734 try_leave( Result = FALSE ); 00735 } 00736 } 00737 00738 // 00739 // At this point, we did not find a full existing mapping for the 00740 // Lbn and count. But there might be some overlapping runs that we'll 00741 // need to now remove from the vmcb structure. So for each Lbn in 00742 // the range we're after, check to see if it is mapped and remove the 00743 // mapping. We only need to do this test if the sector count is less 00744 // than or equal to a page size. Because those are the only 00745 // structures that we know we'll try an remove/overwrite. 00746 // 00747 00748 if (SectorCount <= PageAlign(Vmcb, 1)) { 00749 00750 if (UdfVmcbLookupMcbEntry( &Vmcb->LbnIndexed, 00751 Lbn, 00752 Vbn, 00753 &LocalCount, 00754 NULL )) { 00755 00756 UdfRemoveVmcbMapping( Vmcb, *Vbn, PageAlign(Vmcb, 1) ); 00757 } 00758 } 00759 00760 // 00761 // We need to add this new run at the end of the Vbns. To do this we 00762 // need to look up the last mcb entry or use a vbn for the second 00763 // page, if the mcb is empty. We'll also special case the situation 00764 // where the last lbn of the mapping and the mapping we're adding 00765 // simply flow into each other in which case we'll not bother bumping 00766 // the vbn to a page alignment 00767 // 00768 00769 if (FsRtlLookupLastMcbEntry( &Vmcb->VbnIndexed, &LocalVbn, &LocalLbn )) { 00770 00771 if (LocalLbn + 1 == Lbn) { 00772 00773 LocalVbn = LocalVbn + 1; 00774 LocalLbn = LocalLbn + 1; 00775 00776 } else { 00777 00778 // 00779 // Get the next available Vbn Page, and calculate the 00780 // Lbn for the page containing the Lbn 00781 // 00782 00783 LocalVbn = PageAlign( Vmcb, LocalVbn + 1 ); 00784 LocalLbn = PageAlign( Vmcb, Lbn + 1 ) - PageAlign( Vmcb, 1 ); 00785 } 00786 00787 } else { 00788 00789 // 00790 // Get the first available Vbn page, and calculate the 00791 // Lbn for the page containing the Lbn. 00792 // 00793 00794 00795 LocalVbn = 0; 00796 LocalLbn = PageAlign( Vmcb, Lbn + 1 ) - PageAlign( Vmcb, 1 ); 00797 } 00798 00799 // 00800 // Calculate the number of sectors that we need to map to keep 00801 // everything on a page granularity. 00802 // 00803 00804 LocalCount = PageAlign( Vmcb, SectorCount + (Lbn - LocalLbn) ); 00805 00806 // 00807 // See if we should use a hole to map the alignment at the end of the request. 00808 // 00809 00810 if (ExactEnd && Lbn + SectorCount < LocalLbn + LocalCount) { 00811 00812 LocalCount = SectorCount + (Lbn - LocalLbn); 00813 } 00814 00815 // 00816 // Add the double mapping 00817 // 00818 00819 FsRtlAddMcbEntry( &Vmcb->VbnIndexed, 00820 LocalVbn, 00821 LocalLbn, 00822 LocalCount ); 00823 00824 VbnMcbAdded = TRUE; 00825 00826 FsRtlAddMcbEntry( &Vmcb->LbnIndexed, 00827 LocalLbn, 00828 LocalVbn, 00829 LocalCount ); 00830 00831 LbnMcbAdded = TRUE; 00832 00833 *Vbn = LocalVbn + (Lbn - LocalLbn); 00834 *AlignedSectorCount = LocalCount - (Lbn - LocalLbn); 00835 00836 try_leave( Result = TRUE ); 00837 00838 } finally { 00839 00840 // 00841 // If this is an abnormal termination then clean up any mcb's that we 00842 // might have modified. 00843 // 00844 00845 if (AbnormalTermination()) { 00846 00847 if (VbnMcbAdded) { FsRtlRemoveMcbEntry( &Vmcb->VbnIndexed, LocalVbn, LocalCount ); } 00848 if (LbnMcbAdded) { FsRtlRemoveMcbEntry( &Vmcb->LbnIndexed, LocalLbn, LocalCount ); } 00849 } 00850 00851 (VOID) KeReleaseMutex( &Vmcb->Mutex, FALSE ); 00852 00853 DebugUnwind("UdfAddVmcbMapping"); 00854 DebugTrace(( 0, Dbg, " LocalVbn = %08x\n", LocalVbn )); 00855 DebugTrace(( 0, Dbg, " LocalLbn = %08x\n", LocalLbn )); 00856 DebugTrace(( 0, Dbg, " LocalCount = %08x\n", LocalCount )); 00857 DebugTrace(( 0, Dbg, " *Vbn = %08x\n", *Vbn )); 00858 DebugTrace(( 0, Dbg, " *AlignedSectorCount = %08x\n", *AlignedSectorCount )); 00859 DebugTrace((-1, Dbg, "UdfAddVmcbMapping -> %08x\n", Result )); 00860 } 00861 00862 return Result; 00863 } 00864 00865 00866 VOID 00867 UdfRemoveVmcbMapping ( 00868 IN PVMCB Vmcb, 00869 IN VBN Vbn, 00870 IN ULONG SectorCount 00871 ) 00872 00873 /*++ 00874 00875 Routine Description: 00876 00877 This routine removes a Vmcb mapping. 00878 00879 If pool is not available to store the information this routine will 00880 raise a status value indicating insufficient resources. 00881 00882 Arguments: 00883 00884 Vmcb - Supplies the Vmcb being updated. 00885 00886 Vbn - Supplies the VBN to remove 00887 00888 SectorCount - Supplies the number of sectors to remove. 00889 00890 Return Value: 00891 00892 None. 00893 00894 --*/ 00895 00896 { 00897 LBN Lbn; 00898 ULONG LocalCount; 00899 ULONG i; 00900 00901 PAGED_CODE(); 00902 00903 DebugTrace((+1, Dbg, "UdfRemoveVmcbMapping, Vbn = %08x\n", Vbn )); 00904 DebugTrace(( 0, Dbg, " SectorCount = %08x\n", SectorCount )); 00905 00906 // 00907 // Now grab the mutex for the vmcb 00908 // 00909 00910 (VOID)KeWaitForSingleObject( &Vmcb->Mutex, 00911 Executive, 00912 KernelMode, 00913 FALSE, 00914 (PLARGE_INTEGER) NULL ); 00915 00916 try { 00917 00918 for (i = 0; i < SectorCount; i += 1) { 00919 00920 // 00921 // Lookup the Vbn so we can get its current Lbn mapping 00922 // 00923 00924 if (!UdfVmcbLookupMcbEntry( &Vmcb->VbnIndexed, 00925 Vbn + i, 00926 &Lbn, 00927 &LocalCount, 00928 NULL )) { 00929 00930 UdfBugCheck( 0, 0, 0 ); 00931 } 00932 00933 FsRtlRemoveMcbEntry( &Vmcb->VbnIndexed, 00934 Vbn + i, 00935 1 ); 00936 00937 FsRtlRemoveMcbEntry( &Vmcb->LbnIndexed, 00938 Lbn, 00939 1 ); 00940 } 00941 00942 { 00943 DebugTrace(( 0, Dbg, "VbnIndex:\n", 0 )); 00944 DebugTrace(( 0, Dbg, "LbnIndex:\n", 0 )); 00945 } 00946 00947 } finally { 00948 00949 (VOID) KeReleaseMutex( &Vmcb->Mutex, FALSE ); 00950 00951 DebugUnwind( "UdfRemoveVmcbMapping" ); 00952 DebugTrace(( -1, Dbg, "UdfRemoveVmcbMapping -> VOID\n" )); 00953 } 00954 00955 return; 00956 } 00957 00958 00959 // 00960 // Local support routine 00961 // 00962 00963 BOOLEAN 00964 UdfVmcbLookupMcbEntry ( 00965 IN PMCB Mcb, 00966 IN VBN Vbn, 00967 OUT PLBN Lbn, 00968 OUT PULONG SectorCount OPTIONAL, 00969 OUT PULONG Index OPTIONAL 00970 ) 00971 00972 /*++ 00973 00974 Routine Description: 00975 00976 This routine retrieves the mapping of a Vbn to an Lbn from an Mcb. 00977 It indicates if the mapping exists and the size of the run. 00978 00979 The only difference betweent this and the regular FsRtlLookupMcbEntry 00980 is that we undo the behavior of returning TRUE in holes in the allocation. 00981 This is because we don't want to avoid mapping at Lbn 0, which is how the 00982 emulated behavior of the small Mcb package tells callers that there is no 00983 mapping at that location in a hole. We have holes all over our Vbn space 00984 in the VbnIndexed map. 00985 00986 The small Mcb package was able to get away with this because Lbn 0 was the 00987 boot sector (or similar magic location) on the disc. In our metadata stream, 00988 we wish to use Vbn 0 (remember this is a double map). 00989 00990 Arguments: 00991 00992 Mcb - Supplies the Mcb being examined. 00993 00994 Vbn - Supplies the Vbn to lookup. 00995 00996 Lbn - Receives the Lbn corresponding to the Vbn. A value of -1 is 00997 returned if the Vbn does not have a corresponding Lbn. 00998 00999 SectorCount - Receives the number of sectors that map from the Vbn to 01000 contiguous Lbn values beginning with the input Vbn. 01001 01002 Index - Receives the index of the run found. 01003 01004 Return Value: 01005 01006 BOOLEAN - TRUE if the Vbn is within the range of VBNs mapped by the 01007 MCB (not if it corresponds to a hole in the mapping), and FALSE 01008 if the Vbn is beyond the range of the MCB's mapping. 01009 01010 For example, if an MCB has a mapping for VBNs 5 and 7 but not for 01011 6, then a lookup on Vbn 5 or 7 will yield a non zero Lbn and a sector 01012 count of 1. A lookup for Vbn 6 will return FALSE with an Lbn value of 01013 0, and lookup for Vbn 8 or above will return FALSE. 01014 01015 --*/ 01016 01017 { 01018 BOOLEAN Results; 01019 LONGLONG LiLbn; 01020 LONGLONG LiSectorCount; 01021 01022 Results = FsRtlLookupLargeMcbEntry( (PLARGE_MCB)Mcb, 01023 (LONGLONG)(Vbn), 01024 &LiLbn, 01025 ARGUMENT_PRESENT(SectorCount) ? &LiSectorCount : NULL, 01026 NULL, 01027 NULL, 01028 Index ); 01029 01030 if ((ULONG)LiLbn == -1) { 01031 01032 *Lbn = 0; 01033 Results = FALSE; 01034 01035 } else { 01036 01037 *Lbn = (ULONG)LiLbn; 01038 } 01039 01040 if (ARGUMENT_PRESENT(SectorCount)) { *SectorCount = ((ULONG)LiSectorCount); } 01041 01042 return Results; 01043 } 01044 01045 01046 #if VMCB_WRITE_SUPPORT 01047 VOID 01048 PbSetDirtyVmcb ( 01049 IN PVMCB Vmcb, 01050 IN ULONG LbnPageNumber, 01051 IN ULONG Mask 01052 ) 01053 01054 /*++ 01055 01056 Routine Description: 01057 01058 This routine sets the sectors within a page as dirty based on the input 01059 mask. 01060 01061 If pool is not available to store the information this routine will 01062 raise a status value indicating insufficient resources. 01063 01064 Arguments: 01065 01066 Vmcb - Supplies the Vmcb being manipulated. 01067 01068 LbnPageNumber - Supplies the Page Number (LBN based) of the page being 01069 modified. For example, with a page size of 8 a page number of 0 01070 corresponds to LBN values 0 through 7, a page number of 1 corresponds 01071 to 8 through 15, and so on. 01072 01073 Mask - Supplies the mask of dirty sectors to set for the Page (a 1 bit 01074 means to set it dirty). For example to set LBN 9 dirty on a system 01075 with a page size of 8 the LbnPageNumber will be 1, and the mask will 01076 be 0x00000002. 01077 01078 Return Value: 01079 01080 None. 01081 01082 --*/ 01083 01084 { 01085 DIRTY_PAGE Key; 01086 PDIRTY_PAGE Entry; 01087 01088 PAGED_CODE(); 01089 01090 DebugTrace(+1, Dbg, ( "UdfSetDirtyVmcb\n", 0 ) ); 01091 DebugTrace( 0, Dbg, ( " LbnPageNumber = %08x\n", LbnPageNumber ) ); 01092 DebugTrace( 0, Dbg, ( " Mask = %08x\n", Mask ) ); 01093 01094 Key.LbnPageNumber = LbnPageNumber; 01095 Key.DirtyMask = 0; 01096 01097 // 01098 // Now grab the mutex for the vmcb 01099 // 01100 01101 (VOID)KeWaitForSingleObject( &Vmcb->Mutex, 01102 Executive, 01103 KernelMode, 01104 FALSE, 01105 (PLARGE_INTEGER) NULL ); 01106 01107 try { 01108 01109 Entry = RtlInsertElementGenericTable( &Vmcb->DirtyTable, 01110 &Key, 01111 sizeof(DIRTY_PAGE), 01112 NULL ); 01113 01114 Entry->DirtyMask = (Entry->DirtyMask | Mask) & (SECTOR_MASK); //**** change to manifest constant 01115 01116 DebugTrace(0, Dbg, ( "DirtyMask = %08x\n", Entry->DirtyMask ) ); 01117 01118 { 01119 DebugTrace(0, Dbg, ( "", PbDumpDirtyVmcb(Vmcb) ) ); 01120 } 01121 01122 } finally { 01123 01124 (VOID) KeReleaseMutex( &Vmcb->Mutex, FALSE ); 01125 01126 DebugUnwind("UdfSetDirtyVmcb"); 01127 DebugTrace(-1, Dbg, ( "UdfSetDirtyVmcb -> VOID\n", 0 ) ); 01128 } 01129 01130 return; 01131 } 01132 #endif // VMCB_WRITE_SUPPORT 01133 01134 01135 #if VMCB_WRITE_SUPPORT 01136 VOID 01137 PbSetCleanVmcb ( 01138 IN PVMCB Vmcb, 01139 IN ULONG LbnPageNumber, 01140 IN ULONG Mask 01141 ) 01142 01143 /*++ 01144 01145 Routine Description: 01146 01147 This routine sets all of the sectors within a page as clean. All 01148 of the sectors in a page whether they are dirty or not are set clean 01149 by this procedure. 01150 01151 Arguments: 01152 01153 Vmcb - Supplies the Vmcb being manipulated. 01154 01155 LbnPageNumber - Supplies the Page Number (Lbn based) of page being 01156 modified. For example, with a page size of 8 a page number of 0 01157 corresponds to LBN values 0 through 7, a page number of 1 corresponds 01158 to 8 through 15, and so on. 01159 01160 Mask - Supplies the mask of clean sectors to set for the Page (a 1 bit 01161 means to set it clean). For example to set LBN 9 clean on a system 01162 with a page size of 8 the LbnPageNumber will be 1, and the mask will 01163 be 0x00000002. 01164 01165 Return Value: 01166 01167 None. 01168 01169 --*/ 01170 01171 { 01172 DIRTY_PAGE Key; 01173 PDIRTY_PAGE Entry; 01174 01175 PAGED_CODE(); 01176 01177 DebugTrace(+1, Dbg, ( "UdfSetCleanVmcb\n", 0 ) ); 01178 DebugTrace( 0, Dbg, ( " LbnPageNumber = %08x\n", LbnPageNumber ) ); 01179 DebugTrace( 0, Dbg, ( " Mask = %08x\n", Mask ) ); 01180 01181 Key.LbnPageNumber = LbnPageNumber; 01182 01183 // 01184 // Now grab the mutex for the vmcb 01185 // 01186 01187 (VOID)KeWaitForSingleObject( &Vmcb->Mutex, 01188 Executive, 01189 KernelMode, 01190 FALSE, 01191 (PLARGE_INTEGER) NULL ); 01192 01193 try { 01194 01195 // 01196 // If the page is not in the table, it is already all clean 01197 // 01198 01199 if (Entry = RtlLookupElementGenericTable( &Vmcb->DirtyTable, &Key )) { 01200 01201 Entry->DirtyMask &= ~Mask; 01202 01203 DebugTrace(0, Dbg, ( "DirtyMask = %08x\n", Entry->DirtyMask ) ); 01204 01205 // 01206 // If the mask is all clean now, delete the entry 01207 // 01208 01209 if (Entry->DirtyMask == 0) { 01210 01211 (VOID)RtlDeleteElementGenericTable( &Vmcb->DirtyTable, &Key ); 01212 } 01213 } 01214 01215 { 01216 DebugTrace(0, Dbg, ( "", PbDumpDirtyVmcb(Vmcb) ) ); 01217 } 01218 01219 } finally { 01220 01221 (VOID) KeReleaseMutex( &Vmcb->Mutex, FALSE ); 01222 01223 DebugTrace(-1, Dbg, ( "UdfSetCleanVcmb -> VOID\n", 0 ) ); 01224 } 01225 01226 return; 01227 } 01228 #endif // VMCB_WRITE_SUPPORT 01229 01230 01231 #if VMCB_WRITE_SUPPORT 01232 ULONG 01233 PbGetDirtySectorsVmcb ( 01234 IN PVMCB Vmcb, 01235 IN ULONG LbnPageNumber 01236 ) 01237 01238 /*++ 01239 01240 Routine Description: 01241 01242 This routine returns to its caller a mask of dirty sectors within a page. 01243 01244 Arguments: 01245 01246 Vmcb - Supplies the Vmcb being manipulated 01247 01248 LbnPageNumber - Supplies the Page Number (Lbn based) of page being 01249 modified. For example, with a page size of 8 a page number of 0 01250 corresponds to LBN values 0 through 7, a page number of 1 corresponds 01251 to 8 through 15, and so on. 01252 01253 Return Value: 01254 01255 ULONG - Receives a mask of dirty sectors within the specified page. 01256 (a 1 bit indicates that the sector is dirty). 01257 01258 --*/ 01259 01260 { 01261 DIRTY_PAGE Key; 01262 PDIRTY_PAGE Entry; 01263 ULONG Mask; 01264 01265 DebugTrace(+1, Dbg, ( "UdfGetDirtySectorsVmcb\n", 0 ) ); 01266 DebugTrace( 0, Dbg, ( " LbnPageNumber = %08x\n", LbnPageNumber ) ); 01267 01268 Key.LbnPageNumber = LbnPageNumber; 01269 01270 // 01271 // Now grab the mutex for the vmcb 01272 // 01273 01274 (VOID)KeWaitForSingleObject( &Vmcb->Mutex, 01275 Executive, 01276 KernelMode, 01277 FALSE, 01278 (PLARGE_INTEGER) NULL ); 01279 01280 try { 01281 01282 if ((Entry = RtlLookupElementGenericTable( &Vmcb->DirtyTable, 01283 &Key )) == NULL) { 01284 01285 DebugTrace(0, Dbg, ( "Entry not found\n", 0 ) ); 01286 01287 try_leave( Mask = 0 ); 01288 } 01289 01290 Mask = Entry->DirtyMask & (SECTOR_MASK); //**** change to manifest constant 01291 01292 } finally { 01293 01294 (VOID) KeReleaseMutex( &Vmcb->Mutex, FALSE ); 01295 01296 DebugTrace(-1, Dbg, ( "UdfGetDirtySectorsVmcb -> %08x\n", Mask ) ); 01297 } 01298 01299 return Mask; 01300 } 01301 #endif // VMCB_WRITE_SUPPORT 01302 01303 01304 #if VMCB_WRITE_SUPPORT 01305 ULONG 01306 PbGetAndCleanDirtyVmcb ( 01307 IN PVMCB Vmcb, 01308 IN ULONG LbnPageNumber 01309 ) 01310 01311 /*++ 01312 01313 Routine Description: 01314 01315 This routine returns to its caller a mask of dirty sectors within a page, 01316 and atomically clear the bits. 01317 01318 Arguments: 01319 01320 Vmcb - Supplies the Vmcb being manipulated 01321 01322 LbnPageNumber - Supplies the Page Number (Lbn based) of page being 01323 modified. For example, with a page size of 8 a page number of 0 01324 corresponds to LBN values 0 through 7, a page number of 1 corresponds 01325 to 8 through 15, and so on. 01326 01327 Return Value: 01328 01329 ULONG - Receives a mask of dirty sectors within the specified page. 01330 (a 1 bit indicates that the sector is dirty). 01331 01332 --*/ 01333 01334 { 01335 DIRTY_PAGE Key; 01336 PDIRTY_PAGE Entry; 01337 ULONG Mask; 01338 01339 PAGED_CODE(); 01340 01341 DebugTrace(+1, Dbg, ( "UdfGetAndCleanDirtyVmcb\n", 0 ) ); 01342 DebugTrace( 0, Dbg, ( " LbnPageNumber = %08x\n", LbnPageNumber ) ); 01343 01344 Key.LbnPageNumber = LbnPageNumber; 01345 01346 // 01347 // Now grab the mutex for the vmcb 01348 // 01349 01350 (VOID)KeWaitForSingleObject( &Vmcb->Mutex, 01351 Executive, 01352 KernelMode, 01353 FALSE, 01354 (PLARGE_INTEGER) NULL ); 01355 01356 try { 01357 01358 // 01359 // Locate the dirty page within the dirty table 01360 // 01361 01362 if ((Entry = RtlLookupElementGenericTable( &Vmcb->DirtyTable, 01363 &Key )) == NULL) { 01364 01365 DebugTrace(0, Dbg, ( "Entry not found\n", 0 ) ); 01366 01367 try_leave( Mask = 0 ); 01368 } 01369 01370 // 01371 // We found a page so generate a proper mask and then 01372 // delete the dirty page 01373 // 01374 01375 Mask = Entry->DirtyMask & (SECTOR_MASK); //**** change to manifest constant 01376 01377 (VOID) RtlDeleteElementGenericTable( &Vmcb->DirtyTable, &Key ); 01378 01379 } finally { 01380 01381 (VOID) KeReleaseMutex( &Vmcb->Mutex, FALSE ); 01382 01383 DebugTrace(-1, Dbg, ( "UdfGetAndCleanDirtyVmcb -> %08x\n", Mask ) ); 01384 } 01385 01386 return Mask; 01387 } 01388 #endif // VMCB_WRITE_SUPPORT 01389 01390 01391 // 01392 // Local support routines 01393 // 01394 01395 #if VMCB_WRITE_SUPPORT 01396 RTL_GENERIC_COMPARE_RESULTS 01397 PbCompareDirtyVmcb ( 01398 IN PRTL_GENERIC_TABLE DirtyTable, 01399 IN PVOID FirstStruct, 01400 IN PVOID SecondStruct 01401 ) 01402 01403 /*++ 01404 01405 Routine Description: 01406 01407 This generic table support routine compares two dirty page structures 01408 01409 Arguments: 01410 01411 DirtyTable - Supplies the generic table being queried 01412 01413 FirstStruct - Really supplies the first structure to compare 01414 01415 SecondStruct - Really supplies the second structure to compare 01416 01417 Return Value: 01418 01419 RTL_GENERIDC_COMPARE_RESULTS - The results of comparing the two 01420 input structures 01421 01422 --*/ 01423 01424 { 01425 01426 PDIRTY_PAGE DirtyPage1 = FirstStruct; 01427 PDIRTY_PAGE DirtyPage2 = SecondStruct; 01428 01429 UNREFERENCED_PARAMETER( DirtyTable ); 01430 01431 PAGED_CODE(); 01432 01433 if (DirtyPage1->LbnPageNumber < DirtyPage2->LbnPageNumber) { 01434 01435 return GenericLessThan; 01436 01437 } else if (DirtyPage1->LbnPageNumber > DirtyPage2->LbnPageNumber) { 01438 01439 return GenericGreaterThan; 01440 01441 } else { 01442 01443 return GenericEqual; 01444 } 01445 } 01446 #endif // VMCB_WRITE_SUPPORT 01447 01448 01449 // 01450 // Local support routines 01451 // 01452 01453 #if VMCB_WRITE_SUPPORT 01454 PVOID 01455 PbAllocateDirtyVmcb ( 01456 IN PRTL_GENERIC_TABLE DirtyTable, 01457 IN CLONG ByteSize 01458 ) 01459 01460 /*++ 01461 01462 Routine Description: 01463 01464 This generic table support routine allocates memory 01465 01466 Arguments: 01467 01468 DirtyTable - Supplies the generic table being modified 01469 01470 ByteSize - Supplies the size, in bytes, to allocate 01471 01472 Return Value: 01473 01474 PVOID - Returns a pointer to the allocated data 01475 01476 --*/ 01477 01478 { 01479 PAGED_CODE(); 01480 01481 return FsRtlAllocatePoolWithTag( (POOL_TYPE)DirtyTable->TableContext, ByteSize, 'bcmV' ); 01482 } 01483 #endif // VMCB_WRITE_SUPPORT 01484 01485 01486 // 01487 // Local support routines 01488 // 01489 01490 #if VMCB_WRITE_SUPPORT 01491 VOID 01492 PbDeallocateDirtyVmcb ( 01493 IN PRTL_GENERIC_TABLE DirtyTable, 01494 IN PVOID Buffer 01495 ) 01496 01497 /*++ 01498 01499 Routine Description: 01500 01501 This generic table support routine deallocates memory 01502 01503 Arguments: 01504 01505 DirtyTable - Supplies the generic table being modified 01506 01507 Buffer - Supplies the buffer being deallocated 01508 01509 Return Value: 01510 01511 None. 01512 01513 --*/ 01514 01515 { 01516 UNREFERENCED_PARAMETER( DirtyTable ); 01517 01518 PAGED_CODE(); 01519 01520 ExFreePool( Buffer ); 01521 01522 return; 01523 } 01524 #endif // VMCB_WRITE_SUPPORT 01525 01526 01527 // 01528 // Local support routines 01529 // 01530 01531 #if VMCB_WRITE_SUPPORT 01532 ULONG 01533 PbDumpDirtyVmcb ( 01534 IN PVMCB Vmcb 01535 ) 01536 01537 /*++ 01538 01539 Routine Description: 01540 01541 Arguments: 01542 01543 Return Value: 01544 01545 --*/ 01546 01547 { 01548 PDIRTY_PAGE Ptr; 01549 01550 PAGED_CODE(); 01551 01552 KdPrint((" Dump Dirty Vmcb\n")); 01553 01554 for (Ptr = RtlEnumerateGenericTable( &Vmcb->DirtyTable, TRUE ); 01555 Ptr != NULL; 01556 Ptr = RtlEnumerateGenericTable( &Vmcb->DirtyTable, FALSE )) { 01557 01558 KdPrint((" LbnPageNumber = %08x, ", Ptr->LbnPageNumber )); 01559 KdPrint(("DirtyMask = %08x\n", Ptr->DirtyMask )); 01560 } 01561 01562 return 0; 01563 } 01564 #endif // VMCB_WRITE_SUPPORT 01565 01566 01567 #if VMCB_WRITE_SUPPORT 01568 NTSTATUS 01569 PbFlushVolumeFile ( 01570 IN PIRP_CONTEXT IrpContext, 01571 IN PVCB Vcb 01572 ) 01573 01574 /*++ 01575 01576 Routine Description: 01577 01578 The function carefully flushes the entire volume file. It is nessecary 01579 to dance around a bit because of complicated synchronization reasons. 01580 01581 Arguments: 01582 01583 Vcb - Supplies the Vcb being flushed 01584 01585 Return Value: 01586 01587 NTSTATUS - The status of the flush operation 01588 01589 --*/ 01590 01591 { 01592 ULONG ElementNumber; 01593 ULONG NumberOfDirtyPages; 01594 PULONG VbnsToFlush; 01595 01596 LBN Lbn; 01597 PDIRTY_PAGE Ptr; 01598 01599 NTSTATUS ReturnStatus = STATUS_SUCCESS; 01600 01601 PVMCB Vmcb = (PNONOPAQUE_VMCB)&Vcb->Vmcb; 01602 01603 // 01604 // The only way we have to correctly synchronize things is to 01605 // repin stuff, and then unpin repin it with WriteThrough as TRUE. 01606 // 01607 // Grab the mutex for the vmcb 01608 // 01609 01610 (VOID)KeWaitForSingleObject( &Vmcb->Mutex, 01611 Executive, 01612 KernelMode, 01613 FALSE, 01614 (PLARGE_INTEGER) NULL ); 01615 01616 NumberOfDirtyPages = RtlNumberGenericTableElements(&Vmcb->DirtyTable); 01617 01618 // 01619 // If there are no dirty sectors, no need to flush. 01620 // 01621 01622 if (NumberOfDirtyPages == 0) { 01623 01624 (VOID)KeReleaseMutex( &Vmcb->Mutex, FALSE ); 01625 return STATUS_SUCCESS; 01626 } 01627 01628 try { 01629 01630 VbnsToFlush = FsRtlAllocatePoolWithTag( PagedPool, NumberOfDirtyPages * sizeof(ULONG), 'bcmV' ); 01631 01632 } finally { 01633 01634 if (AbnormalTermination()) { 01635 01636 (VOID)KeReleaseMutex( &Vmcb->Mutex, FALSE ); 01637 } 01638 } 01639 01640 for (Ptr = RtlEnumerateGenericTable( &Vmcb->DirtyTable, TRUE ), 01641 ElementNumber = 0; 01642 Ptr != NULL; 01643 Ptr = RtlEnumerateGenericTable( &Vmcb->DirtyTable, FALSE ), 01644 ElementNumber += 1) { 01645 01646 VBN Vbn; 01647 BOOLEAN Result; 01648 01649 // 01650 // Lbn pages always map to Vbn pages. Thus any sector in an Lbn 01651 // page will map to the same Vbn page. So it suffices to map the 01652 // first Lbn in the page to a Vbn and flush that page. 01653 // 01654 01655 Lbn = Ptr->LbnPageNumber * (PAGE_SIZE / 512); 01656 01657 ASSERT(Ptr->DirtyMask != 0); 01658 01659 Result = PbVmcbLbnToVbn( &Vcb->Vmcb, Lbn, &Vbn, NULL ); 01660 01661 // 01662 // This lookup must work as the LBN page was dirty. 01663 // 01664 01665 if (!Result) { 01666 01667 PbBugCheck( 0, 0, 0 ); 01668 } 01669 01670 // 01671 // Bring store this Vbn away for flushing later. 01672 // 01673 01674 ASSERT( ElementNumber < NumberOfDirtyPages ); 01675 ASSERT( (Vbn & (PAGE_SIZE/512 - 1)) == 0 ); 01676 01677 VbnsToFlush[ElementNumber] = Vbn; 01678 } 01679 01680 ASSERT( ElementNumber == NumberOfDirtyPages ); 01681 01682 // 01683 // Now drop the mutex and walk through the dirty Vbn list generated 01684 // above. We cannot hold the mutex while doing IO as this will cause 01685 // a deadlock with the cache manager. 01686 // 01687 01688 (VOID)KeReleaseMutex( &Vmcb->Mutex, FALSE ); 01689 01690 for ( ElementNumber = 0; 01691 ElementNumber < NumberOfDirtyPages; 01692 ElementNumber += 1) { 01693 01694 PBCB Bcb; 01695 PVOID DontCare; 01696 LARGE_INTEGER Offset; 01697 IO_STATUS_BLOCK Iosb; 01698 01699 // 01700 // This page is dirty. Flush it by writing it though. 01701 // 01702 01703 Offset.QuadPart = VbnsToFlush[ElementNumber] << 9; 01704 01705 try { 01706 01707 (VOID)CcPinRead( Vcb->VirtualVolumeFile, 01708 &Offset, 01709 PAGE_SIZE, 01710 TRUE, 01711 &Bcb, 01712 &DontCare ); 01713 01714 CcSetDirtyPinnedData( Bcb, NULL ); 01715 CcRepinBcb( Bcb ); 01716 CcUnpinData( Bcb ); 01717 CcUnpinRepinnedBcb( Bcb, TRUE, &Iosb ); 01718 01719 if (!NT_SUCCESS(Iosb.Status)) { 01720 01721 ReturnStatus = Iosb.Status; 01722 } 01723 01724 } except(PbExceptionFilter(IrpContext, GetExceptionInformation())) { 01725 01726 ReturnStatus = IrpContext->ExceptionStatus; 01727 } 01728 } 01729 01730 ExFreePool( VbnsToFlush ); 01731 01732 return ReturnStatus; 01733 } 01734 #endif // VMCB_WRITE_SUPPORT 01735

Generated on Sat May 15 19:42:24 2004 for test by doxygen 1.3.7