Leaked source code of windows server 2003
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.

3949 lines
119 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 below
  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. PFREE_HBIN FreeBin;
  648. ULONG Offset;
  649. ULONG FileOffset;
  650. HCELL_INDEX TailStart;
  651. ULONG Start;
  652. ULONG End;
  653. ULONG BitLength;
  654. PCM_VIEW_OF_FILE CmView;
  655. PCMHIVE CmHive;
  656. ULONG FileOffsetStart;
  657. ULONG FileOffsetEnd;
  658. PHMAP_ENTRY Me;
  659. ULONG i;
  660. PHBIN Bin;
  661. ULONG BinSize;
  662. ULONG Current;
  663. PRTL_BITMAP BitMap;
  664. PUCHAR Address;
  665. BOOLEAN rc;
  666. ULONG ReadLength;
  667. HCELL_INDEX p;
  668. PHMAP_ENTRY t;
  669. ULONG checkstatus;
  670. ULONG OldFileLength;
  671. LIST_ENTRY PinViewListHead;
  672. ULONG Size;
  673. LARGE_INTEGER PurgeOffset;
  674. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  675. //
  676. // noop or assert on various uninteresting or bogus conditions
  677. //
  678. if (Hive->DirtyCount == 0) {
  679. return;
  680. }
  681. ASSERT(Hive->HiveFlags & HIVE_NOLAZYFLUSH);
  682. ASSERT(Hive->Storage[Volatile].Length == 0);
  683. //
  684. // be sure the hive is not already trash
  685. //
  686. checkstatus = HvCheckHive(Hive, NULL);
  687. if (checkstatus != 0) {
  688. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,1,Hive,checkstatus);
  689. }
  690. // store it for the shrink/grow at the end.
  691. OldFileLength = Hive->Storage[Stable].Length + HBLOCK_SIZE;
  692. //
  693. // Capture the LinkCell backpointer in the hive's root cell. We need this in case
  694. // the first bin is overwritten with what was on disk.
  695. //
  696. RootCell = Hive->BaseBlock->RootCell;
  697. RootNode = (PCM_KEY_NODE)HvGetCell(Hive, RootCell);
  698. if( RootNode == NULL ) {
  699. //
  700. // we couldn't map a view for this cell
  701. // we're low on resources, so we couldn't refresh the hive.
  702. //
  703. return;
  704. }
  705. // release the cell here as we are holding the reglock exclusive
  706. HvReleaseCell(Hive,RootCell);
  707. LinkCell = RootNode->Parent;
  708. Hive->RefreshCount++;
  709. //
  710. // 1. Remove all discardable bins from FreeBins list
  711. // - remove the discardable flag from the ones that
  712. // have not yet been discarded
  713. // - for discarded ones, just remove the marker from
  714. // the FreeBins list
  715. //
  716. //
  717. // Any bins that have been marked as discardable, but not yet flushed to
  718. // disk, are going to be overwritten with old data. Bring them back into
  719. // memory and remove their FREE_HBIN marker from the list. Other bins are
  720. // either discarded, or mapped into views
  721. //
  722. /*
  723. DRAGOS: This is not needed anymore (see Comments)
  724. List = Hive->Storage[Stable].FreeBins.Flink;
  725. while (List != &Hive->Storage[Stable].FreeBins) {
  726. FreeBin = CONTAINING_RECORD(List, FREE_HBIN, ListEntry);
  727. List = List->Flink;
  728. if (FreeBin->Flags & FREE_HBIN_DISCARDABLE) {
  729. for (i=0; i<FreeBin->Size; i+=HBLOCK_SIZE) {
  730. Me = HvpGetCellMap(Hive, FreeBin->FileOffset+i);
  731. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FreeBin->FileOffset+i);
  732. Me->BlockAddress = HBIN_BASE(Me->BinAddress)+i;
  733. Me->BinAddress &= ~HMAP_DISCARDABLE;
  734. }
  735. RemoveEntryList(&FreeBin->ListEntry);
  736. (Hive->Free)(FreeBin, sizeof(FREE_HBIN));
  737. }
  738. }
  739. */
  740. //
  741. // 2. read the base block, and eventually free the tail of the hive
  742. //
  743. //
  744. // OverRead base block.
  745. //
  746. Offset = 0;
  747. if ( (Hive->FileRead)(
  748. Hive,
  749. HFILE_TYPE_PRIMARY,
  750. &Offset,
  751. Hive->BaseBlock,
  752. HBLOCK_SIZE
  753. ) != TRUE)
  754. {
  755. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,2,Hive,Offset);
  756. }
  757. TailStart = (HCELL_INDEX)(Hive->BaseBlock->Length);
  758. //
  759. // Free "tail" memory and maps for it, update hive size pointers
  760. //
  761. HvFreeHivePartial(Hive, TailStart, Stable);
  762. //
  763. // Clear dirty vector for data past Hive->BaseBlock->Length
  764. //
  765. Start = Hive->BaseBlock->Length / HSECTOR_SIZE;
  766. End = Hive->DirtyVector.SizeOfBitMap;
  767. BitLength = End - Start;
  768. RtlClearBits(&(Hive->DirtyVector), Start, BitLength);
  769. HvpAdjustHiveFreeDisplay(Hive,Hive->Storage[Stable].Length,Stable);
  770. //
  771. // 3. unpin and purge all pinned views; also clear the free cell
  772. // hint for mapped bins.
  773. //
  774. CmHive = (PCMHIVE)Hive;
  775. InitializeListHead(&PinViewListHead);
  776. //
  777. // for each pinned view
  778. //
  779. while(IsListEmpty(&(CmHive->PinViewListHead)) == FALSE) {
  780. //
  781. // Remove the first view from the pin view list
  782. //
  783. CmView = (PCM_VIEW_OF_FILE)RemoveHeadList(&(CmHive->PinViewListHead));
  784. CmView = CONTAINING_RECORD( CmView,
  785. CM_VIEW_OF_FILE,
  786. PinViewList);
  787. //
  788. // the real file offset starts after the header
  789. //
  790. FileOffsetStart = CmView->FileOffset;
  791. FileOffsetEnd = FileOffsetStart + CmView->Size;
  792. FileOffsetEnd -= HBLOCK_SIZE;
  793. if( FileOffsetStart != 0 ) {
  794. //
  795. // just at the begining of the file, subtract the header
  796. //
  797. FileOffsetStart -= HBLOCK_SIZE;
  798. }
  799. FileOffset = FileOffsetStart;
  800. //
  801. // now, for every block in this range which is mapped in view
  802. // clear the dirty bit, and the free cell hint
  803. //
  804. while(FileOffset < FileOffsetEnd) {
  805. Me = HvpGetCellMap(Hive, FileOffset);
  806. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileOffset);
  807. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  808. //
  809. // ignore the bins loaded into paged pool; we'll deal with them later on
  810. //
  811. if( Me->BinAddress & HMAP_INVIEW ) {
  812. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  813. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  814. // free bins comming from mapped views are not discardable
  815. ASSERT( (FreeBin->Flags & FREE_HBIN_DISCARDABLE) == 0 );
  816. //
  817. // go and clear the discardable flag for all blocks of this bin
  818. //
  819. for( i=FileOffset;i<FileOffset+FreeBin->Size;i+=HBLOCK_SIZE) {
  820. Me = HvpGetCellMap(Hive, i);
  821. VALIDATE_CELL_MAP(__LINE__,Me,Hive,i);
  822. Me->BinAddress &= ~HMAP_DISCARDABLE;
  823. }
  824. //
  825. // get rid of the entry from FreeBins list
  826. // it'll be added again after sync is done if bin is still
  827. // discardable
  828. //
  829. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  830. ASSERT(FreeBin->FileOffset == FileOffset);
  831. RemoveEntryList(&FreeBin->ListEntry);
  832. BinSize = FreeBin->Size;
  833. (Hive->Free)(FreeBin, sizeof(FREE_HBIN));
  834. } else {
  835. //
  836. // bin is mapped in view. Then, this should be the beggining of the bin
  837. //
  838. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  839. ASSERT(Bin->FileOffset == FileOffset);
  840. BinSize = Bin->Size;
  841. }
  842. //
  843. // clear of the dirty bits for this bin
  844. //
  845. RtlClearBits(&Hive->DirtyVector,FileOffset/HSECTOR_SIZE,BinSize/HSECTOR_SIZE);
  846. //
  847. // now clear the free cell hint for this bin
  848. //
  849. for( i=0;i<HHIVE_FREE_DISPLAY_SIZE;i++) {
  850. RtlClearBits (&(Hive->Storage[Stable].FreeDisplay[i].Display), FileOffset / HBLOCK_SIZE, BinSize / HBLOCK_SIZE);
  851. if( RtlNumberOfSetBits(&(Hive->Storage[Stable].FreeDisplay[i].Display) ) != 0 ) {
  852. //
  853. // there are still some other free cells of this size
  854. //
  855. Hive->Storage[Stable].FreeSummary |= (1 << i);
  856. } else {
  857. //
  858. // entire bitmap is 0 (i.e. no other free cells of this size)
  859. //
  860. Hive->Storage[Stable].FreeSummary &= (~(1 << i));
  861. }
  862. }
  863. } else {
  864. //
  865. // bin in paged pool
  866. //
  867. ASSERT( Me->BinAddress & HMAP_INPAGEDPOOL );
  868. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  869. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  870. ASSERT(FreeBin->FileOffset == FileOffset);
  871. BinSize = FreeBin->Size;
  872. } else {
  873. //
  874. // Then, this should be the beggining of the bin
  875. //
  876. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  877. ASSERT(Bin->FileOffset == FileOffset);
  878. BinSize = Bin->Size;
  879. }
  880. }
  881. FileOffset += BinSize;
  882. }// while (FileOffset<FileOffsetEnd)
  883. //
  884. // Just unmap the view, without marking the data dirty; We'll flush cache after we finish
  885. // unpinning and unmapping all neccessary views
  886. //
  887. ASSERT( CmView->UseCount == 0 );
  888. // store this for later
  889. FileOffset = CmView->FileOffset;
  890. Size = CmView->Size;
  891. CmpUnmapCmView (CmHive,CmView,TRUE,TRUE);
  892. //
  893. // we use the PinViewList member of these views to keep track of all pinned
  894. // views that need to be remapped after the purge
  895. //
  896. InsertTailList(
  897. &PinViewListHead,
  898. &(CmView->PinViewList)
  899. );
  900. //
  901. // remove the view from the LRU list
  902. //
  903. RemoveEntryList(&(CmView->LRUViewList));
  904. //
  905. // store the FileOffset and address so we know what to map afterwards
  906. //
  907. CmView->FileOffset = FileOffset;
  908. CmView->Size = Size;
  909. //
  910. // now we need to make sure the 256K window surrounding this offset is not
  911. // mapped in any way
  912. //
  913. FileOffset = FileOffset & (~(_256K - 1));
  914. Size = FileOffset + _256K;
  915. Size = (Size > OldFileLength)?OldFileLength:Size;
  916. //
  917. // we are not allowed to purge in shared mode.
  918. //
  919. while( FileOffset < Size ) {
  920. CmpUnmapCmViewSurroundingOffset((PCMHIVE)Hive,FileOffset);
  921. FileOffset += CM_VIEW_SIZE;
  922. }
  923. }// while IsListEmpty(&(CmHive->PinViewListHead))
  924. //
  925. // Now we need to purge the the previously pinned views
  926. //
  927. PurgeOffset.HighPart = 0;
  928. CmView = (PCM_VIEW_OF_FILE)PinViewListHead.Flink;
  929. while( CmHive->PinnedViews ) {
  930. ASSERT( CmView != (PCM_VIEW_OF_FILE)(&(PinViewListHead)) );
  931. CmView = CONTAINING_RECORD( CmView,
  932. CM_VIEW_OF_FILE,
  933. PinViewList);
  934. //
  935. // now purge as a private writer
  936. //
  937. PurgeOffset.LowPart = CmView->FileOffset;
  938. CcPurgeCacheSection(CmHive->FileObject->SectionObjectPointer,(PLARGE_INTEGER)(((ULONG_PTR)(&PurgeOffset)) + 1)/*we are private writers*/,
  939. CmView->Size,FALSE);
  940. //
  941. // advance to the next view
  942. //
  943. CmView = (PCM_VIEW_OF_FILE)(CmView->PinViewList.Flink);
  944. CmHive->PinnedViews--;
  945. }
  946. ASSERT( ((PCMHIVE)CmHive)->PinnedViews == 0 );
  947. //
  948. // 4.remap views purged at 3 and reenlist the bins inside. this
  949. // will fix free bins discarded at 1.
  950. //
  951. while(IsListEmpty(&PinViewListHead) == FALSE) {
  952. //
  953. // Remove the first view from the pin view list
  954. //
  955. CmView = (PCM_VIEW_OF_FILE)RemoveHeadList(&PinViewListHead);
  956. CmView = CONTAINING_RECORD( CmView,
  957. CM_VIEW_OF_FILE,
  958. PinViewList);
  959. //
  960. // the real file offset starts after the header
  961. //
  962. FileOffsetStart = CmView->FileOffset;
  963. FileOffsetEnd = FileOffsetStart + CmView->Size;
  964. FileOffsetEnd -= HBLOCK_SIZE;
  965. if( FileOffsetStart != 0 ) {
  966. //
  967. // just at the begining of the file, subtract the header
  968. //
  969. FileOffsetStart -= HBLOCK_SIZE;
  970. }
  971. if( FileOffsetEnd > Hive->BaseBlock->Length ) {
  972. FileOffsetEnd = Hive->BaseBlock->Length;
  973. }
  974. //
  975. // be sure to free this view as nobody is using it anymore
  976. //
  977. #if DBG
  978. CmView->FileOffset = CmView->Size = 0;
  979. InitializeListHead(&(CmView->PinViewList));
  980. InitializeListHead(&(CmView->LRUViewList));
  981. #endif
  982. CmpFreeCmView (CmView);
  983. if( FileOffsetStart >= FileOffsetEnd ) {
  984. continue;
  985. }
  986. //
  987. // remap it with the right data
  988. //
  989. if( !NT_SUCCESS(CmpMapCmView(CmHive,FileOffsetStart,&CmView,TRUE) ) ) {
  990. //
  991. // this is bad. We have altered the hive and now we have no way of restoring it
  992. // bugcheck!
  993. //
  994. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,3,CmHive,FileOffsetStart);
  995. }
  996. //
  997. // touch the view
  998. //
  999. CmpTouchView((PCMHIVE)Hive,CmView,FileOffsetStart);
  1000. FileOffset = FileOffsetStart;
  1001. while(FileOffset < FileOffsetEnd) {
  1002. Me = HvpGetCellMap(Hive, FileOffset);
  1003. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileOffset);
  1004. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  1005. //
  1006. // ignore paged bins
  1007. //
  1008. if( Me->BinAddress & HMAP_INVIEW ) {
  1009. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  1010. ASSERT(Bin->FileOffset == FileOffset);
  1011. // enlisting freecells will fix the free bins problem too
  1012. if ( ! HvpEnlistFreeCells(Hive, Bin, Bin->FileOffset) ) {
  1013. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,4,Bin,Bin->FileOffset);
  1014. }
  1015. FileOffset += Bin->Size;
  1016. } else {
  1017. FileOffset += HBLOCK_SIZE;
  1018. }
  1019. }
  1020. } // while (IsListEmpty(&PinViewListHead))
  1021. // 5. iterate through the map; read and reenlist all bins that are
  1022. // in paged-pool (and dirty)
  1023. //
  1024. // Scan dirty blocks. Read contiguous blocks off disk into hive.
  1025. // Stop when we get to reduced length.
  1026. //
  1027. BitMap = &(Hive->DirtyVector);
  1028. Current = 0;
  1029. while (HvpFindNextDirtyBlock(
  1030. Hive,
  1031. &Hive->DirtyVector,
  1032. &Current, &Address,
  1033. &ReadLength,
  1034. &Offset
  1035. ))
  1036. {
  1037. ASSERT(Offset < (Hive->BaseBlock->Length + sizeof(HBASE_BLOCK)));
  1038. rc = (Hive->FileRead)(
  1039. Hive,
  1040. HFILE_TYPE_PRIMARY,
  1041. &Offset,
  1042. (PVOID)Address,
  1043. ReadLength
  1044. );
  1045. if (rc == FALSE) {
  1046. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,5,Offset,Address);
  1047. }
  1048. }
  1049. //
  1050. // If we read the start of any HBINs into memory, it is likely
  1051. // their MemAlloc fields are invalid. Walk through the HBINs
  1052. // and write valid MemAlloc values for any HBINs whose first
  1053. // sector was reread.
  1054. //
  1055. // HvpFindNextDirtyBlock knows how to deal with free bins. If we
  1056. // reread a free bin, we need to delist it from the list first and
  1057. // reenlist it again (it may not be free on the disk)
  1058. //
  1059. p=0;
  1060. while (p < Hive->Storage[Stable].Length) {
  1061. t = HvpGetCellMap(Hive, p);
  1062. VALIDATE_CELL_MAP(__LINE__,t,Hive,p);
  1063. Bin = (PHBIN)HBIN_BASE(t->BlockAddress);
  1064. if (RtlCheckBit(&Hive->DirtyVector, p / HSECTOR_SIZE)==1) {
  1065. if ((t->BinAddress & HMAP_DISCARDABLE) != 0) {
  1066. //
  1067. // this was a free bin. It may not be a free bin on the disk
  1068. //
  1069. FreeBin = (PFREE_HBIN)t->BlockAddress;
  1070. // free bins comming from paged pool are always discardable
  1071. ASSERT( FreeBin->Flags & FREE_HBIN_DISCARDABLE );
  1072. // if the bin has been discarded since the last save, all bin should be dirty!!!
  1073. ASSERT(FreeBin->FileOffset == p);
  1074. //
  1075. // go and clear the discardable flag for all blocks of this bin
  1076. //
  1077. for( i=0;i<FreeBin->Size;i+=HBLOCK_SIZE) {
  1078. Me = HvpGetCellMap(Hive, p + i);
  1079. VALIDATE_CELL_MAP(__LINE__,Me,Hive,p+i);
  1080. Me->BlockAddress = HBIN_BASE(Me->BinAddress)+i;
  1081. Me->BinAddress &= ~HMAP_DISCARDABLE;
  1082. }
  1083. Bin = (PHBIN)HBIN_BASE(t->BlockAddress);
  1084. //
  1085. // get rid of the entry from FreeBins list
  1086. // it'll be added again after sync is done if bin is still
  1087. // discardable
  1088. //
  1089. RemoveEntryList(&FreeBin->ListEntry);
  1090. (Hive->Free)(FreeBin, sizeof(FREE_HBIN));
  1091. }
  1092. //
  1093. // only paged bins should be dirty at this time
  1094. //
  1095. ASSERT( t->BinAddress & HMAP_INPAGEDPOOL );
  1096. //
  1097. // The first sector in the HBIN is dirty.
  1098. //
  1099. // Reset the BinAddress to the Block address to cover
  1100. // the case where a few smaller bins have been coalesced
  1101. // into a larger bin. We want the smaller bins back now.
  1102. //
  1103. t->BinAddress = HBIN_FLAGS(t->BinAddress) | t->BlockAddress;
  1104. // Check the map to see if this is the start
  1105. // of a memory allocation or not.
  1106. //
  1107. if (t->BinAddress & HMAP_NEWALLOC) {
  1108. //
  1109. // Walk through the map to determine the length
  1110. // of the allocation.
  1111. //
  1112. PULONG BinAlloc = &(t->MemAlloc);
  1113. *BinAlloc = 0;
  1114. do {
  1115. t = HvpGetCellMap(Hive, p + (*BinAlloc) + HBLOCK_SIZE);
  1116. (*BinAlloc) += HBLOCK_SIZE;
  1117. if (p + (*BinAlloc) == Hive->Storage[Stable].Length) {
  1118. //
  1119. // Reached the end of the hive.
  1120. //
  1121. break;
  1122. }
  1123. VALIDATE_CELL_MAP(__LINE__,t,Hive,p + (*BinAlloc));
  1124. } while ( (t->BinAddress & HMAP_NEWALLOC) == 0);
  1125. //
  1126. // this will reenlist the bin if free
  1127. //
  1128. if ( ! HvpEnlistFreeCells(Hive, Bin, Bin->FileOffset)) {
  1129. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,6,Bin,Bin->FileOffset);
  1130. }
  1131. } else {
  1132. t->MemAlloc = 0;
  1133. }
  1134. RtlClearBits(&Hive->DirtyVector,Bin->FileOffset/HSECTOR_SIZE,Bin->Size/HSECTOR_SIZE);
  1135. p = Bin->FileOffset + Bin->Size;
  1136. } else {
  1137. //
  1138. // we do that to avoid touching bins that may not be mapped
  1139. //
  1140. p += HBLOCK_SIZE;
  1141. }
  1142. }
  1143. //
  1144. // be sure we haven't filled memory with trash
  1145. //
  1146. checkstatus = HvCheckHive(Hive, NULL);
  1147. if (checkstatus != 0) {
  1148. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,7,Hive,checkstatus);
  1149. }
  1150. //
  1151. // Finally we need to rewrite the parent field in the root hcell. This is
  1152. // patched in at hive load time so the correct value could have just been
  1153. // overwritten with whatever happened to be on disk.
  1154. //
  1155. RootNode = (PCM_KEY_NODE)HvGetCell(Hive, RootCell);
  1156. if( RootNode == NULL ) {
  1157. //
  1158. // we couldn't map a view for this cell
  1159. // there is nothing we can do here, other than pray for this not to happen
  1160. //
  1161. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,8,Hive,RootCell);
  1162. return;
  1163. }
  1164. // release the cell here as we are holding the reglock exclusive
  1165. HvReleaseCell(Hive,RootCell);
  1166. RootNode->Parent = LinkCell;
  1167. RootNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
  1168. //
  1169. // all bits in the dirty vector should be clean by now
  1170. //
  1171. ASSERT( RtlNumberOfSetBits( &(Hive->DirtyVector) ) == 0 );
  1172. Hive->DirtyCount = 0;
  1173. #ifdef CM_ENABLE_WRITE_ONLY_BINS
  1174. HvpMarkAllBinsWriteOnly(Hive);
  1175. #endif //CM_ENABLE_WRITE_ONLY_BINS
  1176. //
  1177. // Adjust the file size, if this fails, ignore it, since it just
  1178. // means the file is too big. Do it here, where we are sure we have
  1179. // no pinned data whatsoever.
  1180. //
  1181. (Hive->FileSetSize)(
  1182. Hive,
  1183. HFILE_TYPE_PRIMARY,
  1184. (Hive->BaseBlock->Length + HBLOCK_SIZE),
  1185. OldFileLength
  1186. );
  1187. //
  1188. // be sure there are no security cells thrown away in the cache
  1189. //
  1190. if( !CmpRebuildSecurityCache((PCMHIVE)Hive) ) {
  1191. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,9,Hive,0);
  1192. }
  1193. //
  1194. // be sure the structure of the thing is OK after all this
  1195. //
  1196. checkstatus = CmCheckRegistry((PCMHIVE)Hive, CM_CHECK_REGISTRY_FORCE_CLEAN);
  1197. if (checkstatus != 0) {
  1198. CM_BUGCHECK(REGISTRY_ERROR,REFRESH_HIVE,10,Hive,checkstatus);
  1199. }
  1200. return;
  1201. }
  1202. #ifdef WRITE_PROTECTED_REGISTRY_POOL
  1203. VOID
  1204. HvpChangeBinAllocation(
  1205. PHBIN Bin,
  1206. BOOLEAN ReadOnly
  1207. )
  1208. {
  1209. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  1210. //
  1211. // Here to call the code to mark the memory pointed by Bin as Read/Write or ReadOnly, depending on the ReadOnly argument
  1212. //
  1213. }
  1214. VOID
  1215. HvpMarkBinReadWrite(
  1216. PHHIVE Hive,
  1217. HCELL_INDEX Cell
  1218. )
  1219. /*++
  1220. Routine Description:
  1221. Marks the memory allocated for the bin containing the specified cell as read/write.
  1222. Arguments:
  1223. Hive - supplies a pointer to the hive control structure for the
  1224. hive of interest
  1225. Cell - hcell_index of cell
  1226. Return Value:
  1227. NONE (It should work!)
  1228. --*/
  1229. {
  1230. ULONG Type;
  1231. PHMAP_ENTRY Me;
  1232. PHBIN Bin;
  1233. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1234. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1235. Type = HvGetCellType(Cell);
  1236. if ( (Hive->HiveFlags & HIVE_VOLATILE) ||
  1237. (Type == Volatile) )
  1238. {
  1239. // nothing to do on a volatile hive
  1240. return;
  1241. }
  1242. Me = HvpGetCellMap(Hive, Cell);
  1243. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  1244. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  1245. HvpChangeBinAllocation(Bin,FALSE);
  1246. }
  1247. #endif //WRITE_PROTECTED_REGISTRY_POOL
  1248. #if DBG
  1249. BOOLEAN
  1250. HvIsCellDirty(
  1251. IN PHHIVE Hive,
  1252. IN HCELL_INDEX Cell
  1253. )
  1254. /*++
  1255. Routine Description:
  1256. Given a hive and a cell, checks whether the corresponding sector
  1257. is marked as dirty.
  1258. NOTE: This function assumes the view containing the bin is
  1259. mapped into system space.
  1260. Arguments:
  1261. Hive - Supplies a pointer to the hive control structure
  1262. Cell - Supplies the HCELL_INDEX of the Cell.
  1263. Return Value:
  1264. TRUE - Data is marked as dirty.
  1265. FALSE - Data is NOT marked as dirty.
  1266. --*/
  1267. {
  1268. ULONG Type;
  1269. PRTL_BITMAP Bitmap;
  1270. ULONG Offset;
  1271. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvIsCellDirty:\n\t"));
  1272. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Cell:%08lx\n", Hive, Cell));
  1273. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1274. ASSERT(Hive->ReadOnly == FALSE);
  1275. Type = HvGetCellType(Cell);
  1276. if ( (Hive->HiveFlags & HIVE_VOLATILE) ||
  1277. (Type == Volatile) )
  1278. {
  1279. //
  1280. // we don't care as we are never going to save this data
  1281. //
  1282. return TRUE;
  1283. }
  1284. Bitmap = &(Hive->DirtyVector);
  1285. Offset = Cell / HSECTOR_SIZE;
  1286. if (RtlCheckBit(Bitmap, Offset)==1) {
  1287. return(TRUE);
  1288. }
  1289. return FALSE;
  1290. }
  1291. #endif
  1292. /*
  1293. !!!not used anymore!!!
  1294. BOOLEAN
  1295. HvMarkClean(
  1296. PHHIVE Hive,
  1297. HCELL_INDEX Start,
  1298. ULONG Length
  1299. )
  1300. */
  1301. /*++
  1302. Routine Description:
  1303. Clears the dirty bits for a given portion of a hive. This is
  1304. the inverse of HvMarkDirty, although it does not give up any
  1305. file space in the primary or log that HvMarkDirty may have reserved.
  1306. This is a noop for Volatile address range.
  1307. Arguments:
  1308. Hive - supplies a pointer to the hive control structure for the
  1309. hive of interest
  1310. Start - supplies a hive virtual address (i.e., an HCELL_INDEX or
  1311. like form address) of the start of the area to mark dirty.
  1312. Length - inclusive length in bytes of area to mark dirty.
  1313. Return Value:
  1314. TRUE - it worked
  1315. --*/
  1316. /*
  1317. {
  1318. ULONG Type;
  1319. PRTL_BITMAP BitMap;
  1320. ULONG First;
  1321. ULONG Last;
  1322. ULONG i;
  1323. ULONG Cluster;
  1324. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvMarkClean:\n\t"));
  1325. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Start:%08lx Length:%08lx\n", Hive, Start, Length));
  1326. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1327. ASSERT(Hive->ReadOnly == FALSE);
  1328. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1329. Type = HvGetCellType(Start);
  1330. if ( (Hive->HiveFlags & HIVE_VOLATILE) ||
  1331. (Type == Volatile) )
  1332. {
  1333. return TRUE;
  1334. }
  1335. BitMap = &(Hive->DirtyVector);
  1336. First = Start / HSECTOR_SIZE;
  1337. Last = (Start + Length - 1) / HSECTOR_SIZE;
  1338. Cluster = Hive->Cluster;
  1339. if (Cluster > 1) {
  1340. //
  1341. // Force Start down to base of cluster
  1342. // Force End up to top of cluster
  1343. //
  1344. First = First & ~(Cluster - 1);
  1345. Last = ROUND_UP(Last+1, Cluster) - 1;
  1346. }
  1347. if (Last >= BitMap->SizeOfBitMap) {
  1348. Last = BitMap->SizeOfBitMap-1;
  1349. }
  1350. //
  1351. // Subtract out the dirty count and
  1352. // and clear the dirty bits.
  1353. //
  1354. for (i=First; i<=Last; i++) {
  1355. if (RtlCheckBit(BitMap,i)==1) {
  1356. --Hive->DirtyCount;
  1357. RtlClearBits(BitMap, i, 1);
  1358. }
  1359. }
  1360. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1361. return(TRUE);
  1362. }
  1363. */
  1364. BOOLEAN
  1365. HvpGrowLog2(
  1366. PHHIVE Hive,
  1367. ULONG Size
  1368. )
  1369. /*++
  1370. Routine Description:
  1371. Adjust the log for growth in the size of the hive, in particular,
  1372. account for the increased space needed for a bigger dirty vector.
  1373. Arguments:
  1374. Hive - supplies a pointer to the hive control structure for the
  1375. hive of interest
  1376. Size - proposed growth in size in bytes.
  1377. Return Value:
  1378. TRUE - it worked
  1379. FALSE - could not allocate log space, failure!
  1380. --*/
  1381. {
  1382. ULONG ClusterSize;
  1383. ULONG RequiredSize;
  1384. ULONG DirtyBytes;
  1385. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvpGrowLog2:\n\t"));
  1386. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Size:%08lx\n", Hive, Size));
  1387. ASSERT(Hive->ReadOnly == FALSE);
  1388. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1389. //
  1390. // If logging is off, tell caller world is OK.
  1391. //
  1392. if (Hive->Log == FALSE) {
  1393. return TRUE;
  1394. }
  1395. ASSERT( (Size % HSECTOR_SIZE) == 0 );
  1396. ClusterSize = Hive->Cluster * HSECTOR_SIZE;
  1397. ASSERT( (((Hive->Storage[Stable].Length + Size) / HSECTOR_SIZE) % 8) == 0);
  1398. DirtyBytes = (Hive->DirtyVector.SizeOfBitMap / 8) +
  1399. ((Size / HSECTOR_SIZE) / 8) +
  1400. sizeof(ULONG); // signature
  1401. DirtyBytes = ROUND_UP(DirtyBytes, ClusterSize);
  1402. RequiredSize =
  1403. ClusterSize + // 1 cluster for header
  1404. (Hive->DirtyCount * HSECTOR_SIZE) +
  1405. DirtyBytes;
  1406. RequiredSize = ROUND_UP(RequiredSize, HLOG_GROW);
  1407. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1408. if ( ! (Hive->FileSetSize)(Hive, HFILE_TYPE_LOG, RequiredSize,Hive->LogSize)) {
  1409. return FALSE;
  1410. }
  1411. if( CmRegistryLogSizeLimit > 0 ) {
  1412. //
  1413. // see if log is too big and set flush on lock release
  1414. //
  1415. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1416. if( RequiredSize >= (ULONG)(CmRegistryLogSizeLimit * ONE_K) ) {
  1417. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"LogFile for hive %p is %lx; will flush upon lock release\n",Hive,RequiredSize);
  1418. CmpFlushOnLockRelease = TRUE;;
  1419. }
  1420. }
  1421. Hive->LogSize = RequiredSize;
  1422. ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
  1423. return TRUE;
  1424. }
  1425. BOOLEAN
  1426. HvSyncHive(
  1427. PHHIVE Hive
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. Force backing store to match the memory image of the Stable
  1432. part of the hive's space.
  1433. Logs, primary, and alternate data can be written. Primary is
  1434. always written. Normally either a log or an alternate, but
  1435. not both, will also be written.
  1436. It is possible to write only the primary.
  1437. All dirty bits will be set clear.
  1438. Arguments:
  1439. Hive - supplies a pointer to the hive control structure for the
  1440. hive of interest
  1441. Return Value:
  1442. TRUE - it worked
  1443. FALSE - some failure.
  1444. --*/
  1445. {
  1446. BOOLEAN oldFlag;
  1447. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvSyncHive:\n\t"));
  1448. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p\n", Hive));
  1449. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1450. ASSERT(Hive->ReadOnly == FALSE);
  1451. //
  1452. // Punt if post shutdown
  1453. //
  1454. if (HvShutdownComplete) {
  1455. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"HvSyncHive: Attempt to sync AFTER SHUTDOWN\n"));
  1456. return FALSE;
  1457. }
  1458. //
  1459. // If nothing dirty, do nothing
  1460. //
  1461. if (Hive->DirtyCount == 0) {
  1462. return TRUE;
  1463. }
  1464. //
  1465. // Discard the write(s) to system hives if needed
  1466. //
  1467. if (CmpMiniNTBoot) {
  1468. ULONG Index;
  1469. PCMHIVE CurrentHive = (PCMHIVE)Hive;
  1470. BOOLEAN SkipWrite = FALSE;
  1471. for (Index = 0; Index < CM_NUMBER_OF_MACHINE_HIVES; Index++) {
  1472. if ((CmpMachineHiveList[Index].Name != NULL) &&
  1473. ((CmpMachineHiveList[Index].CmHive == CurrentHive) ||
  1474. (CmpMachineHiveList[Index].CmHive2 == CurrentHive))) {
  1475. SkipWrite = TRUE;
  1476. break;
  1477. }
  1478. }
  1479. if (SkipWrite) {
  1480. return TRUE;
  1481. }
  1482. }
  1483. HvpTruncateBins(Hive);
  1484. //
  1485. // If hive is volatile, do nothing
  1486. //
  1487. if (Hive->HiveFlags & HIVE_VOLATILE) {
  1488. return TRUE;
  1489. }
  1490. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"\tDirtyCount:%08lx\n", Hive->DirtyCount));
  1491. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"\tDirtyVector:"));
  1492. //DumpDirtyVector(&(Hive->DirtyVector));
  1493. //
  1494. // disable hard error popups, to avoid self deadlock on bogus devices
  1495. //
  1496. oldFlag = IoSetThreadHardErrorMode(FALSE);
  1497. //
  1498. // Write a log.
  1499. //
  1500. if (Hive->Log == TRUE) {
  1501. if (HvpWriteLog(Hive) == FALSE) {
  1502. IoSetThreadHardErrorMode(oldFlag);
  1503. return FALSE;
  1504. }
  1505. }
  1506. //
  1507. // Write the primary
  1508. //
  1509. if (HvpDoWriteHive(Hive, HFILE_TYPE_PRIMARY) == FALSE) {
  1510. IoSetThreadHardErrorMode(oldFlag);
  1511. return FALSE;
  1512. }
  1513. //
  1514. // restore hard error popups mode
  1515. //
  1516. IoSetThreadHardErrorMode(oldFlag);
  1517. //
  1518. // Hive was successfully written out, discard any bins marked as
  1519. // discardable.
  1520. //
  1521. // We don't need this anymore as the bins are not using paged pool
  1522. //HvpDiscardBins(Hive);
  1523. //
  1524. // Free bins allocated from page-pool at the end of the hive.
  1525. // These bins were allocated as a temporary till the hive would be saved
  1526. //
  1527. HvpDropPagedBins(Hive
  1528. #if DBG
  1529. , TRUE
  1530. #endif
  1531. );
  1532. //
  1533. // Clear the dirty map
  1534. //
  1535. RtlClearAllBits(&(Hive->DirtyVector));
  1536. Hive->DirtyCount = 0;
  1537. #ifdef CM_ENABLE_WRITE_ONLY_BINS
  1538. HvpMarkAllBinsWriteOnly(Hive);
  1539. #endif CM_ENABLE_WRITE_ONLY_BINS
  1540. return TRUE;
  1541. }
  1542. //
  1543. // Code for syncing a hive to backing store
  1544. //
  1545. VOID
  1546. HvpFlushMappedData(
  1547. IN PHHIVE Hive,
  1548. IN OUT PRTL_BITMAP DirtyVector
  1549. )
  1550. /*++
  1551. Routine Description:
  1552. This functions will flush all pinned views for the specified hive.
  1553. It will clean the bits in the DirtyVector for the blocks that are
  1554. flushed.
  1555. Additionally, it sets the timestamp on the first bin.
  1556. It iterates through the pinned view list, and unpin all of them.
  1557. Arguments:
  1558. Hive - pointer to Hive for which dirty data is to be written.
  1559. DirtyVector - copy of the DirtyVector for the hive
  1560. Return Value:
  1561. TRUE - it worked
  1562. FALSE - it failed
  1563. --*/
  1564. {
  1565. PCMHIVE CmHive;
  1566. ULONG FileOffsetStart;
  1567. ULONG FileOffsetEnd;
  1568. PCM_VIEW_OF_FILE CmView;
  1569. PHMAP_ENTRY Me;
  1570. PHBIN Bin;
  1571. PFREE_HBIN FreeBin;
  1572. PAGED_CODE();
  1573. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"[HvpFlushMappedData] (Entry) DirtyVector:"));
  1574. //DumpDirtyVector(DirtyVector);
  1575. CmHive = (PCMHIVE)Hive;
  1576. //
  1577. // for each pinned view
  1578. //
  1579. while(IsListEmpty(&(CmHive->PinViewListHead)) == FALSE) {
  1580. //
  1581. // Remove the first view from the pin view list
  1582. //
  1583. CmView = (PCM_VIEW_OF_FILE)RemoveHeadList(&(CmHive->PinViewListHead));
  1584. CmView = CONTAINING_RECORD( CmView,
  1585. CM_VIEW_OF_FILE,
  1586. PinViewList);
  1587. //
  1588. // the real file offset starts after the header
  1589. //
  1590. FileOffsetStart = CmView->FileOffset;
  1591. FileOffsetEnd = FileOffsetStart + CmView->Size;
  1592. FileOffsetEnd -= HBLOCK_SIZE;
  1593. if( FileOffsetStart != 0 ) {
  1594. //
  1595. // just at the begining of the file, subtract the header
  1596. //
  1597. FileOffsetStart -= HBLOCK_SIZE;
  1598. }
  1599. if( (FileOffsetEnd / HSECTOR_SIZE) > DirtyVector->SizeOfBitMap ) {
  1600. //
  1601. // Cc has mapped more than its valid
  1602. //
  1603. ASSERT( (FileOffsetEnd % HSECTOR_SIZE) == 0 );
  1604. FileOffsetEnd = DirtyVector->SizeOfBitMap * HSECTOR_SIZE;
  1605. }
  1606. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"[HvpFlushMappedData] CmView %p mapping from %lx to %lx\n",CmView,FileOffsetStart,FileOffsetEnd));
  1607. //
  1608. // now, for every block in this range which is mapped in view
  1609. // clear the dirty bit
  1610. //
  1611. while(FileOffsetStart < FileOffsetEnd) {
  1612. if( FileOffsetStart >= Hive->Storage[Stable].Length ) {
  1613. //
  1614. // This mean the hive has shrunk during the HvpTruncateBins call
  1615. // all we have to do is clear the dirty bits and bail out
  1616. //
  1617. RtlClearBits(DirtyVector,FileOffsetStart/HSECTOR_SIZE,(FileOffsetEnd - FileOffsetStart)/HSECTOR_SIZE);
  1618. break;
  1619. }
  1620. Me = HvpGetCellMap(Hive, FileOffsetStart);
  1621. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileOffsetStart);
  1622. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  1623. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  1624. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  1625. //
  1626. // update the file offset
  1627. //
  1628. FileOffsetStart = FreeBin->FileOffset + FreeBin->Size;
  1629. //
  1630. // bin is discardable, or discarded; still, if it was mapped,
  1631. // clear of the dirty bits
  1632. //
  1633. if( Me->BinAddress & HMAP_INVIEW ) {
  1634. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"[HvpFlushMappedData] Clearing DISCARDABLE %lu Bits starting at %lu\n",
  1635. FreeBin->Size/HSECTOR_SIZE,FreeBin->FileOffset/HSECTOR_SIZE));
  1636. RtlClearBits(DirtyVector,FreeBin->FileOffset/HSECTOR_SIZE,FreeBin->Size/HSECTOR_SIZE);
  1637. }
  1638. } else {
  1639. if( Me->BinAddress & HMAP_INVIEW ) {
  1640. //
  1641. // bin is mapped in view. Then, this should be the beggining of the bin
  1642. //
  1643. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  1644. ASSERT(Bin->FileOffset == FileOffsetStart);
  1645. //
  1646. // clear the dirty bits for this bin as dirty blocks will
  1647. // be saved while unpinning the view
  1648. //
  1649. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"[HvpFlushMappedData] Clearing %lu Bits starting at %lu\n",
  1650. Bin->Size/HSECTOR_SIZE,Bin->FileOffset/HSECTOR_SIZE));
  1651. RtlClearBits(DirtyVector,Bin->FileOffset/HSECTOR_SIZE,Bin->Size/HSECTOR_SIZE);
  1652. FileOffsetStart += Bin->Size;
  1653. } else {
  1654. //
  1655. // bin is in paged pool. This should be the begining too
  1656. //
  1657. //
  1658. // we could fall into cross boundary problem here; advance carrefully
  1659. // (two day spent on this problem !!!)
  1660. //
  1661. ASSERT(Bin->Signature == HBIN_SIGNATURE);
  1662. FileOffsetStart += HBLOCK_SIZE;
  1663. }
  1664. }
  1665. }// while (FileOffsetStart<FileOffsetEnd)
  1666. //
  1667. // UnPin the view; this will flush all dirty blocks to the backing storage
  1668. //
  1669. CmpUnPinCmView (CmHive,CmView,FALSE,TRUE);
  1670. } // while (IsListEmpty)
  1671. }
  1672. //#define TEST_LOG_SUPPORT
  1673. #ifdef TEST_LOG_SUPPORT
  1674. ULONG CmpFailPrimarySave = 0;
  1675. #endif //TEST_LOG_SUPPORT
  1676. BOOLEAN
  1677. HvpDoWriteHive(
  1678. PHHIVE Hive,
  1679. ULONG FileType
  1680. )
  1681. /*++
  1682. Routine Description:
  1683. Write dirty parts of the hive out to either its primary or alternate
  1684. file. Write the header, flush, write all data, flush, update header,
  1685. flush. Assume either logging or primary/alternate pairs used.
  1686. NOTE: TimeStamp is not set, assumption is that HvpWriteLog set
  1687. that. It is only used for checking if Logs correspond anyway.
  1688. Arguments:
  1689. Hive - pointer to Hive for which dirty data is to be written.
  1690. FileType - indicated whether primary or alternate file should be written.
  1691. Return Value:
  1692. TRUE - it worked
  1693. FALSE - it failed
  1694. --*/
  1695. {
  1696. PHBASE_BLOCK BaseBlock;
  1697. ULONG Offset;
  1698. PUCHAR Address;
  1699. ULONG Length;
  1700. BOOLEAN rc;
  1701. ULONG Current;
  1702. PRTL_BITMAP BitMap;
  1703. PHMAP_ENTRY Me;
  1704. PHBIN Bin;
  1705. BOOLEAN ShrinkHive;
  1706. PCMP_OFFSET_ARRAY offsetArray;
  1707. CMP_OFFSET_ARRAY offsetElement;
  1708. ULONG Count;
  1709. ULONG SetBitCount;
  1710. PULONG CopyDirtyVector;
  1711. ULONG CopyDirtyVectorSize;
  1712. RTL_BITMAP CopyBitMap;
  1713. LARGE_INTEGER FileOffset;
  1714. ULONG OldFileSize;
  1715. BOOLEAN GrowHive = FALSE;
  1716. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvpDoWriteHive:\n\t"));
  1717. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p FileType:%08lx\n", Hive, FileType));
  1718. if (Hive->DirtyCount == 0) {
  1719. return TRUE;
  1720. }
  1721. FileOffset.HighPart = FileOffset.LowPart =0;
  1722. //
  1723. // flush first, so that the filesystem structures get written to
  1724. // disk if we have grown the file.
  1725. //
  1726. if ( (((PCMHIVE)Hive)->FileHandles[HFILE_TYPE_PRIMARY] == NULL) ||
  1727. !(Hive->FileFlush)(Hive, FileType,NULL,Hive->Storage[Stable].Length+HBLOCK_SIZE) ) {
  1728. #ifndef _CM_LDR_
  1729. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[1]: Failed to flush hive %p\n", Hive);
  1730. #endif //_CM_LDR_
  1731. return(FALSE);
  1732. }
  1733. #ifdef TEST_LOG_SUPPORT
  1734. if(CmpFailPrimarySave == 1) {
  1735. return FALSE;
  1736. }
  1737. #endif //TEST_LOG_SUPPORT
  1738. BaseBlock = Hive->BaseBlock;
  1739. //
  1740. // we should never come to this
  1741. //
  1742. ASSERT( Hive->Storage[Stable].Length != 0 );
  1743. ASSERT( Hive->BaseBlock->RootCell != HCELL_NIL );
  1744. OldFileSize = BaseBlock->Length;
  1745. if (BaseBlock->Length > Hive->Storage[Stable].Length) {
  1746. ShrinkHive = TRUE;
  1747. } else {
  1748. ShrinkHive = FALSE;
  1749. if( BaseBlock->Length < Hive->Storage[Stable].Length ) {
  1750. GrowHive = TRUE;
  1751. }
  1752. }
  1753. //
  1754. // --- Write out header first time, flush ---
  1755. //
  1756. ASSERT(BaseBlock->Signature == HBASE_BLOCK_SIGNATURE);
  1757. ASSERT(BaseBlock->Major == HSYS_MAJOR);
  1758. ASSERT(BaseBlock->Format == HBASE_FORMAT_MEMORY);
  1759. ASSERT(Hive->ReadOnly == FALSE);
  1760. if (BaseBlock->Sequence1 != BaseBlock->Sequence2) {
  1761. //
  1762. // Some previous log attempt failed, or this hive needs to
  1763. // be recovered, so punt.
  1764. //
  1765. #ifndef _CM_LDR_
  1766. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[2,%s]: Invalid sequence number for hive%p\n", "Primary",Hive);
  1767. #endif //_CM_LDR_
  1768. return FALSE;
  1769. }
  1770. BaseBlock->Length = Hive->Storage[Stable].Length;
  1771. BaseBlock->Sequence1++;
  1772. BaseBlock->Type = HFILE_TYPE_PRIMARY;
  1773. BaseBlock->Cluster = Hive->Cluster;
  1774. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  1775. Offset = 0;
  1776. offsetElement.FileOffset = Offset;
  1777. offsetElement.DataBuffer = (PVOID) BaseBlock;
  1778. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  1779. if( HiveWritesThroughCache(Hive,FileType) == TRUE ) {
  1780. //
  1781. // if we use Cc, do the write with the pin interface
  1782. //
  1783. rc = CmpFileWriteThroughCache( Hive,
  1784. FileType,
  1785. &offsetElement,
  1786. 1);
  1787. } else {
  1788. rc = (Hive->FileWrite)(
  1789. Hive,
  1790. FileType,
  1791. &offsetElement,
  1792. 1,
  1793. &Offset
  1794. );
  1795. }
  1796. if (rc == FALSE) {
  1797. #ifndef _CM_LDR_
  1798. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[3,%s]: Failed to write header for hive%p\n", "Primary",Hive);
  1799. #endif //_CM_LDR_
  1800. return FALSE;
  1801. }
  1802. if ( ! (Hive->FileFlush)(Hive, FileType,&FileOffset,offsetElement.DataLength)) {
  1803. #ifndef _CM_LDR_
  1804. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[4,%s]: Failed to flush header for hive%p\n", "Primary",Hive);
  1805. #endif //_CM_LDR_
  1806. return FALSE;
  1807. }
  1808. Offset = ROUND_UP(Offset, HBLOCK_SIZE);
  1809. #ifdef TEST_LOG_SUPPORT
  1810. if(CmpFailPrimarySave == 2) {
  1811. return FALSE;
  1812. }
  1813. #endif //TEST_LOG_SUPPORT
  1814. //
  1815. // --- Write out dirty data (only if there is any) ---
  1816. //
  1817. if (Hive->DirtyVector.Buffer != NULL) {
  1818. //
  1819. // First sector of first bin will always be dirty, write it out
  1820. // with the TimeStamp value overlaid on its Link field.
  1821. //
  1822. BitMap = &(Hive->DirtyVector);
  1823. //
  1824. // make a copy of the dirty vector; we don't want to alter the
  1825. // original dirty vector in case things go wrong
  1826. //
  1827. CopyDirtyVectorSize = BitMap->SizeOfBitMap / 8;
  1828. CopyDirtyVector = (Hive->Allocate)(ROUND_UP(CopyDirtyVectorSize,sizeof(ULONG)), FALSE,CM_FIND_LEAK_TAG38);
  1829. if (CopyDirtyVector == NULL) {
  1830. #ifndef _CM_LDR_
  1831. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[5,%s]: Failed to allocate CopyDirtyVectorfor hive%p\n", "Primary",Hive);
  1832. #endif //_CM_LDR_
  1833. return FALSE;
  1834. }
  1835. RtlCopyMemory(CopyDirtyVector,BitMap->Buffer,CopyDirtyVectorSize);
  1836. RtlInitializeBitMap (&CopyBitMap,CopyDirtyVector,BitMap->SizeOfBitMap);
  1837. ASSERT(RtlCheckBit(BitMap, 0) == 1);
  1838. ASSERT(RtlCheckBit(BitMap, (Hive->Cluster - 1)) == 1);
  1839. ASSERT(sizeof(LIST_ENTRY) >= sizeof(LARGE_INTEGER));
  1840. Me = HvpGetCellMap(Hive, 0);
  1841. VALIDATE_CELL_MAP(__LINE__,Me,Hive,0);
  1842. if( (Me->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0 ) {
  1843. //
  1844. // first view is not mapped
  1845. //
  1846. //
  1847. // fatal error: Dirty Data is not pinned !!!!
  1848. //
  1849. CM_BUGCHECK(REGISTRY_ERROR,FATAL_MAPPING_ERROR,3,0,Me);
  1850. }
  1851. Address = (PUCHAR)Me->BlockAddress;
  1852. Bin = (PHBIN)Address;
  1853. Bin->TimeStamp = BaseBlock->TimeStamp;
  1854. //
  1855. // flush first the mapped data
  1856. //
  1857. try {
  1858. HvpFlushMappedData(Hive,&CopyBitMap);
  1859. } except (EXCEPTION_EXECUTE_HANDLER) {
  1860. //
  1861. // in-page exception while flushing the mapped data; this is due to the map_no_read scheme.
  1862. //
  1863. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive : HvpFlushMappedData has raised :%08lx\n",GetExceptionCode()));
  1864. return FALSE;
  1865. }
  1866. #ifdef TEST_LOG_SUPPORT
  1867. if(CmpFailPrimarySave == 3) {
  1868. return FALSE;
  1869. }
  1870. #endif //TEST_LOG_SUPPORT
  1871. //
  1872. // Write out the rest of the dirty data
  1873. //
  1874. Current = 0;
  1875. SetBitCount = RtlNumberOfSetBits(&CopyBitMap);
  1876. if( SetBitCount > 0 ) {
  1877. //
  1878. // we still have some dirty data
  1879. // this must reside in paged-pool bins
  1880. // save it in the old-fashioned way (non-cached)
  1881. //
  1882. offsetArray =(PCMP_OFFSET_ARRAY)ExAllocatePool(PagedPool,sizeof(CMP_OFFSET_ARRAY) * SetBitCount);
  1883. if (offsetArray == NULL) {
  1884. CmpFree(CopyDirtyVector, ROUND_UP(CopyDirtyVectorSize,sizeof(ULONG)));
  1885. #ifndef _CM_LDR_
  1886. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[8,%s]: Failed to allocate offsetArray for hive%p\n", "Primary",Hive);
  1887. #endif //_CM_LDR_
  1888. return FALSE;
  1889. }
  1890. Count = 0;
  1891. while (HvpFindNextDirtyBlock(
  1892. Hive,
  1893. &CopyBitMap,
  1894. &Current,
  1895. &Address,
  1896. &Length,
  1897. &Offset
  1898. ) == TRUE)
  1899. {
  1900. // Gather data into array.
  1901. ASSERT(Count < SetBitCount);
  1902. offsetArray[Count].FileOffset = Offset;
  1903. offsetArray[Count].DataBuffer = Address;
  1904. offsetArray[Count].DataLength = Length;
  1905. Offset += Length;
  1906. ASSERT((Offset % (Hive->Cluster * HSECTOR_SIZE)) == 0);
  1907. Count++;
  1908. }
  1909. if( HiveWritesThroughCache(Hive,FileType) == TRUE ) {
  1910. //
  1911. // if we use Cc, do the write with the pin interface
  1912. //
  1913. rc = CmpFileWriteThroughCache( Hive,
  1914. FileType,
  1915. offsetArray,
  1916. Count);
  1917. } else {
  1918. //
  1919. // for primary file, issue all IOs at the same time.
  1920. //
  1921. rc = (Hive->FileWrite)(
  1922. Hive,
  1923. FileType,
  1924. offsetArray,
  1925. Count,
  1926. &Offset // Just an OUT parameter which returns the point
  1927. // in the file after the last write.
  1928. );
  1929. }
  1930. #ifdef SYNC_HIVE_VALIDATION
  1931. if( rc == TRUE ) {
  1932. ULONG i;
  1933. for ( i = Current; i < CopyBitMap.SizeOfBitMap; i++) {
  1934. if(RtlCheckBit(&CopyBitMap, i) == 1) {
  1935. //
  1936. // cause of zero-at the end corruption
  1937. //
  1938. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\n\n HARD CODED BREAKPOINT IN REGISTRY !!! \n");
  1939. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive - Zero-at-the-end code bug in HvpFindNextDirtyBlock\n");
  1940. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Dirty data at the end residing in paged pool is not saved to the hive\n");
  1941. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Hive: %p :: Bitmap = [%p] CopyBitMap = [%p]\n",Hive,BitMap,&CopyBitMap);
  1942. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpFindNextDirtyBlock reported Current = %lu, i = %lx, bitmap size = %lx\n",Current,i,CopyBitMap.SizeOfBitMap);
  1943. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\nThanks for hitting this! Please send remote to dragoss\n\n");
  1944. DbgBreakPoint();
  1945. break;
  1946. }
  1947. }
  1948. }
  1949. #endif //SYNC_HIVE_VALIDATION
  1950. ExFreePool(offsetArray);
  1951. if (rc == FALSE) {
  1952. CmpFree(CopyDirtyVector, ROUND_UP(CopyDirtyVectorSize,sizeof(ULONG)));
  1953. #ifndef _CM_LDR_
  1954. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[10,%s]: Failed to write dirty run for hive%p\n", "Primary",Hive);
  1955. #endif //_CM_LDR_
  1956. return FALSE;
  1957. }
  1958. }
  1959. //
  1960. // first bin header must be saved !
  1961. //
  1962. ASSERT(RtlCheckBit(BitMap, 0) == 1);
  1963. ASSERT(RtlCheckBit(BitMap, (Hive->Cluster - 1)) == 1);
  1964. CmpFree(CopyDirtyVector, ROUND_UP(CopyDirtyVectorSize,sizeof(ULONG)));
  1965. }
  1966. #ifdef TEST_LOG_SUPPORT
  1967. if(CmpFailPrimarySave == 4) {
  1968. return FALSE;
  1969. }
  1970. #endif //TEST_LOG_SUPPORT
  1971. if ( ! (Hive->FileFlush)(Hive, FileType,NULL,Hive->Storage[Stable].Length+HBLOCK_SIZE)) {
  1972. #ifndef _CM_LDR_
  1973. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[11,%s]: Failed to flush hive%p\n", "Primary",Hive);
  1974. #endif //_CM_LDR_
  1975. return FALSE;
  1976. }
  1977. #ifdef TEST_LOG_SUPPORT
  1978. if(CmpFailPrimarySave == 5) {
  1979. return FALSE;
  1980. }
  1981. #endif //TEST_LOG_SUPPORT
  1982. if ( GrowHive && HiveWritesThroughCache(Hive,FileType) ) {
  1983. IO_STATUS_BLOCK IoStatus;
  1984. if(!NT_SUCCESS(ZwFlushBuffersFile(((PCMHIVE)Hive)->FileHandles[FileType],&IoStatus))) {
  1985. #ifndef _CM_LDR_
  1986. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[12,%s]: CcSetValidDataFailed for hive %p\n", Hive, "Primary");
  1987. #endif //_CM_LDR_
  1988. return FALSE;
  1989. }
  1990. /*
  1991. // thsi was supposed to be the elegant way to do it.
  1992. //
  1993. // We need to set the size of the file; Tell FS to update it!!!
  1994. //
  1995. FileOffset.LowPart = Hive->Storage[Stable].Length + HBLOCK_SIZE;
  1996. if(!NT_SUCCESS(CcSetValidData(((PCMHIVE)Hive)->FileObject,&FileOffset)) ) {
  1997. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[12,%s]: CcSetValidDataFailed for hive %p\n", Hive, "Primary");
  1998. }
  1999. */
  2000. }
  2001. #ifdef TEST_LOG_SUPPORT
  2002. if(CmpFailPrimarySave == 6) {
  2003. return FALSE;
  2004. }
  2005. #endif //TEST_LOG_SUPPORT
  2006. //
  2007. // --- Write header again to report completion ---
  2008. //
  2009. BaseBlock->Sequence2++;
  2010. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  2011. Offset = 0;
  2012. offsetElement.FileOffset = Offset;
  2013. offsetElement.DataBuffer = (PVOID) BaseBlock;
  2014. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  2015. if( HiveWritesThroughCache(Hive,FileType) == TRUE ) {
  2016. //
  2017. // if we use Cc, do the write with the pin interface
  2018. //
  2019. rc = CmpFileWriteThroughCache( Hive,
  2020. FileType,
  2021. &offsetElement,
  2022. 1);
  2023. } else {
  2024. rc = (Hive->FileWrite)(
  2025. Hive,
  2026. FileType,
  2027. &offsetElement,
  2028. 1,
  2029. &Offset
  2030. );
  2031. }
  2032. if (rc == FALSE) {
  2033. #ifndef _CM_LDR_
  2034. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[13,%s]: Failed to write header for hive%p\n","Primary",Hive);
  2035. #endif //_CM_LDR_
  2036. return FALSE;
  2037. }
  2038. if (ShrinkHive) {
  2039. //
  2040. // Hive has shrunk, give up the excess space.
  2041. //
  2042. CmpDoFileSetSize(Hive, FileType, Hive->Storage[Stable].Length + HBLOCK_SIZE,OldFileSize + HBLOCK_SIZE);
  2043. }
  2044. #ifdef TEST_LOG_SUPPORT
  2045. if(CmpFailPrimarySave == 7) {
  2046. return FALSE;
  2047. }
  2048. #endif //TEST_LOG_SUPPORT
  2049. //
  2050. // make sure data hits the disk.
  2051. //
  2052. if ( ! (Hive->FileFlush)(Hive, FileType,&FileOffset,offsetElement.DataLength)) {
  2053. #ifndef _CM_LDR_
  2054. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpDoWriteHive[14,%s]: Failed to flush hive%p\n", "Primary",Hive);
  2055. #endif //_CM_LDR_
  2056. return FALSE;
  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. #if !defined(_WIN64)
  2240. ASSERT( (Offset % ClusterSize) == 0 );
  2241. #endif
  2242. //
  2243. // --- Write out body of log ---
  2244. //
  2245. SetBitCount = RtlNumberOfSetBits(BitMap);
  2246. offsetArray =
  2247. (PCMP_OFFSET_ARRAY)
  2248. ExAllocatePool(PagedPool,
  2249. sizeof(CMP_OFFSET_ARRAY) * SetBitCount);
  2250. if (offsetArray == NULL) {
  2251. return FALSE;
  2252. }
  2253. Count = 0;
  2254. Current = 0;
  2255. while (HvpFindNextDirtyBlock(
  2256. Hive,
  2257. BitMap,
  2258. &Current,
  2259. &Address,
  2260. &Length,
  2261. &junk
  2262. ) == TRUE)
  2263. {
  2264. // Gather data into array.
  2265. ASSERT(Count < SetBitCount);
  2266. offsetArray[Count].FileOffset = Offset;
  2267. offsetArray[Count].DataBuffer = Address;
  2268. offsetArray[Count].DataLength = Length;
  2269. Offset += Length;
  2270. Count++;
  2271. ASSERT((Offset % ClusterSize) == 0);
  2272. }
  2273. rc = (Hive->FileWrite)(
  2274. Hive,
  2275. HFILE_TYPE_LOG,
  2276. offsetArray,
  2277. Count,
  2278. &Offset // Just an OUT parameter which returns the point
  2279. // in the file after the last write.
  2280. );
  2281. ExFreePool(offsetArray);
  2282. if (rc == FALSE) {
  2283. return FALSE;
  2284. }
  2285. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_LOG,NULL,0)) {
  2286. return FALSE;
  2287. }
  2288. //
  2289. // --- Write header again to report completion ---
  2290. //
  2291. //
  2292. // -- we need to save the new length, in case the hive was grown.
  2293. //
  2294. Length = BaseBlock->Length;
  2295. if( Length < Hive->Storage[Stable].Length ) {
  2296. BaseBlock->Length = Hive->Storage[Stable].Length;
  2297. }
  2298. BaseBlock->Sequence2++;
  2299. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  2300. Offset = 0;
  2301. offsetElement.FileOffset = Offset;
  2302. offsetElement.DataBuffer = (PVOID) BaseBlock;
  2303. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  2304. rc = (Hive->FileWrite)(
  2305. Hive,
  2306. HFILE_TYPE_LOG,
  2307. &offsetElement,
  2308. 1,
  2309. &Offset
  2310. );
  2311. //
  2312. // restore the original length
  2313. //
  2314. BaseBlock->Length = Length;
  2315. if (rc == FALSE) {
  2316. return FALSE;
  2317. }
  2318. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_LOG,NULL,0)) {
  2319. return FALSE;
  2320. }
  2321. return TRUE;
  2322. }
  2323. BOOLEAN
  2324. HvpFindNextDirtyBlock(
  2325. PHHIVE Hive,
  2326. PRTL_BITMAP BitMap,
  2327. PULONG Current,
  2328. PUCHAR *Address,
  2329. PULONG Length,
  2330. PULONG Offset
  2331. )
  2332. /*++
  2333. Routine Description:
  2334. This routine finds and reports the largest run of dirty logical
  2335. sectors in the hive, which are contiguous in memory and on disk.
  2336. Arguments:
  2337. Hive - pointer to Hive of interest.
  2338. BitMap - supplies a pointer to a bitmap structure, which
  2339. describes what is dirty.
  2340. Current - supplies a pointer to a varible that tracks position
  2341. in the bitmap. It is a bitnumber. It is updated by
  2342. this call.
  2343. Address - supplies a pointer to a variable to receive a pointer
  2344. to the area in memory to be written out.
  2345. Length - supplies a pointer to a variable to receive the length
  2346. of the region to read/write
  2347. Offset - supplies a pointer to a variable to receive the offset
  2348. in the backing file to which the data should be written.
  2349. (not valid for log files)
  2350. Return Value:
  2351. TRUE - more to write, ret values good
  2352. FALSE - all data has been written
  2353. --*/
  2354. {
  2355. ULONG i;
  2356. ULONG EndOfBitMap;
  2357. ULONG Start;
  2358. ULONG End;
  2359. HCELL_INDEX FileBaseAddress;
  2360. HCELL_INDEX FileEndAddress;
  2361. PHMAP_ENTRY Me;
  2362. PUCHAR Block;
  2363. PUCHAR StartBlock;
  2364. PUCHAR NextBlock;
  2365. ULONG RunSpan;
  2366. ULONG RunLength;
  2367. ULONG FileLength;
  2368. PFREE_HBIN FreeBin;
  2369. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvpFindNextDirtyBlock:\n\t"));
  2370. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"Hive:%p Current:%08lx\n", Hive, *Current));
  2371. EndOfBitMap = BitMap->SizeOfBitMap;
  2372. if (*Current >= EndOfBitMap) {
  2373. return FALSE;
  2374. }
  2375. //
  2376. // Find next run of set bits
  2377. //
  2378. for (i = *Current; i < EndOfBitMap; i++) {
  2379. if (RtlCheckBit(BitMap, i) == 1) {
  2380. break;
  2381. }
  2382. }
  2383. Start = i;
  2384. for ( ; i < EndOfBitMap; i++) {
  2385. if (RtlCheckBit(BitMap, i) == 0) {
  2386. break;
  2387. }
  2388. if( HvpCheckViewBoundary(Start*HSECTOR_SIZE,i*HSECTOR_SIZE) == FALSE ) {
  2389. break;
  2390. }
  2391. }
  2392. End = i;
  2393. //
  2394. // Compute hive virtual addresses, beginning file address, memory address
  2395. //
  2396. FileBaseAddress = Start * HSECTOR_SIZE;
  2397. FileEndAddress = End * HSECTOR_SIZE;
  2398. FileLength = FileEndAddress - FileBaseAddress;
  2399. if (FileLength == 0) {
  2400. *Address = NULL;
  2401. *Current = 0xffffffff;
  2402. *Length = 0;
  2403. return FALSE;
  2404. }
  2405. Me = HvpGetCellMap(Hive, FileBaseAddress);
  2406. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileBaseAddress);
  2407. if( (Me->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0 ) {
  2408. //
  2409. // this is really bad, bugcheck!!!
  2410. //
  2411. #ifndef _CM_LDR_
  2412. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"FileAddress = %lx, Map = %lx",FileBaseAddress,Me);
  2413. #endif //_CM_LDR_
  2414. CM_BUGCHECK(REGISTRY_ERROR,FATAL_MAPPING_ERROR,1,FileBaseAddress,Me);
  2415. }
  2416. ASSERT_BIN_VALID(Me);
  2417. if (Me->BinAddress & HMAP_DISCARDABLE) {
  2418. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  2419. StartBlock = (PUCHAR)(HBIN_BASE(Me->BinAddress) + FileBaseAddress - FreeBin->FileOffset );
  2420. } else {
  2421. StartBlock = (PUCHAR)Me->BlockAddress;
  2422. }
  2423. Block = StartBlock;
  2424. ASSERT(((PHBIN)HBIN_BASE(Me->BinAddress))->Signature == HBIN_SIGNATURE);
  2425. *Address = Block + (FileBaseAddress & HCELL_OFFSET_MASK);
  2426. *Offset = FileBaseAddress + HBLOCK_SIZE;
  2427. //
  2428. // Build up length. First, account for sectors in first block.
  2429. //
  2430. RunSpan = HSECTOR_COUNT - (Start % HSECTOR_COUNT);
  2431. if ((End - Start) <= RunSpan) {
  2432. //
  2433. // Entire length is in first block, return it
  2434. //
  2435. *Length = FileLength;
  2436. *Current = End;
  2437. return TRUE;
  2438. } else {
  2439. RunLength = RunSpan * HSECTOR_SIZE;
  2440. FileBaseAddress = ROUND_UP(FileBaseAddress+1, HBLOCK_SIZE);
  2441. }
  2442. //
  2443. // Scan forward through blocks, filling up length as we go.
  2444. //
  2445. // NOTE: This loop grows forward 1 block at time. If we were
  2446. // really clever we'd fill forward a bin at time, since
  2447. // bins are always contiguous. But most bins will be
  2448. // one block long anyway, so we won't bother for now.
  2449. //
  2450. while (RunLength < FileLength) {
  2451. Me = HvpGetCellMap(Hive, FileBaseAddress);
  2452. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FileBaseAddress);
  2453. if( (Me->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0 ) {
  2454. //
  2455. // this is really bad, bugcheck!!!
  2456. //
  2457. #ifndef _CM_LDR_
  2458. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"FileAddress = %lx, Map = %lx",FileBaseAddress,Me);
  2459. #endif //_CM_LDR_
  2460. CM_BUGCHECK(REGISTRY_ERROR,FATAL_MAPPING_ERROR,2,FileBaseAddress,Me);
  2461. }
  2462. ASSERT(((PHBIN)HBIN_BASE(Me->BinAddress))->Signature == HBIN_SIGNATURE);
  2463. if (Me->BinAddress & HMAP_DISCARDABLE) {
  2464. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  2465. NextBlock = (PUCHAR)(HBIN_BASE(Me->BinAddress) + FileBaseAddress - FreeBin->FileOffset );
  2466. } else {
  2467. NextBlock = (PUCHAR)Me->BlockAddress;
  2468. }
  2469. if ( (NextBlock - Block) != HBLOCK_SIZE) {
  2470. //
  2471. // We've hit a discontinuity in memory. RunLength is
  2472. // as long as it's going to get.
  2473. //
  2474. break;
  2475. }
  2476. if ((FileEndAddress - FileBaseAddress) <= HBLOCK_SIZE) {
  2477. //
  2478. // We've reached the tail block, all is contiguous,
  2479. // fill up to end and return.
  2480. //
  2481. *Length = FileLength;
  2482. *Current = End;
  2483. return TRUE;
  2484. }
  2485. //
  2486. // Just another contiguous block, fill forward
  2487. //
  2488. RunLength += HBLOCK_SIZE;
  2489. RunSpan += HSECTOR_COUNT;
  2490. FileBaseAddress += HBLOCK_SIZE;
  2491. Block = NextBlock;
  2492. }
  2493. //
  2494. // We either hit a discontinuity, OR, we're at the end of the range
  2495. // we're trying to fill. In either case, return.
  2496. //
  2497. *Length = RunLength;
  2498. *Current = Start + RunSpan;
  2499. return TRUE;
  2500. }
  2501. /*
  2502. !!!we don't need this anymore as the bins are not allocated from paged pool anymore!!!
  2503. Big chunks of discardable registry allocations will just not be mapped.
  2504. VOID
  2505. HvpDiscardBins(
  2506. IN PHHIVE Hive
  2507. )
  2508. */
  2509. /*++
  2510. Routine Description:
  2511. Walks through the dirty bins in a hive to see if any are marked
  2512. discardable. If so, they are discarded and the map is updated to
  2513. reflect this.
  2514. Arguments:
  2515. Hive - Supplies the hive control structure.
  2516. Return Value:
  2517. None.
  2518. --*/
  2519. /*
  2520. {
  2521. PHBIN Bin;
  2522. PHMAP_ENTRY Map;
  2523. PFREE_HBIN FreeBin;
  2524. PLIST_ENTRY List;
  2525. List = Hive->Storage[Stable].FreeBins.Flink;
  2526. while (List != &Hive->Storage[Stable].FreeBins) {
  2527. ASSERT_LISTENTRY(List);
  2528. FreeBin = CONTAINING_RECORD(List, FREE_HBIN, ListEntry);
  2529. if (FreeBin->Flags & FREE_HBIN_DISCARDABLE) {
  2530. Map = HvpGetCellMap(Hive, FreeBin->FileOffset);
  2531. VALIDATE_CELL_MAP(__LINE__,Map,Hive,FreeBin->FileOffset);
  2532. Bin = (PHBIN)HBIN_BASE(Map->BinAddress);
  2533. ASSERT(Map->BinAddress & HMAP_DISCARDABLE);
  2534. //
  2535. // Note we use ExFreePool directly here to avoid
  2536. // giving back the quota for this bin. By charging
  2537. // registry quota for discarded bins, we prevent
  2538. // sparse hives from requiring more quota after
  2539. // a reboot than on a running system.
  2540. //
  2541. ExFreePool(Bin);
  2542. FreeBin->Flags &= ~FREE_HBIN_DISCARDABLE;
  2543. }
  2544. List=List->Flink;
  2545. }
  2546. }
  2547. */
  2548. BOOLEAN
  2549. HvHiveWillShrink(
  2550. IN PHHIVE Hive
  2551. )
  2552. /*++
  2553. Routine Description:
  2554. Applies to stable storage only. Helps determining whether the hive
  2555. will shrink on first flush
  2556. --*/
  2557. {
  2558. PHMAP_ENTRY Map;
  2559. ULONG NewLength;
  2560. ULONG OldLength;
  2561. OldLength = Hive->BaseBlock->Length;
  2562. NewLength = Hive->Storage[Stable].Length;
  2563. if( OldLength > NewLength ) {
  2564. return TRUE;
  2565. }
  2566. if( NewLength > 0 ) {
  2567. ASSERT( (NewLength % HBLOCK_SIZE) == 0);
  2568. Map = HvpGetCellMap(Hive, (NewLength - HBLOCK_SIZE));
  2569. VALIDATE_CELL_MAP(__LINE__,Map,Hive,(NewLength - HBLOCK_SIZE));
  2570. if (Map->BinAddress & HMAP_DISCARDABLE) {
  2571. return TRUE;
  2572. }
  2573. }
  2574. return FALSE;
  2575. }
  2576. VOID
  2577. HvpTruncateBins(
  2578. IN PHHIVE Hive
  2579. )
  2580. /*++
  2581. Routine Description:
  2582. Attempts to shrink the hive by truncating any bins that are discardable at
  2583. the end of the hive. Applies to both stable and volatile storage.
  2584. Arguments:
  2585. Hive - Supplies the hive to be truncated.
  2586. Return Value:
  2587. None.
  2588. --*/
  2589. {
  2590. HSTORAGE_TYPE i;
  2591. PHMAP_ENTRY Map;
  2592. ULONG NewLength;
  2593. PFREE_HBIN FreeBin;
  2594. //
  2595. // stable and volatile
  2596. //
  2597. for (i=0;i<HTYPE_COUNT;i++) {
  2598. //
  2599. // find the last in-use bin in the hive
  2600. //
  2601. NewLength = Hive->Storage[i].Length;
  2602. while (NewLength > 0) {
  2603. Map = HvpGetCellMap(Hive, (NewLength - HBLOCK_SIZE) + (i*HCELL_TYPE_MASK));
  2604. VALIDATE_CELL_MAP(__LINE__,Map,Hive,(NewLength - HBLOCK_SIZE) + (i*HCELL_TYPE_MASK));
  2605. if (Map->BinAddress & HMAP_DISCARDABLE) {
  2606. FreeBin = (PFREE_HBIN)Map->BlockAddress;
  2607. #ifdef HV_TRACK_FREE_SPACE
  2608. Hive->Storage[i].FreeStorage -= (FreeBin->Size - sizeof(HBIN));
  2609. ASSERT( (LONG)(Hive->Storage[i].FreeStorage) >= 0 );
  2610. #endif
  2611. NewLength = FreeBin->FileOffset;
  2612. } else {
  2613. break;
  2614. }
  2615. }
  2616. if (NewLength < Hive->Storage[i].Length) {
  2617. //
  2618. // There are some free bins to truncate.
  2619. //
  2620. HvFreeHivePartial(Hive, NewLength, i);
  2621. }
  2622. }
  2623. }
  2624. VOID
  2625. HvpDropPagedBins(
  2626. IN PHHIVE Hive
  2627. #if DBG
  2628. ,
  2629. IN BOOLEAN Check
  2630. #endif
  2631. )
  2632. /*++
  2633. Routine Description:
  2634. Frees all bins allocated from page pool, which are at
  2635. the end of the hive, then update their map (clears the
  2636. HMAP_INPAGEDPOOL flag). Next attempt to read from those
  2637. bins will map a view for them. Checks for CM_VIEW_SIZE boundary,
  2638. before freeing a bin.
  2639. It also tags each start of the bin with HMAP_NEWALLOC; This will
  2640. allow us to use MAP_NO_READ flag in CcMapData (now that we enabled
  2641. MNW feature for registry streams, we know that Mm will fault only one
  2642. page at the time for these king of streams)
  2643. Applies only to permanent storage.
  2644. Arguments:
  2645. Hive - Supplies the hive to operate on..
  2646. Check - debug only, beggining of the bin should already tagged as
  2647. HMAP_NEWALLOC
  2648. Return Value:
  2649. None.
  2650. --*/
  2651. {
  2652. ULONG_PTR Address;
  2653. LONG Length;
  2654. LONG Offset;
  2655. PHMAP_ENTRY Me;
  2656. PHBIN Bin;
  2657. PFREE_HBIN FreeBin;
  2658. BOOLEAN UnMap = FALSE;
  2659. PAGED_CODE();
  2660. if( (Hive->Storage[Stable].Length == 0) || // empty hive
  2661. (((PCMHIVE)Hive)->FileObject == NULL) // or hive not using the mapped views technique
  2662. ) {
  2663. return;
  2664. }
  2665. CmLockHiveViews((PCMHIVE)Hive);
  2666. if( ((PCMHIVE)Hive)->UseCount != 0 ) {
  2667. //
  2668. // this is not a good time to do that
  2669. //
  2670. CmUnlockHiveViews((PCMHIVE)Hive);
  2671. return;
  2672. }
  2673. //
  2674. // start at the end of the hive
  2675. //
  2676. Length = Hive->Storage[Stable].Length - HBLOCK_SIZE;
  2677. while(Length >= 0) {
  2678. //
  2679. // get the bin
  2680. //
  2681. Me = HvpGetCellMap(Hive, Length);
  2682. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Length);
  2683. if( !(Me->BinAddress & HMAP_INPAGEDPOOL) ) {
  2684. //
  2685. // bail out; we are interested only in bins allocated from paged pool
  2686. //
  2687. break;
  2688. }
  2689. if(Me->BinAddress & HMAP_DISCARDABLE) {
  2690. //
  2691. // bin is discardable, skip it !
  2692. //
  2693. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  2694. Length = FreeBin->FileOffset - HBLOCK_SIZE;
  2695. continue;
  2696. }
  2697. Address = HBIN_BASE(Me->BinAddress);
  2698. Bin = (PHBIN)Address;
  2699. // sanity
  2700. ASSERT( Bin->Signature == HBIN_SIGNATURE );
  2701. //
  2702. // advance (backward) to the previous bin
  2703. //
  2704. Length = Bin->FileOffset - HBLOCK_SIZE;
  2705. //
  2706. // finaly, see if we can free it;
  2707. //
  2708. if( HvpCheckViewBoundary(Bin->FileOffset,Bin->FileOffset + Bin->Size - 1) ) {
  2709. //
  2710. // free its storage and mark the map accordingly;
  2711. // next attempt to read a cell from this bin will map a view.
  2712. //
  2713. Offset = Bin->FileOffset;
  2714. while( Offset < (LONG)(Bin->FileOffset + Bin->Size) ) {
  2715. Me = HvpGetCellMap(Hive, Offset);
  2716. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  2717. ASSERT_BIN_INPAGEDPOOL(Me);
  2718. //
  2719. // clear off the HMAP_INPAGEDPOOL flag
  2720. //
  2721. Me->BinAddress &= ~HMAP_INPAGEDPOOL;
  2722. if( (ULONG)Offset == Bin->FileOffset ) {
  2723. #if DBG
  2724. if( Check == TRUE ) {
  2725. // should already be tagged
  2726. ASSERT( Me->BinAddress & HMAP_NEWALLOC );
  2727. }
  2728. #endif
  2729. //
  2730. // tag it as a new alloc, so we can rely on this flag in CmpMapCmView
  2731. //
  2732. Me->BinAddress |= HMAP_NEWALLOC;
  2733. } else {
  2734. //
  2735. // remove the NEWALLOC flag (if any), so we can rely on this flag in CmpMapCmView
  2736. //
  2737. Me->BinAddress &= ~HMAP_NEWALLOC;
  2738. }
  2739. // advance to the next HBLOCK_SIZE of this bin
  2740. Offset += HBLOCK_SIZE;
  2741. }
  2742. //
  2743. // free the bin
  2744. //
  2745. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Dropping temporary bin (from paged pool) at offset %lx size %lx\n",Bin->FileOffset,Bin->Size));
  2746. if( HvpGetBinMemAlloc(Hive,Bin,Stable) ) {
  2747. CmpFree(Bin, HvpGetBinMemAlloc(Hive,Bin,Stable));
  2748. }
  2749. UnMap = TRUE;
  2750. } else {
  2751. //
  2752. // this bin has a good reason to reside in page-pool (it's crossing the boundaries).
  2753. // leave it like that !
  2754. //
  2755. NOTHING;
  2756. }
  2757. }
  2758. if( UnMap == TRUE ) {
  2759. //
  2760. // unmap the last view, to make sure the map will be updated
  2761. //
  2762. ASSERT( Length >= -HBLOCK_SIZE );
  2763. Offset = (Length + HBLOCK_SIZE) & (~(CM_VIEW_SIZE - 1));
  2764. if( Offset != 0 ) {
  2765. //
  2766. // account for the header
  2767. //
  2768. Offset -= HBLOCK_SIZE;
  2769. }
  2770. Length = Hive->Storage[Stable].Length;
  2771. while( Offset < Length ) {
  2772. Me = HvpGetCellMap(Hive, Offset);
  2773. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  2774. if( Me->BinAddress & HMAP_INVIEW ) {
  2775. //
  2776. // get this view and unmap it; then bail out.
  2777. //
  2778. CmpUnmapCmView( (PCMHIVE)Hive,Me->CmView,TRUE,TRUE);
  2779. break;
  2780. }
  2781. // next, please ?
  2782. Offset += HBLOCK_SIZE;
  2783. }
  2784. }
  2785. CmUnlockHiveViews((PCMHIVE)Hive);
  2786. }
  2787. VOID
  2788. HvpDropAllPagedBins(
  2789. IN PHHIVE Hive
  2790. )
  2791. /*++
  2792. Routine Description:
  2793. Works as HvpDropPagedBins, only that it iterates through
  2794. the entire hive. No views are mapped at this point.
  2795. Arguments:
  2796. Hive - Supplies the hive to operate on..
  2797. Return Value:
  2798. None.
  2799. --*/
  2800. {
  2801. ULONG_PTR Address;
  2802. ULONG Length;
  2803. ULONG Offset;
  2804. PHMAP_ENTRY Me;
  2805. PHBIN Bin;
  2806. PFREE_HBIN FreeBin;
  2807. PAGED_CODE();
  2808. if( (Hive->Storage[Stable].Length == 0) || // empty hive
  2809. (((PCMHIVE)Hive)->FileObject == NULL) // or hive not using the mapped views technique
  2810. ) {
  2811. return;
  2812. }
  2813. ASSERT( (((PCMHIVE)Hive)->MappedViews == 0) && (((PCMHIVE)Hive)->PinnedViews == 0) && (((PCMHIVE)Hive)->UseCount == 0) );
  2814. //
  2815. // start at the end of the hive
  2816. //
  2817. Length = Hive->Storage[Stable].Length - HBLOCK_SIZE;
  2818. Offset = 0;
  2819. while( Offset < Length ) {
  2820. //
  2821. // get the bin
  2822. //
  2823. Me = HvpGetCellMap(Hive, Offset);
  2824. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  2825. ASSERT( Me->BinAddress & HMAP_INPAGEDPOOL );
  2826. if(Me->BinAddress & HMAP_DISCARDABLE) {
  2827. //
  2828. // bin is discardable, skip it !
  2829. //
  2830. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  2831. ASSERT( Offset == FreeBin->FileOffset );
  2832. Offset += FreeBin->Size;
  2833. continue;
  2834. }
  2835. Address = HBIN_BASE(Me->BinAddress);
  2836. Bin = (PHBIN)Address;
  2837. // sanity
  2838. ASSERT( Bin->Signature == HBIN_SIGNATURE );
  2839. //
  2840. // finaly, see if we can free it;
  2841. //
  2842. if( HvpCheckViewBoundary(Bin->FileOffset,Bin->FileOffset + Bin->Size - 1) ) {
  2843. //
  2844. // free its storage and mark the map accordingly;
  2845. // next attempt to read a cell from this bin will map a view.
  2846. //
  2847. Offset = Bin->FileOffset;
  2848. while( Offset < (Bin->FileOffset + Bin->Size) ) {
  2849. Me = HvpGetCellMap(Hive, Offset);
  2850. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  2851. ASSERT_BIN_INPAGEDPOOL(Me);
  2852. //
  2853. // clear off the HMAP_INPAGEDPOOL flag
  2854. //
  2855. Me->BinAddress &= ~HMAP_INPAGEDPOOL;
  2856. if( (ULONG)Offset == Bin->FileOffset ) {
  2857. //
  2858. // tag it as a new alloc, so we can rely on this flag in CmpMapCmView
  2859. //
  2860. Me->BinAddress |= HMAP_NEWALLOC;
  2861. } else {
  2862. //
  2863. // remove the NEWALLOC flag (if any), so we can rely on this flag in CmpMapCmView
  2864. //
  2865. Me->BinAddress &= ~HMAP_NEWALLOC;
  2866. }
  2867. // advance to the next HBLOCK_SIZE of this bin
  2868. Offset += HBLOCK_SIZE;
  2869. }
  2870. //
  2871. // free the bin
  2872. //
  2873. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Dropping temporary bin (from paged pool) at offset %lx size %lx\n",Bin->FileOffset,Bin->Size));
  2874. if( HvpGetBinMemAlloc(Hive,Bin,Stable) ) {
  2875. CmpFree(Bin, HvpGetBinMemAlloc(Hive,Bin,Stable));
  2876. }
  2877. } else {
  2878. //
  2879. // this bin has a good reason to reside in page-pool (it's crossing the boundaries).
  2880. // leave it like that !
  2881. //
  2882. Offset += Bin->Size;
  2883. }
  2884. }
  2885. }
  2886. NTSTATUS
  2887. HvWriteHive(
  2888. PHHIVE Hive,
  2889. BOOLEAN DontGrow,
  2890. BOOLEAN WriteThroughCache,
  2891. BOOLEAN CrashSafe
  2892. )
  2893. /*++
  2894. Routine Description:
  2895. Write the hive out. Write only to the Primary file, neither
  2896. logs nor alternates will be updated. The hive will be written
  2897. to the HFILE_TYPE_EXTERNAL handle.
  2898. Intended for use in applications like SaveKey.
  2899. Only Stable storage will be written (as for any hive.)
  2900. Presumption is that layer above has set HFILE_TYPE_EXTERNAL
  2901. handle to point to correct place.
  2902. Applying this call to an active hive will generally hose integrity
  2903. measures.
  2904. HOW IT WORKS:
  2905. Saves the BaseBlock.
  2906. Iterates through the entire hive and save it bin by bin
  2907. Arguments:
  2908. Hive - supplies a pointer to the hive control structure for the
  2909. hive of interest.
  2910. DontGrow - we know that the file is big enough, don't attempt to grow it.
  2911. Return Value:
  2912. Status.
  2913. --*/
  2914. {
  2915. PHBASE_BLOCK BaseBlock;
  2916. NTSTATUS status;
  2917. ULONG Offset;
  2918. PHBIN Bin = NULL;
  2919. PFREE_HBIN FreeBin = NULL;
  2920. ULONG BinSize;
  2921. PVOID Address;
  2922. ULONG BinOffset;
  2923. ULONG Length;
  2924. CMP_OFFSET_ARRAY offsetElement;
  2925. PHMAP_ENTRY Me;
  2926. PHCELL FirstCell;
  2927. BOOLEAN rc;
  2928. PCM_VIEW_OF_FILE CmView = NULL;
  2929. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"HvWriteHive: \n"));
  2930. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"\tHive = %p\n"));
  2931. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  2932. ASSERT(Hive->ReadOnly == FALSE);
  2933. //
  2934. // Punt if post shutdown
  2935. //
  2936. if (HvShutdownComplete) {
  2937. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"HvWriteHive: Attempt to write hive AFTER SHUTDOWN\n"));
  2938. return STATUS_REGISTRY_IO_FAILED;
  2939. }
  2940. Length = Hive->Storage[Stable].Length;
  2941. //
  2942. // we should never come to this
  2943. //
  2944. ASSERT( Length != 0 );
  2945. ASSERT( Hive->BaseBlock->RootCell != HCELL_NIL );
  2946. if( !DontGrow ){
  2947. //
  2948. // Ensure the file can be made big enough, then do the deed
  2949. //
  2950. status = CmpDoFileSetSize(Hive,
  2951. HFILE_TYPE_EXTERNAL,
  2952. Length + HBLOCK_SIZE,
  2953. 0);
  2954. if (!NT_SUCCESS(status)) {
  2955. return status;
  2956. }
  2957. }
  2958. BaseBlock = Hive->BaseBlock;
  2959. //
  2960. // --- Write out header first time ---
  2961. //
  2962. ASSERT(BaseBlock->Signature == HBASE_BLOCK_SIGNATURE);
  2963. ASSERT(BaseBlock->Major == HSYS_MAJOR);
  2964. ASSERT(BaseBlock->Format == HBASE_FORMAT_MEMORY);
  2965. ASSERT(Hive->ReadOnly == FALSE);
  2966. if (BaseBlock->Sequence1 != BaseBlock->Sequence2) {
  2967. //
  2968. // Some previous log attempt failed, or this hive needs to
  2969. // be recovered, so punt.
  2970. //
  2971. return STATUS_REGISTRY_IO_FAILED;
  2972. }
  2973. if( CrashSafe ) {
  2974. //
  2975. // change sequence numbers, in case we experience a machine crash
  2976. //
  2977. BaseBlock->Sequence1++;
  2978. }
  2979. BaseBlock->Length = Length;
  2980. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  2981. Offset = 0;
  2982. offsetElement.FileOffset = Offset;
  2983. offsetElement.DataBuffer = (PVOID) BaseBlock;
  2984. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  2985. if(WriteThroughCache) {
  2986. //
  2987. // if we use Cc, do the write with the pin interface
  2988. //
  2989. rc = CmpFileWriteThroughCache( Hive,
  2990. HFILE_TYPE_EXTERNAL,
  2991. &offsetElement,
  2992. 1);
  2993. Offset += offsetElement.DataLength;
  2994. } else {
  2995. rc = (Hive->FileWrite)( Hive,
  2996. HFILE_TYPE_EXTERNAL,
  2997. &offsetElement,
  2998. 1,
  2999. &Offset );
  3000. }
  3001. if (rc == FALSE) {
  3002. return STATUS_REGISTRY_IO_FAILED;
  3003. }
  3004. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_EXTERNAL,NULL,0)) {
  3005. return STATUS_REGISTRY_IO_FAILED;
  3006. }
  3007. Offset = ROUND_UP(Offset, HBLOCK_SIZE);
  3008. //
  3009. // --- Write out data (ALL !!!) ---
  3010. //
  3011. BinOffset = 0;
  3012. while (BinOffset < Hive->Storage[Stable].Length) {
  3013. //
  3014. // we need to grab the viewlock here to protect against a racing HvGetCell
  3015. //
  3016. CmLockHiveViews ((PCMHIVE)Hive);
  3017. Me = HvpGetCellMap(Hive, BinOffset);
  3018. if( (Me->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0) {
  3019. //
  3020. // view is not mapped, neither in paged pool try to map it.
  3021. //
  3022. if( !NT_SUCCESS(CmpMapThisBin((PCMHIVE)Hive,BinOffset,TRUE)) ) {
  3023. CmUnlockHiveViews ((PCMHIVE)Hive);
  3024. status = STATUS_INSUFFICIENT_RESOURCES;
  3025. goto ErrorExit;
  3026. }
  3027. }
  3028. //
  3029. // reference the view so it doesn't go away from under us;
  3030. // first remove any old ref
  3031. //
  3032. if( Me->BinAddress & HMAP_INVIEW ) {
  3033. CmpDereferenceHiveView((PCMHIVE)Hive,CmView);
  3034. CmpReferenceHiveView((PCMHIVE)Hive,CmView = Me->CmView);
  3035. }
  3036. CmUnlockHiveViews ((PCMHIVE)Hive);
  3037. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  3038. //
  3039. // bin is discardable. If it is not discarded yet, save it as it is
  3040. // else, allocate, initialize and save a fake bin
  3041. //
  3042. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  3043. BinSize = FreeBin->Size;
  3044. if( FreeBin->Flags & FREE_HBIN_DISCARDABLE ){
  3045. //
  3046. // HBIN still in memory
  3047. //
  3048. Address = (PVOID)HBIN_BASE(Me->BinAddress);
  3049. } else {
  3050. //
  3051. // HBIN discarded, we have to allocate a new bin and mark it as a
  3052. // BIG free cell
  3053. //
  3054. // don't charge quota for it as we will give it back
  3055. Bin = (PHBIN)ExAllocatePoolWithTag(PagedPool, BinSize, CM_HVBIN_TAG);
  3056. if( Bin == NULL ){
  3057. status = STATUS_INSUFFICIENT_RESOURCES;
  3058. goto ErrorExit;
  3059. }
  3060. //
  3061. // Initialize the bin
  3062. //
  3063. Bin->Signature = HBIN_SIGNATURE;
  3064. Bin->FileOffset = BinOffset;
  3065. Bin->Size = BinSize;
  3066. FirstCell = (PHCELL)(Bin+1);
  3067. FirstCell->Size = BinSize - sizeof(HBIN);
  3068. if (USE_OLD_CELL(Hive)) {
  3069. FirstCell->u.OldCell.Last = (ULONG)HBIN_NIL;
  3070. }
  3071. Address = (PVOID)Bin;
  3072. }
  3073. } else {
  3074. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  3075. ASSERT( Bin->Signature == HBIN_SIGNATURE );
  3076. ASSERT( Bin->FileOffset == BinOffset );
  3077. Address = (PVOID)Bin;
  3078. try {
  3079. BinSize = Bin->Size;
  3080. } except (EXCEPTION_EXECUTE_HANDLER) {
  3081. //
  3082. // in low-memory scenarios or disk error, touching the bin may throw STATUS_IN_PAGE_ERROR
  3083. //
  3084. status = GetExceptionCode();
  3085. goto ErrorExit;
  3086. }
  3087. }
  3088. //
  3089. // write the bin to the file
  3090. //
  3091. offsetElement.FileOffset = Offset;
  3092. offsetElement.DataBuffer = Address;
  3093. offsetElement.DataLength = BinSize;
  3094. if(WriteThroughCache) {
  3095. //
  3096. // if we use Cc, do the write with the pin interface
  3097. // Take extra care not to cross the view boundaries
  3098. //
  3099. if( HvpCheckViewBoundary(Offset - HBLOCK_SIZE,Offset - HBLOCK_SIZE + BinSize - 1) ) {
  3100. rc = CmpFileWriteThroughCache( Hive,
  3101. HFILE_TYPE_EXTERNAL,
  3102. &offsetElement,
  3103. 1);
  3104. } else {
  3105. //
  3106. // write one HBLOCK_SIZE at a time.
  3107. //
  3108. ULONG ToWrite = BinSize;
  3109. offsetElement.DataLength = HBLOCK_SIZE;
  3110. while( ToWrite > 0 ) {
  3111. rc = CmpFileWriteThroughCache( Hive,
  3112. HFILE_TYPE_EXTERNAL,
  3113. &offsetElement,
  3114. 1);
  3115. if( rc == FALSE ) {
  3116. status = STATUS_REGISTRY_IO_FAILED;
  3117. goto ErrorExit;
  3118. }
  3119. ToWrite -= HBLOCK_SIZE;
  3120. offsetElement.DataBuffer = (PUCHAR)offsetElement.DataBuffer + HBLOCK_SIZE;
  3121. offsetElement.FileOffset += HBLOCK_SIZE;
  3122. }
  3123. }
  3124. Offset += BinSize;
  3125. } else {
  3126. rc = (Hive->FileWrite)( Hive,
  3127. HFILE_TYPE_EXTERNAL,
  3128. &offsetElement,
  3129. 1,
  3130. &Offset );
  3131. }
  3132. if (rc == FALSE) {
  3133. status = STATUS_REGISTRY_IO_FAILED;
  3134. goto ErrorExit;
  3135. }
  3136. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  3137. if( (FreeBin->Flags & FREE_HBIN_DISCARDABLE) == 0){
  3138. ASSERT( FreeBin == (PFREE_HBIN)Me->BlockAddress );
  3139. ASSERT( Bin );
  3140. //
  3141. // give back the paged pool used
  3142. //
  3143. ExFreePool(Bin);
  3144. }
  3145. }
  3146. //
  3147. // advance to the next bin
  3148. //
  3149. BinOffset += BinSize;
  3150. }
  3151. //
  3152. // let go last view referenced (if any)
  3153. //
  3154. CmpDereferenceHiveViewWithLock((PCMHIVE)Hive,CmView);
  3155. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_EXTERNAL,NULL,0)) {
  3156. return STATUS_REGISTRY_IO_FAILED;
  3157. }
  3158. if( CrashSafe ) {
  3159. //
  3160. // change sequence numbers, in case we experience a machine crash
  3161. //
  3162. BaseBlock->Sequence2++;
  3163. BaseBlock->CheckSum = HvpHeaderCheckSum(BaseBlock);
  3164. ASSERT( BaseBlock->Sequence1 == BaseBlock->Sequence2 );
  3165. Offset = 0;
  3166. offsetElement.FileOffset = Offset;
  3167. offsetElement.DataBuffer = (PVOID) BaseBlock;
  3168. offsetElement.DataLength = HSECTOR_SIZE * Hive->Cluster;
  3169. if(WriteThroughCache) {
  3170. //
  3171. // if we use Cc, do the write with the pin interface
  3172. //
  3173. rc = CmpFileWriteThroughCache( Hive,
  3174. HFILE_TYPE_EXTERNAL,
  3175. &offsetElement,
  3176. 1);
  3177. Offset += offsetElement.DataLength;
  3178. } else {
  3179. rc = (Hive->FileWrite)( Hive,
  3180. HFILE_TYPE_EXTERNAL,
  3181. &offsetElement,
  3182. 1,
  3183. &Offset );
  3184. }
  3185. if (rc == FALSE) {
  3186. return STATUS_REGISTRY_IO_FAILED;
  3187. }
  3188. if ( ! (Hive->FileFlush)(Hive, HFILE_TYPE_EXTERNAL,NULL,0)) {
  3189. return STATUS_REGISTRY_IO_FAILED;
  3190. }
  3191. if( DontGrow ){
  3192. //
  3193. // file has shrunk
  3194. //
  3195. CmpDoFileSetSize(Hive,HFILE_TYPE_EXTERNAL,Length + HBLOCK_SIZE,0);
  3196. }
  3197. }
  3198. // it seems like everything went OK
  3199. return STATUS_SUCCESS;
  3200. ErrorExit:
  3201. CmpDereferenceHiveViewWithLock((PCMHIVE)Hive,CmView);
  3202. return status;
  3203. }
  3204. #ifdef CM_ENABLE_WRITE_ONLY_BINS
  3205. VOID HvpMarkAllBinsWriteOnly(IN PHHIVE Hive)
  3206. {
  3207. HCELL_INDEX p;
  3208. ULONG Length;
  3209. PHMAP_ENTRY t;
  3210. PHBIN Bin;
  3211. ULONG i;
  3212. PFREE_HBIN FreeBin;
  3213. p = 0;
  3214. PAGED_CODE();
  3215. Length = Hive->Storage[Stable].Length;
  3216. //
  3217. // for each bin in the stable storage
  3218. //
  3219. while (p < Length) {
  3220. t = HvpGetCellMap(Hive, p);
  3221. VALIDATE_CELL_MAP(__LINE__,t,Hive,p);
  3222. if( (t->BinAddress &HMAP_INPAGEDPOOL) == 0) {
  3223. //
  3224. // at this point we only work with paged pool bins
  3225. //
  3226. break;
  3227. }
  3228. if ((t->BinAddress & HMAP_DISCARDABLE) == 0) {
  3229. Bin = (PHBIN)HBIN_BASE(t->BinAddress);
  3230. for( i=0;i<Bin->Size;i += PAGE_SIZE ) {
  3231. if( !MmProtectSpecialPool((PUCHAR)Bin + i,PAGE_READONLY) ) {
  3232. DbgPrint("Failed to set READONLY protection on page at %p Bin %p size = %lx\n",Bin+i,Bin,Bin->Size);
  3233. }
  3234. }
  3235. /*
  3236. if( !MmSetPageProtection(Bin,Bin->Size,PAGE_READONLY) ) {
  3237. DbgPrint("Failed to set READONLY protection on bin at %p size = %lx\n",Bin,Bin->Size);
  3238. }
  3239. */
  3240. p = (ULONG)p + Bin->Size;
  3241. } else {
  3242. //
  3243. // Bin is not present, skip it and advance to the next one.
  3244. //
  3245. FreeBin = (PFREE_HBIN)t->BlockAddress;
  3246. p+=FreeBin->Size;
  3247. }
  3248. }
  3249. }
  3250. #endif //CM_ENABLE_WRITE_ONLY_BINS