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

3942 lines
115 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. hivesync.c
  5. Abstract:
  6. This module implements procedures to write dirty parts of a hive's
  7. stable store to backing media.
  8. Author:
  9. Bryan M. Willman (bryanwi) 28-Mar-92
  10. Environment:
  11. Revision History:
  12. --*/
  13. #include "cmp.h"
  14. #define ONE_K 1024
  15. extern BOOLEAN HvShutdownComplete; // Set to true after shutdown
  16. // to disable any further I/O
  17. extern BOOLEAN CmpDontGrowLogFile;
  18. extern PUCHAR CmpStashBuffer;
  19. extern ULONG CmpStashBufferSize;
  20. extern BOOLEAN CmpFlushOnLockRelease;
  21. extern LONG CmRegistryLogSizeLimit;
  22. extern HIVE_LIST_ENTRY CmpMachineHiveList[];
  23. VOID
  24. CmpFreeCmView (
  25. PCM_VIEW_OF_FILE CmView
  26. );
  27. VOID
  28. CmpUnmapCmViewSurroundingOffset(
  29. IN PCMHIVE CmHive,
  30. IN ULONG FileOffset
  31. );
  32. VOID
  33. CmpReferenceHiveView( IN PCMHIVE CmHive,
  34. IN PCM_VIEW_OF_FILE CmView
  35. );
  36. VOID
  37. CmpDereferenceHiveView( IN PCMHIVE CmHive,
  38. IN PCM_VIEW_OF_FILE CmView
  39. );
  40. VOID
  41. CmpReferenceHiveViewWithLock( IN PCMHIVE CmHive,
  42. IN PCM_VIEW_OF_FILE CmView
  43. );
  44. VOID
  45. CmpDereferenceHiveViewWithLock( IN PCMHIVE CmHive,
  46. IN PCM_VIEW_OF_FILE CmView
  47. );
  48. #if DBG
  49. #ifndef _CM_LDR_
  50. #define DumpDirtyVector(BitMap) \
  51. { \
  52. ULONG BitMapSize; \
  53. PUCHAR BitBuffer; \
  54. ULONG i; \
  55. UCHAR Byte; \
  56. \
  57. BitMapSize = ((BitMap)->SizeOfBitMap) / 8; \
  58. BitBuffer = (PUCHAR)((BitMap)->Buffer); \
  59. for (i = 0; i < BitMapSize; i++) { \
  60. if ((i % 8) == 0) { \
  61. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"\n\t"); \
  62. } \
  63. Byte = BitBuffer[i]; \
  64. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"%02x ", Byte); \
  65. } \
  66. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"\n"); \
  67. }
  68. #endif //_CM_LDR_
  69. #else
  70. #define DumpDirtyVector(BitMap)
  71. #endif
  72. //
  73. // Private prototypes
  74. //
  75. BOOLEAN
  76. HvpFindNextDirtyBlock(
  77. PHHIVE Hive,
  78. PRTL_BITMAP BitMap,
  79. PULONG Current,
  80. PUCHAR *Address,
  81. PULONG Length,
  82. PULONG Offset
  83. );
  84. /*
  85. VOID
  86. HvpDiscardBins(
  87. PHHIVE Hive
  88. );
  89. */
  90. VOID
  91. HvpTruncateBins(
  92. PHHIVE Hive
  93. );
  94. VOID
  95. HvRefreshHive(
  96. PHHIVE Hive
  97. );
  98. VOID
  99. HvpFlushMappedData(
  100. IN PHHIVE Hive,
  101. IN OUT PRTL_BITMAP DirtyVector
  102. );
  103. VOID
  104. CmpUnmapCmView(
  105. IN PCMHIVE CmHive,
  106. IN PCM_VIEW_OF_FILE CmView,
  107. IN BOOLEAN MapIsValid,
  108. IN BOOLEAN MoveToEnd
  109. );
  110. #ifdef ALLOC_PRAGMA
  111. #pragma alloc_text(PAGE,HvMarkCellDirty)
  112. #if DBG
  113. #pragma alloc_text(PAGE,HvIsCellDirty)
  114. #endif //DBG
  115. #pragma alloc_text(PAGE,HvMarkDirty)
  116. //#pragma alloc_text(PAGE,HvMarkClean)
  117. #pragma alloc_text(PAGE,HvpGrowLog1)
  118. #pragma alloc_text(PAGE,HvpGrowLog2)
  119. #pragma alloc_text(PAGE,HvSyncHive)
  120. #pragma alloc_text(PAGE,HvpDoWriteHive)
  121. #pragma alloc_text(PAGE,HvpWriteLog)
  122. #pragma alloc_text(PAGE,HvpFindNextDirtyBlock)
  123. #pragma alloc_text(PAGE,HvWriteHive)
  124. #pragma alloc_text(PAGE,HvRefreshHive)
  125. //#pragma alloc_text(PAGE,HvpDiscardBins)
  126. #pragma alloc_text(PAGE,HvHiveWillShrink)
  127. #pragma alloc_text(PAGE,HvpTruncateBins)
  128. #pragma alloc_text(PAGE,HvpDropPagedBins)
  129. #pragma alloc_text(PAGE,HvpDropAllPagedBins)
  130. #pragma alloc_text(PAGE,HvpFlushMappedData)
  131. #ifdef WRITE_PROTECTED_REGISTRY_POOL
  132. #pragma alloc_text(PAGE,HvpChangeBinAllocation)
  133. #pragma alloc_text(PAGE,HvpMarkBinReadWrite)
  134. #endif //WRITE_PROTECTED_REGISTRY_POOL
  135. #ifdef CM_ENABLE_WRITE_ONLY_BINS
  136. //
  137. // This code uses MmProtectSpecialPool to protect large paged-pool allocations.
  138. // To do so, the system must be booted with special pool enabled (doesn't have
  139. // to actually get used) *AND* ntos\mm\specpool.c must be compiled with
  140. // _PROTECT_PAGED_POOL defined.
  141. //
  142. #pragma alloc_text(PAGE,HvpMarkAllBinsWriteOnly)
  143. #endif //CM_ENABLE_WRITE_ONLY_BINS
  144. #endif
  145. BOOLEAN
  146. HvMarkCellDirty(
  147. PHHIVE Hive,
  148. HCELL_INDEX Cell
  149. )
  150. /*++
  151. Routine Description:
  152. Marks the data for the specified cell dirty.
  153. Arguments:
  154. Hive - supplies a pointer to the hive control structure for the
  155. hive of interest
  156. Cell - hcell_index of cell that is being edited
  157. Return Value:
  158. TRUE - it worked
  159. FALSE - could not allocate log space, failure!
  160. --*/
  161. {
  162. ULONG Type;
  163. ULONG Size;
  164. PHCELL pCell;
  165. PHMAP_ENTRY Me;
  166. HCELL_INDEX Base;
  167. PHBIN Bin;
  168. PCMHIVE CmHive;
  169. #if DBG
  170. ULONG DirtyCount = RtlNumberOfSetBits(&Hive->DirtyVector);
  171. #endif
  172. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvMarkCellDirty:\n\t"));
  173. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Cell:%08lx\n", Hive, Cell));
  174. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  175. ASSERT(Hive->ReadOnly == FALSE);
  176. ASSERT(DirtyCount == Hive->DirtyCount);
  177. //
  178. // we have the lock exclusive or nobody is operating inside this hive
  179. //
  180. //ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  181. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  182. Type = HvGetCellType(Cell);
  183. CmHive = (PCMHIVE)Hive;
  184. if ( (Hive->HiveFlags & HIVE_VOLATILE) ||
  185. (Type == Volatile) )
  186. {
  187. return TRUE;
  188. }
  189. //
  190. // this call will make sure the view containing the bin is maped in the system cache
  191. //
  192. pCell = HvpGetHCell(Hive,Cell);
  193. if( pCell == NULL ) {
  194. //
  195. // we couldn't map view for this cell
  196. // we will fail to make the cell dirty.
  197. //
  198. return FALSE;
  199. }
  200. // release the cell here as the reglock is held exclusive
  201. HvReleaseCell(Hive,Cell);
  202. Me = HvpGetCellMap(Hive, Cell);
  203. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  204. #if DBG
  205. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  206. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  207. #endif
  208. if( Me->BinAddress & HMAP_INVIEW ) {
  209. //
  210. // bin is mapped. Pin the view into memory
  211. //
  212. ASSERT( Me->CmView != NULL );
  213. if( IsListEmpty(&(Me->CmView->PinViewList)) == TRUE ) {
  214. //
  215. // the view is not already pinned. pin it
  216. //
  217. ASSERT_VIEW_MAPPED( Me->CmView );
  218. if( !NT_SUCCESS(CmpPinCmView ((PCMHIVE)CmHive,Me->CmView)) ) {
  219. //
  220. // couldn't pin view- some obscure error down in CcPinMappedData;
  221. // this will be treated as STATUS_NO_LOG_SPACE
  222. //
  223. return FALSE;
  224. }
  225. } else {
  226. //
  227. // view is already pinned; do nothing
  228. //
  229. ASSERT_VIEW_PINNED( Me->CmView );
  230. }
  231. }
  232. //
  233. // If it's an old format hive, mark the entire
  234. // bin dirty, because the Last backpointers are
  235. // such a pain to deal with in the partial
  236. // alloc and free-coalescing cases.
  237. //
  238. if (USE_OLD_CELL(Hive)) {
  239. Me = HvpGetCellMap(Hive, Cell);
  240. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  241. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  242. Base = Bin->FileOffset;
  243. Size = Bin->Size;
  244. return HvMarkDirty(Hive, Base, Size,FALSE);
  245. } else {
  246. if (pCell->Size < 0) {
  247. Size = -pCell->Size;
  248. } else {
  249. Size = pCell->Size;
  250. }
  251. ASSERT(Size < Bin->Size);
  252. return HvMarkDirty(Hive, Cell-FIELD_OFFSET(HCELL,u.NewCell), Size,FALSE);
  253. }
  254. }
  255. BOOLEAN
  256. HvMarkDirty(
  257. PHHIVE Hive,
  258. HCELL_INDEX Start,
  259. ULONG Length,
  260. BOOLEAN DirtyAndPin
  261. )
  262. /*++
  263. Routine Description:
  264. Marks the relevent parts of a hive dirty, so that they will
  265. be flushed to backing store.
  266. If Hive->Cluster is not 1, then adjacent all logical sectors
  267. in the given cluster will be forced dirty (and log space
  268. allocated for them.) This must be done here rather than in
  269. HvSyncHive so that we can know how much to grow the log.
  270. This is a noop for Volatile address range.
  271. NOTE: Range will not be marked dirty if operation fails.
  272. ATTENTION: This routine assumes that no more than a bin is marked
  273. dirty at the time.
  274. Arguments:
  275. Hive - supplies a pointer to the hive control structure for the
  276. hive of interest
  277. Start - supplies a hive virtual address (i.e., an HCELL_INDEX or
  278. like form address) of the start of the area to mark dirty.
  279. Length - inclusive length in bytes of area to mark dirty.
  280. DirtyAndPin - indicates whether we should also pin the bin marked as dirty in memory
  281. Return Value:
  282. TRUE - it worked
  283. FALSE - could not allocate log space, failure!
  284. --*/
  285. {
  286. ULONG Type;
  287. PRTL_BITMAP BitMap;
  288. ULONG First;
  289. ULONG Last;
  290. ULONG EndOfFile;
  291. ULONG i;
  292. ULONG Cluster;
  293. ULONG OriginalDirtyCount;
  294. ULONG DirtySectors;
  295. BOOLEAN Result = TRUE;
  296. PHMAP_ENTRY Map;
  297. ULONG AdjustedFirst;
  298. ULONG AdjustedLast;
  299. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvMarkDirty:\n\t"));
  300. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Start:%08lx Length:%08lx\n", Hive, Start, Length));
  301. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  302. ASSERT(Hive->ReadOnly == FALSE);
  303. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  304. Type = HvGetCellType(Start);
  305. if ( (Hive->HiveFlags & HIVE_VOLATILE) ||
  306. (Type == Volatile) )
  307. {
  308. return TRUE;
  309. }
  310. BitMap = &(Hive->DirtyVector);
  311. OriginalDirtyCount = Hive->DirtyCount;
  312. if( (DirtyAndPin == TRUE) && (((PCMHIVE)Hive)->FileObject != NULL) ) {
  313. Map = HvpGetCellMap(Hive, Start);
  314. VALIDATE_CELL_MAP(__LINE__,Map,Hive,Start);
  315. if( (Map->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0){
  316. PCM_VIEW_OF_FILE CmView;
  317. //
  318. // bin is neither in paged pool, nor in a mapped view
  319. //
  320. if( !NT_SUCCESS (CmpMapCmView((PCMHIVE)Hive,Start,&CmView,TRUE) ) ) {
  321. return FALSE;
  322. }
  323. #if DBG
  324. if(CmView != Map->CmView) {
  325. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmView = %p Map->CmView = %p\n",CmView,Map->CmView));
  326. }
  327. #endif
  328. ASSERT( CmView == Map->CmView );
  329. }
  330. if( Map->BinAddress & HMAP_INVIEW ) {
  331. //
  332. // bin is mapped. Pin the view into memory
  333. //
  334. ASSERT( Map->CmView != NULL );
  335. if( IsListEmpty(&(Map->CmView->PinViewList)) == TRUE ) {
  336. //
  337. // the view is not already pinned. pin it
  338. //
  339. ASSERT_VIEW_MAPPED( Map->CmView );
  340. if( !NT_SUCCESS(CmpPinCmView ((PCMHIVE)Hive,Map->CmView)) ) {
  341. //
  342. // couldn't pin view- some obscure error down in CcPinMappedData;
  343. // this will be treated as STATUS_NO_LOG_SPACE
  344. //
  345. return FALSE;
  346. }
  347. } else {
  348. //
  349. // view is already pinned; do nothing
  350. //
  351. ASSERT_VIEW_PINNED( Map->CmView );
  352. }
  353. }
  354. }
  355. AdjustedFirst = First = Start / HSECTOR_SIZE;
  356. AdjustedLast = Last = (Start + Length - 1) / HSECTOR_SIZE;
  357. Cluster = Hive->Cluster;
  358. if (Cluster > 1) {
  359. //
  360. // Force Start down to base of cluster
  361. // Force End up to top of cluster
  362. //
  363. AdjustedFirst = AdjustedFirst & ~(Cluster - 1);
  364. AdjustedLast = ROUND_UP(AdjustedLast+1, Cluster) - 1;
  365. }
  366. //
  367. // we need to mark all page(s) dirty, so we don't conflict with cache manager
  368. //
  369. ASSERT( PAGE_SIZE >= HSECTOR_SIZE );
  370. ASSERT( (PAGE_SIZE % HSECTOR_SIZE) == 0 );
  371. //
  372. // adjust the range to fit an entire page
  373. // make sure we account for the first HBLOCK at the beggining of the hive
  374. //
  375. AdjustedFirst = (AdjustedFirst + HSECTOR_COUNT) & ~(HSECTOR_PER_PAGE_COUNT - 1);
  376. AdjustedLast = ROUND_UP(AdjustedLast + HSECTOR_COUNT + 1, HSECTOR_PER_PAGE_COUNT) - 1;
  377. AdjustedLast -= HSECTOR_COUNT;
  378. if( AdjustedFirst ) {
  379. AdjustedFirst -= HSECTOR_COUNT;
  380. }
  381. //
  382. // when the PAGE_SIZE > HBLOCK_SIZE and the length of the hive does not round at PAGE_SIZE boundary
  383. //
  384. EndOfFile = Hive->Storage[Stable].Length / HSECTOR_SIZE;
  385. if (AdjustedLast >= EndOfFile) {
  386. AdjustedLast = EndOfFile-1;
  387. }
  388. //
  389. // make sure that between first and last all bins are valid (either pinned
  390. // or allocated from paged pool). Case hit on John's IA64 machine on
  391. // Feb 18 2000, when at the previous save a bin (at offset 3ff000 and size 0x2000)
  392. // was dropped, then some new bins were added, and the whole 400000 - 402000 region
  393. // was marked dirty (PAGE_SIZE == 0x2000), remember?
  394. //
  395. ASSERT( First >= AdjustedFirst );
  396. ASSERT( Last <= AdjustedLast );
  397. //CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"HvMarkDirty - First = %08lx, Last = %08lx ",First,Last));
  398. //
  399. // adjust First and Last at HBLOCK_SIZE boundaries
  400. //
  401. First = First & ~(HSECTOR_COUNT - 1);
  402. Last = ROUND_UP(Last+1, HSECTOR_COUNT) - 1;
  403. //
  404. // sanity asserts; these prove we can skip HSECTOR_COUNT at one time bellow
  405. //
  406. ASSERT( First >= AdjustedFirst );
  407. ASSERT( Last <= AdjustedLast );
  408. ASSERT( (First % HSECTOR_COUNT) == 0 );
  409. ASSERT( (AdjustedFirst % HSECTOR_COUNT) == 0 );
  410. ASSERT( ((Last+1) % HSECTOR_COUNT) == 0 );
  411. ASSERT( ((AdjustedLast +1) % HSECTOR_COUNT) == 0 );
  412. ASSERT( ((First - AdjustedFirst) % HSECTOR_COUNT) == 0 );
  413. ASSERT( ((AdjustedLast - Last) % HSECTOR_COUNT) == 0 );
  414. //
  415. // when we exit this loop; First is always a valid bin/sector
  416. //
  417. while( First > AdjustedFirst ) {
  418. //
  419. // map-in this address, and if is valid, decrement First, else break out of the loop
  420. //
  421. First -= HSECTOR_COUNT;
  422. Map = HvpGetCellMap(Hive, First*HSECTOR_SIZE);
  423. if( BIN_MAP_ALLOCATION_TYPE(Map) == 0 ) {
  424. //
  425. // oops this bin is not valid ! bail out !
  426. //
  427. First += HSECTOR_COUNT;
  428. break;
  429. }
  430. if( Map->BinAddress & HMAP_INVIEW ) {
  431. //
  432. // previous bin mapped in view ==> view needs to be pinned
  433. //
  434. ASSERT( Map->CmView );
  435. if( IsListEmpty(&(Map->CmView->PinViewList) ) == TRUE ) {
  436. //
  437. // oops; bin not pinned; bail out;
  438. //
  439. First += HSECTOR_COUNT;
  440. break;
  441. }
  442. }
  443. }
  444. //
  445. // when we exit this loop; Last is always a valid bin/sector
  446. //
  447. while( Last < AdjustedLast ) {
  448. //
  449. // map-in this address, and if is valid, increment Last, else break out of the loop
  450. //
  451. Last += HSECTOR_COUNT;
  452. Map = HvpGetCellMap(Hive, Last*HSECTOR_SIZE);
  453. if( BIN_MAP_ALLOCATION_TYPE(Map) == 0 ) {
  454. //
  455. // oops this bin is not valid ! bail out !
  456. //
  457. Last -= HSECTOR_COUNT;
  458. break;
  459. }
  460. if( Map->BinAddress & HMAP_INVIEW ) {
  461. //
  462. // previous bin mapped in view ==> view needs to be pinned
  463. //
  464. ASSERT( Map->CmView );
  465. if( IsListEmpty(&(Map->CmView->PinViewList) ) == TRUE ) {
  466. //
  467. // oops; bin not pinned; bail out;
  468. //
  469. Last -= HSECTOR_COUNT;
  470. break;
  471. }
  472. }
  473. }
  474. //CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL," Adjusted : First = %08lx, Last = %08lx\n",First,Last));
  475. //
  476. // Try and grow the log enough to accomodate all the dirty sectors.
  477. //
  478. DirtySectors = 0;
  479. for (i = First; i <= Last; i++) {
  480. if (RtlCheckBit(BitMap, i)==0) {
  481. ++DirtySectors;
  482. }
  483. }
  484. if (DirtySectors != 0) {
  485. if (HvpGrowLog1(Hive, DirtySectors) == FALSE) {
  486. return(FALSE);
  487. }
  488. if ((OriginalDirtyCount == 0) && (First != 0)) {
  489. Result = HvMarkDirty(Hive, 0, sizeof(HBIN),TRUE); // force header of 1st bin dirty
  490. if (Result==FALSE) {
  491. return(FALSE);
  492. }
  493. }
  494. //
  495. // Log has been successfully grown, go ahead
  496. // and set the dirty bits.
  497. //
  498. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  499. ASSERT( First <= Last );
  500. if( First <= Last ) {
  501. Hive->DirtyCount += DirtySectors;
  502. RtlSetBits(BitMap, First, Last-First+1);
  503. }
  504. }
  505. #ifdef CM_ENABLE_WRITE_ONLY_BINS
  506. {
  507. PHMAP_ENTRY t;
  508. PHBIN Bin;
  509. ULONG i;
  510. t = HvpGetCellMap(Hive, First*HSECTOR_SIZE);
  511. VALIDATE_CELL_MAP(__LINE__,t,Hive,First*HSECTOR_SIZE);
  512. Bin = (PHBIN)HBIN_BASE(t->BinAddress);
  513. if( t->BinAddress & HMAP_INPAGEDPOOL ) {
  514. PFREE_HBIN FreeBin;
  515. BOOLEAN SetReadWrite = TRUE;
  516. // get the free_bin and see if it's still around. if not forget about it.
  517. if(t->BinAddress & HMAP_DISCARDABLE) {
  518. FreeBin = (PFREE_HBIN)t->BlockAddress;
  519. //if(! ( FreeBin->Flags & FREE_HBIN_DISCARDABLE ) ) {
  520. SetReadWrite = FALSE;
  521. //}
  522. }
  523. //
  524. // at this point we only work with paged pool bins
  525. //
  526. if( SetReadWrite == TRUE ) {
  527. for( i=0;i<(Last-First+1)*HSECTOR_SIZE;i += PAGE_SIZE ) {
  528. if( !MmProtectSpecialPool((PUCHAR)Bin + i + First*HSECTOR_SIZE - Bin->FileOffset,PAGE_READWRITE) ) {
  529. DbgPrint("Failed to set PAGE_READWRITE protection on page at %p Bin %p size = %lx\n",Bin+i,Bin,(Last-First+1)*HSECTOR_SIZE);
  530. }
  531. }
  532. }
  533. /*
  534. if( !MmSetPageProtection(Bin,DirtySectors*HSECTOR_SIZE,PAGE_READWRITE) ) {
  535. DbgPrint("Failed to set READWRITE protection on bin at %p, size = %lx\n",Bin,DirtySectors*HSECTOR_SIZE);
  536. }
  537. */
  538. }
  539. }
  540. #endif CM_ENABLE_WRITE_ONLY_BINS
  541. // mark this bin as writable
  542. HvpMarkBinReadWrite(Hive,Start);
  543. if (!(Hive->HiveFlags & HIVE_NOLAZYFLUSH)) {
  544. CmpLazyFlush();
  545. }
  546. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  547. return(TRUE);
  548. }
  549. BOOLEAN
  550. HvpGrowLog1(
  551. PHHIVE Hive,
  552. ULONG Count
  553. )
  554. /*++
  555. Routine Description:
  556. Adjust the log for growth in the number of sectors of dirty
  557. data that are desired.
  558. Arguments:
  559. Hive - supplies a pointer to the hive control structure for the
  560. hive of interest
  561. Count - number of additional logical sectors of log space needed
  562. Return Value:
  563. TRUE - it worked
  564. FALSE - could not allocate log space, failure!
  565. --*/
  566. {
  567. ULONG ClusterSize;
  568. ULONG RequiredSize;
  569. ULONG tmp;
  570. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvpGrowLog1:\n\t"));
  571. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Count:%08lx\n", Hive, Count));
  572. ASSERT(Hive->ReadOnly == FALSE);
  573. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  574. //
  575. // If logging is off, tell caller world is OK.
  576. //
  577. if( (Hive->Log == FALSE) || CmpDontGrowLogFile) {
  578. return TRUE;
  579. }
  580. ClusterSize = Hive->Cluster * HSECTOR_SIZE;
  581. tmp = Hive->DirtyVector.SizeOfBitMap / 8; // bytes
  582. tmp += sizeof(ULONG); // signature
  583. RequiredSize =
  584. ClusterSize + // 1 cluster for header
  585. ROUND_UP(tmp, ClusterSize) +
  586. ((Hive->DirtyCount + Count) * HSECTOR_SIZE);
  587. RequiredSize = ROUND_UP(RequiredSize, HLOG_GROW);
  588. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  589. if ( ! (Hive->FileSetSize)(Hive, HFILE_TYPE_LOG, RequiredSize,Hive->LogSize)) {
  590. return FALSE;
  591. }
  592. if( CmRegistryLogSizeLimit > 0 ) {
  593. //
  594. // see if log is too big and set flush on lock release
  595. //
  596. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  597. if( RequiredSize >= (ULONG)(CmRegistryLogSizeLimit * ONE_K) ) {
  598. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"LogFile for hive %p is %lx; will flush upon lock release\n",Hive,RequiredSize);
  599. CmpFlushOnLockRelease = TRUE;
  600. }
  601. }
  602. Hive->LogSize = RequiredSize;
  603. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  604. return TRUE;
  605. }
  606. VOID
  607. HvRefreshHive(
  608. PHHIVE Hive
  609. )
  610. /*++
  611. Routine Description:
  612. Undo the last sync.
  613. The story behind the scene:
  614. 1. remove all discardable bins from FreeBins list. they'll be
  615. enlisted afterwards with the right (accurate) values.
  616. 2. read the base block, and eventually free the tail of the hive
  617. 3. unpin and purge all pinned views; also clear the free cell
  618. hint for mapped bins.
  619. 4. remap views purged at 3 and reenlist the bins inside. this
  620. will fix free bins discarded at 1.
  621. 5. iterate through the map; read and reenlist all bins that are
  622. in paged-pool (and dirty)
  623. All I/O is done via HFILE_TYPE_PRIMARY.
  624. Arguments:
  625. Hive - supplies a pointer to the hive control structure for the
  626. hive of interest.
  627. Return Value:
  628. NONE. Either works or BugChecks.
  629. Comments:
  630. In the new implementation, bins are not discarded anymore. Step 1.
  631. above is not needed anymore.
  632. Discardable bins with FREE_HBIN_DISCARDABLE flag set fall into one
  633. of the categories:
  634. 1. new bins (at the end of the hive) which didn't get a chance to
  635. be saved yet. HvFreeHivePartial will take care of them.
  636. 2. bins inside the hive allocated from paged pool and discarded.
  637. This can only happen for bins that are crossing the CM_VIEW_SIZE boundary.
  638. We will take care of them at step 5
  639. Discardable bins with FREE_HBIN_DISCARDABLE flag NOT set are free bins
  640. which came from mapped views. Step 3 will remove them from the FreeBins
  641. list and step 4 will reenlist the ones that are still free after remapping
  642. --*/
  643. {
  644. HCELL_INDEX RootCell;
  645. PCM_KEY_NODE RootNode;
  646. HCELL_INDEX LinkCell;
  647. PLIST_ENTRY List;
  648. PFREE_HBIN FreeBin;
  649. ULONG Offset;
  650. ULONG FileOffset;
  651. HCELL_INDEX TailStart;
  652. ULONG Start;
  653. ULONG End;
  654. ULONG BitLength;
  655. PCM_VIEW_OF_FILE CmView;
  656. PCMHIVE CmHive;
  657. ULONG FileOffsetStart;
  658. ULONG FileOffsetEnd;
  659. PHMAP_ENTRY Me;
  660. ULONG i;
  661. PHBIN Bin;
  662. ULONG BinSize;
  663. ULONG Current;
  664. PRTL_BITMAP BitMap;
  665. PUCHAR Address;
  666. BOOLEAN rc;
  667. ULONG ReadLength;
  668. HCELL_INDEX p;
  669. PHMAP_ENTRY t;
  670. ULONG checkstatus;
  671. ULONG OldFileLength;
  672. LIST_ENTRY PinViewListHead;
  673. ULONG Size;
  674. LARGE_INTEGER PurgeOffset;
  675. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  676. //
  677. // noop or assert on various uninteresting or bogus conditions
  678. //
  679. if (Hive->DirtyCount == 0) {
  680. return;
  681. }
  682. ASSERT(Hive->HiveFlags & HIVE_NOLAZYFLUSH);
  683. ASSERT(Hive->Storage[Volatile].Length == 0);
  684. //
  685. // be sure the hive is not already trash
  686. //
  687. checkstatus = HvCheckHive(Hive, NULL);
  688. if (checkstatus != 0) {
  689. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,1,Hive,checkstatus);
  690. }
  691. // store it for the shrink/grow at the end.
  692. OldFileLength = Hive->Storage[Stable].Length + HBLOCK_SIZE;
  693. //
  694. // Capture the LinkCell backpointer in the hive's root cell. We need this in case
  695. // the first bin is overwritten with what was on disk.
  696. //
  697. RootCell = Hive->BaseBlock->RootCell;
  698. RootNode = (PCM_KEY_NODE)HvGetCell(Hive, RootCell);
  699. if( RootNode == NULL ) {
  700. //
  701. // we couldn't map a view for this cell
  702. // we're low on resources, so we couldn't refresh the hive.
  703. //
  704. return;
  705. }
  706. // release the cell here as we are holding the reglock exclusive
  707. HvReleaseCell(Hive,RootCell);
  708. LinkCell = RootNode->Parent;
  709. Hive->RefreshCount++;
  710. //
  711. // 1. Remove all discardable bins from FreeBins list
  712. // - remove the discardable flag from the ones that
  713. // have not yet been discarded
  714. // - for discarded ones, just remove the marker from
  715. // the FreeBins list
  716. //
  717. //
  718. // Any bins that have been marked as discardable, but not yet flushed to
  719. // disk, are going to be overwritten with old data. Bring them back into
  720. // memory and remove their FREE_HBIN marker from the list. Other bins are
  721. // either discarded, or mapped into views
  722. //
  723. /*
  724. DRAGOS: This is not needed anymore (see Comments)
  725. List = Hive->Storage[Stable].FreeBins.Flink;
  726. while (List != &Hive->Storage[Stable].FreeBins) {
  727. FreeBin = CONTAINING_RECORD(List, FREE_HBIN, ListEntry);
  728. List = List->Flink;
  729. if (FreeBin->Flags & FREE_HBIN_DISCARDABLE) {
  730. for (i=0; i<FreeBin->Size; i+=HBLOCK_SIZE) {
  731. Me = HvpGetCellMap(Hive, FreeBin->FileOffset+i);
  732. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FreeBin->FileOffset+i);
  733. Me->BlockAddress = HBIN_BASE(Me->BinAddress)+i;
  734. Me->BinAddress &= ~HMAP_DISCARDABLE;
  735. }
  736. RemoveEntryList(&FreeBin->ListEntry);
  737. (Hive->Free)(FreeBin, sizeof(FREE_HBIN));
  738. }
  739. }
  740. */
  741. //
  742. // 2. read the base block, and eventually free the tail of the hive
  743. //
  744. //
  745. // OverRead base block.
  746. //
  747. Offset = 0;
  748. if ( (Hive->FileRead)(
  749. Hive,
  750. HFILE_TYPE_PRIMARY,
  751. &Offset,
  752. Hive->BaseBlock,
  753. HBLOCK_SIZE
  754. ) != TRUE)
  755. {
  756. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,2,Hive,Offset);
  757. }
  758. TailStart = (HCELL_INDEX)(Hive->BaseBlock->Length);
  759. //
  760. // Free "tail" memory and maps for it, update hive size pointers
  761. //
  762. HvFreeHivePartial(Hive, TailStart, Stable);
  763. //
  764. // Clear dirty vector for data past Hive->BaseBlock->Length
  765. //
  766. Start = Hive->BaseBlock->Length / HSECTOR_SIZE;
  767. End = Hive->DirtyVector.SizeOfBitMap;
  768. BitLength = End - Start;
  769. RtlClearBits(&(Hive->DirtyVector), Start, BitLength);
  770. HvpAdjustHiveFreeDisplay(Hive,Hive->Storage[Stable].Length,Stable);
  771. //
  772. // 3. unpin and purge all pinned views; also clear the free cell
  773. // hint for mapped bins.
  774. //
  775. CmHive = (PCMHIVE)Hive;
  776. InitializeListHead(&PinViewListHead);
  777. //
  778. // for each pinned view
  779. //
  780. while(IsListEmpty(&(CmHive->PinViewListHead)) == FALSE) {
  781. //
  782. // Remove the first view from the pin view list
  783. //
  784. CmView = (PCM_VIEW_OF_FILE)RemoveHeadList(&(CmHive->PinViewListHead));
  785. CmView = CONTAINING_RECORD( CmView,
  786. CM_VIEW_OF_FILE,
  787. PinViewList);
  788. //
  789. // the real file offset starts after the header
  790. //
  791. FileOffsetStart = CmView->FileOffset;
  792. FileOffsetEnd = FileOffsetStart + CmView->Size;
  793. FileOffsetEnd -= HBLOCK_SIZE;
  794. if( FileOffsetStart != 0 ) {
  795. //
  796. // just at the begining of the file, subtract the header
  797. //
  798. FileOffsetStart -= HBLOCK_SIZE;
  799. }
  800. FileOffset = FileOffsetStart;
  801. //
  802. // now, for every block in this range which is mapped in view
  803. // clear the dirty bit, and the free cell hint
  804. //
  805. while(FileOffset < FileOffsetEnd) {
  806. Me = HvpGetCellMap(Hive, FileOffset);
  807. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileOffset);
  808. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  809. //
  810. // ignore the bins loaded into paged pool; we'll deal with them later on
  811. //
  812. if( Me->BinAddress & HMAP_INVIEW ) {
  813. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  814. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  815. // free bins comming from mapped views are not discardable
  816. ASSERT( (FreeBin->Flags & FREE_HBIN_DISCARDABLE) == 0 );
  817. //
  818. // go and clear the discardable flag for all blocks of this bin
  819. //
  820. for( i=FileOffset;i<FileOffset+FreeBin->Size;i+=HBLOCK_SIZE) {
  821. Me = HvpGetCellMap(Hive, i);
  822. VALIDATE_CELL_MAP(__LINE__,Me,Hive,i);
  823. Me->BinAddress &= ~HMAP_DISCARDABLE;
  824. }
  825. //
  826. // get rid of the entry from FreeBins list
  827. // it'll be added again after sync is done if bin is still
  828. // discardable
  829. //
  830. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  831. ASSERT(FreeBin->FileOffset == FileOffset);
  832. RemoveEntryList(&FreeBin->ListEntry);
  833. BinSize = FreeBin->Size;
  834. (Hive->Free)(FreeBin, sizeof(FREE_HBIN));
  835. } else {
  836. //
  837. // bin is mapped in view. Then, this should be the beggining of the bin
  838. //
  839. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  840. ASSERT(Bin->FileOffset == FileOffset);
  841. BinSize = Bin->Size;
  842. }
  843. //
  844. // clear of the dirty bits for this bin
  845. //
  846. RtlClearBits(&Hive->DirtyVector,FileOffset/HSECTOR_SIZE,BinSize/HSECTOR_SIZE);
  847. //
  848. // now clear the free cell hint for this bin
  849. //
  850. for( i=0;i<HHIVE_FREE_DISPLAY_SIZE;i++) {
  851. RtlClearBits (&(Hive->Storage[Stable].FreeDisplay[i]), FileOffset / HBLOCK_SIZE, BinSize / HBLOCK_SIZE);
  852. if( RtlNumberOfSetBits(&(Hive->Storage[Stable].FreeDisplay[i]) ) != 0 ) {
  853. //
  854. // there are still some other free cells of this size
  855. //
  856. Hive->Storage[Stable].FreeSummary |= (1 << i);
  857. } else {
  858. //
  859. // entire bitmap is 0 (i.e. no other free cells of this size)
  860. //
  861. Hive->Storage[Stable].FreeSummary &= (~(1 << i));
  862. }
  863. }
  864. } else {
  865. //
  866. // bin in paged pool
  867. //
  868. ASSERT( Me->BinAddress & HMAP_INPAGEDPOOL );
  869. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  870. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  871. ASSERT(FreeBin->FileOffset == FileOffset);
  872. BinSize = FreeBin->Size;
  873. } else {
  874. //
  875. // Then, this should be the beggining of the bin
  876. //
  877. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  878. ASSERT(Bin->FileOffset == FileOffset);
  879. BinSize = Bin->Size;
  880. }
  881. }
  882. FileOffset += BinSize;
  883. }// while (FileOffset<FileOffsetEnd)
  884. //
  885. // Just unmap the view, without marking the data dirty; We'll flush cache after we finish
  886. // unpinning and unmapping all neccessary views
  887. //
  888. ASSERT( CmView->UseCount == 0 );
  889. // store this for later
  890. FileOffset = CmView->FileOffset;
  891. Size = CmView->Size;
  892. CmpUnmapCmView (CmHive,CmView,TRUE,TRUE);
  893. //
  894. // we use the PinViewList member of these views to keep track of all pinned
  895. // views that need to be remapped after the purge
  896. //
  897. InsertTailList(
  898. &PinViewListHead,
  899. &(CmView->PinViewList)
  900. );
  901. //
  902. // remove the view from the LRU list
  903. //
  904. RemoveEntryList(&(CmView->LRUViewList));
  905. //
  906. // store the FileOffset and address so we know what to map afterwards
  907. //
  908. CmView->FileOffset = FileOffset;
  909. CmView->Size = Size;
  910. //
  911. // now we need to make sure the 256K window surrounding this offset is not
  912. // mapped in any way
  913. //
  914. FileOffset = FileOffset & (~(_256K - 1));
  915. Size = FileOffset + _256K;
  916. Size = (Size > OldFileLength)?OldFileLength:Size;
  917. //
  918. // we are not allowed to purge in shared mode.
  919. //
  920. while( FileOffset < Size ) {
  921. CmpUnmapCmViewSurroundingOffset((PCMHIVE)Hive,FileOffset);
  922. FileOffset += CM_VIEW_SIZE;
  923. }
  924. }// while IsListEmpty(&(CmHive->PinViewListHead))
  925. //
  926. // Now we need to purge the the previously pinned views
  927. //
  928. PurgeOffset.HighPart = 0;
  929. CmView = (PCM_VIEW_OF_FILE)PinViewListHead.Flink;
  930. while( CmHive->PinnedViews ) {
  931. ASSERT( CmView != (PCM_VIEW_OF_FILE)(&(PinViewListHead)) );
  932. CmView = CONTAINING_RECORD( CmView,
  933. CM_VIEW_OF_FILE,
  934. PinViewList);
  935. //
  936. // now purge as a private writer
  937. //
  938. PurgeOffset.LowPart = CmView->FileOffset;
  939. CcPurgeCacheSection(CmHive->FileObject->SectionObjectPointer,(PLARGE_INTEGER)(((ULONG_PTR)(&PurgeOffset)) + 1)/*we are private writers*/,
  940. CmView->Size,FALSE);
  941. //
  942. // advance to the next view
  943. //
  944. CmView = (PCM_VIEW_OF_FILE)(CmView->PinViewList.Flink);
  945. CmHive->PinnedViews--;
  946. }
  947. ASSERT( ((PCMHIVE)CmHive)->PinnedViews == 0 );
  948. //
  949. // 4.remap views purged at 3 and reenlist the bins inside. this
  950. // will fix free bins discarded at 1.
  951. //
  952. while(IsListEmpty(&PinViewListHead) == FALSE) {
  953. //
  954. // Remove the first view from the pin view list
  955. //
  956. CmView = (PCM_VIEW_OF_FILE)RemoveHeadList(&PinViewListHead);
  957. CmView = CONTAINING_RECORD( CmView,
  958. CM_VIEW_OF_FILE,
  959. PinViewList);
  960. //
  961. // the real file offset starts after the header
  962. //
  963. FileOffsetStart = CmView->FileOffset;
  964. FileOffsetEnd = FileOffsetStart + CmView->Size;
  965. FileOffsetEnd -= HBLOCK_SIZE;
  966. if( FileOffsetStart != 0 ) {
  967. //
  968. // just at the begining of the file, subtract the header
  969. //
  970. FileOffsetStart -= HBLOCK_SIZE;
  971. }
  972. if( FileOffsetEnd > Hive->BaseBlock->Length ) {
  973. FileOffsetEnd = Hive->BaseBlock->Length;
  974. }
  975. //
  976. // be sure to free this view as nobody is using it anymore
  977. //
  978. #if DBG
  979. CmView->FileOffset = CmView->Size = 0;
  980. InitializeListHead(&(CmView->PinViewList));
  981. InitializeListHead(&(CmView->LRUViewList));
  982. #endif
  983. CmpFreeCmView (CmView);
  984. if( FileOffsetStart >= FileOffsetEnd ) {
  985. continue;
  986. }
  987. //
  988. // remap it with the right data
  989. //
  990. if( !NT_SUCCESS(CmpMapCmView(CmHive,FileOffsetStart,&CmView,TRUE) ) ) {
  991. //
  992. // this is bad. We have altered the hive and now we have no way of restoring it
  993. // bugcheck!
  994. //
  995. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,3,CmHive,FileOffsetStart);
  996. }
  997. //
  998. // touch the view
  999. //
  1000. CmpTouchView((PCMHIVE)Hive,CmView,FileOffsetStart);
  1001. FileOffset = FileOffsetStart;
  1002. while(FileOffset < FileOffsetEnd) {
  1003. Me = HvpGetCellMap(Hive, FileOffset);
  1004. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileOffset);
  1005. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  1006. //
  1007. // ignore paged bins
  1008. //
  1009. if( Me->BinAddress & HMAP_INVIEW ) {
  1010. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  1011. ASSERT(Bin->FileOffset == FileOffset);
  1012. // enlisting freecells will fix the free bins problem too
  1013. if ( ! HvpEnlistFreeCells(Hive, Bin, Bin->FileOffset) ) {
  1014. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,4,Bin,Bin->FileOffset);
  1015. }
  1016. FileOffset += Bin->Size;
  1017. } else {
  1018. FileOffset += HBLOCK_SIZE;
  1019. }
  1020. }
  1021. } // while (IsListEmpty(&PinViewListHead))
  1022. // 5. iterate through the map; read and reenlist all bins that are
  1023. // in paged-pool (and dirty)
  1024. //
  1025. // Scan dirty blocks. Read contiguous blocks off disk into hive.
  1026. // Stop when we get to reduced length.
  1027. //
  1028. BitMap = &(Hive->DirtyVector);
  1029. Current = 0;
  1030. while (HvpFindNextDirtyBlock(
  1031. Hive,
  1032. &Hive->DirtyVector,
  1033. &Current, &Address,
  1034. &ReadLength,
  1035. &Offset
  1036. ))
  1037. {
  1038. ASSERT(Offset < (Hive->BaseBlock->Length + sizeof(HBASE_BLOCK)));
  1039. rc = (Hive->FileRead)(
  1040. Hive,
  1041. HFILE_TYPE_PRIMARY,
  1042. &Offset,
  1043. (PVOID)Address,
  1044. ReadLength
  1045. );
  1046. if (rc == FALSE) {
  1047. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,5,Offset,Address);
  1048. }
  1049. }
  1050. //
  1051. // If we read the start of any HBINs into memory, it is likely
  1052. // their MemAlloc fields are invalid. Walk through the HBINs
  1053. // and write valid MemAlloc values for any HBINs whose first
  1054. // sector was reread.
  1055. //
  1056. // HvpFindNextDirtyBlock knows how to deal with free bins. If we
  1057. // reread a free bin, we need to delist it from the list first and
  1058. // reenlist it again (it may not be free on the disk)
  1059. //
  1060. p=0;
  1061. while (p < Hive->Storage[Stable].Length) {
  1062. t = HvpGetCellMap(Hive, p);
  1063. VALIDATE_CELL_MAP(__LINE__,t,Hive,p);
  1064. Bin = (PHBIN)HBIN_BASE(t->BlockAddress);
  1065. if (RtlCheckBit(&Hive->DirtyVector, p / HSECTOR_SIZE)==1) {
  1066. if ((t->BinAddress & HMAP_DISCARDABLE) != 0) {
  1067. //
  1068. // this was a free bin. It may not be a free bin on the disk
  1069. //
  1070. FreeBin = (PFREE_HBIN)t->BlockAddress;
  1071. // free bins comming from paged pool are always discardable
  1072. ASSERT( FreeBin->Flags & FREE_HBIN_DISCARDABLE );
  1073. // if the bin has been discarded since the last save, all bin should be dirty!!!
  1074. ASSERT(FreeBin->FileOffset == p);
  1075. //
  1076. // go and clear the discardable flag for all blocks of this bin
  1077. //
  1078. for( i=0;i<FreeBin->Size;i+=HBLOCK_SIZE) {
  1079. Me = HvpGetCellMap(Hive, p + i);
  1080. VALIDATE_CELL_MAP(__LINE__,Me,Hive,p+i);
  1081. Me->BlockAddress = HBIN_BASE(Me->BinAddress)+i;
  1082. Me->BinAddress &= ~HMAP_DISCARDABLE;
  1083. }
  1084. Bin = (PHBIN)HBIN_BASE(t->BlockAddress);
  1085. //
  1086. // get rid of the entry from FreeBins list
  1087. // it'll be added again after sync is done if bin is still
  1088. // discardable
  1089. //
  1090. RemoveEntryList(&FreeBin->ListEntry);
  1091. (Hive->Free)(FreeBin, sizeof(FREE_HBIN));
  1092. }
  1093. //
  1094. // only paged bins should be dirty at this time
  1095. //
  1096. ASSERT( t->BinAddress & HMAP_INPAGEDPOOL );
  1097. //
  1098. // The first sector in the HBIN is dirty.
  1099. //
  1100. // Reset the BinAddress to the Block address to cover
  1101. // the case where a few smaller bins have been coalesced
  1102. // into a larger bin. We want the smaller bins back now.
  1103. //
  1104. t->BinAddress = HBIN_FLAGS(t->BinAddress) | t->BlockAddress;
  1105. // Check the map to see if this is the start
  1106. // of a memory allocation or not.
  1107. //
  1108. if (t->BinAddress & HMAP_NEWALLOC) {
  1109. //
  1110. // Walk through the map to determine the length
  1111. // of the allocation.
  1112. //
  1113. PULONG BinAlloc = &(t->MemAlloc);
  1114. *BinAlloc = 0;
  1115. do {
  1116. t = HvpGetCellMap(Hive, p + (*BinAlloc) + HBLOCK_SIZE);
  1117. (*BinAlloc) += HBLOCK_SIZE;
  1118. if (p + (*BinAlloc) == Hive->Storage[Stable].Length) {
  1119. //
  1120. // Reached the end of the hive.
  1121. //
  1122. break;
  1123. }
  1124. VALIDATE_CELL_MAP(__LINE__,t,Hive,p + (*BinAlloc));
  1125. } while ( (t->BinAddress & HMAP_NEWALLOC) == 0);
  1126. //
  1127. // this will reenlist the bin if free
  1128. //
  1129. if ( ! HvpEnlistFreeCells(Hive, Bin, Bin->FileOffset)) {
  1130. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,6,Bin,Bin->FileOffset);
  1131. }
  1132. } else {
  1133. t->MemAlloc = 0;
  1134. }
  1135. RtlClearBits(&Hive->DirtyVector,Bin->FileOffset/HSECTOR_SIZE,Bin->Size/HSECTOR_SIZE);
  1136. p = Bin->FileOffset + Bin->Size;
  1137. } else {
  1138. //
  1139. // we do that to avoid touching bins that may not be mapped
  1140. //
  1141. p += HBLOCK_SIZE;
  1142. }
  1143. }
  1144. //
  1145. // be sure we haven't filled memory with trash
  1146. //
  1147. checkstatus = HvCheckHive(Hive, NULL);
  1148. if (checkstatus != 0) {
  1149. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,7,Hive,checkstatus);
  1150. }
  1151. //
  1152. // Finally we need to rewrite the parent field in the root hcell. This is
  1153. // patched in at hive load time so the correct value could have just been
  1154. // overwritten with whatever happened to be on disk.
  1155. //
  1156. RootNode = (PCM_KEY_NODE)HvGetCell(Hive, RootCell);
  1157. if( RootNode == NULL ) {
  1158. //
  1159. // we couldn't map a view for this cell
  1160. // there is nothing we can do here, other than pray for this not to happen
  1161. //
  1162. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,8,Hive,RootCell);
  1163. return;
  1164. }
  1165. // release the cell here as we are holding the reglock exclusive
  1166. HvReleaseCell(Hive,RootCell);
  1167. RootNode->Parent = LinkCell;
  1168. RootNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
  1169. //
  1170. // all bits in the dirty vector should be clean by now
  1171. //
  1172. ASSERT( RtlNumberOfSetBits( &(Hive->DirtyVector) ) == 0 );
  1173. Hive->DirtyCount = 0;
  1174. #ifdef CM_ENABLE_WRITE_ONLY_BINS
  1175. HvpMarkAllBinsWriteOnly(Hive);
  1176. #endif //CM_ENABLE_WRITE_ONLY_BINS
  1177. //
  1178. // Adjust the file size, if this fails, ignore it, since it just
  1179. // means the file is too big. Do it here, where we are sure we have
  1180. // no pinned data whatsoever.
  1181. //
  1182. (Hive->FileSetSize)(
  1183. Hive,
  1184. HFILE_TYPE_PRIMARY,
  1185. (Hive->BaseBlock->Length + HBLOCK_SIZE),
  1186. OldFileLength
  1187. );
  1188. //
  1189. // be sure the structure of the thing is OK after all this
  1190. //
  1191. checkstatus = CmCheckRegistry((PCMHIVE)Hive, CM_CHECK_REGISTRY_FORCE_CLEAN);
  1192. if (checkstatus != 0) {
  1193. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,9,Hive,checkstatus);
  1194. }
  1195. //
  1196. // be sure there are no security cells thrown away in the cache
  1197. //
  1198. if( !CmpRebuildSecurityCache((PCMHIVE)Hive) ) {
  1199. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,10,Hive,0);
  1200. }
  1201. return;
  1202. }
  1203. #ifdef WRITE_PROTECTED_REGISTRY_POOL
  1204. VOID
  1205. HvpChangeBinAllocation(
  1206. PHBIN Bin,
  1207. BOOLEAN ReadOnly
  1208. )
  1209. {
  1210. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  1211. //
  1212. // Here to call the code to mark the memory pointed by Bin as Read/Write or ReadOnly, depending on the ReadOnly argument
  1213. //
  1214. }
  1215. VOID
  1216. HvpMarkBinReadWrite(
  1217. PHHIVE Hive,
  1218. HCELL_INDEX Cell
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. Marks the memory allocated for the bin containing the specified cell as read/write.
  1223. Arguments:
  1224. Hive - supplies a pointer to the hive control structure for the
  1225. hive of interest
  1226. Cell - hcell_index of cell
  1227. Return Value:
  1228. NONE (It should work!)
  1229. --*/
  1230. {
  1231. ULONG Type;
  1232. PHMAP_ENTRY Me;
  1233. PHBIN Bin;
  1234. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1235. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1236. Type = HvGetCellType(Cell);
  1237. if ( (Hive->HiveFlags & HIVE_VOLATILE) ||
  1238. (Type == Volatile) )
  1239. {
  1240. // nothing to do on a volatile hive
  1241. return;
  1242. }
  1243. Me = HvpGetCellMap(Hive, Cell);
  1244. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  1245. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  1246. HvpChangeBinAllocation(Bin,FALSE);
  1247. }
  1248. #endif //WRITE_PROTECTED_REGISTRY_POOL
  1249. #if DBG
  1250. BOOLEAN
  1251. HvIsCellDirty(
  1252. IN PHHIVE Hive,
  1253. IN HCELL_INDEX Cell
  1254. )
  1255. /*++
  1256. Routine Description:
  1257. Given a hive and a cell, checks whether the corresponding sector
  1258. is marked as dirty.
  1259. NOTE: This function assumes the view containing the bin is
  1260. mapped into system space.
  1261. Arguments:
  1262. Hive - Supplies a pointer to the hive control structure
  1263. Cell - Supplies the HCELL_INDEX of the Cell.
  1264. Return Value:
  1265. TRUE - Data is marked as dirty.
  1266. FALSE - Data is NOT marked as dirty.
  1267. --*/
  1268. {
  1269. ULONG Type;
  1270. PRTL_BITMAP Bitmap;
  1271. ULONG Offset;
  1272. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvIsCellDirty:\n\t"));
  1273. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Cell:%08lx\n", Hive, Cell));
  1274. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1275. ASSERT(Hive->ReadOnly == FALSE);
  1276. Type = HvGetCellType(Cell);
  1277. if ( (Hive->HiveFlags & HIVE_VOLATILE) ||
  1278. (Type == Volatile) )
  1279. {
  1280. //
  1281. // we don't care as we are never going to save this data
  1282. //
  1283. return TRUE;
  1284. }
  1285. Bitmap = &(Hive->DirtyVector);
  1286. Offset = Cell / HSECTOR_SIZE;
  1287. if (RtlCheckBit(Bitmap, Offset)==1) {
  1288. return(TRUE);
  1289. }
  1290. return FALSE;
  1291. }
  1292. #endif
  1293. /*
  1294. !!!not used anymore!!!
  1295. BOOLEAN
  1296. HvMarkClean(
  1297. PHHIVE Hive,
  1298. HCELL_INDEX Start,
  1299. ULONG Length
  1300. )
  1301. */
  1302. /*++
  1303. Routine Description:
  1304. Clears the dirty bits for a given portion of a hive. This is
  1305. the inverse of HvMarkDirty, although it does not give up any
  1306. file space in the primary or log that HvMarkDirty may have reserved.
  1307. This is a noop for Volatile address range.
  1308. Arguments:
  1309. Hive - supplies a pointer to the hive control structure for the
  1310. hive of interest
  1311. Start - supplies a hive virtual address (i.e., an HCELL_INDEX or
  1312. like form address) of the start of the area to mark dirty.
  1313. Length - inclusive length in bytes of area to mark dirty.
  1314. Return Value:
  1315. TRUE - it worked
  1316. --*/
  1317. /*
  1318. {
  1319. ULONG Type;
  1320. PRTL_BITMAP BitMap;
  1321. ULONG First;
  1322. ULONG Last;
  1323. ULONG i;
  1324. ULONG Cluster;
  1325. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvMarkClean:\n\t"));
  1326. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Start:%08lx Length:%08lx\n", Hive, Start, Length));
  1327. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1328. ASSERT(Hive->ReadOnly == FALSE);
  1329. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1330. Type = HvGetCellType(Start);
  1331. if ( (Hive->HiveFlags & HIVE_VOLATILE) ||
  1332. (Type == Volatile) )
  1333. {
  1334. return TRUE;
  1335. }
  1336. BitMap = &(Hive->DirtyVector);
  1337. First = Start / HSECTOR_SIZE;
  1338. Last = (Start + Length - 1) / HSECTOR_SIZE;
  1339. Cluster = Hive->Cluster;
  1340. if (Cluster > 1) {
  1341. //
  1342. // Force Start down to base of cluster
  1343. // Force End up to top of cluster
  1344. //
  1345. First = First & ~(Cluster - 1);
  1346. Last = ROUND_UP(Last+1, Cluster) - 1;
  1347. }
  1348. if (Last >= BitMap->SizeOfBitMap) {
  1349. Last = BitMap->SizeOfBitMap-1;
  1350. }
  1351. //
  1352. // Subtract out the dirty count and
  1353. // and clear the dirty bits.
  1354. //
  1355. for (i=First; i<=Last; i++) {
  1356. if (RtlCheckBit(BitMap,i)==1) {
  1357. --Hive->DirtyCount;
  1358. RtlClearBits(BitMap, i, 1);
  1359. }
  1360. }
  1361. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1362. return(TRUE);
  1363. }
  1364. */
  1365. BOOLEAN
  1366. HvpGrowLog2(
  1367. PHHIVE Hive,
  1368. ULONG Size
  1369. )
  1370. /*++
  1371. Routine Description:
  1372. Adjust the log for growth in the size of the hive, in particular,
  1373. account for the increased space needed for a bigger dirty vector.
  1374. Arguments:
  1375. Hive - supplies a pointer to the hive control structure for the
  1376. hive of interest
  1377. Size - proposed growth in size in bytes.
  1378. Return Value:
  1379. TRUE - it worked
  1380. FALSE - could not allocate log space, failure!
  1381. --*/
  1382. {
  1383. ULONG ClusterSize;
  1384. ULONG RequiredSize;
  1385. ULONG DirtyBytes;
  1386. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvpGrowLog2:\n\t"));
  1387. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Size:%08lx\n", Hive, Size));
  1388. ASSERT(Hive->ReadOnly == FALSE);
  1389. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1390. //
  1391. // If logging is off, tell caller world is OK.
  1392. //
  1393. if (Hive->Log == FALSE) {
  1394. return TRUE;
  1395. }
  1396. ASSERT( (Size % HSECTOR_SIZE) == 0 );
  1397. ClusterSize = Hive->Cluster * HSECTOR_SIZE;
  1398. ASSERT( (((Hive->Storage[Stable].Length + Size) / HSECTOR_SIZE) % 8) == 0);
  1399. DirtyBytes = (Hive->DirtyVector.SizeOfBitMap / 8) +
  1400. ((Size / HSECTOR_SIZE) / 8) +
  1401. sizeof(ULONG); // signature
  1402. DirtyBytes = ROUND_UP(DirtyBytes, ClusterSize);
  1403. RequiredSize =
  1404. ClusterSize + // 1 cluster for header
  1405. (Hive->DirtyCount * HSECTOR_SIZE) +
  1406. DirtyBytes;
  1407. RequiredSize = ROUND_UP(RequiredSize, HLOG_GROW);
  1408. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1409. if ( ! (Hive->FileSetSize)(Hive, HFILE_TYPE_LOG, RequiredSize,Hive->LogSize)) {
  1410. return FALSE;
  1411. }
  1412. if( CmRegistryLogSizeLimit > 0 ) {
  1413. //
  1414. // see if log is too big and set flush on lock release
  1415. //
  1416. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1417. if( RequiredSize >= (ULONG)(CmRegistryLogSizeLimit * ONE_K) ) {
  1418. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"LogFile for hive %p is %lx; will flush upon lock release\n",Hive,RequiredSize);
  1419. CmpFlushOnLockRelease = TRUE;;
  1420. }
  1421. }
  1422. Hive->LogSize = RequiredSize;
  1423. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1424. return TRUE;
  1425. }
  1426. BOOLEAN
  1427. HvSyncHive(
  1428. PHHIVE Hive
  1429. )
  1430. /*++
  1431. Routine Description:
  1432. Force backing store to match the memory image of the Stable
  1433. part of the hive's space.
  1434. Logs, primary, and alternate data can be written. Primary is
  1435. always written. Normally either a log or an alternate, but
  1436. not both, will also be written.
  1437. It is possible to write only the primary.
  1438. All dirty bits will be set clear.
  1439. Arguments:
  1440. Hive - supplies a pointer to the hive control structure for the
  1441. hive of interest
  1442. Return Value:
  1443. TRUE - it worked
  1444. FALSE - some failure.
  1445. --*/
  1446. {
  1447. BOOLEAN oldFlag;
  1448. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvSyncHive:\n\t"));
  1449. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p\n", Hive));
  1450. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1451. ASSERT(Hive->ReadOnly == FALSE);
  1452. //
  1453. // Punt if post shutdown
  1454. //
  1455. if (HvShutdownComplete) {
  1456. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"HvSyncHive: Attempt to sync AFTER SHUTDOWN\n"));
  1457. return FALSE;
  1458. }
  1459. //
  1460. // If nothing dirty, do nothing
  1461. //
  1462. if (Hive->DirtyCount == 0) {
  1463. return TRUE;
  1464. }
  1465. //
  1466. // Discard the write(s) to system hives if needed
  1467. //
  1468. if (CmpMiniNTBoot) {
  1469. ULONG Index;
  1470. PCMHIVE CurrentHive = (PCMHIVE)Hive;
  1471. BOOLEAN SkipWrite = FALSE;
  1472. for (Index = 0; Index < CM_NUMBER_OF_MACHINE_HIVES; Index++) {
  1473. if ((CmpMachineHiveList[Index].Name != NULL) &&
  1474. ((CmpMachineHiveList[Index].CmHive == CurrentHive) ||
  1475. (CmpMachineHiveList[Index].CmHive2 == CurrentHive))) {
  1476. SkipWrite = TRUE;
  1477. break;
  1478. }
  1479. }
  1480. if (SkipWrite) {
  1481. return TRUE;
  1482. }
  1483. }
  1484. HvpTruncateBins(Hive);
  1485. //
  1486. // If hive is volatile, do nothing
  1487. //
  1488. if (Hive->HiveFlags & HIVE_VOLATILE) {
  1489. return TRUE;
  1490. }
  1491. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"\tDirtyCount:%08lx\n", Hive->DirtyCount));
  1492. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"\tDirtyVector:"));
  1493. //DumpDirtyVector(&(Hive->DirtyVector));
  1494. //
  1495. // disable hard error popups, to avoid self deadlock on bogus devices
  1496. //
  1497. oldFlag = IoSetThreadHardErrorMode(FALSE);
  1498. //
  1499. // Write a log.
  1500. //
  1501. if (Hive->Log == TRUE) {
  1502. if (HvpWriteLog(Hive) == FALSE) {
  1503. IoSetThreadHardErrorMode(oldFlag);
  1504. return FALSE;
  1505. }
  1506. }
  1507. //
  1508. // Write the primary
  1509. //
  1510. if (HvpDoWriteHive(Hive, HFILE_TYPE_PRIMARY) == FALSE) {
  1511. IoSetThreadHardErrorMode(oldFlag);
  1512. return FALSE;
  1513. }
  1514. //
  1515. // restore hard error popups mode
  1516. //
  1517. IoSetThreadHardErrorMode(oldFlag);
  1518. //
  1519. // Hive was successfully written out, discard any bins marked as
  1520. // discardable.
  1521. //
  1522. // We don't need this anymore as the bins are not using paged pool
  1523. //HvpDiscardBins(Hive);
  1524. //
  1525. // Free bins allocated from page-pool at the end of the hive.
  1526. // These bins were allocated as a temporary till the hive would be saved
  1527. //
  1528. HvpDropPagedBins(Hive
  1529. #if DBG
  1530. , TRUE
  1531. #endif
  1532. );
  1533. //
  1534. // Clear the dirty map
  1535. //
  1536. RtlClearAllBits(&(Hive->DirtyVector));
  1537. Hive->DirtyCount = 0;
  1538. #ifdef CM_ENABLE_WRITE_ONLY_BINS
  1539. HvpMarkAllBinsWriteOnly(Hive);
  1540. #endif CM_ENABLE_WRITE_ONLY_BINS
  1541. return TRUE;
  1542. }
  1543. //
  1544. // Code for syncing a hive to backing store
  1545. //
  1546. VOID
  1547. HvpFlushMappedData(
  1548. IN PHHIVE Hive,
  1549. IN OUT PRTL_BITMAP DirtyVector
  1550. )
  1551. /*++
  1552. Routine Description:
  1553. This functions will flush all pinned views for the specified hive.
  1554. It will clean the bits in the DirtyVector for the blocks that are
  1555. flushed.
  1556. Additionally, it sets the timestamp on the first bin.
  1557. It iterates through the pinned view list, and unpin all of them.
  1558. Arguments:
  1559. Hive - pointer to Hive for which dirty data is to be written.
  1560. DirtyVector - copy of the DirtyVector for the hive
  1561. Return Value:
  1562. TRUE - it worked
  1563. FALSE - it failed
  1564. --*/
  1565. {
  1566. PCMHIVE CmHive;
  1567. ULONG FileOffsetStart;
  1568. ULONG FileOffsetEnd;
  1569. PCM_VIEW_OF_FILE CmView;
  1570. PHMAP_ENTRY Me;
  1571. PHBIN Bin;
  1572. PFREE_HBIN FreeBin;
  1573. PAGED_CODE();
  1574. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"[HvpFlushMappedData] (Entry) DirtyVector:"));
  1575. //DumpDirtyVector(DirtyVector);
  1576. CmHive = (PCMHIVE)Hive;
  1577. //
  1578. // for each pinned view
  1579. //
  1580. while(IsListEmpty(&(CmHive->PinViewListHead)) == FALSE) {
  1581. //
  1582. // Remove the first view from the pin view list
  1583. //
  1584. CmView = (PCM_VIEW_OF_FILE)RemoveHeadList(&(CmHive->PinViewListHead));
  1585. CmView = CONTAINING_RECORD( CmView,
  1586. CM_VIEW_OF_FILE,
  1587. PinViewList);
  1588. //
  1589. // the real file offset starts after the header
  1590. //
  1591. FileOffsetStart = CmView->FileOffset;
  1592. FileOffsetEnd = FileOffsetStart + CmView->Size;
  1593. FileOffsetEnd -= HBLOCK_SIZE;
  1594. if( FileOffsetStart != 0 ) {
  1595. //
  1596. // just at the begining of the file, subtract the header
  1597. //
  1598. FileOffsetStart -= HBLOCK_SIZE;
  1599. }
  1600. if( (FileOffsetEnd / HSECTOR_SIZE) > DirtyVector->SizeOfBitMap ) {
  1601. //
  1602. // Cc has mapped more than its valid
  1603. //
  1604. ASSERT( (FileOffsetEnd % HSECTOR_SIZE) == 0 );
  1605. FileOffsetEnd = DirtyVector->SizeOfBitMap * HSECTOR_SIZE;
  1606. }
  1607. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"[HvpFlushMappedData] CmView %p mapping from %lx to %lx\n",CmView,FileOffsetStart,FileOffsetEnd));
  1608. //
  1609. // now, for every block in this range which is mapped in view
  1610. // clear the dirty bit
  1611. //
  1612. while(FileOffsetStart < FileOffsetEnd) {
  1613. if( FileOffsetStart >= Hive->Storage[Stable].Length ) {
  1614. //
  1615. // This mean the hive has shrunk during the HvpTruncateBins call
  1616. // all we have to do is clear the dirty bits and bail out
  1617. //
  1618. RtlClearBits(DirtyVector,FileOffsetStart/HSECTOR_SIZE,(FileOffsetEnd - FileOffsetStart)/HSECTOR_SIZE);
  1619. break;
  1620. }
  1621. Me = HvpGetCellMap(Hive, FileOffsetStart);
  1622. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileOffsetStart);
  1623. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  1624. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  1625. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  1626. //
  1627. // update the file offset
  1628. //
  1629. FileOffsetStart = FreeBin->FileOffset + FreeBin->Size;
  1630. //
  1631. // bin is discardable, or discarded; still, if it was mapped,
  1632. // clear of the dirty bits
  1633. //
  1634. if( Me->BinAddress & HMAP_INVIEW ) {
  1635. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"[HvpFlushMappedData] Clearing DISCARDABLE %lu Bits starting at %lu\n",
  1636. FreeBin->Size/HSECTOR_SIZE,FreeBin->FileOffset/HSECTOR_SIZE));
  1637. RtlClearBits(DirtyVector,FreeBin->FileOffset/HSECTOR_SIZE,FreeBin->Size/HSECTOR_SIZE);
  1638. }
  1639. } else {
  1640. if( Me->BinAddress & HMAP_INVIEW ) {
  1641. //
  1642. // bin is mapped in view. Then, this should be the beggining of the bin
  1643. //
  1644. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  1645. ASSERT(Bin->FileOffset == FileOffsetStart);
  1646. //
  1647. // clear the dirty bits for this bin as dirty blocks will
  1648. // be saved while unpinning the view
  1649. //
  1650. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"[HvpFlushMappedData] Clearing %lu Bits starting at %lu\n",
  1651. Bin->Size/HSECTOR_SIZE,Bin->FileOffset/HSECTOR_SIZE));
  1652. RtlClearBits(DirtyVector,Bin->FileOffset/HSECTOR_SIZE,Bin->Size/HSECTOR_SIZE);
  1653. FileOffsetStart += Bin->Size;
  1654. } else {
  1655. //
  1656. // bin is in paged pool. This should be the begining too
  1657. //
  1658. //
  1659. // we could fall into cross boundary problem here; advance carrefully
  1660. // (two day spent on this problem !!!)
  1661. //
  1662. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  1663. FileOffsetStart += HBLOCK_SIZE;
  1664. }
  1665. }
  1666. }// while (FileOffsetStart<FileOffsetEnd)
  1667. //
  1668. // UnPin the view; this will flush all dirty blocks to the backing storage
  1669. //
  1670. CmpUnPinCmView (CmHive,CmView,FALSE,TRUE);
  1671. } // while (IsListEmpty)
  1672. }
  1673. //#define TEST_LOG_SUPPORT
  1674. #ifdef TEST_LOG_SUPPORT
  1675. ULONG CmpFailPrimarySave = 0;
  1676. #endif //TEST_LOG_SUPPORT
  1677. BOOLEAN
  1678. HvpDoWriteHive(
  1679. PHHIVE Hive,
  1680. ULONG FileType
  1681. )
  1682. /*++
  1683. Routine Description:
  1684. Write dirty parts of the hive out to either its primary or alternate
  1685. file. Write the header, flush, write all data, flush, update header,
  1686. flush. Assume either logging or primary/alternate pairs used.
  1687. NOTE: TimeStamp is not set, assumption is that HvpWriteLog set
  1688. that. It is only used for checking if Logs correspond anyway.
  1689. Arguments:
  1690. Hive - pointer to Hive for which dirty data is to be written.
  1691. FileType - indicated whether primary or alternate file should be written.
  1692. Return Value:
  1693. TRUE - it worked
  1694. FALSE - it failed
  1695. --*/
  1696. {
  1697. PHBASE_BLOCK BaseBlock;
  1698. ULONG Offset;
  1699. PUCHAR Address;
  1700. ULONG Length;
  1701. BOOLEAN rc;
  1702. ULONG Current;
  1703. PRTL_BITMAP BitMap;
  1704. PHMAP_ENTRY Me;
  1705. PHBIN Bin;
  1706. BOOLEAN ShrinkHive;
  1707. PCMP_OFFSET_ARRAY offsetArray;
  1708. CMP_OFFSET_ARRAY offsetElement;
  1709. ULONG Count;
  1710. ULONG SetBitCount;
  1711. PULONG CopyDirtyVector;
  1712. ULONG CopyDirtyVectorSize;
  1713. RTL_BITMAP CopyBitMap;
  1714. LARGE_INTEGER FileOffset;
  1715. ULONG OldFileSize;
  1716. BOOLEAN GrowHive = FALSE;
  1717. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvpDoWriteHive:\n\t"));
  1718. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p FileType:%08lx\n", Hive, FileType));
  1719. FileOffset.HighPart = FileOffset.LowPart =0;
  1720. //
  1721. // flush first, so that the filesystem structures get written to
  1722. // disk if we have grown the file.
  1723. //
  1724. if ( (((PCMHIVE)Hive)->FileHandles[HFILE_TYPE_PRIMARY] == NULL) ||
  1725. !(Hive->FileFlush)(Hive, FileType,NULL,Hive->Storage[Stable].Length+HBLOCK_SIZE) ) {
  1726. #ifndef _CM_LDR_
  1727. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[1]: Failed to flush hive %p\n", Hive);
  1728. #endif //_CM_LDR_
  1729. return(FALSE);
  1730. }
  1731. #ifdef TEST_LOG_SUPPORT
  1732. if(CmpFailPrimarySave == 1) {
  1733. return FALSE;
  1734. }
  1735. #endif //TEST_LOG_SUPPORT
  1736. BaseBlock = Hive->BaseBlock;
  1737. //
  1738. // we should never come to this
  1739. //
  1740. ASSERT( Hive->Storage[Stable].Length != 0 );
  1741. ASSERT( Hive->BaseBlock->RootCell != HCELL_NIL );
  1742. OldFileSize = BaseBlock->Length;
  1743. if (BaseBlock->Length > Hive->Storage[Stable].Length) {
  1744. ShrinkHive = TRUE;
  1745. } else {
  1746. ShrinkHive = FALSE;
  1747. if( BaseBlock->Length < Hive->Storage[Stable].Length ) {
  1748. GrowHive = TRUE;
  1749. }
  1750. }
  1751. //
  1752. // --- Write out header first time, flush ---
  1753. //
  1754. ASSERT(BaseBlock->Signature == HBASE_BLOCK_SIGNATURE);
  1755. ASSERT(BaseBlock->Major == HSYS_MAJOR);
  1756. ASSERT(BaseBlock->Format == HBASE_FORMAT_MEMORY);
  1757. ASSERT(Hive->ReadOnly == FALSE);
  1758. if (BaseBlock->Sequence1 != BaseBlock->Sequence2) {
  1759. //
  1760. // Some previous log attempt failed, or this hive needs to
  1761. // be recovered, so punt.
  1762. //
  1763. #ifndef _CM_LDR_
  1764. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[2,%s]: Invalid sequence number for hive%p\n", "Primary",Hive);
  1765. #endif //_CM_LDR_
  1766. return FALSE;
  1767. }
  1768. BaseBlock->Length = Hive->Storage[Stable].Length;
  1769. BaseBlock->Sequence1++;
  1770. BaseBlock->Type = HFILE_TYPE_PRIMARY;
  1771. BaseBlock->Cluster = Hive->Cluster;
  1772. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  1773. Offset = 0;
  1774. offsetElement.FileOffset = Offset;
  1775. offsetElement.DataBuffer = (PVOID) BaseBlock;
  1776. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  1777. if( HiveWritesThroughCache(Hive,FileType) == TRUE ) {
  1778. //
  1779. // if we use Cc, do the write with the pin interface
  1780. //
  1781. rc = CmpFileWriteThroughCache( Hive,
  1782. FileType,
  1783. &offsetElement,
  1784. 1);
  1785. } else {
  1786. rc = (Hive->FileWrite)(
  1787. Hive,
  1788. FileType,
  1789. &offsetElement,
  1790. 1,
  1791. &Offset
  1792. );
  1793. }
  1794. if (rc == FALSE) {
  1795. #ifndef _CM_LDR_
  1796. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[3,%s]: Failed to write header for hive%p\n", "Primary",Hive);
  1797. #endif //_CM_LDR_
  1798. return FALSE;
  1799. }
  1800. if ( ! (Hive->FileFlush)(Hive, FileType,&FileOffset,offsetElement.DataLength)) {
  1801. #ifndef _CM_LDR_
  1802. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[4,%s]: Failed to flush header for hive%p\n", "Primary",Hive);
  1803. #endif //_CM_LDR_
  1804. return FALSE;
  1805. }
  1806. Offset = ROUND_UP(Offset, HBLOCK_SIZE);
  1807. #ifdef TEST_LOG_SUPPORT
  1808. if(CmpFailPrimarySave == 2) {
  1809. return FALSE;
  1810. }
  1811. #endif //TEST_LOG_SUPPORT
  1812. //
  1813. // --- Write out dirty data (only if there is any) ---
  1814. //
  1815. if (Hive->DirtyVector.Buffer != NULL) {
  1816. //
  1817. // First sector of first bin will always be dirty, write it out
  1818. // with the TimeStamp value overlaid on its Link field.
  1819. //
  1820. BitMap = &(Hive->DirtyVector);
  1821. //
  1822. // make a copy of the dirty vector; we don't want to alter the
  1823. // original dirty vector in case things go wrong
  1824. //
  1825. CopyDirtyVectorSize = BitMap->SizeOfBitMap / 8;
  1826. CopyDirtyVector = (Hive->Allocate)(ROUND_UP(CopyDirtyVectorSize,sizeof(ULONG)), FALSE,CM_FIND_LEAK_TAG38);
  1827. if (CopyDirtyVector == NULL) {
  1828. #ifndef _CM_LDR_
  1829. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[5,%s]: Failed to allocate CopyDirtyVectorfor hive%p\n", "Primary",Hive);
  1830. #endif //_CM_LDR_
  1831. return FALSE;
  1832. }
  1833. RtlCopyMemory(CopyDirtyVector,BitMap->Buffer,CopyDirtyVectorSize);
  1834. RtlInitializeBitMap (&CopyBitMap,CopyDirtyVector,BitMap->SizeOfBitMap);
  1835. ASSERT(RtlCheckBit(BitMap, 0) == 1);
  1836. ASSERT(RtlCheckBit(BitMap, (Hive->Cluster - 1)) == 1);
  1837. ASSERT(sizeof(LIST_ENTRY) >= sizeof(LARGE_INTEGER));
  1838. Me = HvpGetCellMap(Hive, 0);
  1839. VALIDATE_CELL_MAP(__LINE__,Me,Hive,0);
  1840. if( (Me->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0 ) {
  1841. //
  1842. // first view is not mapped
  1843. //
  1844. //
  1845. // fatal error: Dirty Data is not pinned !!!!
  1846. //
  1847. CM_BUGCHECK(REGISTRY_ERROR,FATAL_MAPPING_ERROR,3,0,Me);
  1848. }
  1849. Address = (PUCHAR)Me->BlockAddress;
  1850. Bin = (PHBIN)Address;
  1851. Bin->TimeStamp = BaseBlock->TimeStamp;
  1852. //
  1853. // flush first the mapped data
  1854. //
  1855. try {
  1856. HvpFlushMappedData(Hive,&CopyBitMap);
  1857. } except (EXCEPTION_EXECUTE_HANDLER) {
  1858. //
  1859. // in-page exception while flushing the mapped data; this is due to the map_no_read scheme.
  1860. //
  1861. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive : HvpFlushMappedData has raised :%08lx\n",GetExceptionCode()));
  1862. return FALSE;
  1863. }
  1864. #ifdef TEST_LOG_SUPPORT
  1865. if(CmpFailPrimarySave == 3) {
  1866. return FALSE;
  1867. }
  1868. #endif //TEST_LOG_SUPPORT
  1869. //
  1870. // Write out the rest of the dirty data
  1871. //
  1872. Current = 0;
  1873. SetBitCount = RtlNumberOfSetBits(&CopyBitMap);
  1874. if( SetBitCount > 0 ) {
  1875. //
  1876. // we still have some dirty data
  1877. // this must reside in paged-pool bins
  1878. // save it in the old-fashioned way (non-cached)
  1879. //
  1880. offsetArray =(PCMP_OFFSET_ARRAY)ExAllocatePool(PagedPool,sizeof(CMP_OFFSET_ARRAY) * SetBitCount);
  1881. if (offsetArray == NULL) {
  1882. CmpFree(CopyDirtyVector, ROUND_UP(CopyDirtyVectorSize,sizeof(ULONG)));
  1883. #ifndef _CM_LDR_
  1884. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[8,%s]: Failed to allocate offsetArray for hive%p\n", "Primary",Hive);
  1885. #endif //_CM_LDR_
  1886. return FALSE;
  1887. }
  1888. Count = 0;
  1889. while (HvpFindNextDirtyBlock(
  1890. Hive,
  1891. &CopyBitMap,
  1892. &Current,
  1893. &Address,
  1894. &Length,
  1895. &Offset
  1896. ) == TRUE)
  1897. {
  1898. // Gather data into array.
  1899. ASSERT(Count < SetBitCount);
  1900. offsetArray[Count].FileOffset = Offset;
  1901. offsetArray[Count].DataBuffer = Address;
  1902. offsetArray[Count].DataLength = Length;
  1903. Offset += Length;
  1904. ASSERT((Offset % (Hive->Cluster * HSECTOR_SIZE)) == 0);
  1905. Count++;
  1906. }
  1907. if( HiveWritesThroughCache(Hive,FileType) == TRUE ) {
  1908. //
  1909. // if we use Cc, do the write with the pin interface
  1910. //
  1911. rc = CmpFileWriteThroughCache( Hive,
  1912. FileType,
  1913. offsetArray,
  1914. Count);
  1915. } else {
  1916. //
  1917. // for primary file, issue all IOs at the same time.
  1918. //
  1919. rc = (Hive->FileWrite)(
  1920. Hive,
  1921. FileType,
  1922. offsetArray,
  1923. Count,
  1924. &Offset // Just an OUT parameter which returns the point
  1925. // in the file after the last write.
  1926. );
  1927. }
  1928. #ifdef SYNC_HIVE_VALIDATION
  1929. if( rc == TRUE ) {
  1930. ULONG i;
  1931. for ( i = Current; i < CopyBitMap.SizeOfBitMap; i++) {
  1932. if(RtlCheckBit(&CopyBitMap, i) == 1) {
  1933. //
  1934. // cause of zero-at the end corruption
  1935. //
  1936. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\n\n HARD CODED BREAKPOINT IN REGISTRY !!! \n");
  1937. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive - Zero-at-the-end code bug in HvpFindNextDirtyBlock\n");
  1938. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Dirty data at the end residing in paged pool is not saved to the hive\n");
  1939. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Hive: %p :: Bitmap = [%p] CopyBitMap = [%p]\n",Hive,BitMap,&CopyBitMap);
  1940. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpFindNextDirtyBlock reported Current = %lu, i = %lx, bitmap size = %lx\n",Current,i,CopyBitMap.SizeOfBitMap);
  1941. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\nThanks for hitting this! Please send remote to dragoss\n\n");
  1942. DbgBreakPoint();
  1943. break;
  1944. }
  1945. }
  1946. }
  1947. #endif //SYNC_HIVE_VALIDATION
  1948. ExFreePool(offsetArray);
  1949. if (rc == FALSE) {
  1950. CmpFree(CopyDirtyVector, ROUND_UP(CopyDirtyVectorSize,sizeof(ULONG)));
  1951. #ifndef _CM_LDR_
  1952. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[10,%s]: Failed to write dirty run for hive%p\n", "Primary",Hive);
  1953. #endif //_CM_LDR_
  1954. return FALSE;
  1955. }
  1956. }
  1957. //
  1958. // first bin header must be saved !
  1959. //
  1960. ASSERT(RtlCheckBit(BitMap, 0) == 1);
  1961. ASSERT(RtlCheckBit(BitMap, (Hive->Cluster - 1)) == 1);
  1962. CmpFree(CopyDirtyVector, ROUND_UP(CopyDirtyVectorSize,sizeof(ULONG)));
  1963. }
  1964. #ifdef TEST_LOG_SUPPORT
  1965. if(CmpFailPrimarySave == 4) {
  1966. return FALSE;
  1967. }
  1968. #endif //TEST_LOG_SUPPORT
  1969. if ( ! (Hive->FileFlush)(Hive, FileType,NULL,Hive->Storage[Stable].Length+HBLOCK_SIZE)) {
  1970. #ifndef _CM_LDR_
  1971. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[11,%s]: Failed to flush hive%p\n", "Primary",Hive);
  1972. #endif //_CM_LDR_
  1973. return FALSE;
  1974. }
  1975. #ifdef TEST_LOG_SUPPORT
  1976. if(CmpFailPrimarySave == 5) {
  1977. return FALSE;
  1978. }
  1979. #endif //TEST_LOG_SUPPORT
  1980. if ( GrowHive && HiveWritesThroughCache(Hive,FileType) ) {
  1981. IO_STATUS_BLOCK IoStatus;
  1982. if(!NT_SUCCESS(ZwFlushBuffersFile(((PCMHIVE)Hive)->FileHandles[FileType],&IoStatus))) {
  1983. #ifndef _CM_LDR_
  1984. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[12,%s]: CcSetValidDataFailed for hive %p\n", Hive, "Primary");
  1985. #endif //_CM_LDR_
  1986. return FALSE;
  1987. }
  1988. /*
  1989. // thsi was supposed to be the elegant way to do it.
  1990. //
  1991. // We need to set the size of the file; Tell FS to update it!!!
  1992. //
  1993. FileOffset.LowPart = Hive->Storage[Stable].Length + HBLOCK_SIZE;
  1994. if(!NT_SUCCESS(CcSetValidData(((PCMHIVE)Hive)->FileObject,&FileOffset)) ) {
  1995. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[12,%s]: CcSetValidDataFailed for hive %p\n", Hive, "Primary");
  1996. }
  1997. */
  1998. }
  1999. #ifdef TEST_LOG_SUPPORT
  2000. if(CmpFailPrimarySave == 6) {
  2001. return FALSE;
  2002. }
  2003. #endif //TEST_LOG_SUPPORT
  2004. //
  2005. // --- Write header again to report completion ---
  2006. //
  2007. BaseBlock->Sequence2++;
  2008. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  2009. Offset = 0;
  2010. offsetElement.FileOffset = Offset;
  2011. offsetElement.DataBuffer = (PVOID) BaseBlock;
  2012. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  2013. if( HiveWritesThroughCache(Hive,FileType) == TRUE ) {
  2014. //
  2015. // if we use Cc, do the write with the pin interface
  2016. //
  2017. rc = CmpFileWriteThroughCache( Hive,
  2018. FileType,
  2019. &offsetElement,
  2020. 1);
  2021. } else {
  2022. rc = (Hive->FileWrite)(
  2023. Hive,
  2024. FileType,
  2025. &offsetElement,
  2026. 1,
  2027. &Offset
  2028. );
  2029. }
  2030. if (rc == FALSE) {
  2031. #ifndef _CM_LDR_
  2032. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[11,%s]: Failed to write header for hive%p\n", Hive, "Primary");
  2033. #endif //_CM_LDR_
  2034. return FALSE;
  2035. }
  2036. if (ShrinkHive) {
  2037. //
  2038. // Hive has shrunk, give up the excess space.
  2039. //
  2040. CmpDoFileSetSize(Hive, FileType, Hive->Storage[Stable].Length + HBLOCK_SIZE,OldFileSize + HBLOCK_SIZE);
  2041. }
  2042. #ifdef TEST_LOG_SUPPORT
  2043. if(CmpFailPrimarySave == 7) {
  2044. return FALSE;
  2045. }
  2046. #endif //TEST_LOG_SUPPORT
  2047. //
  2048. // if we wrote through cache, we don't need to flush anymore
  2049. //
  2050. if( HiveWritesThroughCache(Hive,FileType) == FALSE ){
  2051. if ( ! (Hive->FileFlush)(Hive, FileType,&FileOffset,offsetElement.DataLength)) {
  2052. #ifndef _CM_LDR_
  2053. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[12,%s]: Failed to flush hive%p\n", "Primary",Hive);
  2054. #endif //_CM_LDR_
  2055. return FALSE;
  2056. }
  2057. }
  2058. if ((Hive->Log) &&
  2059. (Hive->LogSize > HLOG_MINSIZE(Hive))) {
  2060. //
  2061. // Shrink log back down, reserve at least two clusters
  2062. // worth of space so that if all the disk space is
  2063. // consumed, there will still be enough space prereserved
  2064. // to allow a minimum of registry operations so the user
  2065. // can log on.
  2066. //
  2067. CmpDoFileSetSize(Hive, HFILE_TYPE_LOG, HLOG_MINSIZE(Hive),Hive->LogSize);
  2068. Hive->LogSize = HLOG_MINSIZE(Hive);
  2069. }
  2070. #if DBG
  2071. {
  2072. NTSTATUS Status;
  2073. FILE_END_OF_FILE_INFORMATION FileInfo;
  2074. IO_STATUS_BLOCK IoStatus;
  2075. Status = NtQueryInformationFile(
  2076. ((PCMHIVE)Hive)->FileHandles[HFILE_TYPE_PRIMARY],
  2077. &IoStatus,
  2078. (PVOID)&FileInfo,
  2079. sizeof(FILE_END_OF_FILE_INFORMATION),
  2080. FileEndOfFileInformation
  2081. );
  2082. if (NT_SUCCESS(Status)) {
  2083. ASSERT(IoStatus.Status == Status);
  2084. ASSERT( FileInfo.EndOfFile.LowPart == (Hive->Storage[Stable].Length + HBLOCK_SIZE));
  2085. }
  2086. }
  2087. #endif //DBG
  2088. return TRUE;
  2089. }
  2090. //
  2091. // Code for tracking modifications and ensuring adequate log space
  2092. //
  2093. BOOLEAN
  2094. HvpWriteLog(
  2095. PHHIVE Hive
  2096. )
  2097. /*++
  2098. Routine Description:
  2099. Write a header, the DirtyVector, and all the dirty data into
  2100. the log file. Do flushes at the right places. Update the header.
  2101. Arguments:
  2102. Hive - pointer to Hive for which dirty data is to be logged.
  2103. Return Value:
  2104. TRUE - it worked
  2105. FALSE - it failed
  2106. --*/
  2107. {
  2108. PHBASE_BLOCK BaseBlock;
  2109. ULONG Offset;
  2110. PUCHAR Address;
  2111. ULONG Length;
  2112. BOOLEAN rc;
  2113. ULONG Current;
  2114. ULONG junk;
  2115. ULONG ClusterSize;
  2116. ULONG HeaderLength;
  2117. PRTL_BITMAP BitMap;
  2118. ULONG DirtyVectorSignature = HLOG_DV_SIGNATURE;
  2119. LARGE_INTEGER systemtime;
  2120. PCMP_OFFSET_ARRAY offsetArray;
  2121. CMP_OFFSET_ARRAY offsetElement;
  2122. ULONG Count;
  2123. ULONG SetBitCount;
  2124. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvpWriteLog:\n\t"));
  2125. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p\n", Hive));
  2126. ClusterSize = Hive->Cluster * HSECTOR_SIZE;
  2127. //
  2128. // make sure the log size accomodates the dirty data we are about to write.
  2129. //
  2130. {
  2131. ULONG tmp;
  2132. ULONG RequiredSize;
  2133. tmp = Hive->DirtyVector.SizeOfBitMap / 8; // bytes
  2134. tmp += sizeof(ULONG); // signature
  2135. RequiredSize =
  2136. ClusterSize + // 1 cluster for header
  2137. ROUND_UP(tmp, ClusterSize) +
  2138. ((Hive->DirtyCount) * HSECTOR_SIZE);
  2139. RequiredSize = ROUND_UP(RequiredSize, HLOG_GROW);
  2140. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  2141. if( Hive->LogSize >= RequiredSize ) {
  2142. //
  2143. // this is a noop. log is already big enough
  2144. //
  2145. NOTHING;
  2146. } else {
  2147. if( !NT_SUCCESS(CmpDoFileSetSize(Hive, HFILE_TYPE_LOG, RequiredSize,Hive->LogSize)) ) {
  2148. return FALSE;
  2149. }
  2150. Hive->LogSize = RequiredSize;
  2151. }
  2152. }
  2153. BitMap = &Hive->DirtyVector;
  2154. //
  2155. // --- Write out header first time, flush ---
  2156. //
  2157. BaseBlock = Hive->BaseBlock;
  2158. ASSERT(BaseBlock->Signature == HBASE_BLOCK_SIGNATURE);
  2159. ASSERT(BaseBlock->Major == HSYS_MAJOR);
  2160. ASSERT(BaseBlock->Format == HBASE_FORMAT_MEMORY);
  2161. ASSERT(Hive->ReadOnly == FALSE);
  2162. if (BaseBlock->Sequence1 != BaseBlock->Sequence2) {
  2163. //
  2164. // Some previous log attempt failed, or this hive needs to
  2165. // be recovered, so punt.
  2166. //
  2167. return FALSE;
  2168. }
  2169. BaseBlock->Sequence1++;
  2170. KeQuerySystemTime(&systemtime);
  2171. BaseBlock->TimeStamp = systemtime;
  2172. BaseBlock->Type = HFILE_TYPE_LOG;
  2173. HeaderLength = ROUND_UP(HLOG_HEADER_SIZE, ClusterSize);
  2174. BaseBlock->Cluster = Hive->Cluster;
  2175. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  2176. Offset = 0;
  2177. offsetElement.FileOffset = Offset;
  2178. offsetElement.DataBuffer = (PVOID) BaseBlock;
  2179. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  2180. rc = (Hive->FileWrite)(
  2181. Hive,
  2182. HFILE_TYPE_LOG,
  2183. &offsetElement,
  2184. 1,
  2185. &Offset
  2186. );
  2187. if (rc == FALSE) {
  2188. return FALSE;
  2189. }
  2190. Offset = ROUND_UP(Offset, HeaderLength);
  2191. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_LOG,NULL,0)) {
  2192. return FALSE;
  2193. }
  2194. //
  2195. // --- Write out dirty vector ---
  2196. //
  2197. //
  2198. // try to allocate a stash buffer. if we fail. we fail to save the hive
  2199. // only save what is relevant
  2200. //
  2201. Length = (Hive->Storage[Stable].Length / HSECTOR_SIZE) / 8;
  2202. LOCK_STASH_BUFFER();
  2203. if( CmpStashBufferSize < (Length + sizeof(DirtyVectorSignature)) ) {
  2204. PUCHAR TempBuffer = ExAllocatePoolWithTag(PagedPool, ROUND_UP((Length + sizeof(DirtyVectorSignature)),PAGE_SIZE),CM_STASHBUFFER_TAG);
  2205. if (TempBuffer == NULL) {
  2206. UNLOCK_STASH_BUFFER();
  2207. return FALSE;
  2208. }
  2209. if( CmpStashBuffer != NULL ) {
  2210. ExFreePool( CmpStashBuffer );
  2211. }
  2212. CmpStashBuffer = TempBuffer;
  2213. CmpStashBufferSize = ROUND_UP((Length + sizeof(DirtyVectorSignature)),PAGE_SIZE);
  2214. }
  2215. ASSERT(sizeof(ULONG) == sizeof(DirtyVectorSignature)); // See GrowLog1 above
  2216. //
  2217. // signature
  2218. //
  2219. (*((ULONG *)CmpStashBuffer)) = DirtyVectorSignature;
  2220. //
  2221. // dirty vector content
  2222. //
  2223. Address = (PUCHAR)(Hive->DirtyVector.Buffer);
  2224. RtlCopyMemory(CmpStashBuffer + sizeof(DirtyVectorSignature),Address,Length);
  2225. offsetElement.FileOffset = Offset;
  2226. offsetElement.DataBuffer = (PVOID)CmpStashBuffer;
  2227. offsetElement.DataLength = ROUND_UP((Length + sizeof(DirtyVectorSignature)),ClusterSize);
  2228. rc = (Hive->FileWrite)(
  2229. Hive,
  2230. HFILE_TYPE_LOG,
  2231. &offsetElement,
  2232. 1,
  2233. &Offset
  2234. );
  2235. UNLOCK_STASH_BUFFER();
  2236. if (rc == FALSE) {
  2237. return FALSE;
  2238. }
  2239. ASSERT( (Offset % ClusterSize) == 0 );
  2240. //
  2241. // --- Write out body of log ---
  2242. //
  2243. SetBitCount = RtlNumberOfSetBits(BitMap);
  2244. offsetArray =
  2245. (PCMP_OFFSET_ARRAY)
  2246. ExAllocatePool(PagedPool,
  2247. sizeof(CMP_OFFSET_ARRAY) * SetBitCount);
  2248. if (offsetArray == NULL) {
  2249. return FALSE;
  2250. }
  2251. Count = 0;
  2252. Current = 0;
  2253. while (HvpFindNextDirtyBlock(
  2254. Hive,
  2255. BitMap,
  2256. &Current,
  2257. &Address,
  2258. &Length,
  2259. &junk
  2260. ) == TRUE)
  2261. {
  2262. // Gather data into array.
  2263. ASSERT(Count < SetBitCount);
  2264. offsetArray[Count].FileOffset = Offset;
  2265. offsetArray[Count].DataBuffer = Address;
  2266. offsetArray[Count].DataLength = Length;
  2267. Offset += Length;
  2268. Count++;
  2269. ASSERT((Offset % ClusterSize) == 0);
  2270. }
  2271. rc = (Hive->FileWrite)(
  2272. Hive,
  2273. HFILE_TYPE_LOG,
  2274. offsetArray,
  2275. Count,
  2276. &Offset // Just an OUT parameter which returns the point
  2277. // in the file after the last write.
  2278. );
  2279. ExFreePool(offsetArray);
  2280. if (rc == FALSE) {
  2281. return FALSE;
  2282. }
  2283. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_LOG,NULL,0)) {
  2284. return FALSE;
  2285. }
  2286. //
  2287. // --- Write header again to report completion ---
  2288. //
  2289. //
  2290. // -- we need to save the new length, in case the hive was grown.
  2291. //
  2292. Length = BaseBlock->Length;
  2293. if( Length < Hive->Storage[Stable].Length ) {
  2294. BaseBlock->Length = Hive->Storage[Stable].Length;
  2295. }
  2296. BaseBlock->Sequence2++;
  2297. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  2298. Offset = 0;
  2299. offsetElement.FileOffset = Offset;
  2300. offsetElement.DataBuffer = (PVOID) BaseBlock;
  2301. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  2302. rc = (Hive->FileWrite)(
  2303. Hive,
  2304. HFILE_TYPE_LOG,
  2305. &offsetElement,
  2306. 1,
  2307. &Offset
  2308. );
  2309. //
  2310. // restore the original length
  2311. //
  2312. BaseBlock->Length = Length;
  2313. if (rc == FALSE) {
  2314. return FALSE;
  2315. }
  2316. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_LOG,NULL,0)) {
  2317. return FALSE;
  2318. }
  2319. return TRUE;
  2320. }
  2321. BOOLEAN
  2322. HvpFindNextDirtyBlock(
  2323. PHHIVE Hive,
  2324. PRTL_BITMAP BitMap,
  2325. PULONG Current,
  2326. PUCHAR *Address,
  2327. PULONG Length,
  2328. PULONG Offset
  2329. )
  2330. /*++
  2331. Routine Description:
  2332. This routine finds and reports the largest run of dirty logical
  2333. sectors in the hive, which are contiguous in memory and on disk.
  2334. Arguments:
  2335. Hive - pointer to Hive of interest.
  2336. BitMap - supplies a pointer to a bitmap structure, which
  2337. describes what is dirty.
  2338. Current - supplies a pointer to a varible that tracks position
  2339. in the bitmap. It is a bitnumber. It is updated by
  2340. this call.
  2341. Address - supplies a pointer to a variable to receive a pointer
  2342. to the area in memory to be written out.
  2343. Length - supplies a pointer to a variable to receive the length
  2344. of the region to read/write
  2345. Offset - supplies a pointer to a variable to receive the offset
  2346. in the backing file to which the data should be written.
  2347. (not valid for log files)
  2348. Return Value:
  2349. TRUE - more to write, ret values good
  2350. FALSE - all data has been written
  2351. --*/
  2352. {
  2353. ULONG i;
  2354. ULONG EndOfBitMap;
  2355. ULONG Start;
  2356. ULONG End;
  2357. HCELL_INDEX FileBaseAddress;
  2358. HCELL_INDEX FileEndAddress;
  2359. PHMAP_ENTRY Me;
  2360. PUCHAR Block;
  2361. PUCHAR StartBlock;
  2362. PUCHAR NextBlock;
  2363. ULONG RunSpan;
  2364. ULONG RunLength;
  2365. ULONG FileLength;
  2366. PFREE_HBIN FreeBin;
  2367. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvpFindNextDirtyBlock:\n\t"));
  2368. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Current:%08lx\n", Hive, *Current));
  2369. EndOfBitMap = BitMap->SizeOfBitMap;
  2370. if (*Current >= EndOfBitMap) {
  2371. return FALSE;
  2372. }
  2373. //
  2374. // Find next run of set bits
  2375. //
  2376. for (i = *Current; i < EndOfBitMap; i++) {
  2377. if (RtlCheckBit(BitMap, i) == 1) {
  2378. break;
  2379. }
  2380. }
  2381. Start = i;
  2382. for ( ; i < EndOfBitMap; i++) {
  2383. if (RtlCheckBit(BitMap, i) == 0) {
  2384. break;
  2385. }
  2386. if( HvpCheckViewBoundary(Start*HSECTOR_SIZE,i*HSECTOR_SIZE) == FALSE ) {
  2387. break;
  2388. }
  2389. }
  2390. End = i;
  2391. //
  2392. // Compute hive virtual addresses, beginning file address, memory address
  2393. //
  2394. FileBaseAddress = Start * HSECTOR_SIZE;
  2395. FileEndAddress = End * HSECTOR_SIZE;
  2396. FileLength = FileEndAddress - FileBaseAddress;
  2397. if (FileLength == 0) {
  2398. *Address = NULL;
  2399. *Current = 0xffffffff;
  2400. *Length = 0;
  2401. return FALSE;
  2402. }
  2403. Me = HvpGetCellMap(Hive, FileBaseAddress);
  2404. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileBaseAddress);
  2405. if( (Me->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0 ) {
  2406. //
  2407. // this is really bad, bugcheck!!!
  2408. //
  2409. #ifndef _CM_LDR_
  2410. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"FileAddress = %lx, Map = %lx",FileBaseAddress,Me);
  2411. #endif //_CM_LDR_
  2412. CM_BUGCHECK(REGISTRY_ERROR,FATAL_MAPPING_ERROR,1,FileBaseAddress,Me);
  2413. }
  2414. ASSERT_BIN_VALID(Me);
  2415. if (Me->BinAddress & HMAP_DISCARDABLE) {
  2416. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  2417. StartBlock = (PUCHAR)(HBIN_BASE(Me->BinAddress) + FileBaseAddress - FreeBin->FileOffset );
  2418. } else {
  2419. StartBlock = (PUCHAR)Me->BlockAddress;
  2420. }
  2421. Block = StartBlock;
  2422. ASSERT(((PHBIN)HBIN_BASE(Me->BinAddress))->Signature == HBIN_SIGNATURE);
  2423. *Address = Block + (FileBaseAddress & HCELL_OFFSET_MASK);
  2424. *Offset = FileBaseAddress + HBLOCK_SIZE;
  2425. //
  2426. // Build up length. First, account for sectors in first block.
  2427. //
  2428. RunSpan = HSECTOR_COUNT - (Start % HSECTOR_COUNT);
  2429. if ((End - Start) <= RunSpan) {
  2430. //
  2431. // Entire length is in first block, return it
  2432. //
  2433. *Length = FileLength;
  2434. *Current = End;
  2435. return TRUE;
  2436. } else {
  2437. RunLength = RunSpan * HSECTOR_SIZE;
  2438. FileBaseAddress = ROUND_UP(FileBaseAddress+1, HBLOCK_SIZE);
  2439. }
  2440. //
  2441. // Scan forward through blocks, filling up length as we go.
  2442. //
  2443. // NOTE: This loop grows forward 1 block at time. If we were
  2444. // really clever we'd fill forward a bin at time, since
  2445. // bins are always contiguous. But most bins will be
  2446. // one block long anyway, so we won't bother for now.
  2447. //
  2448. while (RunLength < FileLength) {
  2449. Me = HvpGetCellMap(Hive, FileBaseAddress);
  2450. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileBaseAddress);
  2451. if( (Me->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0 ) {
  2452. //
  2453. // this is really bad, bugcheck!!!
  2454. //
  2455. #ifndef _CM_LDR_
  2456. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"FileAddress = %lx, Map = %lx",FileBaseAddress,Me);
  2457. #endif //_CM_LDR_
  2458. CM_BUGCHECK(REGISTRY_ERROR,FATAL_MAPPING_ERROR,2,FileBaseAddress,Me);
  2459. }
  2460. ASSERT(((PHBIN)HBIN_BASE(Me->BinAddress))->Signature == HBIN_SIGNATURE);
  2461. if (Me->BinAddress & HMAP_DISCARDABLE) {
  2462. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  2463. NextBlock = (PUCHAR)(HBIN_BASE(Me->BinAddress) + FileBaseAddress - FreeBin->FileOffset );
  2464. } else {
  2465. NextBlock = (PUCHAR)Me->BlockAddress;
  2466. }
  2467. if ( (NextBlock - Block) != HBLOCK_SIZE) {
  2468. //
  2469. // We've hit a discontinuity in memory. RunLength is
  2470. // as long as it's going to get.
  2471. //
  2472. break;
  2473. }
  2474. if ((FileEndAddress - FileBaseAddress) <= HBLOCK_SIZE) {
  2475. //
  2476. // We've reached the tail block, all is contiguous,
  2477. // fill up to end and return.
  2478. //
  2479. *Length = FileLength;
  2480. *Current = End;
  2481. return TRUE;
  2482. }
  2483. //
  2484. // Just another contiguous block, fill forward
  2485. //
  2486. RunLength += HBLOCK_SIZE;
  2487. RunSpan += HSECTOR_COUNT;
  2488. FileBaseAddress += HBLOCK_SIZE;
  2489. Block = NextBlock;
  2490. }
  2491. //
  2492. // We either hit a discontinuity, OR, we're at the end of the range
  2493. // we're trying to fill. In either case, return.
  2494. //
  2495. *Length = RunLength;
  2496. *Current = Start + RunSpan;
  2497. return TRUE;
  2498. }
  2499. /*
  2500. !!!we don't need this anymore as the bins are not allocated from paged pool anymore!!!
  2501. Big chunks of discardable registry allocations will just not be mapped.
  2502. VOID
  2503. HvpDiscardBins(
  2504. IN PHHIVE Hive
  2505. )
  2506. */
  2507. /*++
  2508. Routine Description:
  2509. Walks through the dirty bins in a hive to see if any are marked
  2510. discardable. If so, they are discarded and the map is updated to
  2511. reflect this.
  2512. Arguments:
  2513. Hive - Supplies the hive control structure.
  2514. Return Value:
  2515. None.
  2516. --*/
  2517. /*
  2518. {
  2519. PHBIN Bin;
  2520. PHMAP_ENTRY Map;
  2521. PFREE_HBIN FreeBin;
  2522. PLIST_ENTRY List;
  2523. List = Hive->Storage[Stable].FreeBins.Flink;
  2524. while (List != &Hive->Storage[Stable].FreeBins) {
  2525. ASSERT_LISTENTRY(List);
  2526. FreeBin = CONTAINING_RECORD(List, FREE_HBIN, ListEntry);
  2527. if (FreeBin->Flags & FREE_HBIN_DISCARDABLE) {
  2528. Map = HvpGetCellMap(Hive, FreeBin->FileOffset);
  2529. VALIDATE_CELL_MAP(__LINE__,Map,Hive,FreeBin->FileOffset);
  2530. Bin = (PHBIN)HBIN_BASE(Map->BinAddress);
  2531. ASSERT(Map->BinAddress & HMAP_DISCARDABLE);
  2532. //
  2533. // Note we use ExFreePool directly here to avoid
  2534. // giving back the quota for this bin. By charging
  2535. // registry quota for discarded bins, we prevent
  2536. // sparse hives from requiring more quota after
  2537. // a reboot than on a running system.
  2538. //
  2539. ExFreePool(Bin);
  2540. FreeBin->Flags &= ~FREE_HBIN_DISCARDABLE;
  2541. }
  2542. List=List->Flink;
  2543. }
  2544. }
  2545. */
  2546. BOOLEAN
  2547. HvHiveWillShrink(
  2548. IN PHHIVE Hive
  2549. )
  2550. /*++
  2551. Routine Description:
  2552. Applies to stable storage only. Helps determining whether the hive
  2553. will shrink on first flush
  2554. --*/
  2555. {
  2556. PHMAP_ENTRY Map;
  2557. ULONG NewLength;
  2558. ULONG OldLength;
  2559. OldLength = Hive->BaseBlock->Length;
  2560. NewLength = Hive->Storage[Stable].Length;
  2561. if( OldLength > NewLength ) {
  2562. return TRUE;
  2563. }
  2564. if( NewLength > 0 ) {
  2565. ASSERT( (NewLength % HBLOCK_SIZE) == 0);
  2566. Map = HvpGetCellMap(Hive, (NewLength - HBLOCK_SIZE));
  2567. VALIDATE_CELL_MAP(__LINE__,Map,Hive,(NewLength - HBLOCK_SIZE));
  2568. if (Map->BinAddress & HMAP_DISCARDABLE) {
  2569. return TRUE;
  2570. }
  2571. }
  2572. return FALSE;
  2573. }
  2574. VOID
  2575. HvpTruncateBins(
  2576. IN PHHIVE Hive
  2577. )
  2578. /*++
  2579. Routine Description:
  2580. Attempts to shrink the hive by truncating any bins that are discardable at
  2581. the end of the hive. Applies to both stable and volatile storage.
  2582. Arguments:
  2583. Hive - Supplies the hive to be truncated.
  2584. Return Value:
  2585. None.
  2586. --*/
  2587. {
  2588. HSTORAGE_TYPE i;
  2589. PHMAP_ENTRY Map;
  2590. ULONG NewLength;
  2591. PFREE_HBIN FreeBin;
  2592. //
  2593. // stable and volatile
  2594. //
  2595. for (i=0;i<HTYPE_COUNT;i++) {
  2596. //
  2597. // find the last in-use bin in the hive
  2598. //
  2599. NewLength = Hive->Storage[i].Length;
  2600. while (NewLength > 0) {
  2601. Map = HvpGetCellMap(Hive, (NewLength - HBLOCK_SIZE) + (i*HCELL_TYPE_MASK));
  2602. VALIDATE_CELL_MAP(__LINE__,Map,Hive,(NewLength - HBLOCK_SIZE) + (i*HCELL_TYPE_MASK));
  2603. if (Map->BinAddress & HMAP_DISCARDABLE) {
  2604. FreeBin = (PFREE_HBIN)Map->BlockAddress;
  2605. #ifdef HV_TRACK_FREE_SPACE
  2606. Hive->Storage[i].FreeStorage -= (FreeBin->Size - sizeof(HBIN));
  2607. ASSERT( (LONG)(Hive->Storage[i].FreeStorage) >= 0 );
  2608. #endif
  2609. NewLength = FreeBin->FileOffset;
  2610. } else {
  2611. break;
  2612. }
  2613. }
  2614. if (NewLength < Hive->Storage[i].Length) {
  2615. //
  2616. // There are some free bins to truncate.
  2617. //
  2618. HvFreeHivePartial(Hive, NewLength, i);
  2619. }
  2620. }
  2621. }
  2622. VOID
  2623. HvpDropPagedBins(
  2624. IN PHHIVE Hive
  2625. #if DBG
  2626. ,
  2627. IN BOOLEAN Check
  2628. #endif
  2629. )
  2630. /*++
  2631. Routine Description:
  2632. Frees all bins allocated from page pool, which are at
  2633. the end of the hive, then update their map (clears the
  2634. HMAP_INPAGEDPOOL flag). Next attempt to read from those
  2635. bins will map a view for them. Checks for CM_VIEW_SIZE boundary,
  2636. before freeing a bin.
  2637. It also tags each start of the bin with HMAP_NEWALLOC; This will
  2638. allow us to use MAP_NO_READ flag in CcMapData (now that we enabled
  2639. MNW feature for registry streams, we know that Mm will fault only one
  2640. page at the time for these king of streams)
  2641. Applies only to permanent storage.
  2642. Arguments:
  2643. Hive - Supplies the hive to operate on..
  2644. Check - debug only, beggining of the bin should already tagged as
  2645. HMAP_NEWALLOC
  2646. Return Value:
  2647. None.
  2648. --*/
  2649. {
  2650. ULONG_PTR Address;
  2651. LONG Length;
  2652. LONG Offset;
  2653. PHMAP_ENTRY Me;
  2654. PHBIN Bin;
  2655. PFREE_HBIN FreeBin;
  2656. BOOLEAN UnMap = FALSE;
  2657. PAGED_CODE();
  2658. if( (Hive->Storage[Stable].Length == 0) || // empty hive
  2659. (((PCMHIVE)Hive)->FileObject == NULL) // or hive not using the mapped views technique
  2660. ) {
  2661. return;
  2662. }
  2663. CmLockHiveViews((PCMHIVE)Hive);
  2664. if( ((PCMHIVE)Hive)->UseCount != 0 ) {
  2665. //
  2666. // this is not a good time to do that
  2667. //
  2668. CmUnlockHiveViews((PCMHIVE)Hive);
  2669. return;
  2670. }
  2671. //
  2672. // start at the end of the hive
  2673. //
  2674. Length = Hive->Storage[Stable].Length - HBLOCK_SIZE;
  2675. while(Length >= 0) {
  2676. //
  2677. // get the bin
  2678. //
  2679. Me = HvpGetCellMap(Hive, Length);
  2680. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Length);
  2681. if( !(Me->BinAddress & HMAP_INPAGEDPOOL) ) {
  2682. //
  2683. // bail out; we are interested only in bins allocated from paged pool
  2684. //
  2685. break;
  2686. }
  2687. if(Me->BinAddress & HMAP_DISCARDABLE) {
  2688. //
  2689. // bin is discardable, skip it !
  2690. //
  2691. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  2692. Length = FreeBin->FileOffset - HBLOCK_SIZE;
  2693. continue;
  2694. }
  2695. Address = HBIN_BASE(Me->BinAddress);
  2696. Bin = (PHBIN)Address;
  2697. // sanity
  2698. ASSERT( Bin->Signature == HBIN_SIGNATURE );
  2699. //
  2700. // advance (backward) to the previous bin
  2701. //
  2702. Length = Bin->FileOffset - HBLOCK_SIZE;
  2703. //
  2704. // finaly, see if we can free it;
  2705. //
  2706. if( HvpCheckViewBoundary(Bin->FileOffset,Bin->FileOffset + Bin->Size - 1) ) {
  2707. //
  2708. // free its storage and mark the map accordingly;
  2709. // next attempt to read a cell from this bin will map a view.
  2710. //
  2711. Offset = Bin->FileOffset;
  2712. while( Offset < (LONG)(Bin->FileOffset + Bin->Size) ) {
  2713. Me = HvpGetCellMap(Hive, Offset);
  2714. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  2715. ASSERT_BIN_INPAGEDPOOL(Me);
  2716. //
  2717. // clear off the HMAP_INPAGEDPOOL flag
  2718. //
  2719. Me->BinAddress &= ~HMAP_INPAGEDPOOL;
  2720. if( (ULONG)Offset == Bin->FileOffset ) {
  2721. #if DBG
  2722. if( Check == TRUE ) {
  2723. // should already be tagged
  2724. ASSERT( Me->BinAddress & HMAP_NEWALLOC );
  2725. }
  2726. #endif
  2727. //
  2728. // tag it as a new alloc, so we can rely on this flag in CmpMapCmView
  2729. //
  2730. Me->BinAddress |= HMAP_NEWALLOC;
  2731. } else {
  2732. //
  2733. // remove the NEWALLOC flag (if any), so we can rely on this flag in CmpMapCmView
  2734. //
  2735. Me->BinAddress &= ~HMAP_NEWALLOC;
  2736. }
  2737. // advance to the next HBLOCK_SIZE of this bin
  2738. Offset += HBLOCK_SIZE;
  2739. }
  2740. //
  2741. // free the bin
  2742. //
  2743. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Dropping temporary bin (from paged pool) at offset %lx size %lx\n",Bin->FileOffset,Bin->Size));
  2744. if( HvpGetBinMemAlloc(Hive,Bin,Stable) ) {
  2745. CmpFree(Bin, HvpGetBinMemAlloc(Hive,Bin,Stable));
  2746. }
  2747. UnMap = TRUE;
  2748. } else {
  2749. //
  2750. // this bin has a good reason to reside in page-pool (it's crossing the boundaries).
  2751. // leave it like that !
  2752. //
  2753. NOTHING;
  2754. }
  2755. }
  2756. if( UnMap == TRUE ) {
  2757. //
  2758. // unmap the last view, to make sure the map will be updated
  2759. //
  2760. ASSERT( Length >= -HBLOCK_SIZE );
  2761. Offset = (Length + HBLOCK_SIZE) & (~(CM_VIEW_SIZE - 1));
  2762. if( Offset != 0 ) {
  2763. //
  2764. // account for the header
  2765. //
  2766. Offset -= HBLOCK_SIZE;
  2767. }
  2768. Length = Hive->Storage[Stable].Length;
  2769. while( Offset < Length ) {
  2770. Me = HvpGetCellMap(Hive, Offset);
  2771. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  2772. if( Me->BinAddress & HMAP_INVIEW ) {
  2773. //
  2774. // get this view and unmap it; then bail out.
  2775. //
  2776. CmpUnmapCmView( (PCMHIVE)Hive,Me->CmView,TRUE,TRUE);
  2777. break;
  2778. }
  2779. // next, please ?
  2780. Offset += HBLOCK_SIZE;
  2781. }
  2782. }
  2783. CmUnlockHiveViews((PCMHIVE)Hive);
  2784. }
  2785. VOID
  2786. HvpDropAllPagedBins(
  2787. IN PHHIVE Hive
  2788. )
  2789. /*++
  2790. Routine Description:
  2791. Works as HvpDropPagedBins, only that it iterates through
  2792. the entire hive. No views are mapped at this point.
  2793. Arguments:
  2794. Hive - Supplies the hive to operate on..
  2795. Return Value:
  2796. None.
  2797. --*/
  2798. {
  2799. ULONG_PTR Address;
  2800. ULONG Length;
  2801. ULONG Offset;
  2802. PHMAP_ENTRY Me;
  2803. PHBIN Bin;
  2804. PFREE_HBIN FreeBin;
  2805. PAGED_CODE();
  2806. if( (Hive->Storage[Stable].Length == 0) || // empty hive
  2807. (((PCMHIVE)Hive)->FileObject == NULL) // or hive not using the mapped views technique
  2808. ) {
  2809. return;
  2810. }
  2811. ASSERT( (((PCMHIVE)Hive)->MappedViews == 0) && (((PCMHIVE)Hive)->PinnedViews == 0) && (((PCMHIVE)Hive)->UseCount == 0) );
  2812. //
  2813. // start at the end of the hive
  2814. //
  2815. Length = Hive->Storage[Stable].Length - HBLOCK_SIZE;
  2816. Offset = 0;
  2817. while( Offset < Length ) {
  2818. //
  2819. // get the bin
  2820. //
  2821. Me = HvpGetCellMap(Hive, Offset);
  2822. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  2823. ASSERT( Me->BinAddress & HMAP_INPAGEDPOOL );
  2824. if(Me->BinAddress & HMAP_DISCARDABLE) {
  2825. //
  2826. // bin is discardable, skip it !
  2827. //
  2828. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  2829. ASSERT( Offset == FreeBin->FileOffset );
  2830. Offset += FreeBin->Size;
  2831. continue;
  2832. }
  2833. Address = HBIN_BASE(Me->BinAddress);
  2834. Bin = (PHBIN)Address;
  2835. // sanity
  2836. ASSERT( Bin->Signature == HBIN_SIGNATURE );
  2837. //
  2838. // finaly, see if we can free it;
  2839. //
  2840. if( HvpCheckViewBoundary(Bin->FileOffset,Bin->FileOffset + Bin->Size - 1) ) {
  2841. //
  2842. // free its storage and mark the map accordingly;
  2843. // next attempt to read a cell from this bin will map a view.
  2844. //
  2845. Offset = Bin->FileOffset;
  2846. while( Offset < (Bin->FileOffset + Bin->Size) ) {
  2847. Me = HvpGetCellMap(Hive, Offset);
  2848. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  2849. ASSERT_BIN_INPAGEDPOOL(Me);
  2850. //
  2851. // clear off the HMAP_INPAGEDPOOL flag
  2852. //
  2853. Me->BinAddress &= ~HMAP_INPAGEDPOOL;
  2854. if( (ULONG)Offset == Bin->FileOffset ) {
  2855. //
  2856. // tag it as a new alloc, so we can rely on this flag in CmpMapCmView
  2857. //
  2858. Me->BinAddress |= HMAP_NEWALLOC;
  2859. } else {
  2860. //
  2861. // remove the NEWALLOC flag (if any), so we can rely on this flag in CmpMapCmView
  2862. //
  2863. Me->BinAddress &= ~HMAP_NEWALLOC;
  2864. }
  2865. // advance to the next HBLOCK_SIZE of this bin
  2866. Offset += HBLOCK_SIZE;
  2867. }
  2868. //
  2869. // free the bin
  2870. //
  2871. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Dropping temporary bin (from paged pool) at offset %lx size %lx\n",Bin->FileOffset,Bin->Size));
  2872. if( HvpGetBinMemAlloc(Hive,Bin,Stable) ) {
  2873. CmpFree(Bin, HvpGetBinMemAlloc(Hive,Bin,Stable));
  2874. }
  2875. } else {
  2876. //
  2877. // this bin has a good reason to reside in page-pool (it's crossing the boundaries).
  2878. // leave it like that !
  2879. //
  2880. Offset += Bin->Size;
  2881. }
  2882. }
  2883. }
  2884. NTSTATUS
  2885. HvWriteHive(
  2886. PHHIVE Hive,
  2887. BOOLEAN DontGrow,
  2888. BOOLEAN WriteThroughCache,
  2889. BOOLEAN CrashSafe
  2890. )
  2891. /*++
  2892. Routine Description:
  2893. Write the hive out. Write only to the Primary file, neither
  2894. logs nor alternates will be updated. The hive will be written
  2895. to the HFILE_TYPE_EXTERNAL handle.
  2896. Intended for use in applications like SaveKey.
  2897. Only Stable storage will be written (as for any hive.)
  2898. Presumption is that layer above has set HFILE_TYPE_EXTERNAL
  2899. handle to point to correct place.
  2900. Applying this call to an active hive will generally hose integrity
  2901. measures.
  2902. HOW IT WORKS:
  2903. Saves the BaseBlock.
  2904. Iterates through the entire hive and save it bin by bin
  2905. Arguments:
  2906. Hive - supplies a pointer to the hive control structure for the
  2907. hive of interest.
  2908. DontGrow - we know that the file is big enough, don't attempt to grow it.
  2909. Return Value:
  2910. Status.
  2911. --*/
  2912. {
  2913. PHBASE_BLOCK BaseBlock;
  2914. NTSTATUS status;
  2915. ULONG Offset;
  2916. PHBIN Bin = NULL;
  2917. PFREE_HBIN FreeBin = NULL;
  2918. ULONG BinSize;
  2919. PVOID Address;
  2920. ULONG BinOffset;
  2921. ULONG Length;
  2922. CMP_OFFSET_ARRAY offsetElement;
  2923. PHMAP_ENTRY Me;
  2924. PHCELL FirstCell;
  2925. BOOLEAN rc;
  2926. PCM_VIEW_OF_FILE CmView = NULL;
  2927. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvWriteHive: \n"));
  2928. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"\tHive = %p\n"));
  2929. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  2930. ASSERT(Hive->ReadOnly == FALSE);
  2931. //
  2932. // Punt if post shutdown
  2933. //
  2934. if (HvShutdownComplete) {
  2935. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"HvWriteHive: Attempt to write hive AFTER SHUTDOWN\n"));
  2936. return STATUS_REGISTRY_IO_FAILED;
  2937. }
  2938. Length = Hive->Storage[Stable].Length;
  2939. //
  2940. // we should never come to this
  2941. //
  2942. ASSERT( Length != 0 );
  2943. ASSERT( Hive->BaseBlock->RootCell != HCELL_NIL );
  2944. if( !DontGrow ){
  2945. //
  2946. // Ensure the file can be made big enough, then do the deed
  2947. //
  2948. status = CmpDoFileSetSize(Hive,
  2949. HFILE_TYPE_EXTERNAL,
  2950. Length + HBLOCK_SIZE,
  2951. 0);
  2952. if (!NT_SUCCESS(status)) {
  2953. return status;
  2954. }
  2955. }
  2956. BaseBlock = Hive->BaseBlock;
  2957. //
  2958. // --- Write out header first time ---
  2959. //
  2960. ASSERT(BaseBlock->Signature == HBASE_BLOCK_SIGNATURE);
  2961. ASSERT(BaseBlock->Major == HSYS_MAJOR);
  2962. ASSERT(BaseBlock->Format == HBASE_FORMAT_MEMORY);
  2963. ASSERT(Hive->ReadOnly == FALSE);
  2964. if (BaseBlock->Sequence1 != BaseBlock->Sequence2) {
  2965. //
  2966. // Some previous log attempt failed, or this hive needs to
  2967. // be recovered, so punt.
  2968. //
  2969. return STATUS_REGISTRY_IO_FAILED;
  2970. }
  2971. if( CrashSafe ) {
  2972. //
  2973. // change sequence numbers, in case we experience a machine crash
  2974. //
  2975. BaseBlock->Sequence1++;
  2976. }
  2977. BaseBlock->Length = Length;
  2978. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  2979. Offset = 0;
  2980. offsetElement.FileOffset = Offset;
  2981. offsetElement.DataBuffer = (PVOID) BaseBlock;
  2982. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  2983. if(WriteThroughCache) {
  2984. //
  2985. // if we use Cc, do the write with the pin interface
  2986. //
  2987. rc = CmpFileWriteThroughCache( Hive,
  2988. HFILE_TYPE_EXTERNAL,
  2989. &offsetElement,
  2990. 1);
  2991. Offset += offsetElement.DataLength;
  2992. } else {
  2993. rc = (Hive->FileWrite)( Hive,
  2994. HFILE_TYPE_EXTERNAL,
  2995. &offsetElement,
  2996. 1,
  2997. &Offset );
  2998. }
  2999. if (rc == FALSE) {
  3000. return STATUS_REGISTRY_IO_FAILED;
  3001. }
  3002. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_EXTERNAL,NULL,0)) {
  3003. return STATUS_REGISTRY_IO_FAILED;
  3004. }
  3005. Offset = ROUND_UP(Offset, HBLOCK_SIZE);
  3006. //
  3007. // --- Write out data (ALL !!!) ---
  3008. //
  3009. BinOffset = 0;
  3010. while (BinOffset < Hive->Storage[Stable].Length) {
  3011. //
  3012. // we need to grab the viewlock here to protect against a racing HvGetCell
  3013. //
  3014. CmLockHiveViews ((PCMHIVE)Hive);
  3015. Me = HvpGetCellMap(Hive, BinOffset);
  3016. if( (Me->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0) {
  3017. //
  3018. // view is not mapped, neither in paged pool try to map it.
  3019. //
  3020. if( !NT_SUCCESS(CmpMapThisBin((PCMHIVE)Hive,BinOffset,TRUE)) ) {
  3021. CmUnlockHiveViews ((PCMHIVE)Hive);
  3022. status = STATUS_INSUFFICIENT_RESOURCES;
  3023. goto ErrorExit;
  3024. }
  3025. }
  3026. //
  3027. // reference the view so it doesn't go away from under us;
  3028. // first remove any old ref
  3029. //
  3030. if( Me->BinAddress & HMAP_INVIEW ) {
  3031. CmpDereferenceHiveView((PCMHIVE)Hive,CmView);
  3032. CmpReferenceHiveView((PCMHIVE)Hive,CmView = Me->CmView);
  3033. }
  3034. CmUnlockHiveViews ((PCMHIVE)Hive);
  3035. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  3036. //
  3037. // bin is discardable. If it is not discarded yet, save it as it is
  3038. // else, allocate, initialize and save a fake bin
  3039. //
  3040. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  3041. BinSize = FreeBin->Size;
  3042. if( FreeBin->Flags & FREE_HBIN_DISCARDABLE ){
  3043. //
  3044. // HBIN still in memory
  3045. //
  3046. Address = (PVOID)HBIN_BASE(Me->BinAddress);
  3047. } else {
  3048. //
  3049. // HBIN discarded, we have to allocate a new bin and mark it as a
  3050. // BIG free cell
  3051. //
  3052. // don't charge quota for it as we will give it back
  3053. Bin = (PHBIN)ExAllocatePoolWithTag(PagedPool, BinSize, CM_HVBIN_TAG);
  3054. if( Bin == NULL ){
  3055. status = STATUS_INSUFFICIENT_RESOURCES;
  3056. goto ErrorExit;
  3057. }
  3058. //
  3059. // Initialize the bin
  3060. //
  3061. Bin->Signature = HBIN_SIGNATURE;
  3062. Bin->FileOffset = BinOffset;
  3063. Bin->Size = BinSize;
  3064. FirstCell = (PHCELL)(Bin+1);
  3065. FirstCell->Size = BinSize - sizeof(HBIN);
  3066. if (USE_OLD_CELL(Hive)) {
  3067. FirstCell->u.OldCell.Last = (ULONG)HBIN_NIL;
  3068. }
  3069. Address = (PVOID)Bin;
  3070. }
  3071. } else {
  3072. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  3073. ASSERT( Bin->Signature == HBIN_SIGNATURE );
  3074. ASSERT( Bin->FileOffset == BinOffset );
  3075. Address = (PVOID)Bin;
  3076. try {
  3077. BinSize = Bin->Size;
  3078. } except (EXCEPTION_EXECUTE_HANDLER) {
  3079. //
  3080. // in low-memory scenarios or disk error, touching the bin may throw STATUS_IN_PAGE_ERROR
  3081. //
  3082. status = GetExceptionCode();
  3083. goto ErrorExit;
  3084. }
  3085. }
  3086. //
  3087. // write the bin to the file
  3088. //
  3089. offsetElement.FileOffset = Offset;
  3090. offsetElement.DataBuffer = Address;
  3091. offsetElement.DataLength = BinSize;
  3092. if(WriteThroughCache) {
  3093. //
  3094. // if we use Cc, do the write with the pin interface
  3095. // Take extra care not to cross the view boundaries
  3096. //
  3097. if( HvpCheckViewBoundary(Offset - HBLOCK_SIZE,Offset - HBLOCK_SIZE + BinSize - 1) ) {
  3098. rc = CmpFileWriteThroughCache( Hive,
  3099. HFILE_TYPE_EXTERNAL,
  3100. &offsetElement,
  3101. 1);
  3102. } else {
  3103. //
  3104. // write one HBLOCK_SIZE at a time.
  3105. //
  3106. ULONG ToWrite = BinSize;
  3107. offsetElement.DataLength = HBLOCK_SIZE;
  3108. while( ToWrite > 0 ) {
  3109. rc = CmpFileWriteThroughCache( Hive,
  3110. HFILE_TYPE_EXTERNAL,
  3111. &offsetElement,
  3112. 1);
  3113. if( rc == FALSE ) {
  3114. status = STATUS_REGISTRY_IO_FAILED;
  3115. goto ErrorExit;
  3116. }
  3117. ToWrite -= HBLOCK_SIZE;
  3118. offsetElement.DataBuffer = (PUCHAR)offsetElement.DataBuffer + HBLOCK_SIZE;
  3119. offsetElement.FileOffset += HBLOCK_SIZE;
  3120. }
  3121. }
  3122. Offset += BinSize;
  3123. } else {
  3124. rc = (Hive->FileWrite)( Hive,
  3125. HFILE_TYPE_EXTERNAL,
  3126. &offsetElement,
  3127. 1,
  3128. &Offset );
  3129. }
  3130. if (rc == FALSE) {
  3131. status = STATUS_REGISTRY_IO_FAILED;
  3132. goto ErrorExit;
  3133. }
  3134. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  3135. if( (FreeBin->Flags & FREE_HBIN_DISCARDABLE) == 0){
  3136. ASSERT( FreeBin == (PFREE_HBIN)Me->BlockAddress );
  3137. ASSERT( Bin );
  3138. //
  3139. // give back the paged pool used
  3140. //
  3141. ExFreePool(Bin);
  3142. }
  3143. }
  3144. //
  3145. // advance to the next bin
  3146. //
  3147. BinOffset += BinSize;
  3148. }
  3149. //
  3150. // let go last view referenced (if any)
  3151. //
  3152. CmpDereferenceHiveViewWithLock((PCMHIVE)Hive,CmView);
  3153. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_EXTERNAL,NULL,0)) {
  3154. return STATUS_REGISTRY_IO_FAILED;
  3155. }
  3156. if( CrashSafe ) {
  3157. //
  3158. // change sequence numbers, in case we experience a machine crash
  3159. //
  3160. BaseBlock->Sequence2++;
  3161. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  3162. ASSERT( BaseBlock->Sequence1 == BaseBlock->Sequence2 );
  3163. Offset = 0;
  3164. offsetElement.FileOffset = Offset;
  3165. offsetElement.DataBuffer = (PVOID) BaseBlock;
  3166. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  3167. if(WriteThroughCache) {
  3168. //
  3169. // if we use Cc, do the write with the pin interface
  3170. //
  3171. rc = CmpFileWriteThroughCache( Hive,
  3172. HFILE_TYPE_EXTERNAL,
  3173. &offsetElement,
  3174. 1);
  3175. Offset += offsetElement.DataLength;
  3176. } else {
  3177. rc = (Hive->FileWrite)( Hive,
  3178. HFILE_TYPE_EXTERNAL,
  3179. &offsetElement,
  3180. 1,
  3181. &Offset );
  3182. }
  3183. if (rc == FALSE) {
  3184. return STATUS_REGISTRY_IO_FAILED;
  3185. }
  3186. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_EXTERNAL,NULL,0)) {
  3187. return STATUS_REGISTRY_IO_FAILED;
  3188. }
  3189. if( DontGrow ){
  3190. //
  3191. // file has shrunk
  3192. //
  3193. CmpDoFileSetSize(Hive,HFILE_TYPE_EXTERNAL,Length + HBLOCK_SIZE,0);
  3194. }
  3195. }
  3196. // it seems like everything went OK
  3197. return STATUS_SUCCESS;
  3198. ErrorExit:
  3199. CmpDereferenceHiveViewWithLock((PCMHIVE)Hive,CmView);
  3200. return status;
  3201. }
  3202. #ifdef CM_ENABLE_WRITE_ONLY_BINS
  3203. VOID HvpMarkAllBinsWriteOnly(IN PHHIVE Hive)
  3204. {
  3205. HCELL_INDEX p;
  3206. ULONG Length;
  3207. PHMAP_ENTRY t;
  3208. PHBIN Bin;
  3209. ULONG i;
  3210. PFREE_HBIN FreeBin;
  3211. p = 0;
  3212. PAGED_CODE();
  3213. Length = Hive->Storage[Stable].Length;
  3214. //
  3215. // for each bin in the stable storage
  3216. //
  3217. while (p < Length) {
  3218. t = HvpGetCellMap(Hive, p);
  3219. VALIDATE_CELL_MAP(__LINE__,t,Hive,p);
  3220. if( (t->BinAddress &HMAP_INPAGEDPOOL) == 0) {
  3221. //
  3222. // at this point we only work with paged pool bins
  3223. //
  3224. break;
  3225. }
  3226. if ((t->BinAddress & HMAP_DISCARDABLE) == 0) {
  3227. Bin = (PHBIN)HBIN_BASE(t->BinAddress);
  3228. for( i=0;i<Bin->Size;i += PAGE_SIZE ) {
  3229. if( !MmProtectSpecialPool((PUCHAR)Bin + i,PAGE_READONLY) ) {
  3230. DbgPrint("Failed to set READONLY protection on page at %p Bin %p size = %lx\n",Bin+i,Bin,Bin->Size);
  3231. }
  3232. }
  3233. /*
  3234. if( !MmSetPageProtection(Bin,Bin->Size,PAGE_READONLY) ) {
  3235. DbgPrint("Failed to set READONLY protection on bin at %p size = %lx\n",Bin,Bin->Size);
  3236. }
  3237. */
  3238. p = (ULONG)p + Bin->Size;
  3239. } else {
  3240. //
  3241. // Bin is not present, skip it and advance to the next one.
  3242. //
  3243. FreeBin = (PFREE_HBIN)t->BlockAddress;
  3244. p+=FreeBin->Size;
  3245. }
  3246. }
  3247. }
  3248. #endif //CM_ENABLE_WRITE_ONLY_BINS