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

2549 lines
68 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. cmmapvw.c
  5. Abstract:
  6. This module contains mapped view support for hives.
  7. Author:
  8. Dragos C. Sambotin (dragoss) 14-Jun-1999
  9. Revision History:
  10. --*/
  11. #include "cmp.h"
  12. #define CM_TRACK_DIRTY_PAGES
  13. #ifdef CM_TRACK_DIRTY_PAGES
  14. #include "..\cache\cc.h"
  15. #endif
  16. VOID
  17. CmpUnmapCmView(
  18. IN PCMHIVE CmHive,
  19. IN PCM_VIEW_OF_FILE CmView,
  20. IN BOOLEAN MapIsValid,
  21. IN BOOLEAN MoveToEnd
  22. );
  23. PCM_VIEW_OF_FILE
  24. CmpAllocateCmView (
  25. IN PCMHIVE CmHive
  26. );
  27. VOID
  28. CmpFreeCmView (
  29. PCM_VIEW_OF_FILE CmView
  30. );
  31. VOID
  32. CmpUnmapCmViewSurroundingOffset(
  33. IN PCMHIVE CmHive,
  34. IN ULONG FileOffset
  35. );
  36. VOID
  37. CmpUnmapUnusedViews(
  38. IN PCMHIVE CmHive
  39. );
  40. #ifdef CMP_CMVIEW_VALIDATION
  41. VOID
  42. CmpCheckCmView(
  43. IN PCMHIVE CmHive,
  44. IN PCM_VIEW_OF_FILE CmView
  45. );
  46. #endif //CMP_CMVIEW_VALIDATION
  47. BOOLEAN
  48. CmIsFileLoadedAsHive(PFILE_OBJECT FileObject);
  49. VOID
  50. CmpReferenceHiveView( IN PCMHIVE CmHive,
  51. IN PCM_VIEW_OF_FILE CmView
  52. );
  53. VOID
  54. CmpDereferenceHiveView( IN PCMHIVE CmHive,
  55. IN PCM_VIEW_OF_FILE CmView
  56. );
  57. VOID
  58. CmpReferenceHiveViewWithLock( IN PCMHIVE CmHive,
  59. IN PCM_VIEW_OF_FILE CmView
  60. );
  61. VOID
  62. CmpDereferenceHiveViewWithLock( IN PCMHIVE CmHive,
  63. IN PCM_VIEW_OF_FILE CmView
  64. );
  65. extern LIST_ENTRY CmpHiveListHead;
  66. extern PUCHAR CmpStashBuffer;
  67. extern ULONG CmpStashBufferSize;
  68. BOOLEAN CmpTrackHiveClose = FALSE;
  69. #ifdef ALLOC_PRAGMA
  70. #pragma alloc_text(PAGE,CmpUnmapCmView)
  71. #pragma alloc_text(PAGE,CmpTouchView)
  72. #pragma alloc_text(PAGE,CmpMapCmView)
  73. #pragma alloc_text(PAGE,CmpAquireFileObjectForFile)
  74. #pragma alloc_text(PAGE,CmpDropFileObjectForHive)
  75. #pragma alloc_text(PAGE,CmpInitHiveViewList)
  76. #pragma alloc_text(PAGE,CmpDestroyHiveViewList)
  77. #pragma alloc_text(PAGE,CmpAllocateCmView)
  78. #pragma alloc_text(PAGE,CmpFreeCmView)
  79. #pragma alloc_text(PAGE,CmpPinCmView)
  80. #pragma alloc_text(PAGE,CmpUnPinCmView)
  81. #pragma alloc_text(PAGE,CmpMapThisBin)
  82. #pragma alloc_text(PAGE,CmpFixHiveUsageCount)
  83. #pragma alloc_text(PAGE,CmpUnmapUnusedViews)
  84. #if 0
  85. #pragma alloc_text(PAGE,CmpMapEntireFileInFakeViews)
  86. #pragma alloc_text(PAGE,CmpUnmapFakeViews)
  87. #pragma alloc_text(PAGE,CmpUnmapAditionalViews)
  88. #endif
  89. #ifdef CMP_CMVIEW_VALIDATION
  90. #pragma alloc_text(PAGE,CmpCheckCmView)
  91. #endif //CMP_CMVIEW_VALIDATION
  92. #pragma alloc_text(PAGE,CmpUnmapCmViewSurroundingOffset)
  93. #pragma alloc_text(PAGE,CmpPrefetchHiveFile)
  94. #pragma alloc_text(PAGE,CmPrefetchHivePages)
  95. #pragma alloc_text(PAGE,CmIsFileLoadedAsHive)
  96. #pragma alloc_text(PAGE,CmpReferenceHiveView)
  97. #pragma alloc_text(PAGE,CmpDereferenceHiveView)
  98. #pragma alloc_text(PAGE,CmpReferenceHiveViewWithLock)
  99. #pragma alloc_text(PAGE,CmpDereferenceHiveViewWithLock)
  100. #endif
  101. //
  102. // this controls how many views we allow per each hive (bassically how many address space we
  103. // allow per hive). We use this to optimize boot time.
  104. //
  105. ULONG CmMaxViewsPerHive = MAX_VIEWS_PER_HIVE;
  106. VOID
  107. CmpUnmapCmView(
  108. IN PCMHIVE CmHive,
  109. IN PCM_VIEW_OF_FILE CmView,
  110. IN BOOLEAN MapIsValid,
  111. IN BOOLEAN MoveToEnd
  112. )
  113. /*++
  114. Routine Description:
  115. Unmaps the view by marking all the bins that maps inside of it as invalid.
  116. Arguments:
  117. Hive - Hive containing the section
  118. CmView - pointer to the view to operate on
  119. MapIsValid - Hive's map has been successfully inited (and not yet freed)
  120. MoveToEnd - moves the view to the end of the LRUList after unmapping
  121. This is normally TRUE, unless we want to be able to iterate through
  122. the entire list and unmap views in the same time
  123. Return Value:
  124. <none>
  125. --*/
  126. {
  127. ULONG Offset;
  128. ULONG_PTR Address;
  129. ULONG_PTR AddressEnd;
  130. PHMAP_ENTRY Me;
  131. PAGED_CODE();
  132. ASSERT( (CmView->FileOffset + CmView->Size) != 0 && (CmView->ViewAddress != 0));
  133. //
  134. // it is forbidden to unmap a view still in use!
  135. //
  136. ASSERT( CmView->UseCount == 0 );
  137. //
  138. // only if the map is still valid
  139. //
  140. if( MapIsValid == TRUE ) {
  141. Offset = CmView->FileOffset;
  142. AddressEnd = Address = (ULONG_PTR)(CmView->ViewAddress);
  143. AddressEnd += CmView->Size;
  144. if( Offset == 0 ) {
  145. //
  146. // oops; we are at the beginning, we have to skip the base block
  147. //
  148. Address += HBLOCK_SIZE;
  149. } else {
  150. //
  151. // we are in the middle of the file. just adjust the offset
  152. //
  153. Offset -= HBLOCK_SIZE;
  154. }
  155. while((Address < AddressEnd) && (Offset < CmHive->Hive.Storage[Stable].Length))
  156. {
  157. Me = HvpGetCellMap(&(CmHive->Hive), Offset);
  158. VALIDATE_CELL_MAP(__LINE__,Me,&(CmHive->Hive),Offset);
  159. if( Me->BinAddress & HMAP_INPAGEDPOOL ) {
  160. //
  161. // if bin is mapped in paged pool for some ubiquitous reason,
  162. // leave it like that (don't alter it's mapping).
  163. //
  164. } else {
  165. //
  166. // Invalidate the bin
  167. //
  168. //ASSERT_BIN_INVIEW(Me);
  169. Me->BinAddress &= (~HMAP_INVIEW);
  170. // we don't need to set it - just for debug purposes
  171. ASSERT( (Me->CmView = NULL) == NULL );
  172. }
  173. Offset += HBLOCK_SIZE;
  174. Address += HBLOCK_SIZE;
  175. }
  176. }
  177. //
  178. // Invalidate the view
  179. //
  180. CcUnpinData( CmView->Bcb );
  181. /*
  182. MmUnmapViewInSystemCache (CmView->ViewAddress,CmHive->HiveSection,FALSE);
  183. */
  184. #if 0 //this code gave me a lot of headache
  185. {
  186. UNICODE_STRING HiveName;
  187. RtlInitUnicodeString(&HiveName, (PCWSTR)CmHive->Hive.BaseBlock->FileName);
  188. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"CmpUnmapCmView for hive (%p) (%.*S), Address = %p Size = %lx\n",CmHive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,CmView->ViewAddress,CmView->Size));
  189. }
  190. #endif
  191. CmView->FileOffset = 0;
  192. CmView->Size = 0;
  193. CmView->ViewAddress = 0;
  194. CmView->Bcb = NULL;
  195. CmView->UseCount = 0;
  196. if( MoveToEnd == TRUE ) {
  197. //
  198. // remove the view from the LRU list
  199. //
  200. RemoveEntryList(&(CmView->LRUViewList));
  201. //
  202. // add it to the end of LRU list
  203. //
  204. InsertTailList(
  205. &(CmHive->LRUViewListHead),
  206. &(CmView->LRUViewList)
  207. );
  208. }
  209. }
  210. VOID
  211. CmpTouchView(
  212. IN PCMHIVE CmHive,
  213. IN PCM_VIEW_OF_FILE CmView,
  214. IN ULONG Cell
  215. )
  216. /*++
  217. Warning:
  218. This function should be called with the viewlock held!!!
  219. Routine Description:
  220. Touches the view by moving it at the top of the LRU list.
  221. This function is to be called from HvpGetCellPaged, every
  222. time a view is touched.
  223. Arguments:
  224. Hive - Hive containing the section
  225. CmView - pointer to the view to operate on
  226. Return Value:
  227. <none>
  228. --*/
  229. {
  230. PAGED_CODE();
  231. #if DBG
  232. {
  233. UNICODE_STRING HiveName;
  234. RtlInitUnicodeString(&HiveName, (PCWSTR)CmHive->Hive.BaseBlock->FileName);
  235. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"CmpTouchView for hive (%p) (%.*S),",CmHive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer));
  236. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"Cell = %8lx ViewAddress = %p ViewSize = %lx\n",Cell,CmView->ViewAddress,CmView->Size));
  237. }
  238. #endif
  239. ASSERT( (CmView->FileOffset + CmView->Size) != 0 && (CmView->ViewAddress != 0));
  240. if( IsListEmpty(&(CmView->PinViewList)) == FALSE ) {
  241. //
  242. // the view is pinned; don't mess with it as it is guaranteed
  243. // that it'll be in memory until the next flush
  244. //
  245. return;
  246. }
  247. //
  248. // optimization: if already is first, do nothing
  249. //
  250. if( CmHive->LRUViewListHead.Flink == &(CmView->LRUViewList) ) {
  251. // remove the bp after making sure it's working properly
  252. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"CmView %p already first\n",CmView));
  253. /*
  254. DbgBreakPoint();
  255. */
  256. //it's already first
  257. return;
  258. }
  259. //
  260. // remove the view from the LRU list
  261. //
  262. RemoveEntryList(&(CmView->LRUViewList));
  263. //
  264. // add it on top of LRU list
  265. //
  266. InsertHeadList(
  267. &(CmHive->LRUViewListHead),
  268. &(CmView->LRUViewList)
  269. );
  270. }
  271. NTSTATUS
  272. CmpMapCmView(
  273. IN PCMHIVE CmHive,
  274. IN ULONG FileOffset,
  275. OUT PCM_VIEW_OF_FILE *CmView,
  276. IN BOOLEAN MapInited
  277. )
  278. /*++
  279. Warning:
  280. This function should be called with the hivelock held!!!
  281. Routine Description:
  282. Unmaps the view by marking all the bins that maps inside of it as invalid.
  283. Arguments:
  284. CmHive - Hive containing the section
  285. FileOffset - Offset where to map the view
  286. CmView - pointer to the view to operate on
  287. MapInited - when TRUE, we can rely on the map info.
  288. Return Value:
  289. status of the operation
  290. --*/
  291. {
  292. PHMAP_ENTRY Me;
  293. NTSTATUS Status = STATUS_SUCCESS;
  294. LARGE_INTEGER SectionOffset;
  295. ULONG Offset;
  296. ULONG_PTR Address;
  297. ULONG_PTR AddressEnd;
  298. ULONG_PTR BinAddress;
  299. PHBIN Bin;
  300. LONG PrevMappedBinSize;
  301. BOOLEAN FirstTry = TRUE;
  302. PAGED_CODE();
  303. if( CmHive->MappedViews == 0 ){
  304. //
  305. // we've run out of views; all are pinned
  306. //
  307. ASSERT( IsListEmpty(&(CmHive->LRUViewListHead)) == TRUE );
  308. *CmView = CmpAllocateCmView(CmHive);
  309. } else {
  310. //
  311. // Remove the last view from LRU list (i.e. the LEAST recently used)
  312. //
  313. *CmView = (PCM_VIEW_OF_FILE)CmHive->LRUViewListHead.Blink;
  314. *CmView = CONTAINING_RECORD( *CmView,
  315. CM_VIEW_OF_FILE,
  316. LRUViewList);
  317. if( (*CmView)->ViewAddress != 0 ) {
  318. PCM_VIEW_OF_FILE TempCmView = NULL;
  319. //
  320. // the last view is mapped
  321. //
  322. if( CmHive->MappedViews < CmMaxViewsPerHive ) {
  323. //
  324. // we are still allowed to add views
  325. //
  326. TempCmView = CmpAllocateCmView(CmHive);
  327. }
  328. if( TempCmView == NULL ) {
  329. //
  330. // we couldn't allocate a new view, or we need to use an existent one
  331. //
  332. if( (*CmView)->UseCount != 0 ) {
  333. BOOLEAN FoundView = FALSE;
  334. //
  335. // view is in use; try walking to the top and find an unused view
  336. //
  337. while( (*CmView)->LRUViewList.Blink != CmHive->LRUViewListHead.Flink ) {
  338. *CmView = (PCM_VIEW_OF_FILE)(*CmView)->LRUViewList.Blink;
  339. *CmView = CONTAINING_RECORD( *CmView,
  340. CM_VIEW_OF_FILE,
  341. LRUViewList);
  342. if( (*CmView)->UseCount == 0 ) {
  343. //
  344. // this one is free go ahead and use it !
  345. // first unmap, then signal that we found it
  346. //
  347. if( (*CmView)->ViewAddress != 0 ) {
  348. //
  349. // unnmap only if mapped
  350. //
  351. CmpUnmapCmView(CmHive,(*CmView),TRUE,TRUE);
  352. }
  353. FoundView = TRUE;
  354. break;
  355. }
  356. }
  357. if( FoundView == FALSE ) {
  358. //
  359. // no luck, all views are in use allocate a new one (we are forced to do so)
  360. //
  361. *CmView = CmpAllocateCmView(CmHive);
  362. }
  363. } else {
  364. //
  365. // unmap it!
  366. //
  367. CmpUnmapCmView(CmHive,(*CmView),TRUE,TRUE);
  368. }
  369. } else {
  370. //
  371. // we successfully allocated a new view
  372. //
  373. (*CmView) = TempCmView;
  374. }
  375. }
  376. }
  377. if( (*CmView) == NULL ) {
  378. //
  379. // we're running low on resources
  380. //
  381. return STATUS_INSUFFICIENT_RESOURCES;
  382. }
  383. #if DBG
  384. {
  385. UNICODE_STRING HiveName;
  386. RtlInitUnicodeString(&HiveName, (PCWSTR)CmHive->Hive.BaseBlock->FileName);
  387. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"CmpMapCmView for hive (%p) (%.*S),",CmHive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer));
  388. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP," FileOfset = %lx ... ",FileOffset));
  389. }
  390. #endif
  391. //
  392. // On this call, FileOffset must be a multiple of CM_VIEW_SIZE
  393. //
  394. //
  395. // adjust the file offset to respect the CM_VIEW_SIZE alingment
  396. //
  397. Offset = ((FileOffset+HBLOCK_SIZE) & ~(CM_VIEW_SIZE - 1) );
  398. SectionOffset.LowPart = Offset;
  399. SectionOffset.HighPart = 0;
  400. (*CmView)->Size = CM_VIEW_SIZE;//(FileOffset + Size) - Offset;
  401. if( (Offset + (*CmView)->Size) > (CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE ) ){
  402. (*CmView)->Size = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE - Offset;
  403. }
  404. /*
  405. Status = MmMapViewInSystemCache ( CmHive->HiveSection,
  406. &((*CmView)->ViewAddress),
  407. &SectionOffset,
  408. &((*CmView)->Size));
  409. */
  410. RetryToMap:
  411. try {
  412. ASSERT( (*CmView)->Size != 0 );
  413. ASSERT( (*CmView)->ViewAddress == NULL );
  414. ASSERT( (*CmView)->UseCount == 0 );
  415. if (!CcMapData( CmHive->FileObject,
  416. (PLARGE_INTEGER)&SectionOffset,
  417. (*CmView)->Size,
  418. MAP_WAIT
  419. #ifdef CM_MAP_NO_READ
  420. | MAP_NO_READ
  421. #endif
  422. ,
  423. (PVOID *)(&((*CmView)->Bcb)),
  424. (PVOID *)(&((*CmView)->ViewAddress)) )) {
  425. Status = STATUS_CANT_WAIT;
  426. }
  427. } except (EXCEPTION_EXECUTE_HANDLER) {
  428. //
  429. // in low-memory scenarios, CcMapData throws a STATUS_IN_PAGE_ERROR
  430. // this happens when the IO issued to touch the just-mapped data fails (usually with
  431. // STATUS_INSUFFICIENT_RESOURCES; We want to catch this and treat as a
  432. // "not enough resources" problem, rather than letting it to surface the kernel call
  433. //
  434. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpMapCmView : CcMapData has raised :%08lx\n",GetExceptionCode()));
  435. Status = STATUS_INSUFFICIENT_RESOURCES;
  436. }
  437. if(!NT_SUCCESS(Status) ){
  438. if( FirstTry == TRUE ) {
  439. //
  440. // unmap all unneccessary views and try again
  441. //
  442. FirstTry = FALSE;
  443. CmpUnmapUnusedViews(CmHive);
  444. Status = STATUS_SUCCESS;
  445. goto RetryToMap;
  446. }
  447. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"Fail\n"));
  448. ASSERT(FALSE);
  449. return Status;
  450. }
  451. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"Succedeed Address = %p Size = %lx\n",(*CmView)->ViewAddress,(*CmView)->Size));
  452. (*CmView)->FileOffset = SectionOffset.LowPart;
  453. ASSERT( Offset == (*CmView)->FileOffset);
  454. AddressEnd = Address = (ULONG_PTR)((*CmView)->ViewAddress);
  455. AddressEnd += (*CmView)->Size;
  456. if( Offset == 0 ) {
  457. //
  458. // oops; we are at the beginning, we have to skip the base block
  459. //
  460. Address += HBLOCK_SIZE;
  461. } else {
  462. //
  463. // we are in the middle of the file. just adjust the offset
  464. //
  465. Offset -= HBLOCK_SIZE;
  466. }
  467. #ifdef CMP_CMVIEW_VALIDATION
  468. CmpCheckCmView(CmHive,*CmView);
  469. #endif //CMP_CMVIEW_VALIDATION
  470. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"CmpMapCmView :: Address = %p AddressEnd = %p ; Size = %lx\n",Address,AddressEnd,(*CmView)->Size));
  471. //
  472. // here we can optimize not to touch all the bins!!!
  473. //
  474. //
  475. // we don't know yet if the first bin is mapped.
  476. //
  477. PrevMappedBinSize = 0;
  478. BinAddress = Address;
  479. while(Address < AddressEnd)
  480. {
  481. Me = HvpGetCellMap(&(CmHive->Hive), Offset);
  482. VALIDATE_CELL_MAP(__LINE__,Me,&(CmHive->Hive),Offset);
  483. if( Me->BinAddress & HMAP_INPAGEDPOOL ) {
  484. //
  485. // if bin is mapped in paged pool for some reason,
  486. // leave it like that (don't alter it's mapping).
  487. //
  488. //
  489. // next mapped bin should start updating his bin address
  490. //
  491. PrevMappedBinSize = 0;
  492. } else {
  493. //
  494. // at this point the bin should be invalid.
  495. //
  496. ASSERT_BIN_INVALID(Me);
  497. Me->BinAddress |= HMAP_INVIEW;
  498. Me->CmView = *CmView;
  499. //
  500. // set the new BinAddress, but take care to preserve the flags
  501. //
  502. ASSERT( HBIN_FLAGS(Address) == 0 );
  503. //
  504. // new bins are Always tagged with this flag (we can start updating BinAddress)
  505. //
  506. if( MapInited && ( Me->BinAddress & HMAP_NEWALLOC ) ) {
  507. #ifdef CM_CHECK_MAP_NO_READ_SCHEME
  508. ASSERT( PrevMappedBinSize == 0 );
  509. //
  510. // Validate the bin
  511. //
  512. Bin = (PHBIN)Address;
  513. //ASSERT( Bin->Signature == HBIN_SIGNATURE );
  514. PrevMappedBinSize = (LONG)Bin->Size;
  515. #endif //CM_CHECK_MAP_NO_READ_SCHEME
  516. //
  517. // we are at the beginning of a new bin
  518. //
  519. BinAddress = Address;
  520. } else if( (!MapInited) &&(PrevMappedBinSize == 0) ) {
  521. //
  522. // we cannot rely on the map to cary the bin flags; we have to fault data in
  523. //
  524. //
  525. // Validate the bin
  526. //
  527. Bin = (PHBIN)Address;
  528. //ASSERT( Bin->Signature == HBIN_SIGNATURE );
  529. PrevMappedBinSize = (LONG)Bin->Size;
  530. //
  531. // we are at the beginning of a new bin
  532. //
  533. BinAddress = Address;
  534. }
  535. //
  536. // common sense
  537. //
  538. ASSERT( (!MapInited) || ((PrevMappedBinSize >=0) && (PrevMappedBinSize%HBLOCK_SIZE == 0)) );
  539. #ifdef CM_CHECK_MAP_NO_READ_SCHEME
  540. ASSERT( (PrevMappedBinSize >=0) && (PrevMappedBinSize%HBLOCK_SIZE == 0) );
  541. #endif //CM_CHECK_MAP_NO_READ_SCHEME
  542. Me->BinAddress = ( HBIN_BASE(BinAddress) | HBIN_FLAGS(Me->BinAddress) );
  543. if( (Me->BinAddress & HMAP_DISCARDABLE) == 0 ) {
  544. //
  545. // for discardable bins do not alter this member, as it contains
  546. // the address of the free bin
  547. //
  548. Me->BlockAddress = Address;
  549. }
  550. if( !MapInited ) {
  551. //
  552. // compute the remaining size of this bin; next iteration will update BinAddress only if
  553. // this variable reaches 0
  554. //
  555. PrevMappedBinSize -= HBLOCK_SIZE;
  556. } else {
  557. #ifdef CM_CHECK_MAP_NO_READ_SCHEME
  558. //
  559. // compute the remaining size of this bin; next iteration will update BinAddress only if
  560. // this variable reaches 0
  561. //
  562. PrevMappedBinSize -= HBLOCK_SIZE;
  563. #endif //CM_CHECK_MAP_NO_READ_SCHEME
  564. }
  565. ASSERT_BIN_INVIEW(Me);
  566. }
  567. Offset += HBLOCK_SIZE;
  568. Address += HBLOCK_SIZE;
  569. }
  570. return Status;
  571. }
  572. VOID
  573. CmpUnmapCmViewSurroundingOffset(
  574. IN PCMHIVE CmHive,
  575. IN ULONG FileOffset
  576. )
  577. /*++
  578. Routine Description:
  579. Parses the mapped view list and if it finds one surrounding this offest, unmaps it.
  580. Arguments:
  581. CmHive - Hive in question
  582. FileOffset - the offest in question
  583. Return Value:
  584. none
  585. Note:
  586. Offset is an absolute value,
  587. --*/
  588. {
  589. PCM_VIEW_OF_FILE CmView;
  590. USHORT NrViews;
  591. BOOLEAN UnMap = FALSE;
  592. PAGED_CODE();
  593. //
  594. // Walk through the LRU list and compare view addresses
  595. //
  596. CmView = (PCM_VIEW_OF_FILE)CmHive->LRUViewListHead.Flink;
  597. for(NrViews = CmHive->MappedViews;NrViews;NrViews--) {
  598. CmView = CONTAINING_RECORD( CmView,
  599. CM_VIEW_OF_FILE,
  600. LRUViewList);
  601. if( ((CmView->Size + CmView->FileOffset) != 0) && (CmView->ViewAddress != 0) ) {
  602. //
  603. // view is valid
  604. //
  605. if( (CmView->FileOffset <= FileOffset) && ((CmView->FileOffset + CmView->Size) > FileOffset) ) {
  606. //
  607. // the file offset is surrounded by this view
  608. //
  609. UnMap = TRUE;
  610. break;
  611. }
  612. }
  613. CmView = (PCM_VIEW_OF_FILE)CmView->LRUViewList.Flink;
  614. }
  615. if( UnMap == TRUE ) {
  616. // unmap the view anyway (this implies unpinning).
  617. ASSERT_VIEW_MAPPED( CmView );
  618. ASSERT( CmView->UseCount == 0 );
  619. CmpUnmapCmView(CmHive,CmView,TRUE,TRUE);
  620. }
  621. }
  622. PCM_VIEW_OF_FILE
  623. CmpAllocateCmView (
  624. IN PCMHIVE CmHive
  625. )
  626. /*++
  627. Routine Description:
  628. Allocate a CM-view.
  629. Insert it in various list.
  630. Arguments:
  631. CmHive - Hive in question
  632. Return Value:
  633. TBS - the new view
  634. --*/
  635. {
  636. PCM_VIEW_OF_FILE CmView;
  637. PAGED_CODE();
  638. CmView = ExAllocatePoolWithTag(PagedPool,sizeof(CM_VIEW_OF_FILE),CM_MAPPEDVIEW_TAG | PROTECTED_POOL);
  639. if (CmView == NULL) {
  640. //
  641. // we're low on resources; we should handle the error path for this.
  642. //
  643. return NULL;
  644. }
  645. //
  646. // Init the view
  647. //
  648. CmView->FileOffset = 0;
  649. CmView->Size = 0;
  650. CmView->ViewAddress = NULL;
  651. CmView->Bcb = NULL;
  652. CmView->UseCount =0;
  653. //
  654. // add it to the list(s)
  655. //
  656. InitializeListHead(&(CmView->PinViewList));
  657. InsertTailList(
  658. &(CmHive->LRUViewListHead),
  659. &(CmView->LRUViewList)
  660. );
  661. CmHive->MappedViews++;
  662. return CmView;
  663. }
  664. VOID
  665. CmpInitHiveViewList (
  666. IN PCMHIVE CmHive
  667. )
  668. /*++
  669. Routine Description:
  670. adds the first view to the LRU list.
  671. others are added as needed.!
  672. Arguments:
  673. CmHive - Hive in question
  674. Return Value:
  675. TBS - status of the operation
  676. --*/
  677. {
  678. PAGED_CODE();
  679. //
  680. // Init the heads.
  681. //
  682. InitializeListHead(&(CmHive->PinViewListHead));
  683. InitializeListHead(&(CmHive->LRUViewListHead));
  684. #if 0
  685. InitializeListHead(&(CmHive->FakeViewListHead));
  686. CmHive->FakeViews = 0;
  687. #endif
  688. CmHive->MappedViews = 0;
  689. CmHive->PinnedViews = 0;
  690. CmHive->UseCount = 0;
  691. }
  692. VOID
  693. CmpDestroyHiveViewList (
  694. IN PCMHIVE CmHive
  695. )
  696. /*++
  697. Routine Description:
  698. Frees the storage fo all the views used by this hive
  699. Arguments:
  700. CmHive - Hive in question
  701. Purge - whether to purge the cache or not.
  702. Return Value:
  703. TBS - status of the operation
  704. --*/
  705. {
  706. PCM_VIEW_OF_FILE CmView;
  707. PAGED_CODE();
  708. if( CmHive->FileObject == NULL ) {
  709. //
  710. // hive is not mapped.
  711. //
  712. return;
  713. }
  714. #if 0
  715. //
  716. // get rid of fake views first; we shouldn't have any fake views here, unless we are on
  717. // some error path (the hive is corrupted).
  718. //
  719. CmpUnmapFakeViews(CmHive);
  720. #endif
  721. //
  722. // Walk through the Pinned View list and free all the views
  723. //
  724. while( IsListEmpty( &(CmHive->PinViewListHead) ) == FALSE ) {
  725. CmView = (PCM_VIEW_OF_FILE)RemoveHeadList(&(CmHive->PinViewListHead));
  726. CmView = CONTAINING_RECORD( CmView,
  727. CM_VIEW_OF_FILE,
  728. PinViewList);
  729. ASSERT_VIEW_PINNED(CmView);
  730. //
  731. // we need to move this view to the mapped view list and remember to purge after all
  732. // views have been unmapped. Otherwise we rick deadlock on CcWaitOnActiveCount, when we purge
  733. //
  734. //
  735. // sanity check; we shouldn't get here for a read-only hive
  736. //
  737. ASSERT( CmHive->Hive.ReadOnly == FALSE );
  738. //
  739. // empty the LRUList for this view
  740. //
  741. InitializeListHead(&(CmView->PinViewList));
  742. //
  743. // update the counters
  744. //
  745. CmHive->PinnedViews--;
  746. CmHive->MappedViews++;
  747. //
  748. // add it at the tail of LRU list for this hive
  749. //
  750. InsertTailList(
  751. &(CmHive->LRUViewListHead),
  752. &(CmView->LRUViewList)
  753. );
  754. }
  755. //
  756. // At this point, there should be no pinned view
  757. //
  758. ASSERT( IsListEmpty(&(CmHive->PinViewListHead)) == TRUE);
  759. ASSERT( CmHive->PinnedViews == 0 );
  760. //
  761. // Walk through the LRU list and free all the views
  762. //
  763. while( IsListEmpty( &(CmHive->LRUViewListHead) ) == FALSE ) {
  764. CmView = (PCM_VIEW_OF_FILE)CmHive->LRUViewListHead.Flink;
  765. CmView = CONTAINING_RECORD( CmView,
  766. CM_VIEW_OF_FILE,
  767. LRUViewList);
  768. if( CmView->ViewAddress != 0 ) {
  769. //
  770. // view is mapped; unmap it
  771. // we should not encounter that in sane systems
  772. // this can happen only when a hive-loading fails
  773. // in HvpMapFileImageAndBuildMap
  774. // no need move it as we are going to free it anyway
  775. //
  776. CmpUnmapCmView(CmHive,CmView,FALSE,FALSE);
  777. }
  778. //
  779. // update the counter
  780. //
  781. CmHive->MappedViews--;
  782. //
  783. // remove the view from the LRU list
  784. //
  785. RemoveEntryList(&(CmView->LRUViewList));
  786. ExFreePoolWithTag(CmView, CM_MAPPEDVIEW_TAG | PROTECTED_POOL);
  787. }
  788. ASSERT( CmHive->MappedViews == 0 );
  789. ASSERT( CmHive->UseCount == 0 );
  790. //
  791. // we need to purge as the FS cannot do it for us (private writers)
  792. // valid data is already on the disk by now (it should!)
  793. // purge and flush everything
  794. //
  795. CcPurgeCacheSection(CmHive->FileObject->SectionObjectPointer,(PLARGE_INTEGER)(((ULONG_PTR)NULL) + 1)/*we are private writers*/,0/*ignored*/,FALSE);
  796. //
  797. // This is for the case where the last flush failed (we couldn't write the log file....)
  798. // .... then : flush the cache to clear dirty hints added by the purge
  799. //
  800. CcFlushCache (CmHive->FileObject->SectionObjectPointer,(PLARGE_INTEGER)(((ULONG_PTR)NULL) + 1)/*we are private writers*/,0/*ignored*/,NULL);
  801. //
  802. // Flush again to take care of the dirty pages that may appear due to FS page zeroing
  803. //
  804. CcFlushCache (CmHive->FileObject->SectionObjectPointer,(PLARGE_INTEGER)(((ULONG_PTR)NULL) + 1)/*we are private writers*/,0/*ignored*/,NULL);
  805. #ifdef CM_TRACK_DIRTY_PAGES
  806. if( ((PSHARED_CACHE_MAP)(CmHive->FileObject->SectionObjectPointer->SharedCacheMap))->DirtyPages != 0 ) {
  807. DbgPrint("SharedCacheMap still has dirty pages after purge and flush; FileObject = %p \n",CmHive->FileObject);
  808. DbgBreakPoint();
  809. }
  810. #endif //CM_TRACK_DIRTY_PAGES
  811. }
  812. VOID
  813. CmpDropFileObjectForHive(
  814. IN PCMHIVE CmHive
  815. )
  816. /*++
  817. Routine Description:
  818. Drops the extra reference kept on the file object (if any)
  819. and frees the name
  820. Arguments:
  821. CmHive
  822. Return Value:
  823. none
  824. --*/
  825. {
  826. PAGED_CODE();
  827. if( CmHive->FileUserName.Buffer != NULL ) {
  828. ExFreePoolWithTag(CmHive->FileUserName.Buffer, CM_NAME_TAG | PROTECTED_POOL);
  829. CmHive->FileUserName.Buffer = NULL;
  830. CmHive->FileUserName.Length = 0;
  831. CmHive->FileUserName.MaximumLength = 0;
  832. } else {
  833. ASSERT(CmHive->FileUserName.Length == 0);
  834. ASSERT(CmHive->FileUserName.MaximumLength == 0);
  835. }
  836. if( CmHive->FileObject == NULL ) {
  837. // debug only code
  838. ASSERT(CmHive->FileFullPath.Buffer == NULL);
  839. ASSERT(CmHive->FileFullPath.Length == 0);
  840. ASSERT(CmHive->FileFullPath.MaximumLength == 0);
  841. return;
  842. }
  843. // debug only code
  844. if( CmHive->FileFullPath.Buffer != NULL ) {
  845. ExFreePoolWithTag(CmHive->FileFullPath.Buffer, CM_NAME_TAG | PROTECTED_POOL);
  846. CmHive->FileFullPath.Buffer = NULL;
  847. CmHive->FileFullPath.Length = 0;
  848. CmHive->FileFullPath.MaximumLength = 0;
  849. } else {
  850. ASSERT(CmHive->FileFullPath.Length == 0);
  851. ASSERT(CmHive->FileFullPath.MaximumLength == 0);
  852. }
  853. ObDereferenceObject((PVOID)(CmHive->FileObject));
  854. CmHive->FileObject = NULL;
  855. }
  856. NTSTATUS
  857. CmpAquireFileObjectForFile(
  858. IN PCMHIVE CmHive,
  859. IN HANDLE FileHandle,
  860. OUT PFILE_OBJECT *FileObject
  861. )
  862. /*++
  863. Routine Description:
  864. Creates the section for the given file handle.
  865. the section is used to map/unmap views of the file
  866. Arguments:
  867. FileHandle - Handle of the file
  868. SectionPointer - the section object
  869. Return Value:
  870. TBS - status of the operation
  871. --*/
  872. {
  873. NTSTATUS Status,Status2;
  874. IO_STATUS_BLOCK IoStatus;
  875. POBJECT_NAME_INFORMATION FileNameInfo;
  876. ULONG ReturnedLength;
  877. ULONG FileNameLength;
  878. PAGED_CODE();
  879. Status = ObReferenceObjectByHandle ( FileHandle,
  880. FILE_READ_DATA | FILE_WRITE_DATA,
  881. IoFileObjectType,
  882. KernelMode,
  883. (PVOID *)FileObject,
  884. NULL );
  885. if (!NT_SUCCESS(Status)) {
  886. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"[CmpAquireFileObjectForFile] Could not reference file object status = %x\n",Status));
  887. } else {
  888. //
  889. // call cc private to mark the stream as Modify-No-Write
  890. //
  891. if( !CcSetPrivateWriteFile(*FileObject) ) {
  892. //
  893. // filter out invalid failures to initialize the cache
  894. // top-level routine CmpInitHiveFromFile will retry to load the hive in the old fashion way.
  895. //
  896. CmpDropFileObjectForHive(CmHive);
  897. (*FileObject) = NULL;
  898. return STATUS_RETRY;
  899. }
  900. LOCK_STASH_BUFFER();
  901. //
  902. // capture the full path of the file
  903. //
  904. ASSERT( CmpStashBuffer != NULL );
  905. FileNameInfo = (POBJECT_NAME_INFORMATION)CmpStashBuffer;
  906. //
  907. // we need to protect against multiple threads using the stash buffer
  908. // this could happen only during the paralel hive loading at boot
  909. //
  910. LOCK_HIVE_LIST();
  911. //
  912. // Try to get the name for the file object.
  913. //
  914. Status2 = ObQueryNameString(*FileObject,
  915. FileNameInfo,
  916. CmpStashBufferSize,
  917. &ReturnedLength);
  918. if (NT_SUCCESS(Status2)) {
  919. //
  920. // Allocate a file name buffer and copy into it.
  921. // The file names will be NUL terminated. Allocate extra for that.
  922. //
  923. FileNameLength = FileNameInfo->Name.Length / sizeof(WCHAR);
  924. CmHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool,
  925. (FileNameLength + 1) * sizeof(WCHAR),
  926. CM_NAME_TAG | PROTECTED_POOL);
  927. if (CmHive->FileFullPath.Buffer) {
  928. RtlCopyMemory(CmHive->FileFullPath.Buffer,
  929. FileNameInfo->Name.Buffer,
  930. FileNameLength * sizeof(WCHAR));
  931. //
  932. // Make sure it is NUL terminated.
  933. //
  934. CmHive->FileFullPath.Buffer[FileNameLength] = 0;
  935. CmHive->FileFullPath.Length = FileNameInfo->Name.Length;
  936. CmHive->FileFullPath.MaximumLength = FileNameInfo->Name.Length + sizeof(WCHAR);
  937. } else {
  938. //
  939. // not fatal, just that we won't be able to prefetch this hive
  940. //
  941. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"[CmpAquireFileObjectForFile] Could not allocate buffer for fullpath for fileobject %p\n",*FileObject));
  942. }
  943. } else {
  944. //
  945. // not fatal, just that we won't be able to prefetch this hive
  946. //
  947. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"[CmpAquireFileObjectForFile] Could not retrieve name for fileobject %p, Status = %lx\n",*FileObject,Status2));
  948. CmHive->FileFullPath.Buffer = NULL;
  949. }
  950. UNLOCK_HIVE_LIST();
  951. UNLOCK_STASH_BUFFER();
  952. }
  953. return Status;
  954. }
  955. NTSTATUS
  956. CmpMapThisBin(
  957. PCMHIVE CmHive,
  958. HCELL_INDEX Cell,
  959. BOOLEAN Touch
  960. )
  961. /*++
  962. Routine Description:
  963. Makes sure the bin is mapped in memory.
  964. Arguments:
  965. Return Value:
  966. --*/
  967. {
  968. PCM_VIEW_OF_FILE CmView;
  969. PAGED_CODE();
  970. //
  971. // ViewLock must be held
  972. //
  973. //
  974. // bin is either mapped, or invalid
  975. //
  976. ASSERT( HvGetCellType(Cell) == Stable );
  977. //
  978. // map the bin
  979. //
  980. if( !NT_SUCCESS (CmpMapCmView(CmHive,Cell,&CmView,TRUE) ) ) {
  981. return STATUS_INSUFFICIENT_RESOURCES;
  982. }
  983. if( Touch == TRUE ) {
  984. //
  985. // touch the view
  986. //
  987. CmpTouchView(CmHive,CmView,(ULONG)Cell);
  988. } else {
  989. //
  990. // if we are here; we should have either the reg lock exclusive
  991. // or the reg lock shared AND the hive lock.
  992. // Find a way to assert that!!!
  993. //
  994. }
  995. return STATUS_SUCCESS;
  996. }
  997. NTSTATUS
  998. CmpPinCmView (
  999. IN PCMHIVE CmHive,
  1000. PCM_VIEW_OF_FILE CmView
  1001. )
  1002. /*++
  1003. Routine Description:
  1004. Pins the specified view into memory
  1005. The view is removed from the LRU list.
  1006. Then, the view is moved to the PinList
  1007. Arguments:
  1008. CmHive - Hive in question
  1009. CmView - View in question
  1010. Return Value:
  1011. TBS - the new view
  1012. --*/
  1013. {
  1014. LARGE_INTEGER SectionOffset;
  1015. NTSTATUS Status = STATUS_SUCCESS;
  1016. PVOID SaveBcb;
  1017. PAGED_CODE();
  1018. #if DBG
  1019. {
  1020. UNICODE_STRING HiveName;
  1021. RtlInitUnicodeString(&HiveName, (PCWSTR)CmHive->Hive.BaseBlock->FileName);
  1022. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"CmpPinCmView %lx for hive (%p) (%.*S), Address = %p Size = %lx\n",CmView,CmHive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,CmView->ViewAddress,CmView->Size));
  1023. }
  1024. #endif
  1025. //
  1026. // We only pin mapped views
  1027. //
  1028. ASSERT_VIEW_MAPPED(CmView);
  1029. //
  1030. // sanity check; we shouldn't get here for a read-only hive
  1031. //
  1032. ASSERT( CmHive->Hive.ReadOnly == FALSE );
  1033. // we may need this later
  1034. SaveBcb = CmView->Bcb;
  1035. SectionOffset.LowPart = CmView->FileOffset;
  1036. SectionOffset.HighPart = 0;
  1037. try {
  1038. //
  1039. // the MOST important: pin the view
  1040. //
  1041. if( !CcPinMappedData( CmHive->FileObject,
  1042. &SectionOffset,
  1043. CmView->Size,
  1044. TRUE, // wait == syncronous call
  1045. &(CmView->Bcb) )) {
  1046. //
  1047. // this should never happen; handle it, though
  1048. //
  1049. ASSERT( FALSE );
  1050. Status = STATUS_INSUFFICIENT_RESOURCES;
  1051. }
  1052. } except (EXCEPTION_EXECUTE_HANDLER) {
  1053. //
  1054. // in low-memory scenarios, CcPinMappedData throws a STATUS_INSUFFICIENT_RESOURCES
  1055. // We want to catch this and treat as a "not enough resources" problem,
  1056. // rather than letting it to surface the kernel call
  1057. //
  1058. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpPinCmView : CcPinMappedData has raised :%08lx\n",GetExceptionCode()));
  1059. Status = STATUS_INSUFFICIENT_RESOURCES;
  1060. }
  1061. if( NT_SUCCESS(Status) ) {
  1062. //
  1063. // Pin succeeded, move the view to the pinned list
  1064. // remove the view from the LRU list
  1065. //
  1066. RemoveEntryList(&(CmView->LRUViewList));
  1067. //
  1068. // empty the LRUList for this view
  1069. //
  1070. InitializeListHead(&(CmView->LRUViewList));
  1071. //
  1072. // add it at the tail of pinned list for this hive
  1073. //
  1074. InsertTailList(
  1075. &(CmHive->PinViewListHead),
  1076. &(CmView->PinViewList)
  1077. );
  1078. //
  1079. // update the counters
  1080. //
  1081. CmHive->MappedViews--;
  1082. CmHive->PinnedViews++;
  1083. } else {
  1084. //
  1085. // pin failed; we need to restore view data that may have been altered by the pin call
  1086. // view will remain mapped
  1087. //
  1088. CmView->Bcb = SaveBcb;
  1089. }
  1090. // make sure we didn't unmapped/punned more than we mapped/pinned
  1091. ASSERT( (CmHive->MappedViews >= 0) ); // && (CmHive->MappedViews < CmMaxViewsPerHive) );
  1092. ASSERT( (CmHive->PinnedViews >= 0) );
  1093. #ifdef CMP_CMVIEW_VALIDATION
  1094. CmpCheckCmView(CmHive,CmView);
  1095. #endif //CMP_CMVIEW_VALIDATION
  1096. return Status;
  1097. }
  1098. VOID
  1099. CmpUnPinCmView (
  1100. IN PCMHIVE CmHive,
  1101. IN PCM_VIEW_OF_FILE CmView,
  1102. IN BOOLEAN SetClean,
  1103. IN BOOLEAN MapValid
  1104. )
  1105. /*++
  1106. Routine Description:
  1107. UnPins the specified view from memory
  1108. The view is NOT in the PinViewList !!! (it has already been removed !!!!!!)
  1109. Then, the view is moved to the LRUList.
  1110. If more than CmMaxViewsPerHive are in LRU list, the view is freed
  1111. This function always grabs the ViewLock for the hive!!!
  1112. Arguments:
  1113. CmHive - Hive in question
  1114. CmView - View in question
  1115. SetClean - Tells whether the changes made to this view should be discarded
  1116. Return Value:
  1117. TBS - the new view
  1118. --*/
  1119. {
  1120. LARGE_INTEGER FileOffset; // where the mapping starts
  1121. ULONG Size; // size the view maps
  1122. PAGED_CODE();
  1123. #if 0 // this gave me a lot of headaches
  1124. {
  1125. UNICODE_STRING HiveName;
  1126. RtlInitUnicodeString(&HiveName, (PCWSTR)CmHive->Hive.BaseBlock->FileName);
  1127. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"CmpUnPinCmView %lx for hive (%p) (%.*S), Address = %p Size = %lx\n",CmView,CmHive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,CmView->ViewAddress,CmView->Size));
  1128. }
  1129. #endif
  1130. //
  1131. // Grab the viewLock, to protect the viewlist
  1132. //
  1133. CmLockHiveViews (CmHive);
  1134. //
  1135. // We only pin mapped views
  1136. //
  1137. ASSERT_VIEW_PINNED(CmView);
  1138. //
  1139. // sanity check; we shouldn't get here for a read-only hive
  1140. //
  1141. ASSERT( CmHive->Hive.ReadOnly == FALSE );
  1142. //
  1143. // empty the LRUList for this view
  1144. //
  1145. InitializeListHead(&(CmView->PinViewList));
  1146. //
  1147. // update the counters
  1148. //
  1149. CmHive->PinnedViews--;
  1150. CmHive->MappedViews++;
  1151. //
  1152. // add it at the tail of LRU list for this hive
  1153. //
  1154. InsertTailList(
  1155. &(CmHive->LRUViewListHead),
  1156. &(CmView->LRUViewList)
  1157. );
  1158. //
  1159. // store the FileOffset and size as we will need them for purging
  1160. //
  1161. FileOffset.LowPart = CmView->FileOffset;
  1162. FileOffset.HighPart = 0;
  1163. Size = CmView->Size;
  1164. if( SetClean == TRUE ) {
  1165. ASSERT( CmView->UseCount == 0 );
  1166. //
  1167. // unmap the view (this implies unpinning).
  1168. //
  1169. CmpUnmapCmView(CmHive,CmView,MapValid,TRUE);
  1170. //
  1171. // purge cache data
  1172. //
  1173. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1174. CcPurgeCacheSection(CmHive->FileObject->SectionObjectPointer,(PLARGE_INTEGER)(((ULONG_PTR)(&FileOffset)) + 1)/*we are private writers*/,Size,FALSE);
  1175. } else {
  1176. PVOID NewBcb;
  1177. PULONG_PTR NewViewAddress;
  1178. NTSTATUS Status = STATUS_SUCCESS;
  1179. //
  1180. // the data is to be saved to the file,
  1181. // notify the cache manager that the data is dirty
  1182. //
  1183. CcSetDirtyPinnedData (CmView->Bcb,NULL);
  1184. //
  1185. // remap this view so we don't lose the refcount on this address range
  1186. //
  1187. try {
  1188. if (!CcMapData( CmHive->FileObject,
  1189. (PLARGE_INTEGER)&FileOffset,
  1190. CmView->Size,
  1191. MAP_WAIT
  1192. #ifdef CM_MAP_NO_READ
  1193. | MAP_NO_READ
  1194. #endif
  1195. ,
  1196. (PVOID *)(&NewBcb),
  1197. (PVOID *)(&NewViewAddress) )) {
  1198. Status = STATUS_CANT_WAIT;
  1199. }
  1200. } except (EXCEPTION_EXECUTE_HANDLER) {
  1201. //
  1202. // in low-memory scenarios, CcMapData throws a STATUS_IN_PAGE_ERROR
  1203. // this happens when the IO issued to touch the just-mapped data fails (usually with
  1204. // STATUS_INSUFFICIENT_RESOURCES; We want to catch this and treat as a
  1205. // "not enough resources" problem, rather than letting it to surface the kernel call
  1206. //
  1207. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpUnPinCmView : CcMapData has raised :%08lx\n",GetExceptionCode()));
  1208. Status = STATUS_INSUFFICIENT_RESOURCES;
  1209. }
  1210. if( !NT_SUCCESS(Status) ) {
  1211. //
  1212. // CcMap didn't succeeded; bad luck, just unmap (implies unpinning).
  1213. //
  1214. CmpUnmapCmView(CmHive,CmView,MapValid,TRUE);
  1215. } else {
  1216. BOOLEAN FoundView = FALSE;
  1217. //
  1218. // sanity asserts; Cc guarantees the same address is returned.
  1219. //
  1220. ASSERT( FileOffset.LowPart == CmView->FileOffset );
  1221. ASSERT( NewViewAddress == CmView->ViewAddress );
  1222. //
  1223. // unpin old data
  1224. //
  1225. CcUnpinData( CmView->Bcb );
  1226. //
  1227. // replace the bcb for this view; there is no need to modify the map as the
  1228. // address and the size of the view remains the same; We just need to update the bcb
  1229. //
  1230. CmView->Bcb = NewBcb;
  1231. //
  1232. // move the view on top of the LRU list (consider it as "hot")
  1233. //
  1234. RemoveEntryList(&(CmView->LRUViewList));
  1235. InsertHeadList(
  1236. &(CmHive->LRUViewListHead),
  1237. &(CmView->LRUViewList)
  1238. );
  1239. //
  1240. // walk the LRU list back-wards until we find an unused view
  1241. //
  1242. CmView = (PCM_VIEW_OF_FILE)CmHive->LRUViewListHead.Blink;
  1243. CmView = CONTAINING_RECORD( CmView,
  1244. CM_VIEW_OF_FILE,
  1245. LRUViewList);
  1246. while( CmView->LRUViewList.Blink != CmHive->LRUViewListHead.Flink ) {
  1247. if( CmView->UseCount == 0 ) {
  1248. //
  1249. // this one is free go ahead and use it !
  1250. // first unmap, then signal that we found it
  1251. //
  1252. if( (CmHive->MappedViews >= CmMaxViewsPerHive) && (CmView->Bcb != NULL) ) {
  1253. CmpUnmapCmView(CmHive,CmView,MapValid,TRUE);
  1254. }
  1255. FoundView = TRUE;
  1256. break;
  1257. }
  1258. CmView = (PCM_VIEW_OF_FILE)CmView->LRUViewList.Blink;
  1259. CmView = CONTAINING_RECORD( CmView,
  1260. CM_VIEW_OF_FILE,
  1261. LRUViewList);
  1262. }
  1263. //
  1264. // all views are in use; bad luck, we just have to live with it (extend past MAX_VIEW_SIZE)
  1265. //
  1266. if( FoundView == FALSE ) {
  1267. CmView = NULL;
  1268. }
  1269. }
  1270. }
  1271. //
  1272. // immediately flush the cache so these dirty pages won't throttle other IOs
  1273. // in case we did a CcPurge, this will clean out the Cc dirty hints.
  1274. //
  1275. CcFlushCache (CmHive->FileObject->SectionObjectPointer,(PLARGE_INTEGER)(((ULONG_PTR)(&FileOffset)) + 1)/*we are private writers*/,Size,NULL);
  1276. if( (CmHive->MappedViews >= CmMaxViewsPerHive) && (CmView != NULL) ) {
  1277. // assert view unmapped
  1278. ASSERT( ((CmView->FileOffset + CmView->Size) == 0) && (CmView->ViewAddress == 0) );
  1279. //
  1280. // no more views are allowed for this hive
  1281. //
  1282. RemoveEntryList(&(CmView->LRUViewList));
  1283. #if DBG
  1284. //
  1285. // do this to signal that LRUViewList is empty.
  1286. //
  1287. InitializeListHead(&(CmView->LRUViewList));
  1288. #endif
  1289. CmpFreeCmView(CmView);
  1290. CmHive->MappedViews --;
  1291. }
  1292. // make sure we didn't unmapped/unpinned more than we mapped/pinned
  1293. ASSERT( (CmHive->MappedViews >= 0) ); // && (CmHive->MappedViews < CmMaxViewsPerHive) );
  1294. ASSERT( (CmHive->PinnedViews >= 0) );
  1295. //
  1296. // at last, release the view lock
  1297. //
  1298. CmUnlockHiveViews (CmHive);
  1299. return;
  1300. }
  1301. VOID
  1302. CmpFreeCmView (
  1303. PCM_VIEW_OF_FILE CmView
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. frees a CM View
  1308. Arguments:
  1309. Return Value:
  1310. TBS - the new view
  1311. --*/
  1312. {
  1313. PAGED_CODE();
  1314. if (CmView == NULL) {
  1315. CM_BUGCHECK(REGISTRY_ERROR,CMVIEW_ERROR,2,0,0);
  1316. }
  1317. //
  1318. // Init the view
  1319. //
  1320. ASSERT( CmView->FileOffset == 0 );
  1321. ASSERT( CmView->Size == 0 );
  1322. ASSERT( CmView->ViewAddress == NULL );
  1323. ASSERT( CmView->Bcb == NULL );
  1324. ASSERT( CmView->UseCount == 0 );
  1325. ASSERT( IsListEmpty(&(CmView->PinViewList)) == TRUE );
  1326. ASSERT( IsListEmpty(&(CmView->LRUViewList)) == TRUE );
  1327. ExFreePoolWithTag(CmView, CM_MAPPEDVIEW_TAG | PROTECTED_POOL);
  1328. return;
  1329. }
  1330. VOID
  1331. CmpFixHiveUsageCount(
  1332. IN PCMHIVE CmHive
  1333. )
  1334. /*++
  1335. Routine Description:
  1336. This is registry's contingency plan against bad and misbehaved apps.
  1337. In a perfect world this should never be called; If we get here, somewhere
  1338. inside a cm function we took an exception and never had a chance to
  1339. release all used cells. We fix that here, and as we hold the reglock exclusive,
  1340. we are safe to do so.
  1341. We have to clear each view UseCount and the hive UseCount.
  1342. Also, unmap all views that are beyond CmMaxViewsPerHive
  1343. Arguments:
  1344. Hive to be fixed
  1345. Return Value:
  1346. none
  1347. --*/
  1348. {
  1349. PCM_VIEW_OF_FILE CmCurrentView;
  1350. USHORT NrViews;
  1351. PAGED_CODE();
  1352. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmpFixHiveUsageCount : Contingency plan, fixing hive %p UseCount = %lx \n",CmHive,CmHive->UseCount));
  1353. //
  1354. // lock should be held exclusive and we should have a good reason to come here
  1355. //
  1356. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1357. ASSERT( CmHive->UseCount );
  1358. //
  1359. // Walk through the LRU list and fix each view
  1360. //
  1361. CmCurrentView = (PCM_VIEW_OF_FILE)CmHive->LRUViewListHead.Flink;
  1362. for(NrViews = CmHive->MappedViews;NrViews;NrViews--) {
  1363. CmCurrentView = CONTAINING_RECORD( CmCurrentView,
  1364. CM_VIEW_OF_FILE,
  1365. LRUViewList);
  1366. CmCurrentView->UseCount = 0;
  1367. CmCurrentView = (PCM_VIEW_OF_FILE)CmCurrentView->LRUViewList.Flink;
  1368. }
  1369. //
  1370. // unmap views from CmHive->MappedViews to CmMaxViewsPerHive
  1371. //
  1372. while( CmHive->MappedViews >= CmMaxViewsPerHive ) {
  1373. //
  1374. // get the last view from the list
  1375. //
  1376. CmCurrentView = (PCM_VIEW_OF_FILE)CmHive->LRUViewListHead.Blink;
  1377. CmCurrentView = CONTAINING_RECORD( CmCurrentView,
  1378. CM_VIEW_OF_FILE,
  1379. LRUViewList);
  1380. //
  1381. // unmap it; no need to move it at the end as we shall free it anyway
  1382. //
  1383. CmpUnmapCmView(CmHive,CmCurrentView,TRUE,FALSE);
  1384. //
  1385. // remove it from LRU list
  1386. //
  1387. RemoveEntryList(&(CmCurrentView->LRUViewList));
  1388. #if DBG
  1389. //
  1390. // do this to signal that LRUViewList is empty.
  1391. //
  1392. InitializeListHead(&(CmCurrentView->LRUViewList));
  1393. #endif
  1394. CmpFreeCmView(CmCurrentView);
  1395. CmHive->MappedViews --;
  1396. }
  1397. //
  1398. // Walk through the pinned list and fix each view
  1399. //
  1400. CmCurrentView = (PCM_VIEW_OF_FILE)CmHive->PinViewListHead.Flink;
  1401. for(NrViews = CmHive->PinnedViews;NrViews;NrViews--) {
  1402. CmCurrentView = CONTAINING_RECORD( CmCurrentView,
  1403. CM_VIEW_OF_FILE,
  1404. PinViewList);
  1405. CmCurrentView->UseCount = 0;
  1406. CmCurrentView = (PCM_VIEW_OF_FILE)CmCurrentView->PinViewList.Flink;
  1407. }
  1408. //
  1409. // finally, fix hive use count
  1410. //
  1411. CmHive->UseCount = 0;
  1412. }
  1413. #ifdef CMP_CMVIEW_VALIDATION
  1414. VOID
  1415. CmpCheckCmView(
  1416. IN PCMHIVE CmHive,
  1417. IN PCM_VIEW_OF_FILE CmView
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. Makes sure the view is not mapped or pinned twice
  1422. and that the entire range mapped by the view is correct
  1423. Arguments:
  1424. Return Value:
  1425. none
  1426. --*/
  1427. {
  1428. PCM_VIEW_OF_FILE CmCurrentView;
  1429. USHORT NrViews;
  1430. ULONG UseCount = 0;
  1431. PAGED_CODE();
  1432. ASSERT( ((CmView->Size + CmView->FileOffset) != 0 ) && (CmView->ViewAddress !=0 ) );
  1433. //
  1434. // Walk through the LRU list and compare view addresses
  1435. //
  1436. CmCurrentView = (PCM_VIEW_OF_FILE)CmHive->LRUViewListHead.Flink;
  1437. for(NrViews = CmHive->MappedViews;NrViews;NrViews--) {
  1438. CmCurrentView = CONTAINING_RECORD( CmCurrentView,
  1439. CM_VIEW_OF_FILE,
  1440. LRUViewList);
  1441. if( ((CmCurrentView->Size + CmCurrentView->FileOffset) != 0) && (CmCurrentView->ViewAddress != 0) ) {
  1442. //
  1443. // view is valid
  1444. //
  1445. if( CmCurrentView != CmView ) {
  1446. //
  1447. // and is not the same view
  1448. //
  1449. if( (CmCurrentView->FileOffset == CmView->FileOffset) ||
  1450. (CmCurrentView->ViewAddress == CmView->ViewAddress)
  1451. ) {
  1452. //
  1453. // that's really bad! 2 views map the same address
  1454. //
  1455. #ifndef _CM_LDR_
  1456. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckCmView:: Two views map the same address (%lx,%p) for hive %p\n",CmView->FileOffset,CmView->ViewAddress,CmHive);
  1457. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tView1 = %p, Size = %lx\n",CmView,CmView->Size);
  1458. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tView2 = %p, Size = %lx\n",CmCurrentView,CmCurrentView->Size);
  1459. DbgBreakPoint();
  1460. #endif //_CM_LDR_
  1461. }
  1462. }
  1463. UseCount += CmCurrentView->UseCount;
  1464. } else {
  1465. ASSERT( CmCurrentView->UseCount == 0 );
  1466. }
  1467. CmCurrentView = (PCM_VIEW_OF_FILE)CmCurrentView->LRUViewList.Flink;
  1468. }
  1469. //
  1470. // Walk through the pinned list and compare view addresses
  1471. //
  1472. CmCurrentView = (PCM_VIEW_OF_FILE)CmHive->PinViewListHead.Flink;
  1473. for(NrViews = CmHive->PinnedViews;NrViews;NrViews--) {
  1474. CmCurrentView = CONTAINING_RECORD( CmCurrentView,
  1475. CM_VIEW_OF_FILE,
  1476. PinViewList);
  1477. if( ((CmCurrentView->Size + CmCurrentView->FileOffset) != 0) && (CmCurrentView->ViewAddress != 0) ) {
  1478. //
  1479. // view is valid
  1480. //
  1481. if( CmCurrentView != CmView ) {
  1482. //
  1483. // and is not the same view
  1484. //
  1485. if( (CmCurrentView->FileOffset == CmView->FileOffset) ||
  1486. (CmCurrentView->ViewAddress == CmView->ViewAddress)
  1487. ) {
  1488. //
  1489. // that's really bad! 2 views map the same address
  1490. //
  1491. #ifndef _CM_LDR_
  1492. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckCmView:: Two views map the same address (%lx,%p) for hive %p\n",CmView->FileOffset,CmView->ViewAddress,CmHive);
  1493. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tView1 = %p, Size = %lx\n",CmView,CmView->Size);
  1494. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tView2 = %p, Size = %lx\n",CmCurrentView,CmCurrentView->Size);
  1495. DbgBreakPoint();
  1496. #endif //_CM_LDR_
  1497. }
  1498. }
  1499. UseCount += CmCurrentView->UseCount;
  1500. } else {
  1501. ASSERT( CmCurrentView->UseCount == 0 );
  1502. }
  1503. CmCurrentView = (PCM_VIEW_OF_FILE)CmCurrentView->PinViewList.Flink;
  1504. }
  1505. if( CmHive->UseCount < UseCount ) {
  1506. #ifndef _CM_LDR_
  1507. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckCmView:: Hive's (%p) UseCount smaller than total views UseCount %lu,%lu\n",CmHive,CmHive->UseCount,UseCount);
  1508. DbgBreakPoint();
  1509. #endif //_CM_LDR_
  1510. }
  1511. }
  1512. #endif //CMP_CMVIEW_VALIDATION
  1513. #if 0
  1514. VOID
  1515. CmpUnmapAditionalViews(
  1516. IN PCMHIVE CmHive
  1517. )
  1518. /*++
  1519. Routine Description:
  1520. Unmap all views that are beyond CmMaxViewsPerHive.
  1521. This routine is to be called at the end of CmpInitializeHiveList
  1522. Arguments:
  1523. Hive to be fixed
  1524. Return Value:
  1525. none
  1526. --*/
  1527. {
  1528. PCM_VIEW_OF_FILE CmCurrentView;
  1529. USHORT NrViews;
  1530. PAGED_CODE();
  1531. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmpUnmapAditionalViews : Fixing hive %p MappedViews = %lx \n",CmHive,CmHive->MappedViews));
  1532. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1533. ASSERT( CmHive->UseCount == 0 );
  1534. //
  1535. // unmap views from CmHive->MappedViews to CmMaxViewsPerHive
  1536. //
  1537. while( CmHive->MappedViews >= CmMaxViewsPerHive ) {
  1538. //
  1539. // get the last view from the list
  1540. //
  1541. CmCurrentView = (PCM_VIEW_OF_FILE)CmHive->LRUViewListHead.Blink;
  1542. CmCurrentView = CONTAINING_RECORD( CmCurrentView,
  1543. CM_VIEW_OF_FILE,
  1544. LRUViewList);
  1545. ASSERT( CmCurrentView->UseCount == 0 );
  1546. //
  1547. // unmap it
  1548. //
  1549. CmpUnmapCmView(CmHive,CmCurrentView,TRUE,FALSE);
  1550. //
  1551. // remove it from LRU list
  1552. //
  1553. RemoveEntryList(&(CmCurrentView->LRUViewList));
  1554. #if DBG
  1555. //
  1556. // do this to signal that LRUViewList is empty.
  1557. //
  1558. InitializeListHead(&(CmCurrentView->LRUViewList));
  1559. #endif
  1560. CmpFreeCmView(CmCurrentView);
  1561. CmHive->MappedViews --;
  1562. }
  1563. }
  1564. VOID
  1565. CmpMapEntireFileInFakeViews(
  1566. IN PCMHIVE CmHive,
  1567. IN ULONG Length
  1568. )
  1569. /*++
  1570. Routine Description:
  1571. Maps and faults all the file in, in chunks of 256K if possible.
  1572. This should improve boot performance; After the hive is mapped
  1573. (maps are build and hive is checked we'll get rid of this aditional
  1574. views
  1575. Arguments:
  1576. CmHive - Hive to be mapped
  1577. Length - length of the hive ==> add HBLOCK_SIZE
  1578. Return Value:
  1579. none
  1580. --*/
  1581. {
  1582. ULONG Offset;
  1583. ULONG Size;
  1584. PCM_VIEW_OF_FILE CmView;
  1585. LARGE_INTEGER SectionOffset;
  1586. PAGED_CODE();
  1587. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1588. ASSERT( IsListEmpty(&(CmHive->FakeViewListHead)) );
  1589. #if DBG
  1590. ASSERT( CmHive->FakeViews == 0 );
  1591. #endif
  1592. //
  1593. // adjust the size to get the real size of the file
  1594. Length += HBLOCK_SIZE;
  1595. //
  1596. // start from the beggining and map 256K of data from the hive
  1597. // allocate a view and insert it in the FakeViewList, use LRUViewList for that.
  1598. //
  1599. Offset =0;
  1600. SectionOffset.HighPart = 0;
  1601. while( Offset < Length ) {
  1602. CmView = ExAllocatePoolWithTag(PagedPool,sizeof(CM_VIEW_OF_FILE),CM_MAPPEDVIEW_TAG | PROTECTED_POOL);
  1603. if (CmView == NULL) {
  1604. CM_BUGCHECK(REGISTRY_ERROR,CMVIEW_ERROR,2,0,0);
  1605. }
  1606. //
  1607. // Init the view
  1608. //
  1609. CmView->ViewAddress = NULL;
  1610. CmView->Bcb = NULL;
  1611. InsertTailList(
  1612. &(CmHive->FakeViewListHead),
  1613. &(CmView->LRUViewList)
  1614. );
  1615. #if DBG
  1616. CmHive->FakeViews++;
  1617. #endif
  1618. //
  1619. // now try to map the view
  1620. //
  1621. Size = _256K;
  1622. if( (Offset + Size) > Length ) {
  1623. Size = Length - Offset;
  1624. }
  1625. SectionOffset.LowPart = Offset;
  1626. try {
  1627. if (!CcMapData( CmHive->FileObject,
  1628. (PLARGE_INTEGER)&SectionOffset,
  1629. Size,
  1630. MAP_WAIT
  1631. #ifdef CM_MAP_NO_READ
  1632. | MAP_NO_READ
  1633. #endif
  1634. ,
  1635. (PVOID *)(&(CmView->Bcb)),
  1636. (PVOID *)(&(CmView->ViewAddress)) )) {
  1637. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmpMapEntireFileInFakeViews: Error mapping data at offset %lx for hive %p\n",Offset,CmHive));
  1638. CmView->Bcb = NULL;
  1639. }
  1640. } except (EXCEPTION_EXECUTE_HANDLER) {
  1641. //
  1642. // in low-memory scenarios, CcMapData throws a STATUS_IN_PAGE_ERROR
  1643. // this happens when the IO issued to touch the just-mapped data fails (usually with
  1644. // STATUS_INSUFFICIENT_RESOURCES; We want to catch this and treat as a
  1645. // "not enough resources" problem, rather than letting it to surface the kernel call
  1646. //
  1647. // signal that the view is not mapped
  1648. CmView->Bcb = NULL;
  1649. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmpMapEntireFileInFakeViews: Error mapping data at offset %lx for hive %p\n",Offset,CmHive));
  1650. }
  1651. if( CmView->Bcb == NULL ) {
  1652. //
  1653. // we are already short on memory; don't make things worse than they are
  1654. // free what we have already allocated and bail out
  1655. //
  1656. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmpMapEntireFileInFakeViews: Could not map entire file for hive %p ... bailing out\n",CmHive));
  1657. CmpUnmapFakeViews(CmHive);
  1658. return;
  1659. }
  1660. //
  1661. // advance the offset
  1662. //
  1663. Offset += Size;
  1664. }
  1665. #if DBG
  1666. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmpMapEntireFileInFakeViews: Successfully mapped %lx FakeViews for hive %p\n",CmHive->FakeViews,CmHive));
  1667. #endif
  1668. }
  1669. VOID
  1670. CmpUnmapFakeViews(
  1671. IN PCMHIVE CmHive
  1672. )
  1673. /*++
  1674. Routine Description:
  1675. Walks through the FakeViewList and unmaps all views.
  1676. Arguments:
  1677. CmHive - Hive to be unmapped
  1678. Return Value:
  1679. none
  1680. --*/
  1681. {
  1682. PCM_VIEW_OF_FILE CmView;
  1683. PAGED_CODE();
  1684. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1685. #if DBG
  1686. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmpUnmapFakeViews: Unmapping %lx views for hive %p\n",CmHive->FakeViews,CmHive));
  1687. #endif
  1688. while( IsListEmpty( &(CmHive->FakeViewListHead) ) == FALSE ) {
  1689. CmView = (PCM_VIEW_OF_FILE)RemoveHeadList(&(CmHive->FakeViewListHead));
  1690. CmView = CONTAINING_RECORD( CmView,
  1691. CM_VIEW_OF_FILE,
  1692. LRUViewList);
  1693. if( CmView->Bcb != NULL ) {
  1694. //
  1695. // view is mapped; unpin it.
  1696. //
  1697. CcUnpinData( CmView->Bcb );
  1698. }
  1699. //
  1700. // now free the memory for this view.
  1701. //
  1702. ExFreePoolWithTag(CmView, CM_MAPPEDVIEW_TAG | PROTECTED_POOL);
  1703. #if DBG
  1704. CmHive->FakeViews--;
  1705. #endif
  1706. }
  1707. ASSERT( IsListEmpty( &(CmHive->FakeViewListHead) ) == TRUE );
  1708. #if DBG
  1709. ASSERT( CmHive->FakeViews == 0 );
  1710. #endif
  1711. }
  1712. #endif
  1713. VOID
  1714. CmpPrefetchHiveFile(
  1715. IN PFILE_OBJECT FileObject,
  1716. IN ULONG Length
  1717. )
  1718. /*++
  1719. Routine Description:
  1720. Prefetch all file into memory.
  1721. We're using MmPrefetchPages fast routine; Pages will be put in the transition
  1722. state, and they'll be used by the hive load worker while mapping data
  1723. Arguments:
  1724. FileObject - file object associated with the file to be prefetched
  1725. Length - length of the file
  1726. Return Value:
  1727. none
  1728. --*/
  1729. {
  1730. ULONG NumberOfPages;
  1731. PREAD_LIST *ReadLists;
  1732. PREAD_LIST ReadList;
  1733. ULONG AllocationSize;
  1734. ULONG Offset;
  1735. PAGED_CODE();
  1736. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1737. NumberOfPages = ROUND_UP(Length,PAGE_SIZE) / PAGE_SIZE ;
  1738. ReadLists = ExAllocatePoolWithTag(NonPagedPool, sizeof(PREAD_LIST), CM_POOL_TAG);
  1739. if (ReadLists == NULL) {
  1740. return;
  1741. }
  1742. AllocationSize = sizeof(READ_LIST) + (NumberOfPages * sizeof(FILE_SEGMENT_ELEMENT));
  1743. ReadList = ExAllocatePoolWithTag(NonPagedPool,AllocationSize,CM_POOL_TAG);
  1744. if (ReadList == NULL) {
  1745. ExFreePool(ReadLists);
  1746. return;
  1747. }
  1748. ReadList->FileObject = FileObject;
  1749. ReadList->IsImage = FALSE;
  1750. ReadList->NumberOfEntries = 0;
  1751. Offset = 0;
  1752. while( Offset < Length ) {
  1753. ReadList->List[ReadList->NumberOfEntries].Alignment = Offset;
  1754. ReadList->NumberOfEntries++;
  1755. Offset += PAGE_SIZE;
  1756. }
  1757. ASSERT( ReadList->NumberOfEntries == NumberOfPages );
  1758. ReadLists[0] = ReadList;
  1759. MmPrefetchPages (1,ReadLists);
  1760. // just to make sure !
  1761. // this assert has been moved inside CcSetPrivateWriteFile !!!
  1762. // there is no need to assert this here
  1763. //ASSERT( MmDisableModifiedWriteOfSection (FileObject->SectionObjectPointer) );
  1764. ExFreePool(ReadList);
  1765. ExFreePool(ReadLists);
  1766. }
  1767. VOID
  1768. CmpUnmapUnusedViews(
  1769. IN PCMHIVE CmHive
  1770. )
  1771. /*++
  1772. Routine Description:
  1773. Unmaps all mapped views than are not currently in-use.
  1774. The purpose of this is to allow a retry in case CcMapData failed
  1775. because of the system having to many mapped views.
  1776. We should not run into this too often ( - at all ).
  1777. Arguments:
  1778. CmHive - hive for which we already have the viewlist lock owned
  1779. Return Value:
  1780. none
  1781. --*/
  1782. {
  1783. PCM_VIEW_OF_FILE CmView;
  1784. USHORT NrViews;
  1785. PCMHIVE CmCurrentHive;
  1786. PLIST_ENTRY p;
  1787. PAGED_CODE();
  1788. //
  1789. // iterate through the hive list
  1790. //
  1791. LOCK_HIVE_LIST();
  1792. p = CmpHiveListHead.Flink;
  1793. while(p != &CmpHiveListHead) {
  1794. CmCurrentHive = (PCMHIVE)CONTAINING_RECORD(p, CMHIVE, HiveList);
  1795. if( CmCurrentHive != CmHive ) {
  1796. //
  1797. // we need to be the only ones operating on this list
  1798. //
  1799. CmLockHiveViews (CmCurrentHive);
  1800. } else {
  1801. //
  1802. // we already have the mutex owned
  1803. //
  1804. NOTHING;
  1805. }
  1806. //
  1807. // try to unmap all mapped views
  1808. //
  1809. CmView = (PCM_VIEW_OF_FILE)CmCurrentHive->LRUViewListHead.Flink;
  1810. for(NrViews = CmCurrentHive->MappedViews;NrViews;NrViews--) {
  1811. CmView = CONTAINING_RECORD( CmView,
  1812. CM_VIEW_OF_FILE,
  1813. LRUViewList);
  1814. if( (CmView->ViewAddress != 0) && ( CmView->UseCount == 0 ) ) {
  1815. //
  1816. // view is mapped and it is not in use
  1817. //
  1818. ASSERT( (CmView->FileOffset + CmView->Size) != 0 && (CmView->Bcb != 0));
  1819. //
  1820. // unmap it without altering its position in the list
  1821. //
  1822. CmpUnmapCmView(CmCurrentHive,CmView,TRUE,FALSE);
  1823. }
  1824. CmView = (PCM_VIEW_OF_FILE)CmView->LRUViewList.Flink;
  1825. }
  1826. if( CmCurrentHive != CmHive ) {
  1827. CmUnlockHiveViews (CmCurrentHive);
  1828. }
  1829. p=p->Flink;
  1830. }
  1831. UNLOCK_HIVE_LIST();
  1832. }
  1833. NTSTATUS
  1834. CmPrefetchHivePages(
  1835. IN PUNICODE_STRING FullHivePath,
  1836. IN OUT PREAD_LIST ReadList
  1837. )
  1838. /*++
  1839. Routine Description:
  1840. Searches through the hive list for a hive with the backing file of name FullHivePath
  1841. Builds a READ_LIST based on the given page offsets array and prefetches the pages
  1842. Arguments:
  1843. FullHivePath - Full Path of the file
  1844. ReadList - read_list of page offsets to be prefetched.
  1845. Return Value:
  1846. STATUS_SUCCESS - OK, pages prefetched
  1847. STATUS_INVALID_PARAMETER - file was not found in the machine's hive list
  1848. else, status returned by MmPrefetchPages.
  1849. --*/
  1850. {
  1851. PCMHIVE CmHive;
  1852. PLIST_ENTRY p;
  1853. BOOLEAN HiveFound = FALSE;
  1854. NTSTATUS Status;
  1855. ULONG i;
  1856. PAGED_CODE();
  1857. CmpLockRegistry();
  1858. //
  1859. // iterate through the hive list
  1860. //
  1861. LOCK_HIVE_LIST();
  1862. p = CmpHiveListHead.Flink;
  1863. while(p != &CmpHiveListHead) {
  1864. CmHive = (PCMHIVE)CONTAINING_RECORD(p, CMHIVE, HiveList);
  1865. if( (CmHive->FileObject != NULL) && (CmHive->FileFullPath.Buffer != NULL) ) {
  1866. //
  1867. // there is a chance this might be the one
  1868. //
  1869. if( RtlCompareUnicodeString(FullHivePath,&(CmHive->FileFullPath),TRUE) == 0 ) {
  1870. //
  1871. // we found it !
  1872. //
  1873. HiveFound = TRUE;
  1874. break;
  1875. }
  1876. }
  1877. p=p->Flink;
  1878. }
  1879. UNLOCK_HIVE_LIST();
  1880. if( (HiveFound == FALSE) || ( ReadList == NULL ) ) {
  1881. //
  1882. // bad luck;
  1883. //
  1884. CmpUnlockRegistry();
  1885. return STATUS_INVALID_PARAMETER;
  1886. }
  1887. ASSERT( CmHive->FileObject != NULL );
  1888. //
  1889. // at this point, we have successfully identified the hive
  1890. //
  1891. //
  1892. // build up the READ_LIST with the requested page offsets
  1893. //
  1894. ReadList->FileObject = CmHive->FileObject;
  1895. ReadList->IsImage = FALSE;
  1896. ASSERT( ReadList->NumberOfEntries != 0 );
  1897. Status = MmPrefetchPages (1,&ReadList);
  1898. // just to make sure !
  1899. ASSERT( MmDisableModifiedWriteOfSection (CmHive->FileObject->SectionObjectPointer) );
  1900. CmpUnlockRegistry();
  1901. return Status;
  1902. }
  1903. BOOLEAN
  1904. CmIsFileLoadedAsHive(PFILE_OBJECT FileObject)
  1905. {
  1906. PCMHIVE CmHive;
  1907. PLIST_ENTRY p;
  1908. BOOLEAN HiveFound = FALSE;
  1909. //
  1910. // iterate through the hive list
  1911. //
  1912. LOCK_HIVE_LIST();
  1913. p = CmpHiveListHead.Flink;
  1914. while(p != &CmpHiveListHead) {
  1915. CmHive = (PCMHIVE)CONTAINING_RECORD(p, CMHIVE, HiveList);
  1916. if( CmHive->FileObject == FileObject ) {
  1917. //
  1918. // we found it !
  1919. //
  1920. HiveFound = TRUE;
  1921. break;
  1922. }
  1923. p=p->Flink;
  1924. }
  1925. UNLOCK_HIVE_LIST();
  1926. return HiveFound;
  1927. }
  1928. VOID
  1929. CmpReferenceHiveView( IN PCMHIVE CmHive,
  1930. IN PCM_VIEW_OF_FILE CmView
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. Adds a refcount to the hive and view, to prevent it from going away from under us;
  1935. Assumes the viewlock is held by the caller.
  1936. Can be converted to a macro.
  1937. Arguments:
  1938. Return Value:
  1939. --*/
  1940. {
  1941. PAGED_CODE();
  1942. if(CmView && CmHive->Hive.ReleaseCellRoutine) {
  1943. //
  1944. // up the view use count if any
  1945. //
  1946. CmView->UseCount++;
  1947. }
  1948. }
  1949. VOID
  1950. CmpDereferenceHiveView( IN PCMHIVE CmHive,
  1951. IN PCM_VIEW_OF_FILE CmView
  1952. )
  1953. /*++
  1954. Routine Description:
  1955. Pair of CmpReferenceHiveView
  1956. Assumes the viewlock is held by the caller.
  1957. Can be converted to a macro.
  1958. Arguments:
  1959. Return Value:
  1960. --*/
  1961. {
  1962. PAGED_CODE();
  1963. if(CmView && CmHive->Hive.ReleaseCellRoutine) {
  1964. CmView->UseCount--;
  1965. }
  1966. }
  1967. VOID
  1968. CmpReferenceHiveViewWithLock( IN PCMHIVE CmHive,
  1969. IN PCM_VIEW_OF_FILE CmView
  1970. )
  1971. /*++
  1972. Routine Description:
  1973. Adds a refcount to the hive and view, to prevent it from going away from under us;
  1974. Can be converted to a macro.
  1975. Arguments:
  1976. Return Value:
  1977. --*/
  1978. {
  1979. PAGED_CODE();
  1980. CmLockHiveViews(CmHive);
  1981. //
  1982. // call the unsafe routine
  1983. //
  1984. CmpReferenceHiveView(CmHive,CmView);
  1985. CmUnlockHiveViews(CmHive);
  1986. }
  1987. VOID
  1988. CmpDereferenceHiveViewWithLock( IN PCMHIVE CmHive,
  1989. IN PCM_VIEW_OF_FILE CmView
  1990. )
  1991. /*++
  1992. Routine Description:
  1993. Pair of CmpDereferenceHiveViewWithLock
  1994. Can be converted to a macro.
  1995. Arguments:
  1996. Return Value:
  1997. --*/
  1998. {
  1999. PAGED_CODE();
  2000. CmLockHiveViews(CmHive);
  2001. //
  2002. // call the unsafe routine
  2003. //
  2004. CmpDereferenceHiveView(CmHive,CmView);
  2005. CmUnlockHiveViews(CmHive);
  2006. }