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

hivesync.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1991 Microsoft Corporation 00004 00005 Module Name: 00006 00007 hivesync.c 00008 00009 Abstract: 00010 00011 This module implements procedures to write dirty parts of a hive's 00012 stable store to backing media. 00013 00014 Author: 00015 00016 Bryan M. Willman (bryanwi) 28-Mar-92 00017 00018 Environment: 00019 00020 00021 Revision History: 00022 00023 --*/ 00024 00025 #include "cmp.h" 00026 00027 extern BOOLEAN HvShutdownComplete; // Set to true after shutdown 00028 // to disable any further I/O 00029 00030 #if DBG 00031 #define DumpDirtyVector(Hive) \ 00032 { \ 00033 PRTL_BITMAP BitMap; \ 00034 ULONG BitMapSize; \ 00035 PUCHAR BitBuffer; \ 00036 ULONG i; \ 00037 UCHAR Byte; \ 00038 \ 00039 BitMap = &(Hive->DirtyVector); \ 00040 BitMapSize = (BitMap->SizeOfBitMap) / 8; \ 00041 BitBuffer = (PUCHAR)(BitMap->Buffer); \ 00042 for (i = 0; i < BitMapSize; i++) { \ 00043 if ((i % 8) == 0) { \ 00044 KdPrint(("\n\t")); \ 00045 } \ 00046 Byte = BitBuffer[i]; \ 00047 KdPrint(("%02x ", Byte)); \ 00048 } \ 00049 KdPrint(("\n")); \ 00050 } 00051 #else 00052 #define DumpDirtyVector(Hive) 00053 #endif 00054 00055 // 00056 // Private prototypes 00057 // 00058 BOOLEAN 00059 HvpWriteLog( 00060 PHHIVE Hive 00061 ); 00062 00063 BOOLEAN 00064 HvpFindNextDirtyBlock( 00065 PHHIVE Hive, 00066 PRTL_BITMAP BitMap, 00067 PULONG Current, 00068 PUCHAR *Address, 00069 PULONG Length, 00070 PULONG Offset 00071 ); 00072 00073 VOID 00074 HvpDiscardBins( 00075 PHHIVE Hive 00076 ); 00077 00078 VOID 00079 HvpTruncateBins( 00080 PHHIVE Hive 00081 ); 00082 00083 VOID 00084 HvRefreshHive( 00085 PHHIVE Hive 00086 ); 00087 00088 #ifdef ALLOC_PRAGMA 00089 #pragma alloc_text(PAGE,HvMarkCellDirty) 00090 #pragma alloc_text(PAGE,HvIsBinDirty) 00091 #pragma alloc_text(PAGE,HvMarkDirty) 00092 #pragma alloc_text(PAGE,HvMarkClean) 00093 #pragma alloc_text(PAGE,HvpGrowLog1) 00094 #pragma alloc_text(PAGE,HvpGrowLog2) 00095 #pragma alloc_text(PAGE,HvSyncHive) 00096 #pragma alloc_text(PAGE,HvpDoWriteHive) 00097 #pragma alloc_text(PAGE,HvpWriteLog) 00098 #pragma alloc_text(PAGE,HvpFindNextDirtyBlock) 00099 #pragma alloc_text(PAGE,HvWriteHive) 00100 #pragma alloc_text(PAGE,HvRefreshHive) 00101 #pragma alloc_text(PAGE,HvpDiscardBins) 00102 #pragma alloc_text(PAGE,HvpTruncateBins) 00103 00104 #ifdef _WRITE_PROTECTED_REGISTRY_POOL 00105 #pragma alloc_text(PAGE,HvpChangeBinAllocation) 00106 #pragma alloc_text(PAGE,HvpMarkBinReadWrite) 00107 #endif 00108 00109 #endif 00110 00111 00112 00113 // 00114 // Code for tracking modifications and ensuring adequate log space 00115 // 00116 BOOLEAN 00117 HvMarkCellDirty( 00118 PHHIVE Hive, 00119 HCELL_INDEX Cell 00120 ) 00121 /*++ 00122 00123 Routine Description: 00124 00125 Marks the data for the specified cell dirty. 00126 00127 Arguments: 00128 00129 Hive - supplies a pointer to the hive control structure for the 00130 hive of interest 00131 00132 Cell - hcell_index of cell that is being edited 00133 00134 Return Value: 00135 00136 TRUE - it worked 00137 00138 FALSE - could not allocate log space, failure! 00139 00140 --*/ 00141 { 00142 ULONG Type; 00143 ULONG Size; 00144 PHCELL pCell; 00145 PHMAP_ENTRY Me; 00146 HCELL_INDEX Base; 00147 PHBIN Bin; 00148 00149 CMLOG(CML_MINOR, CMS_IO) { 00150 KdPrint(("HvMarkCellDirty:\n\t")); 00151 KdPrint(("Hive:%08lx Cell:%08lx\n", Hive, Cell)); 00152 } 00153 00154 ASSERT(Hive->Signature == HHIVE_SIGNATURE); 00155 ASSERT(Hive->ReadOnly == FALSE); 00156 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00157 00158 Type = HvGetCellType(Cell); 00159 00160 if ( (Hive->HiveFlags & HIVE_VOLATILE) || 00161 (Type == Volatile) ) 00162 { 00163 return TRUE; 00164 } 00165 00166 pCell = HvpGetHCell(Hive,Cell); 00167 #if DBG 00168 Me = HvpGetCellMap(Hive, Cell); 00169 VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell); 00170 Bin = (PHBIN)(Me->BinAddress & HMAP_BASE); 00171 ASSERT(Bin->Signature == HBIN_SIGNATURE); 00172 #endif 00173 // 00174 // If it's an old format hive, mark the entire 00175 // bin dirty, because the Last backpointers are 00176 // such a pain to deal with in the partial 00177 // alloc and free-coalescing cases. 00178 // 00179 00180 if (USE_OLD_CELL(Hive)) { 00181 Me = HvpGetCellMap(Hive, Cell); 00182 VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell); 00183 Bin = (PHBIN)(Me->BinAddress & HMAP_BASE); 00184 Base = Bin->FileOffset; 00185 Size = Bin->Size; 00186 return HvMarkDirty(Hive, Base, Size); 00187 } else { 00188 if (pCell->Size < 0) { 00189 Size = -pCell->Size; 00190 } else { 00191 Size = pCell->Size; 00192 } 00193 ASSERT(Size < Bin->Size); 00194 return HvMarkDirty(Hive, Cell-FIELD_OFFSET(HCELL,u.NewCell), Size); 00195 } 00196 } 00197 00198 00199 BOOLEAN 00200 HvIsBinDirty( 00201 IN PHHIVE Hive, 00202 IN HCELL_INDEX Cell 00203 ) 00204 00205 /*++ 00206 00207 Routine Description: 00208 00209 Given a hive and a cell, checks whether the bin containing 00210 that cell has any dirty clusters or not. 00211 00212 Arguments: 00213 00214 Hive - Supplies a pointer to the hive control structure 00215 00216 Cell - Supplies the HCELL_INDEX of the Cell. 00217 00218 Return Value: 00219 00220 TRUE - Bin contains dirty data. 00221 00222 FALSE - Bin does not contain dirty data. 00223 00224 --*/ 00225 00226 { 00227 ULONG Type; 00228 PHCELL pcell; 00229 PRTL_BITMAP Bitmap; 00230 ULONG First; 00231 ULONG Last; 00232 ULONG i; 00233 PHMAP_ENTRY Map; 00234 PHBIN Bin; 00235 00236 CMLOG(CML_MINOR, CMS_IO) { 00237 KdPrint(("HvIsBinDirty:\n\t")); 00238 KdPrint(("Hive:%08lx Cell:%08lx\n", Hive, Cell)); 00239 } 00240 00241 ASSERT(Hive->Signature == HHIVE_SIGNATURE); 00242 ASSERT(Hive->ReadOnly == FALSE); 00243 00244 Type = HvGetCellType(Cell); 00245 00246 if ( (Hive->HiveFlags & HIVE_VOLATILE) || 00247 (Type == Volatile) ) 00248 { 00249 return FALSE; 00250 } 00251 00252 Bitmap = &(Hive->DirtyVector); 00253 00254 Map = HvpGetCellMap(Hive, Cell); 00255 VALIDATE_CELL_MAP(__LINE__,Map,Hive,Cell); 00256 Bin = (PHBIN)(Map->BinAddress & HMAP_BASE); 00257 First = Bin->FileOffset / HSECTOR_SIZE; 00258 Last = (Bin->FileOffset + Bin->Size - 1) / HSECTOR_SIZE; 00259 00260 for (i=First; i<=Last; i++) { 00261 if (RtlCheckBit(Bitmap, i)==1) { 00262 return(TRUE); 00263 } 00264 } 00265 return(FALSE); 00266 } 00267 00268 00269 BOOLEAN 00270 HvMarkDirty( 00271 PHHIVE Hive, 00272 HCELL_INDEX Start, 00273 ULONG Length 00274 ) 00275 /*++ 00276 00277 Routine Description: 00278 00279 Marks the relevent parts of a hive dirty, so that they will 00280 be flushed to backing store. 00281 00282 If Hive->Cluster is not 1, then adjacent all logical sectors 00283 in the given cluster will be forced dirty (and log space 00284 allocated for them.) This must be done here rather than in 00285 HvSyncHive so that we can know how much to grow the log. 00286 00287 This is a noop for Volatile address range. 00288 00289 NOTE: Range will not be marked dirty if operation fails. 00290 00291 Arguments: 00292 00293 Hive - supplies a pointer to the hive control structure for the 00294 hive of interest 00295 00296 Start - supplies a hive virtual address (i.e., an HCELL_INDEX or 00297 like form address) of the start of the area to mark dirty. 00298 00299 Length - inclusive length in bytes of area to mark dirty. 00300 00301 Return Value: 00302 00303 TRUE - it worked 00304 00305 FALSE - could not allocate log space, failure! 00306 00307 --*/ 00308 { 00309 ULONG Type; 00310 PRTL_BITMAP BitMap; 00311 ULONG First; 00312 ULONG Last; 00313 ULONG i; 00314 ULONG Cluster; 00315 ULONG OriginalDirtyCount; 00316 ULONG DirtySectors; 00317 BOOLEAN Result = TRUE; 00318 00319 CMLOG(CML_MINOR, CMS_IO) { 00320 KdPrint(("HvMarkDirty:\n\t")); 00321 KdPrint(("Hive:%08lx Start:%08lx Length:%08lx\n", Hive, Start, Length)); 00322 } 00323 00324 00325 ASSERT(Hive->Signature == HHIVE_SIGNATURE); 00326 ASSERT(Hive->ReadOnly == FALSE); 00327 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00328 00329 Type = HvGetCellType(Start); 00330 00331 if ( (Hive->HiveFlags & HIVE_VOLATILE) || 00332 (Type == Volatile) ) 00333 { 00334 return TRUE; 00335 } 00336 00337 00338 BitMap = &(Hive->DirtyVector); 00339 OriginalDirtyCount = Hive->DirtyCount; 00340 00341 First = Start / HSECTOR_SIZE; 00342 Last = (Start + Length - 1) / HSECTOR_SIZE; 00343 00344 Cluster = Hive->Cluster; 00345 if (Cluster > 1) { 00346 00347 // 00348 // Force Start down to base of cluster 00349 // Force End up to top of cluster 00350 // 00351 First = First & ~(Cluster - 1); 00352 Last = ROUND_UP(Last+1, Cluster) - 1; 00353 } 00354 00355 if (Last >= BitMap->SizeOfBitMap) { 00356 Last = BitMap->SizeOfBitMap-1; 00357 } 00358 00359 // 00360 // Try and grow the log enough to accomodate all the dirty sectors. 00361 // 00362 DirtySectors = 0; 00363 for (i = First; i <= Last; i++) { 00364 if (RtlCheckBit(BitMap, i)==0) { 00365 ++DirtySectors; 00366 } 00367 } 00368 if (DirtySectors != 0) { 00369 if (HvpGrowLog1(Hive, DirtySectors) == FALSE) { 00370 return(FALSE); 00371 } 00372 00373 if ((OriginalDirtyCount == 0) && (First != 0)) { 00374 Result = HvMarkDirty(Hive, 0, sizeof(HBIN)); // force header of 1st bin dirty 00375 if (Result==FALSE) { 00376 return(FALSE); 00377 } 00378 } 00379 00380 // 00381 // Log has been successfully grown, go ahead 00382 // and set the dirty bits. 00383 // 00384 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00385 Hive->DirtyCount += DirtySectors; 00386 RtlSetBits(BitMap, First, Last-First+1); 00387 } 00388 00389 // mark this bin as writable 00390 HvpMarkBinReadWrite(Hive,Start); 00391 00392 if (!(Hive->HiveFlags & HIVE_NOLAZYFLUSH)) { 00393 CmpLazyFlush(); 00394 } 00395 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00396 return(TRUE); 00397 } 00398 00399 00400 BOOLEAN 00401 HvMarkClean( 00402 PHHIVE Hive, 00403 HCELL_INDEX Start, 00404 ULONG Length 00405 ) 00406 /*++ 00407 00408 Routine Description: 00409 00410 Clears the dirty bits for a given portion of a hive. This is 00411 the inverse of HvMarkDirty, although it does not give up any 00412 file space in the primary or log that HvMarkDirty may have reserved. 00413 00414 This is a noop for Volatile address range. 00415 00416 Arguments: 00417 00418 Hive - supplies a pointer to the hive control structure for the 00419 hive of interest 00420 00421 Start - supplies a hive virtual address (i.e., an HCELL_INDEX or 00422 like form address) of the start of the area to mark dirty. 00423 00424 Length - inclusive length in bytes of area to mark dirty. 00425 00426 Return Value: 00427 00428 TRUE - it worked 00429 00430 --*/ 00431 { 00432 ULONG Type; 00433 PRTL_BITMAP BitMap; 00434 ULONG First; 00435 ULONG Last; 00436 ULONG i; 00437 ULONG Cluster; 00438 00439 CMLOG(CML_MINOR, CMS_IO) { 00440 KdPrint(("HvMarkClean:\n\t")); 00441 KdPrint(("Hive:%08lx Start:%08lx Length:%08lx\n", Hive, Start, Length)); 00442 } 00443 00444 00445 ASSERT(Hive->Signature == HHIVE_SIGNATURE); 00446 ASSERT(Hive->ReadOnly == FALSE); 00447 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00448 00449 Type = HvGetCellType(Start); 00450 00451 if ( (Hive->HiveFlags & HIVE_VOLATILE) || 00452 (Type == Volatile) ) 00453 { 00454 return TRUE; 00455 } 00456 00457 BitMap = &(Hive->DirtyVector); 00458 00459 First = Start / HSECTOR_SIZE; 00460 Last = (Start + Length - 1) / HSECTOR_SIZE; 00461 00462 Cluster = Hive->Cluster; 00463 if (Cluster > 1) { 00464 00465 // 00466 // Force Start down to base of cluster 00467 // Force End up to top of cluster 00468 // 00469 First = First & ~(Cluster - 1); 00470 Last = ROUND_UP(Last+1, Cluster) - 1; 00471 } 00472 00473 if (Last >= BitMap->SizeOfBitMap) { 00474 Last = BitMap->SizeOfBitMap-1; 00475 } 00476 00477 // 00478 // Subtract out the dirty count and 00479 // and clear the dirty bits. 00480 // 00481 for (i=First; i<=Last; i++) { 00482 if (RtlCheckBit(BitMap,i)==1) { 00483 --Hive->DirtyCount; 00484 RtlClearBits(BitMap, i, 1); 00485 } 00486 } 00487 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00488 00489 return(TRUE); 00490 } 00491 00492 00493 00494 BOOLEAN 00495 HvpGrowLog1( 00496 PHHIVE Hive, 00497 ULONG Count 00498 ) 00499 /*++ 00500 00501 Routine Description: 00502 00503 Adjust the log for growth in the number of sectors of dirty 00504 data that are desired. 00505 00506 Arguments: 00507 00508 Hive - supplies a pointer to the hive control structure for the 00509 hive of interest 00510 00511 Count - number of additional logical sectors of log space needed 00512 00513 Return Value: 00514 00515 TRUE - it worked 00516 00517 FALSE - could not allocate log space, failure! 00518 00519 --*/ 00520 { 00521 ULONG ClusterSize; 00522 ULONG RequiredSize; 00523 ULONG tmp; 00524 00525 CMLOG(CML_MINOR, CMS_IO) { 00526 KdPrint(("HvpGrowLog1:\n\t")); 00527 KdPrint(("Hive:%08lx Count:%08lx\n", Hive, Count)); 00528 } 00529 00530 ASSERT(Hive->ReadOnly == FALSE); 00531 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00532 00533 // 00534 // If logging is off, tell caller world is OK. 00535 // 00536 if (Hive->Log == FALSE) { 00537 return TRUE; 00538 } 00539 00540 ClusterSize = Hive->Cluster * HSECTOR_SIZE; 00541 00542 tmp = Hive->DirtyVector.SizeOfBitMap / 8; // bytes 00543 tmp += sizeof(ULONG); // signature 00544 00545 RequiredSize = 00546 ClusterSize + // 1 cluster for header 00547 ROUND_UP(tmp, ClusterSize) + 00548 ((Hive->DirtyCount + Count) * HSECTOR_SIZE); 00549 00550 RequiredSize = ROUND_UP(RequiredSize, HLOG_GROW); 00551 00552 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00553 00554 if ( ! (Hive->FileSetSize)(Hive, HFILE_TYPE_LOG, RequiredSize)) { 00555 return FALSE; 00556 } 00557 00558 Hive->LogSize = RequiredSize; 00559 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00560 return TRUE; 00561 } 00562 00563 00564 BOOLEAN 00565 HvpGrowLog2( 00566 PHHIVE Hive, 00567 ULONG Size 00568 ) 00569 /*++ 00570 00571 Routine Description: 00572 00573 Adjust the log for growth in the size of the hive, in particular, 00574 account for the increased space needed for a bigger dirty vector. 00575 00576 Arguments: 00577 00578 Hive - supplies a pointer to the hive control structure for the 00579 hive of interest 00580 00581 Size - proposed growth in size in bytes. 00582 00583 Return Value: 00584 00585 TRUE - it worked 00586 00587 FALSE - could not allocate log space, failure! 00588 00589 --*/ 00590 { 00591 ULONG ClusterSize; 00592 ULONG RequiredSize; 00593 ULONG DirtyBytes; 00594 00595 CMLOG(CML_MINOR, CMS_IO) { 00596 KdPrint(("HvpGrowLog2:\n\t")); 00597 KdPrint(("Hive:%08lx Size:%08lx\n", Hive, Size)); 00598 } 00599 00600 ASSERT(Hive->ReadOnly == FALSE); 00601 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00602 00603 00604 // 00605 // If logging is off, tell caller world is OK. 00606 // 00607 if (Hive->Log == FALSE) { 00608 return TRUE; 00609 } 00610 00611 ASSERT( (Size % HSECTOR_SIZE) == 0 ); 00612 00613 ClusterSize = Hive->Cluster * HSECTOR_SIZE; 00614 00615 ASSERT( (((Hive->Storage[Stable].Length + Size) / HSECTOR_SIZE) % 8) == 0); 00616 00617 DirtyBytes = (Hive->DirtyVector.SizeOfBitMap / 8) + 00618 ((Size / HSECTOR_SIZE) / 8) + 00619 sizeof(ULONG); // signature 00620 DirtyBytes = ROUND_UP(DirtyBytes, ClusterSize); 00621 00622 RequiredSize = 00623 ClusterSize + // 1 cluster for header 00624 (Hive->DirtyCount * HSECTOR_SIZE) + 00625 DirtyBytes; 00626 00627 RequiredSize = ROUND_UP(RequiredSize, HLOG_GROW); 00628 00629 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00630 00631 if ( ! (Hive->FileSetSize)(Hive, HFILE_TYPE_LOG, RequiredSize)) { 00632 return FALSE; 00633 } 00634 00635 Hive->LogSize = RequiredSize; 00636 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 00637 return TRUE; 00638 } 00639 00640 00641 00642 // 00643 // Code for syncing a hive to backing store 00644 // 00645 00646 BOOLEAN 00647 HvSyncHive( 00648 PHHIVE Hive 00649 ) 00650 /*++ 00651 00652 Routine Description: 00653 00654 Force backing store to match the memory image of the Stable 00655 part of the hive's space. 00656 00657 Logs, primary, and alternate data can be written. Primary is 00658 always written. Normally either a log or an alternate, but 00659 not both, will also be written. 00660 00661 It is possible to write only the primary. 00662 00663 All dirty bits will be set clear. 00664 00665 Arguments: 00666 00667 Hive - supplies a pointer to the hive control structure for the 00668 hive of interest 00669 00670 Return Value: 00671 00672 TRUE - it worked 00673 00674 FALSE - some failure. 00675 00676 --*/ 00677 { 00678 BOOLEAN oldFlag; 00679 00680 CMLOG(CML_WORKER, CMS_IO) { 00681 KdPrint(("HvSyncHive:\n\t")); 00682 KdPrint(("Hive:%08lx\n", Hive)); 00683 } 00684 00685 ASSERT(Hive->Signature == HHIVE_SIGNATURE); 00686 ASSERT(Hive->ReadOnly == FALSE); 00687 00688 // 00689 // Punt if post shutdown 00690 // 00691 if (HvShutdownComplete) { 00692 CMLOG(CML_BUGCHECK, CMS_IO) { 00693 KdPrint(("HvSyncHive: Attempt to sync AFTER SHUTDOWN\n")); 00694 } 00695 return FALSE; 00696 } 00697 00698 // 00699 // If nothing dirty, do nothing 00700 // 00701 if (Hive->DirtyCount == 0) { 00702 return TRUE; 00703 } 00704 00705 HvpTruncateBins(Hive); 00706 00707 // 00708 // If hive is volatile, do nothing 00709 // 00710 if (Hive->HiveFlags & HIVE_VOLATILE) { 00711 return TRUE; 00712 } 00713 00714 CMLOG(CML_FLOW, CMS_IO) { 00715 KdPrint(("\tDirtyCount:%08lx\n", Hive->DirtyCount)); 00716 KdPrint(("\tDirtyVector:")); 00717 DumpDirtyVector(Hive); 00718 } 00719 00720 // 00721 // disable hard error popups, to avoid self deadlock on bogus devices 00722 // 00723 oldFlag = IoSetThreadHardErrorMode(FALSE); 00724 00725 // 00726 // Write a log. 00727 // 00728 if (Hive->Log == TRUE) { 00729 if (HvpWriteLog(Hive) == FALSE) { 00730 IoSetThreadHardErrorMode(oldFlag); 00731 return FALSE; 00732 } 00733 } 00734 00735 // 00736 // Write the primary 00737 // 00738 if (HvpDoWriteHive(Hive, HFILE_TYPE_PRIMARY) == FALSE) { 00739 IoSetThreadHardErrorMode(oldFlag); 00740 return FALSE; 00741 } 00742 00743 // 00744 // Write an alternate 00745 // 00746 if (Hive->Alternate == TRUE) { 00747 if (HvpDoWriteHive(Hive, HFILE_TYPE_ALTERNATE) == FALSE) { 00748 IoSetThreadHardErrorMode(oldFlag); 00749 return FALSE; 00750 } 00751 } 00752 00753 // 00754 // restore hard error popups mode 00755 // 00756 IoSetThreadHardErrorMode(oldFlag); 00757 00758 // 00759 // Hive was successfully written out, discard any bins marked as 00760 // discardable. 00761 // 00762 HvpDiscardBins(Hive); 00763 00764 // 00765 // Clear the dirty map 00766 // 00767 RtlClearAllBits(&(Hive->DirtyVector)); 00768 Hive->DirtyCount = 0; 00769 00770 return TRUE; 00771 } 00772 00773 00774 BOOLEAN 00775 HvpDoWriteHive( 00776 PHHIVE Hive, 00777 ULONG FileType 00778 ) 00779 /*++ 00780 00781 Routine Description: 00782 00783 Write dirty parts of the hive out to either its primary or alternate 00784 file. Write the header, flush, write all data, flush, update header, 00785 flush. Assume either logging or primary/alternate pairs used. 00786 00787 NOTE: TimeStamp is not set, assumption is that HvpWriteLog set 00788 that. It is only used for checking if Logs correspond anyway. 00789 00790 Arguments: 00791 00792 Hive - pointer to Hive for which dirty data is to be written. 00793 00794 FileType - indicated whether primary or alternate file should be written. 00795 00796 Return Value: 00797 00798 TRUE - it worked 00799 00800 FALSE - it failed 00801 00802 --*/ 00803 { 00804 PHBASE_BLOCK BaseBlock; 00805 ULONG Offset; 00806 PUCHAR Address; 00807 ULONG Length; 00808 BOOLEAN rc; 00809 ULONG Current; 00810 PRTL_BITMAP BitMap; 00811 PHMAP_ENTRY Me; 00812 PHBIN Bin; 00813 BOOLEAN ShrinkHive; 00814 PCMP_OFFSET_ARRAY offsetArray; 00815 CMP_OFFSET_ARRAY offsetElement; 00816 ULONG Count; 00817 ULONG SetBitCount; 00818 00819 CMLOG(CML_MINOR, CMS_IO) { 00820 KdPrint(("HvpDoWriteHive:\n\t")); 00821 KdPrint(("Hive:%08lx FileType:%08lx\n", Hive, FileType)); 00822 } 00823 00824 // 00825 // flush first, so that the filesystem structures get written to 00826 // disk if we have grown the file. 00827 // 00828 if (!(Hive->FileFlush)(Hive, FileType)) { 00829 return(FALSE); 00830 } 00831 00832 BaseBlock = Hive->BaseBlock; 00833 00834 if (BaseBlock->Length > Hive->Storage[Stable].Length) { 00835 ShrinkHive = TRUE; 00836 } else { 00837 ShrinkHive = FALSE; 00838 } 00839 00840 // 00841 // --- Write out header first time, flush --- 00842 // 00843 ASSERT(BaseBlock->Signature == HBASE_BLOCK_SIGNATURE); 00844 ASSERT(BaseBlock->Major == HSYS_MAJOR); 00845 ASSERT(BaseBlock->Format == HBASE_FORMAT_MEMORY); 00846 ASSERT(Hive->ReadOnly == FALSE); 00847 00848 00849 if (BaseBlock->Sequence1 != BaseBlock->Sequence2) { 00850 00851 // 00852 // Some previous log attempt failed, or this hive needs to 00853 // be recovered, so punt. 00854 // 00855 return FALSE; 00856 } 00857 00858 BaseBlock->Length = Hive->Storage[Stable].Length; 00859 00860 BaseBlock->Sequence1++; 00861 BaseBlock->Type = HFILE_TYPE_PRIMARY; 00862 BaseBlock->Cluster = Hive->Cluster; 00863 BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock); 00864 00865 Offset = 0; 00866 offsetElement.FileOffset = Offset; 00867 offsetElement.DataBuffer = (PVOID) BaseBlock; 00868 offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster; 00869 rc = (Hive->FileWrite)( 00870 Hive, 00871 FileType, 00872 &offsetElement, 00873 1, 00874 &Offset 00875 ); 00876 00877 if (rc == FALSE) { 00878 return FALSE; 00879 } 00880 if ( ! (Hive->FileFlush)(Hive, FileType)) { 00881 return FALSE; 00882 } 00883 Offset = ROUND_UP(Offset, HBLOCK_SIZE); 00884 00885 // 00886 // --- Write out dirty data (only if there is any) --- 00887 // 00888 00889 if (Hive->DirtyVector.Buffer != NULL) { 00890 // 00891 // First sector of first bin will always be dirty, write it out 00892 // with the TimeStamp value overlaid on its Link field. 00893 // 00894 BitMap = &(Hive->DirtyVector); 00895 00896 ASSERT(RtlCheckBit(BitMap, 0) == 1); 00897 ASSERT(RtlCheckBit(BitMap, (Hive->Cluster - 1)) == 1); 00898 ASSERT(sizeof(LIST_ENTRY) >= sizeof(LARGE_INTEGER)); 00899 00900 Me = HvpGetCellMap(Hive, 0); 00901 VALIDATE_CELL_MAP(__LINE__,Me,Hive,0); 00902 Address = (PUCHAR)Me->BlockAddress; 00903 Length = Hive->Cluster * HSECTOR_SIZE; 00904 Bin = (PHBIN)Address; 00905 Bin->TimeStamp = BaseBlock->TimeStamp; 00906 00907 offsetElement.FileOffset = Offset; 00908 offsetElement.DataBuffer = (PVOID) Address; 00909 offsetElement.DataLength = Length; 00910 rc = (Hive->FileWrite)( 00911 Hive, 00912 FileType, 00913 &offsetElement, 00914 1, 00915 &Offset 00916 ); 00917 ASSERT((Offset % (Hive->Cluster * HSECTOR_SIZE)) == 0); 00918 if (rc == FALSE) { 00919 return FALSE; 00920 } 00921 00922 00923 // 00924 // Write out the rest of the dirty data 00925 // 00926 Current = Hive->Cluster; // don't rewrite 1st bin or header 00927 00928 SetBitCount = RtlNumberOfSetBits(BitMap); 00929 offsetArray = 00930 (PCMP_OFFSET_ARRAY) 00931 ExAllocatePool(PagedPool, 00932 sizeof(CMP_OFFSET_ARRAY) * SetBitCount); 00933 if (offsetArray == NULL) { 00934 return FALSE; 00935 } 00936 Count = 0; 00937 00938 while (HvpFindNextDirtyBlock( 00939 Hive, 00940 BitMap, 00941 &Current, 00942 &Address, 00943 &Length, 00944 &Offset 00945 ) == TRUE) 00946 { 00947 // Gather data into array. 00948 ASSERT(Count < SetBitCount); 00949 offsetArray[Count].FileOffset = Offset; 00950 offsetArray[Count].DataBuffer = Address; 00951 offsetArray[Count].DataLength = Length; 00952 Offset += Length; 00953 Count++; 00954 ASSERT((Offset % (Hive->Cluster * HSECTOR_SIZE)) == 0); 00955 } 00956 00957 rc = (Hive->FileWrite)( 00958 Hive, 00959 FileType, 00960 offsetArray, 00961 Count, 00962 &Offset // Just an OUT parameter which returns the point 00963 // in the file after the last write. 00964 ); 00965 ExFreePool(offsetArray); 00966 if (rc == FALSE) { 00967 return FALSE; 00968 } 00969 } 00970 00971 if ( ! (Hive->FileFlush)(Hive, FileType)) { 00972 return FALSE; 00973 } 00974 00975 // 00976 // --- Write header again to report completion --- 00977 // 00978 BaseBlock->Sequence2++; 00979 BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock); 00980 Offset = 0; 00981 00982 offsetElement.FileOffset = Offset; 00983 offsetElement.DataBuffer = (PVOID) BaseBlock; 00984 offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster; 00985 rc = (Hive->FileWrite)( 00986 Hive, 00987 FileType, 00988 &offsetElement, 00989 1, 00990 &Offset 00991 ); 00992 if (rc == FALSE) { 00993 return FALSE; 00994 } 00995 00996 if (ShrinkHive) { 00997 // 00998 // Hive has shrunk, give up the excess space. 00999 // 01000 CmpDoFileSetSize(Hive, FileType, Hive->Storage[Stable].Length + HBLOCK_SIZE); 01001 } 01002 01003 if ( ! (Hive->FileFlush)(Hive, FileType)) { 01004 return FALSE; 01005 } 01006 01007 if ((Hive->Log) && 01008 (Hive->LogSize > HLOG_MINSIZE(Hive))) { 01009 // 01010 // Shrink log back down, reserve at least two clusters 01011 // worth of space so that if all the disk space is 01012 // consumed, there will still be enough space prereserved 01013 // to allow a minimum of registry operations so the user 01014 // can log on. 01015 // 01016 CmpDoFileSetSize(Hive, HFILE_TYPE_LOG, HLOG_MINSIZE(Hive)); 01017 Hive->LogSize = HLOG_MINSIZE(Hive); 01018 } 01019 01020 return TRUE; 01021 } 01022 01023 01024 BOOLEAN 01025 HvpWriteLog( 01026 PHHIVE Hive 01027 ) 01028 /*++ 01029 01030 Routine Description: 01031 01032 Write a header, the DirtyVector, and all the dirty data into 01033 the log file. Do flushes at the right places. Update the header. 01034 01035 Arguments: 01036 01037 Hive - pointer to Hive for which dirty data is to be logged. 01038 01039 Return Value: 01040 01041 TRUE - it worked 01042 01043 FALSE - it failed 01044 01045 --*/ 01046 { 01047 PHBASE_BLOCK BaseBlock; 01048 ULONG Offset; 01049 PUCHAR Address; 01050 ULONG Length; 01051 BOOLEAN rc; 01052 ULONG Current; 01053 ULONG junk; 01054 ULONG ClusterSize; 01055 ULONG HeaderLength; 01056 PRTL_BITMAP BitMap; 01057 ULONG DirtyVectorSignature = HLOG_DV_SIGNATURE; 01058 LARGE_INTEGER systemtime; 01059 PCMP_OFFSET_ARRAY offsetArray; 01060 CMP_OFFSET_ARRAY offsetElement; 01061 ULONG Count; 01062 ULONG SetBitCount; 01063 01064 CMLOG(CML_MINOR, CMS_IO) { 01065 KdPrint(("HvpWriteLog:\n\t")); 01066 KdPrint(("Hive:%08lx\n", Hive)); 01067 } 01068 01069 BitMap = &Hive->DirtyVector; 01070 // 01071 // --- Write out header first time, flush --- 01072 // 01073 BaseBlock = Hive->BaseBlock; 01074 ASSERT(BaseBlock->Signature == HBASE_BLOCK_SIGNATURE); 01075 ASSERT(BaseBlock->Major == HSYS_MAJOR); 01076 ASSERT(BaseBlock->Format == HBASE_FORMAT_MEMORY); 01077 ASSERT(Hive->ReadOnly == FALSE); 01078 01079 01080 if (BaseBlock->Sequence1 != BaseBlock->Sequence2) { 01081 01082 // 01083 // Some previous log attempt failed, or this hive needs to 01084 // be recovered, so punt. 01085 // 01086 return FALSE; 01087 } 01088 01089 BaseBlock->Sequence1++; 01090 KeQuerySystemTime(&systemtime); 01091 BaseBlock->TimeStamp = systemtime; 01092 01093 BaseBlock->Type = HFILE_TYPE_LOG; 01094 01095 ClusterSize = Hive->Cluster * HSECTOR_SIZE; 01096 HeaderLength = ROUND_UP(HLOG_HEADER_SIZE, ClusterSize); 01097 BaseBlock->Cluster = Hive->Cluster; 01098 01099 BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock); 01100 01101 Offset = 0; 01102 offsetElement.FileOffset = Offset; 01103 offsetElement.DataBuffer = (PVOID) BaseBlock; 01104 offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster; 01105 rc = (Hive->FileWrite)( 01106 Hive, 01107 HFILE_TYPE_LOG, 01108 &offsetElement, 01109 1, 01110 &Offset 01111 ); 01112 if (rc == FALSE) { 01113 return FALSE; 01114 } 01115 Offset = ROUND_UP(Offset, HeaderLength); 01116 if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_LOG)) { 01117 return FALSE; 01118 } 01119 01120 // 01121 // --- Write out dirty vector --- 01122 // 01123 ASSERT(sizeof(ULONG) == sizeof(DirtyVectorSignature)); // See GrowLog1 above 01124 offsetElement.FileOffset = Offset; 01125 offsetElement.DataBuffer = (PVOID) &DirtyVectorSignature; 01126 offsetElement.DataLength = sizeof(DirtyVectorSignature); 01127 rc = (Hive->FileWrite)( 01128 Hive, 01129 HFILE_TYPE_LOG, 01130 &offsetElement, 01131 1, 01132 &Offset 01133 ); 01134 if (rc == FALSE) { 01135 return FALSE; 01136 } 01137 01138 Length = Hive->DirtyVector.SizeOfBitMap / 8; 01139 Address = (PUCHAR)(Hive->DirtyVector.Buffer); 01140 offsetElement.FileOffset = Offset; 01141 offsetElement.DataBuffer = (PVOID) Address; 01142 offsetElement.DataLength = Length; 01143 rc = (Hive->FileWrite)( 01144 Hive, 01145 HFILE_TYPE_LOG, 01146 &offsetElement, 01147 1, 01148 &Offset 01149 ); 01150 if (rc == FALSE) { 01151 return FALSE; 01152 } 01153 Offset = ROUND_UP(Offset, ClusterSize); 01154 01155 // 01156 // --- Write out body of log --- 01157 // 01158 SetBitCount = RtlNumberOfSetBits(BitMap); 01159 offsetArray = 01160 (PCMP_OFFSET_ARRAY) 01161 ExAllocatePool(PagedPool, 01162 sizeof(CMP_OFFSET_ARRAY) * SetBitCount); 01163 if (offsetArray == NULL) { 01164 return FALSE; 01165 } 01166 Count = 0; 01167 01168 Current = 0; 01169 while (HvpFindNextDirtyBlock( 01170 Hive, 01171 BitMap, 01172 &Current, 01173 &Address, 01174 &Length, 01175 &junk 01176 ) == TRUE) 01177 { 01178 // Gather data into array. 01179 ASSERT(Count < SetBitCount); 01180 offsetArray[Count].FileOffset = Offset; 01181 offsetArray[Count].DataBuffer = Address; 01182 offsetArray[Count].DataLength = Length; 01183 Offset += Length; 01184 Count++; 01185 ASSERT((Offset % ClusterSize) == 0); 01186 } 01187 01188 rc = (Hive->FileWrite)( 01189 Hive, 01190 HFILE_TYPE_LOG, 01191 offsetArray, 01192 Count, 01193 &Offset // Just an OUT parameter which returns the point 01194 // in the file after the last write. 01195 ); 01196 ExFreePool(offsetArray); 01197 if (rc == FALSE) { 01198 return FALSE; 01199 } 01200 01201 if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_LOG)) { 01202 return FALSE; 01203 } 01204 01205 // 01206 // --- Write header again to report completion --- 01207 // 01208 BaseBlock->Sequence2++; 01209 BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock); 01210 Offset = 0; 01211 offsetElement.FileOffset = Offset; 01212 offsetElement.DataBuffer = (PVOID) BaseBlock; 01213 offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster; 01214 rc = (Hive->FileWrite)( 01215 Hive, 01216 HFILE_TYPE_LOG, 01217 &offsetElement, 01218 1, 01219 &Offset 01220 ); 01221 if (rc == FALSE) { 01222 return FALSE; 01223 } 01224 if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_LOG)) { 01225 return FALSE; 01226 } 01227 01228 return TRUE; 01229 } 01230 01231 01232 BOOLEAN 01233 HvpFindNextDirtyBlock( 01234 PHHIVE Hive, 01235 PRTL_BITMAP BitMap, 01236 PULONG Current, 01237 PUCHAR *Address, 01238 PULONG Length, 01239 PULONG Offset 01240 ) 01241 /*++ 01242 01243 Routine Description: 01244 01245 This routine finds and reports the largest run of dirty logical 01246 sectors in the hive, which are contiguous in memory and on disk. 01247 01248 Arguments: 01249 01250 Hive - pointer to Hive of interest. 01251 01252 BitMap - supplies a pointer to a bitmap structure, which 01253 describes what is dirty. 01254 01255 Current - supplies a pointer to a varible that tracks position 01256 in the bitmap. It is a bitnumber. It is updated by 01257 this call. 01258 01259 Address - supplies a pointer to a variable to receive a pointer 01260 to the area in memory to be written out. 01261 01262 Length - supplies a pointer to a variable to receive the length 01263 of the region to read/write 01264 01265 Offset - supplies a pointer to a variable to receive the offset 01266 in the backing file to which the data should be written. 01267 (not valid for log files) 01268 01269 Return Value: 01270 01271 TRUE - more to write, ret values good 01272 01273 FALSE - all data has been written 01274 01275 --*/ 01276 { 01277 ULONG i; 01278 ULONG EndOfBitMap; 01279 ULONG Start; 01280 ULONG End; 01281 HCELL_INDEX FileBaseAddress; 01282 HCELL_INDEX FileEndAddress; 01283 PHMAP_ENTRY Me; 01284 PUCHAR Block; 01285 PUCHAR StartBlock; 01286 PUCHAR NextBlock; 01287 ULONG RunSpan; 01288 ULONG RunLength; 01289 ULONG FileLength; 01290 PFREE_HBIN FreeBin; 01291 01292 CMLOG(CML_FLOW, CMS_IO) { 01293 KdPrint(("HvpFindNextDirtyBlock:\n\t")); 01294 KdPrint(("Hive:%08lx Current:%08lx\n", Hive, *Current)); 01295 } 01296 01297 01298 EndOfBitMap = BitMap->SizeOfBitMap; 01299 01300 if (*Current >= EndOfBitMap) { 01301 return FALSE; 01302 } 01303 01304 // 01305 // Find next run of set bits 01306 // 01307 for (i = *Current; i < EndOfBitMap; i++) { 01308 if (RtlCheckBit(BitMap, i) == 1) { 01309 break; 01310 } 01311 } 01312 Start = i; 01313 01314 for ( ; i < EndOfBitMap; i++) { 01315 if (RtlCheckBit(BitMap, i) == 0) { 01316 break; 01317 } 01318 } 01319 End = i; 01320 01321 01322 // 01323 // Compute hive virtual addresses, beginning file address, memory address 01324 // 01325 FileBaseAddress = Start * HSECTOR_SIZE; 01326 FileEndAddress = End * HSECTOR_SIZE; 01327 FileLength = FileEndAddress - FileBaseAddress; 01328 if (FileLength == 0) { 01329 *Address = NULL; 01330 *Current = 0xffffffff; 01331 *Length = 0; 01332 return FALSE; 01333 } 01334 Me = HvpGetCellMap(Hive, FileBaseAddress); 01335 VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileBaseAddress); 01336 01337 if (Me->BinAddress & HMAP_DISCARDABLE) { 01338 FreeBin = (PFREE_HBIN)Me->BlockAddress; 01339 StartBlock = (PUCHAR)((Me->BinAddress & HMAP_BASE) + FileBaseAddress - FreeBin->FileOffset ); 01340 } else { 01341 StartBlock = (PUCHAR)Me->BlockAddress; 01342 } 01343 01344 Block = StartBlock; 01345 ASSERT(((PHBIN)(Me->BinAddress & HMAP_BASE))->Signature == HBIN_SIGNATURE); 01346 *Address = Block + (FileBaseAddress & HCELL_OFFSET_MASK); 01347 01348 *Offset = FileBaseAddress + HBLOCK_SIZE; 01349 01350 // 01351 // Build up length. First, account for sectors in first block. 01352 // 01353 RunSpan = HSECTOR_COUNT - (Start % HSECTOR_COUNT); 01354 01355 if ((End - Start) <= RunSpan) { 01356 01357 // 01358 // Entire length is in first block, return it 01359 // 01360 *Length = FileLength; 01361 *Current = End; 01362 return TRUE; 01363 01364 } else { 01365 01366 RunLength = RunSpan * HSECTOR_SIZE; 01367 FileBaseAddress = ROUND_UP(FileBaseAddress+1, HBLOCK_SIZE); 01368 01369 } 01370 01371 // 01372 // Scan forward through blocks, filling up length as we go. 01373 // 01374 // NOTE: This loop grows forward 1 block at time. If we were 01375 // really clever we'd fill forward a bin at time, since 01376 // bins are always contiguous. But most bins will be 01377 // one block long anyway, so we won't bother for now. 01378 // 01379 while (RunLength < FileLength) { 01380 01381 Me = HvpGetCellMap(Hive, FileBaseAddress); 01382 VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileBaseAddress); 01383 ASSERT(((PHBIN)(Me->BinAddress & HMAP_BASE))->Signature == HBIN_SIGNATURE); 01384 01385 if (Me->BinAddress & HMAP_DISCARDABLE) { 01386 FreeBin = (PFREE_HBIN)Me->BlockAddress; 01387 NextBlock = (PUCHAR)((Me->BinAddress & HMAP_BASE) + FileBaseAddress - FreeBin->FileOffset ); 01388 } else { 01389 NextBlock = (PUCHAR)Me->BlockAddress; 01390 } 01391 01392 if ( (NextBlock - Block) != HBLOCK_SIZE) { 01393 01394 // 01395 // We've hit a discontinuity in memory. RunLength is 01396 // as long as it's going to get. 01397 // 01398 break; 01399 } 01400 01401 01402 if ((FileEndAddress - FileBaseAddress) <= HBLOCK_SIZE) { 01403 01404 // 01405 // We've reached the tail block, all is contiguous, 01406 // fill up to end and return. 01407 // 01408 *Length = FileLength; 01409 *Current = End; 01410 return TRUE; 01411 } 01412 01413 // 01414 // Just another contiguous block, fill forward 01415 // 01416 RunLength += HBLOCK_SIZE; 01417 RunSpan += HSECTOR_COUNT; 01418 FileBaseAddress += HBLOCK_SIZE; 01419 Block = NextBlock; 01420 } 01421 01422 // 01423 // We either hit a discontinuity, OR, we're at the end of the range 01424 // we're trying to fill. In either case, return. 01425 // 01426 *Length = RunLength; 01427 *Current = Start + RunSpan; 01428 return TRUE; 01429 } 01430 01431 01432 NTSTATUS 01433 HvWriteHive( 01434 PHHIVE Hive 01435 ) 01436 /*++ 01437 01438 Routine Description: 01439 01440 Write the hive out. Write only to the Primary file, neither 01441 logs nor alternates will be updated. The hive will be written 01442 to the HFILE_TYPE_EXTERNAL handle. 01443 01444 Intended for use in applications like SaveKey. 01445 01446 Only Stable storage will be written (as for any hive.) 01447 01448 Presumption is that layer above has set HFILE_TYPE_EXTERNAL 01449 handle to point to correct place. 01450 01451 Applying this call to an active hive will generally hose integrity 01452 measures. 01453 01454 HOW IT WORKS: 01455 01456 Make a new DirtyVector. Fill it with 1s (all dirty). 01457 Make hive point at it. We now have what looks like 01458 a completely dirty hive. 01459 01460 Call HvpWriteHive, which will write the whole thing to disk. 01461 01462 Put back DirtyVector, and free the extra one we used. 01463 01464 In failure case, force Sequence numbers in Hive and BaseBlock 01465 to match. 01466 01467 Arguments: 01468 01469 Hive - supplies a pointer to the hive control structure for the 01470 hive of interest. 01471 01472 Return Value: 01473 01474 Status. 01475 01476 --*/ 01477 { 01478 PULONG SaveDirtyVector; 01479 ULONG SaveDirtyVectorSize; 01480 PULONG AltDirtyVector; 01481 ULONG AltDirtyVectorSize; 01482 PHBASE_BLOCK SaveBaseBlock; 01483 PHBASE_BLOCK AltBaseBlock; 01484 ULONG Alignment; 01485 01486 NTSTATUS status; 01487 01488 01489 CMLOG(CML_MAJOR, CMS_IO) { 01490 KdPrint(("HvWriteHive: \n")); 01491 KdPrint(("\tHive = %08lx\n")); 01492 } 01493 ASSERT(Hive->Signature == HHIVE_SIGNATURE); 01494 ASSERT(Hive->ReadOnly == FALSE); 01495 01496 01497 // 01498 // Punt if post shutdown 01499 // 01500 if (HvShutdownComplete) { 01501 CMLOG(CML_BUGCHECK, CMS_IO) { 01502 KdPrint(("HvWriteHive: Attempt to write hive AFTER SHUTDOWN\n")); 01503 } 01504 return STATUS_REGISTRY_IO_FAILED; 01505 } 01506 01507 // 01508 // Splice in a duplicate DirtyVector with all bits set. 01509 // 01510 SaveDirtyVector = Hive->DirtyVector.Buffer; 01511 SaveDirtyVectorSize = Hive->DirtyVector.SizeOfBitMap; 01512 SaveBaseBlock = Hive->BaseBlock; 01513 01514 AltDirtyVectorSize = (Hive->Storage[Stable].Length / HSECTOR_SIZE) / 8; 01515 AltDirtyVector = (Hive->Allocate)(ROUND_UP(AltDirtyVectorSize,sizeof(ULONG)), FALSE); 01516 if (AltDirtyVector == NULL) { 01517 status = STATUS_INSUFFICIENT_RESOURCES; 01518 goto Exit1; 01519 } 01520 Hive->DirtyVector.Buffer = AltDirtyVector; 01521 Hive->DirtyVector.SizeOfBitMap = AltDirtyVectorSize * 8; 01522 RtlSetAllBits(&(Hive->DirtyVector)); 01523 01524 // 01525 // Splice in a duplicate BaseBlock 01526 // 01527 AltBaseBlock = (Hive->Allocate)(sizeof(HBASE_BLOCK), TRUE); 01528 if (AltBaseBlock == NULL) { 01529 status = STATUS_INSUFFICIENT_RESOURCES; 01530 goto Exit2; 01531 } 01532 // 01533 // Make sure the buffer we got back is cluster-aligned. If not, try 01534 // harder to get an aligned buffer. 01535 // 01536 Alignment = Hive->Cluster * HSECTOR_SIZE - 1; 01537 if (((ULONG_PTR)AltBaseBlock & Alignment) != 0) { 01538 (Hive->Free)(AltBaseBlock, sizeof(HBASE_BLOCK)); 01539 AltBaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(PAGE_SIZE, TRUE)); 01540 if (AltBaseBlock == NULL) { 01541 status = STATUS_INSUFFICIENT_RESOURCES; 01542 goto Exit2; 01543 } 01544 // 01545 // Return the quota for the extra allocation, as we are not really using 01546 // it and it will not be accounted for later when we free it. 01547 // 01548 CmpReleaseGlobalQuota(PAGE_SIZE - sizeof(HBASE_BLOCK)); 01549 } 01550 01551 RtlMoveMemory(AltBaseBlock, SaveBaseBlock, HSECTOR_SIZE); 01552 Hive->BaseBlock = AltBaseBlock; 01553 01554 // 01555 // Ensure the file can be made big enough, then do the deed 01556 // 01557 status = CmpDoFileSetSize(Hive, 01558 HFILE_TYPE_EXTERNAL, 01559 Hive->Storage[Stable].Length); 01560 01561 if (NT_SUCCESS(status)) { 01562 if (!HvpDoWriteHive(Hive, HFILE_TYPE_EXTERNAL)) { 01563 status = STATUS_REGISTRY_IO_FAILED; 01564 } 01565 } 01566 01567 // 01568 // Clean up, success or failure 01569 // 01570 CmpFree(AltBaseBlock, sizeof(HBASE_BLOCK)); 01571 01572 Exit2: 01573 CmpFree(AltDirtyVector, ROUND_UP(AltDirtyVectorSize,sizeof(ULONG))); 01574 01575 Exit1: 01576 Hive->DirtyVector.Buffer = SaveDirtyVector; 01577 Hive->DirtyVector.SizeOfBitMap = SaveDirtyVectorSize; 01578 Hive->BaseBlock = SaveBaseBlock; 01579 return status; 01580 } 01581 01582 01583 VOID 01584 HvRefreshHive( 01585 PHHIVE Hive 01586 ) 01587 /*++ 01588 01589 Routine Description: 01590 01591 Undo the last sync. We do this by reading back all data which 01592 has been marked dirty from the file into memory. Update the 01593 free list. We will then clear the dirty vector. 01594 01595 Any growth since the last sync will be discarded, and in fact, 01596 the size of the file will be set down. 01597 01598 WARNNOTE: Failure will cause a bugcheck, as we cannot 01599 keep the hive consistent if we fail part way through. 01600 01601 All I/O is done via HFILE_TYPE_PRIMARY. 01602 01603 Arguments: 01604 01605 Hive - supplies a pointer to the hive control structure for the 01606 hive of interest. 01607 01608 Return Value: 01609 01610 NONE. Either works or BugChecks. 01611 01612 --*/ 01613 { 01614 ULONG Offset; 01615 ULONG ReadLength; 01616 ULONG checkstatus; 01617 PUCHAR Address; 01618 ULONG Current; 01619 PRTL_BITMAP BitMap; 01620 BOOLEAN rc; 01621 ULONG Start; 01622 ULONG End; 01623 ULONG BitLength; 01624 HCELL_INDEX TailStart; 01625 HCELL_INDEX p; 01626 PHMAP_ENTRY t; 01627 ULONG i; 01628 PHBIN Bin; 01629 PLIST_ENTRY List; 01630 PFREE_HBIN FreeBin; 01631 PHMAP_ENTRY Map; 01632 HCELL_INDEX RootCell; 01633 PCM_KEY_NODE RootNode; 01634 HCELL_INDEX LinkCell; 01635 01636 // 01637 // this array stores the last elements in each free cell list for the stable storage 01638 // 01639 HCELL_INDEX TailDisplay[HHIVE_FREE_DISPLAY_SIZE]; 01640 01641 // 01642 // noop or assert on various uninteresting or bogus conditions 01643 // 01644 if (Hive->DirtyCount == 0) { 01645 return; 01646 } 01647 ASSERT(Hive->HiveFlags & HIVE_NOLAZYFLUSH); 01648 ASSERT(Hive->Storage[Volatile].Length == 0); 01649 01650 // 01651 // be sure the hive is not already trash 01652 // 01653 checkstatus = HvCheckHive(Hive, NULL); 01654 if (checkstatus != 0) { 01655 KeBugCheckEx(REGISTRY_ERROR,7,0,(ULONG_PTR)Hive,checkstatus); 01656 } 01657 01658 Hive->RefreshCount++; 01659 01660 // 01661 // Capture the LinkCell backpointer in the hive's root cell. We need this in case 01662 // the first bin is overwritten with what was on disk. 01663 // 01664 RootCell = Hive->BaseBlock->RootCell; 01665 RootNode = (PCM_KEY_NODE)HvGetCell(Hive, RootCell); 01666 LinkCell = RootNode->Parent; 01667 01668 // 01669 // Any bins that have been marked as discardable, but not yet flushed to 01670 // disk, are going to be overwritten with old data. Bring them back into 01671 // memory and remove their FREE_HBIN marker from the list. 01672 // 01673 List = Hive->Storage[Stable].FreeBins.Flink; 01674 while (List != &Hive->Storage[Stable].FreeBins) { 01675 01676 FreeBin = CONTAINING_RECORD(List, FREE_HBIN, ListEntry); 01677 List = List->Flink; 01678 01679 if (FreeBin->Flags & FREE_HBIN_DISCARDABLE) { 01680 for (i=0; i<FreeBin->Size; i+=HBLOCK_SIZE) { 01681 Map = HvpGetCellMap(Hive, FreeBin->FileOffset+i); 01682 VALIDATE_CELL_MAP(__LINE__,Map,Hive,FreeBin->FileOffset+i); 01683 Map->BlockAddress = (Map->BinAddress & HMAP_BASE)+i; 01684 Map->BinAddress &= ~HMAP_DISCARDABLE; 01685 } 01686 RemoveEntryList(&FreeBin->ListEntry); 01687 (Hive->Free)(FreeBin, sizeof(FREE_HBIN)); 01688 } 01689 } 01690 01691 // 01692 // OverRead base block. 01693 // 01694 Offset = 0; 01695 if ( (Hive->FileRead)( 01696 Hive, 01697 HFILE_TYPE_PRIMARY, 01698 &Offset, 01699 Hive->BaseBlock, 01700 HBLOCK_SIZE 01701 ) != TRUE) 01702 { 01703 KeBugCheckEx(REGISTRY_ERROR,7,1,0,0); 01704 } 01705 TailStart = (HCELL_INDEX)(Hive->BaseBlock->Length); 01706 01707 // 01708 // Free "tail" memory and maps for it, update hive size pointers 01709 // 01710 HvFreeHivePartial(Hive, TailStart, Stable); 01711 01712 // 01713 // Clear dirty vector for data past Hive->BaseBlock->Length 01714 // 01715 Start = Hive->BaseBlock->Length / HSECTOR_SIZE; 01716 End = Hive->DirtyVector.SizeOfBitMap; 01717 BitLength = End - Start; 01718 01719 RtlClearBits(&(Hive->DirtyVector), Start, BitLength); 01720 01721 // 01722 // Scan dirty blocks. Read contiguous blocks off disk into hive. 01723 // Stop when we get to reduced length. 01724 // 01725 BitMap = &(Hive->DirtyVector); 01726 Current = 0; 01727 while (HvpFindNextDirtyBlock( 01728 Hive, 01729 &Hive->DirtyVector, 01730 &Current, &Address, 01731 &ReadLength, 01732 &Offset 01733 )) 01734 { 01735 ASSERT(Offset < (Hive->BaseBlock->Length + sizeof(HBASE_BLOCK))); 01736 rc = (Hive->FileRead)( 01737 Hive, 01738 HFILE_TYPE_PRIMARY, 01739 &Offset, 01740 (PVOID)Address, 01741 ReadLength 01742 ); 01743 if (rc == FALSE) { 01744 KeBugCheckEx(REGISTRY_ERROR,7,2,(ULONG_PTR)&Offset,rc); 01745 } 01746 } 01747 01748 // 01749 // If we read the start of any HBINs into memory, it is likely 01750 // their MemAlloc fields are invalid. Walk through the HBINs 01751 // and write valid MemAlloc values for any HBINs whose first 01752 // sector was reread. 01753 // 01754 p=0; 01755 while (p < Hive->Storage[Stable].Length) { 01756 t = HvpGetCellMap(Hive, p); 01757 VALIDATE_CELL_MAP(__LINE__,t,Hive,p); 01758 Bin = (PHBIN)(t->BlockAddress & HMAP_BASE); 01759 01760 if ((t->BinAddress & HMAP_DISCARDABLE)==0) { 01761 if (RtlCheckBit(&Hive->DirtyVector, p / HSECTOR_SIZE)==1) { 01762 // 01763 // The first sector in the HBIN is dirty. 01764 // 01765 // Reset the BinAddress to the Block address to cover 01766 // the case where a few smaller bins have been coalesced 01767 // into a larger bin. We want the smaller bins back now. 01768 // 01769 t->BinAddress = (t->BinAddress & ~HMAP_BASE) | t->BlockAddress; 01770 01771 // Check the map to see if this is the start 01772 // of a memory allocation or not. 01773 // 01774 01775 if (t->BinAddress & HMAP_NEWALLOC) { 01776 // 01777 // Walk through the map to determine the length 01778 // of the allocation. 01779 // 01780 Bin->MemAlloc = 0; 01781 do { 01782 t = HvpGetCellMap(Hive, p+Bin->MemAlloc+HBLOCK_SIZE); 01783 Bin->MemAlloc += HBLOCK_SIZE; 01784 if (p+Bin->MemAlloc == Hive->Storage[Stable].Length) { 01785 // 01786 // Reached the end of the hive. 01787 // 01788 break; 01789 } 01790 VALIDATE_CELL_MAP(__LINE__,t,Hive,p+Bin->MemAlloc); 01791 } while ( (t->BinAddress & HMAP_NEWALLOC) == 0); 01792 01793 } else { 01794 Bin->MemAlloc = 0; 01795 } 01796 } 01797 01798 p += Bin->Size; 01799 01800 } else { 01801 FreeBin = (PFREE_HBIN)t->BlockAddress; 01802 p += FreeBin->Size; 01803 } 01804 } 01805 01806 // 01807 // be sure we haven't filled memory with trash 01808 // 01809 checkstatus = HvCheckHive(Hive, NULL); 01810 if (checkstatus != 0) { 01811 KeBugCheckEx(REGISTRY_ERROR,7,3,(ULONG_PTR)Hive,checkstatus); 01812 } 01813 01814 // 01815 // reinit the free list 01816 // 01817 for (i = 0; i < HHIVE_FREE_DISPLAY_SIZE; i++) { 01818 Hive->Storage[Stable].FreeDisplay[i] = HCELL_NIL; 01819 TailDisplay[i] = HCELL_NIL; 01820 } 01821 Hive->Storage[Stable].FreeSummary = 0; 01822 01823 // 01824 // rebuild the free list 01825 // 01826 p = 0; 01827 while (p < Hive->Storage[Stable].Length) { 01828 t = HvpGetCellMap(Hive, p); 01829 VALIDATE_CELL_MAP(__LINE__,t,Hive,p); 01830 01831 if ((t->BinAddress & HMAP_DISCARDABLE) == 0) { 01832 Bin = (PHBIN)((t->BinAddress) & HMAP_BASE); 01833 01834 if ( ! HvpEnlistFreeCells(Hive, Bin, Bin->FileOffset,TailDisplay)) { 01835 KeBugCheckEx(REGISTRY_ERROR,7,5,(ULONG_PTR)Bin,Bin->FileOffset); 01836 } 01837 01838 p = (ULONG)p + Bin->Size; 01839 } else { 01840 FreeBin = (PFREE_HBIN)t->BlockAddress; 01841 p = (ULONG)p + FreeBin->Size; 01842 } 01843 } 01844 01845 // 01846 // Finally we need to rewrite the parent field in the root hcell. This is 01847 // patched in at hive load time so the correct value could have just been 01848 // overwritten with whatever happened to be on disk. 01849 // 01850 RootNode = (PCM_KEY_NODE)HvGetCell(Hive, RootCell); 01851 RootNode->Parent = LinkCell; 01852 RootNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE; 01853 01854 01855 // 01856 // be sure the structure of the thing is OK after all this 01857 // 01858 checkstatus = CmCheckRegistry((PCMHIVE)Hive, FALSE); 01859 if (checkstatus != 0) { 01860 KeBugCheckEx(REGISTRY_ERROR,7,6,(ULONG_PTR)Hive,checkstatus); 01861 } 01862 01863 // 01864 // Clear dirty vector. 01865 // 01866 RtlClearAllBits(&(Hive->DirtyVector)); 01867 Hive->DirtyCount = 0; 01868 01869 01870 // 01871 // Adjust the file size, if this fails, ignore it, since it just 01872 // means the file is too big. 01873 // 01874 (Hive->FileSetSize)( 01875 Hive, 01876 HFILE_TYPE_PRIMARY, 01877 (Hive->BaseBlock->Length + HBLOCK_SIZE) 01878 ); 01879 01880 return; 01881 } 01882 01883 01884 VOID 01885 HvpDiscardBins( 01886 IN PHHIVE Hive 01887 ) 01888 01889 /*++ 01890 01891 Routine Description: 01892 01893 Walks through the dirty bins in a hive to see if any are marked 01894 discardable. If so, they are discarded and the map is updated to 01895 reflect this. 01896 01897 Arguments: 01898 01899 Hive - Supplies the hive control structure. 01900 01901 Return Value: 01902 01903 None. 01904 01905 --*/ 01906 01907 { 01908 PHBIN Bin; 01909 PHMAP_ENTRY Map; 01910 PHMAP_ENTRY PreviousMap; 01911 PHMAP_ENTRY NextMap; 01912 PFREE_HBIN FreeBin; 01913 PFREE_HBIN PreviousFreeBin; 01914 PFREE_HBIN NextFreeBin; 01915 PLIST_ENTRY List; 01916 01917 List = Hive->Storage[Stable].FreeBins.Flink; 01918 01919 while (List != &Hive->Storage[Stable].FreeBins) { 01920 ASSERT_LISTENTRY(List); 01921 FreeBin = CONTAINING_RECORD(List, FREE_HBIN, ListEntry); 01922 01923 if (FreeBin->Flags & FREE_HBIN_DISCARDABLE) { 01924 Map = HvpGetCellMap(Hive, FreeBin->FileOffset); 01925 VALIDATE_CELL_MAP(__LINE__,Map,Hive,FreeBin->FileOffset); 01926 Bin = (PHBIN)(Map->BinAddress & HMAP_BASE); 01927 ASSERT(Map->BinAddress & HMAP_DISCARDABLE); 01928 // 01929 // Note we use ExFreePool directly here to avoid 01930 // giving back the quota for this bin. By charging 01931 // registry quota for discarded bins, we prevent 01932 // sparse hives from requiring more quota after 01933 // a reboot than on a running system. 01934 // 01935 ExFreePool(Bin); 01936 FreeBin->Flags &= ~FREE_HBIN_DISCARDABLE; 01937 } 01938 List=List->Flink; 01939 } 01940 01941 } 01942 01943 01944 01945 VOID 01946 HvpTruncateBins( 01947 IN PHHIVE Hive 01948 ) 01949 01950 /*++ 01951 01952 Routine Description: 01953 01954 Attempts to shrink the hive by truncating any bins that are discardable at 01955 the end of the hive. Applies to both stable and volatile storage. 01956 01957 Arguments: 01958 01959 Hive - Supplies the hive to be truncated. 01960 01961 Return Value: 01962 01963 None. 01964 01965 --*/ 01966 01967 { 01968 HSTORAGE_TYPE i; 01969 PHMAP_ENTRY Map; 01970 ULONG NewLength; 01971 PFREE_HBIN FreeBin; 01972 01973 // 01974 // stable and volatile 01975 // 01976 for (i=0;i<HTYPE_COUNT;i++) { 01977 01978 // 01979 // find the last in-use bin in the hive 01980 // 01981 NewLength = Hive->Storage[i].Length; 01982 01983 while (NewLength > 0) { 01984 Map = HvpGetCellMap(Hive, (NewLength - HBLOCK_SIZE) + (i*HCELL_TYPE_MASK)); 01985 VALIDATE_CELL_MAP(__LINE__,Map,Hive,(NewLength - HBLOCK_SIZE) + (i*HCELL_TYPE_MASK)); 01986 if (Map->BinAddress & HMAP_DISCARDABLE) { 01987 FreeBin = (PFREE_HBIN)Map->BlockAddress; 01988 NewLength = FreeBin->FileOffset; 01989 } else { 01990 break; 01991 } 01992 } 01993 01994 if (NewLength < Hive->Storage[i].Length) { 01995 // 01996 // There are some free bins to truncate. 01997 // 01998 HvFreeHivePartial(Hive, NewLength, i); 01999 } 02000 } 02001 } 02002 02003 #ifdef _WRITE_PROTECTED_REGISTRY_POOL 02004 02005 VOID 02006 HvpChangeBinAllocation( 02007 PHBIN Bin, 02008 BOOLEAN ReadOnly 02009 ) 02010 { 02011 ASSERT(Bin->Signature == HBIN_SIGNATURE); 02012 // 02013 // Here to call the code to mark the memory pointed by Bin as Read/Write or ReadOnly, depending on the ReadOnly argument 02014 // 02015 } 02016 02017 VOID 02018 HvpMarkBinReadWrite( 02019 PHHIVE Hive, 02020 HCELL_INDEX Cell 02021 ) 02022 /*++ 02023 02024 Routine Description: 02025 02026 Marks the memory allocated for the bin containing the specified cell as read/write. 02027 02028 Arguments: 02029 02030 Hive - supplies a pointer to the hive control structure for the 02031 hive of interest 02032 02033 Cell - hcell_index of cell 02034 02035 Return Value: 02036 02037 NONE (It should work!) 02038 02039 --*/ 02040 { 02041 ULONG Type; 02042 PHMAP_ENTRY Me; 02043 PHBIN Bin; 02044 02045 ASSERT(Hive->Signature == HHIVE_SIGNATURE); 02046 ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); 02047 02048 Type = HvGetCellType(Cell); 02049 02050 if ( (Hive->HiveFlags & HIVE_VOLATILE) || 02051 (Type == Volatile) ) 02052 { 02053 // nothing to do on a volatile hive 02054 return; 02055 } 02056 02057 Me = HvpGetCellMap(Hive, Cell); 02058 VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell); 02059 Bin = (PHBIN)(Me->BinAddress & HMAP_BASE); 02060 02061 HvpChangeBinAllocation(Bin,FALSE); 02062 02063 } 02064 02065 #endif 02066

Generated on Sat May 15 19:40:18 2004 for test by doxygen 1.3.7