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.

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