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.

973 lines
28 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. shutdown.c
  5. Abstract:
  6. This module contains the shutdown code for the memory management system.
  7. Author:
  8. Lou Perazzoli (loup) 21-Aug-1991
  9. Landy Wang (landyw) 02-June-1997
  10. Revision History:
  11. --*/
  12. #include "mi.h"
  13. extern ULONG MmSystemShutdown;
  14. VOID
  15. MiReleaseAllMemory (
  16. VOID
  17. );
  18. BOOLEAN
  19. MiShutdownSystem (
  20. VOID
  21. );
  22. LOGICAL
  23. MiZeroPageFile (
  24. VOID
  25. );
  26. #ifdef ALLOC_PRAGMA
  27. #pragma alloc_text(PAGELK,MiZeroPageFile)
  28. #pragma alloc_text(PAGELK,MiShutdownSystem)
  29. #pragma alloc_text(PAGELK,MiReleaseAllMemory)
  30. #pragma alloc_text(PAGELK,MmShutdownSystem)
  31. #endif
  32. ULONG MmZeroPageFile;
  33. extern ULONG MmUnusedSegmentForceFree;
  34. extern LIST_ENTRY MiVerifierDriverAddedThunkListHead;
  35. extern LIST_ENTRY MmLoadedUserImageList;
  36. extern LOGICAL MiZeroingDisabled;
  37. extern ULONG MmNumberOfMappedMdls;
  38. extern ULONG MmNumberOfMappedMdlsInUse;
  39. LOGICAL
  40. MiZeroPageFile (
  41. VOID
  42. )
  43. // Caller must lock down PAGELK.
  44. {
  45. PMMPFN Pfn1;
  46. PPFN_NUMBER Page;
  47. PFN_NUMBER MdlHack[(sizeof(MDL)/sizeof(PFN_NUMBER)) + MM_MAXIMUM_WRITE_CLUSTER];
  48. PMDL Mdl;
  49. NTSTATUS Status;
  50. KEVENT IoEvent;
  51. IO_STATUS_BLOCK IoStatus;
  52. KIRQL OldIrql;
  53. LARGE_INTEGER StartingOffset;
  54. ULONG count;
  55. ULONG i;
  56. PFN_NUMBER j;
  57. PFN_NUMBER first;
  58. ULONG write;
  59. PMMPAGING_FILE PagingFile;
  60. LOGICAL FilesystemsAlive;
  61. //
  62. // Get a page to complete the write request.
  63. //
  64. Mdl = (PMDL) MdlHack;
  65. Page = (PPFN_NUMBER)(Mdl + 1);
  66. KeInitializeEvent (&IoEvent, NotificationEvent, FALSE);
  67. MmInitializeMdl (Mdl, NULL, PAGE_SIZE);
  68. Mdl->MdlFlags |= MDL_PAGES_LOCKED;
  69. Mdl->StartVa = NULL;
  70. j = 0;
  71. i = 0;
  72. Page = (PPFN_NUMBER)(Mdl + 1);
  73. FilesystemsAlive = TRUE;
  74. LOCK_PFN (OldIrql);
  75. if (MmAvailablePages < MM_LOW_LIMIT) {
  76. UNLOCK_PFN (OldIrql);
  77. return TRUE;
  78. }
  79. *Page = MiRemoveZeroPage (0);
  80. Pfn1 = MI_PFN_ELEMENT (*Page);
  81. ASSERT (Pfn1->u2.ShareCount == 0);
  82. ASSERT (Pfn1->u3.e2.ReferenceCount == 0);
  83. Pfn1->u3.e2.ReferenceCount = (USHORT) MmModifiedWriteClusterSize;
  84. Pfn1->PteAddress = (PMMPTE) (ULONG_PTR)(X64K | 0x1);
  85. Pfn1->OriginalPte.u.Long = 0;
  86. MI_SET_PFN_DELETED (Pfn1);
  87. Page += 1;
  88. for (j = 1; j < MmModifiedWriteClusterSize; j += 1) {
  89. *Page = *(PPFN_NUMBER)(Mdl + 1);
  90. Page += 1;
  91. }
  92. while (i < MmNumberOfPagingFiles) {
  93. PagingFile = MmPagingFile[i];
  94. count = 0;
  95. write = FALSE;
  96. //
  97. // Initializing first is not needed for correctness, but
  98. // without it the compiler cannot compile this code W4 to
  99. // check for use of uninitialized variables.
  100. //
  101. first = 0;
  102. for (j = 1; j < PagingFile->Size; j += 1) {
  103. if (RtlCheckBit (PagingFile->Bitmap, j) == 0) {
  104. if (count == 0) {
  105. first = j;
  106. }
  107. //
  108. // Claim the pagefile location as the modified writer
  109. // may already be scanning.
  110. //
  111. RtlSetBit (PagingFile->Bitmap, (ULONG) j);
  112. count += 1;
  113. if (count == MmModifiedWriteClusterSize) {
  114. write = TRUE;
  115. }
  116. }
  117. else {
  118. if (count != 0) {
  119. //
  120. // Issue a write.
  121. //
  122. write = TRUE;
  123. }
  124. }
  125. if ((j == (PagingFile->Size - 1)) && (count != 0)) {
  126. write = TRUE;
  127. }
  128. if (write) {
  129. UNLOCK_PFN (OldIrql);
  130. StartingOffset.QuadPart = (LONGLONG)first << PAGE_SHIFT;
  131. Mdl->ByteCount = count << PAGE_SHIFT;
  132. KeClearEvent (&IoEvent);
  133. Status = IoSynchronousPageWrite (PagingFile->File,
  134. Mdl,
  135. &StartingOffset,
  136. &IoEvent,
  137. &IoStatus);
  138. //
  139. // Ignore all I/O failures - there is nothing that can
  140. // be done at this point.
  141. //
  142. if (!NT_SUCCESS(Status)) {
  143. KeSetEvent (&IoEvent, 0, FALSE);
  144. }
  145. Status = KeWaitForSingleObject (&IoEvent,
  146. WrPageOut,
  147. KernelMode,
  148. FALSE,
  149. (PLARGE_INTEGER)&MmTwentySeconds);
  150. if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) {
  151. MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
  152. }
  153. if (Status == STATUS_TIMEOUT) {
  154. //
  155. // The write did not complete in 20 seconds, assume
  156. // that the file systems are hung and return an
  157. // error.
  158. //
  159. FilesystemsAlive = FALSE;
  160. i = MmNumberOfPagingFiles; // To break out of outer loop
  161. LOCK_PFN (OldIrql);
  162. RtlClearBits (PagingFile->Bitmap, (ULONG) first, count);
  163. break;
  164. }
  165. write = FALSE;
  166. LOCK_PFN (OldIrql);
  167. RtlClearBits (PagingFile->Bitmap, (ULONG) first, count);
  168. count = 0;
  169. }
  170. }
  171. i += 1;
  172. }
  173. j = 0;
  174. Page = (PPFN_NUMBER)(Mdl + 1);
  175. Pfn1 = MI_PFN_ELEMENT (*Page);
  176. ASSERT (Pfn1->u3.e2.ReferenceCount >= MmModifiedWriteClusterSize);
  177. do {
  178. MiDecrementReferenceCountInline (Pfn1, *Page);
  179. j += 1;
  180. } while (j < MmModifiedWriteClusterSize);
  181. UNLOCK_PFN (OldIrql);
  182. return FilesystemsAlive;
  183. }
  184. BOOLEAN
  185. MiShutdownSystem (
  186. VOID
  187. )
  188. /*++
  189. Routine Description:
  190. This function performs the shutdown of memory management. This
  191. is accomplished by writing out all modified pages which are
  192. destined for files other than the paging file.
  193. All processes have already been killed, the registry shutdown and
  194. shutdown IRPs already sent. On return from this phase all mapped
  195. file data must be flushed and the unused segment list emptied.
  196. This releases all the Mm references to file objects, allowing many
  197. drivers (especially the network) to unload.
  198. Arguments:
  199. None.
  200. Return Value:
  201. TRUE if the pages were successfully written, FALSE otherwise.
  202. --*/
  203. {
  204. SIZE_T ImportListSize;
  205. PLOAD_IMPORTS ImportList;
  206. PLOAD_IMPORTS ImportListNonPaged;
  207. PLIST_ENTRY NextEntry;
  208. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  209. PFN_NUMBER ModifiedPage;
  210. PMMPFN Pfn1;
  211. PSUBSECTION Subsection;
  212. PCONTROL_AREA ControlArea;
  213. PPFN_NUMBER Page;
  214. PFILE_OBJECT FilePointer;
  215. ULONG ConsecutiveFileLockFailures;
  216. PFN_NUMBER MdlHack[(sizeof(MDL)/sizeof(PFN_NUMBER)) + MM_MAXIMUM_WRITE_CLUSTER];
  217. PMDL Mdl;
  218. NTSTATUS Status;
  219. KEVENT IoEvent;
  220. IO_STATUS_BLOCK IoStatus;
  221. KIRQL OldIrql;
  222. LARGE_INTEGER StartingOffset;
  223. ULONG count;
  224. ULONG i;
  225. //
  226. // Don't do this more than once.
  227. //
  228. if (MmSystemShutdown == 0) {
  229. Mdl = (PMDL) MdlHack;
  230. Page = (PPFN_NUMBER)(Mdl + 1);
  231. KeInitializeEvent (&IoEvent, NotificationEvent, FALSE);
  232. MmInitializeMdl (Mdl, NULL, PAGE_SIZE);
  233. Mdl->MdlFlags |= MDL_PAGES_LOCKED;
  234. MmLockPagableSectionByHandle (ExPageLockHandle);
  235. LOCK_PFN (OldIrql);
  236. ModifiedPage = MmModifiedPageListHead.Flink;
  237. while (ModifiedPage != MM_EMPTY_LIST) {
  238. //
  239. // There are modified pages.
  240. //
  241. Pfn1 = MI_PFN_ELEMENT (ModifiedPage);
  242. if (Pfn1->OriginalPte.u.Soft.Prototype == 1) {
  243. //
  244. // This page is destined for a file.
  245. //
  246. Subsection = MiGetSubsectionAddress (&Pfn1->OriginalPte);
  247. ControlArea = Subsection->ControlArea;
  248. if ((!ControlArea->u.Flags.Image) &&
  249. (!ControlArea->u.Flags.NoModifiedWriting)) {
  250. MiUnlinkPageFromList (Pfn1);
  251. //
  252. // Issue the write.
  253. //
  254. MI_SET_MODIFIED (Pfn1, 0, 0x28);
  255. //
  256. // Up the reference count for the physical page as there
  257. // is I/O in progress.
  258. //
  259. MI_ADD_LOCKED_PAGE_CHARGE_FOR_MODIFIED_PAGE (Pfn1, TRUE, 26);
  260. Pfn1->u3.e2.ReferenceCount += 1;
  261. *Page = ModifiedPage;
  262. ControlArea->NumberOfMappedViews += 1;
  263. ControlArea->NumberOfPfnReferences += 1;
  264. UNLOCK_PFN (OldIrql);
  265. StartingOffset.QuadPart = MiStartingOffset (Subsection,
  266. Pfn1->PteAddress);
  267. Mdl->StartVa = NULL;
  268. ConsecutiveFileLockFailures = 0;
  269. FilePointer = ControlArea->FilePointer;
  270. retry:
  271. KeClearEvent (&IoEvent);
  272. Status = FsRtlAcquireFileForCcFlushEx (FilePointer);
  273. if (NT_SUCCESS(Status)) {
  274. Status = IoSynchronousPageWrite (FilePointer,
  275. Mdl,
  276. &StartingOffset,
  277. &IoEvent,
  278. &IoStatus);
  279. //
  280. // Release the file we acquired.
  281. //
  282. FsRtlReleaseFileForCcFlush (FilePointer);
  283. }
  284. if (!NT_SUCCESS(Status)) {
  285. //
  286. // Only try the request more than once if the
  287. // filesystem said it had a deadlock.
  288. //
  289. if (Status == STATUS_FILE_LOCK_CONFLICT) {
  290. ConsecutiveFileLockFailures += 1;
  291. if (ConsecutiveFileLockFailures < 5) {
  292. KeDelayExecutionThread (KernelMode,
  293. FALSE,
  294. (PLARGE_INTEGER)&MmShortTime);
  295. goto retry;
  296. }
  297. goto wait_complete;
  298. }
  299. //
  300. // Ignore all I/O failures - there is nothing that
  301. // can be done at this point.
  302. //
  303. KeSetEvent (&IoEvent, 0, FALSE);
  304. }
  305. Status = KeWaitForSingleObject (&IoEvent,
  306. WrPageOut,
  307. KernelMode,
  308. FALSE,
  309. (PLARGE_INTEGER)&MmTwentySeconds);
  310. wait_complete:
  311. if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) {
  312. MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
  313. }
  314. if (Status == STATUS_TIMEOUT) {
  315. //
  316. // The write did not complete in 20 seconds, assume
  317. // that the file systems are hung and return an
  318. // error.
  319. //
  320. LOCK_PFN (OldIrql);
  321. MI_SET_MODIFIED (Pfn1, 1, 0xF);
  322. MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF (Pfn1, 27);
  323. ControlArea->NumberOfMappedViews -= 1;
  324. ControlArea->NumberOfPfnReferences -= 1;
  325. //
  326. // This routine returns with the PFN lock released!
  327. //
  328. MiCheckControlArea (ControlArea, NULL, OldIrql);
  329. MmUnlockPagableImageSection (ExPageLockHandle);
  330. return FALSE;
  331. }
  332. LOCK_PFN (OldIrql);
  333. MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF (Pfn1, 27);
  334. ControlArea->NumberOfMappedViews -= 1;
  335. ControlArea->NumberOfPfnReferences -= 1;
  336. //
  337. // This routine returns with the PFN lock released!
  338. //
  339. MiCheckControlArea (ControlArea, NULL, OldIrql);
  340. LOCK_PFN (OldIrql);
  341. //
  342. // Restart scan at the front of the list.
  343. //
  344. ModifiedPage = MmModifiedPageListHead.Flink;
  345. continue;
  346. }
  347. }
  348. ModifiedPage = Pfn1->u1.Flink;
  349. }
  350. UNLOCK_PFN (OldIrql);
  351. //
  352. // Indicate to the modified page writer that the system has
  353. // shutdown.
  354. //
  355. MmSystemShutdown = 1;
  356. //
  357. // Check to see if the paging file should be overwritten.
  358. // Only free blocks are written.
  359. //
  360. if (MmZeroPageFile) {
  361. MiZeroPageFile ();
  362. }
  363. MmUnlockPagableImageSection (ExPageLockHandle);
  364. }
  365. if (PoCleanShutdownEnabled ()) {
  366. //
  367. // Empty the unused segment list.
  368. //
  369. LOCK_PFN (OldIrql);
  370. MmUnusedSegmentForceFree = (ULONG)-1;
  371. KeSetEvent (&MmUnusedSegmentCleanup, 0, FALSE);
  372. //
  373. // Give it 5 seconds to empty otherwise assume the filesystems are
  374. // hung and march on.
  375. //
  376. for (count = 0; count < 500; count += 1) {
  377. if (IsListEmpty(&MmUnusedSegmentList)) {
  378. break;
  379. }
  380. UNLOCK_PFN (OldIrql);
  381. KeDelayExecutionThread (KernelMode,
  382. FALSE,
  383. (PLARGE_INTEGER)&MmShortTime);
  384. LOCK_PFN (OldIrql);
  385. #if DBG
  386. if (count == 400) {
  387. //
  388. // Everything should have been flushed by now. Give the
  389. // filesystem team a chance to debug this on checked builds.
  390. //
  391. ASSERT (FALSE);
  392. }
  393. #endif
  394. //
  395. // Resignal if needed in case more closed file objects triggered
  396. // additional entries.
  397. //
  398. if (MmUnusedSegmentForceFree == 0) {
  399. MmUnusedSegmentForceFree = (ULONG)-1;
  400. KeSetEvent (&MmUnusedSegmentCleanup, 0, FALSE);
  401. }
  402. }
  403. UNLOCK_PFN (OldIrql);
  404. //
  405. // Get rid of any paged pool references as they will be illegal
  406. // by the time MmShutdownSystem is called again since the filesystems
  407. // will have shutdown.
  408. //
  409. KeWaitForSingleObject (&MmSystemLoadLock,
  410. WrVirtualMemory,
  411. KernelMode,
  412. FALSE,
  413. (PLARGE_INTEGER)NULL);
  414. NextEntry = PsLoadedModuleList.Flink;
  415. while (NextEntry != &PsLoadedModuleList) {
  416. DataTableEntry = CONTAINING_RECORD (NextEntry,
  417. KLDR_DATA_TABLE_ENTRY,
  418. InLoadOrderLinks);
  419. ImportList = (PLOAD_IMPORTS)DataTableEntry->LoadedImports;
  420. if ((ImportList != (PVOID)LOADED_AT_BOOT) &&
  421. (ImportList != (PVOID)NO_IMPORTS_USED) &&
  422. (!SINGLE_ENTRY(ImportList))) {
  423. ImportListSize = ImportList->Count * sizeof(PVOID) + sizeof(SIZE_T);
  424. ImportListNonPaged = (PLOAD_IMPORTS) ExAllocatePoolWithTag (NonPagedPool,
  425. ImportListSize,
  426. 'TDmM');
  427. if (ImportListNonPaged != NULL) {
  428. RtlCopyMemory (ImportListNonPaged, ImportList, ImportListSize);
  429. ExFreePool (ImportList);
  430. DataTableEntry->LoadedImports = ImportListNonPaged;
  431. }
  432. else {
  433. //
  434. // Don't bother with the clean shutdown at this point.
  435. //
  436. PopShutdownCleanly = FALSE;
  437. break;
  438. }
  439. }
  440. //
  441. // Free the full DLL name as it is pagable.
  442. //
  443. if (DataTableEntry->FullDllName.Buffer != NULL) {
  444. ExFreePool (DataTableEntry->FullDllName.Buffer);
  445. DataTableEntry->FullDllName.Buffer = NULL;
  446. }
  447. NextEntry = NextEntry->Flink;
  448. }
  449. KeReleaseMutant (&MmSystemLoadLock, 1, FALSE, FALSE);
  450. //
  451. // Close all the pagefile handles, note we still have an object
  452. // reference to each keeping the underlying object resident.
  453. // At the end of Phase1 shutdown we'll release those references
  454. // to trigger the storage stack unload. The handle close must be
  455. // done here however as it will reference pagable structures.
  456. //
  457. for (i = 0; i < MmNumberOfPagingFiles; i += 1) {
  458. //
  459. // Free each pagefile name now as it resides in paged pool and
  460. // may need to be inpaged to be freed. Since the paging files
  461. // are going to be shutdown shortly, now is the time to access
  462. // pagable stuff and get rid of it. Zeroing the buffer pointer
  463. // is sufficient as the only accesses to this are from the
  464. // try-except-wrapped GetSystemInformation APIs and all the
  465. // user processes are gone already.
  466. //
  467. ASSERT (MmPagingFile[i]->PageFileName.Buffer != NULL);
  468. ExFreePool (MmPagingFile[i]->PageFileName.Buffer);
  469. MmPagingFile[i]->PageFileName.Buffer = NULL;
  470. ZwClose (MmPagingFile[i]->FileHandle);
  471. }
  472. }
  473. return TRUE;
  474. }
  475. BOOLEAN
  476. MmShutdownSystem (
  477. IN ULONG Phase
  478. )
  479. /*++
  480. Routine Description:
  481. This function performs the shutdown of memory management. This
  482. is accomplished by writing out all modified pages which are
  483. destined for files other than the paging file.
  484. Arguments:
  485. Phase - Supplies 0 on the initiation of shutdown. All processes have
  486. already been killed, the registry shutdown and shutdown IRPs already
  487. sent. On return from this phase all mapped file data must be
  488. flushed and the unused segment list emptied. This releases all
  489. the Mm references to file objects, allowing many drivers (especially
  490. the network) to unload.
  491. Supplies 1 on the initiation of shutdown. The filesystem stack
  492. has received its shutdown IRPs (the stack must free its paged pool
  493. allocations here and lock down any pagable code it intends to call)
  494. as no more references to pagable code or data are allowed on return.
  495. ie: Any IoPageRead at this point is illegal.
  496. Close the pagefile handles here so the filesystem stack will be
  497. dereferenced causing those drivers to unload as well.
  498. Supplies 2 on final shutdown of the system. Any resources not
  499. freed by this point are treated as leaks and cause a bugcheck.
  500. Return Value:
  501. TRUE if the pages were successfully written, FALSE otherwise.
  502. --*/
  503. {
  504. ULONG i;
  505. if (Phase == 0) {
  506. return MiShutdownSystem ();
  507. }
  508. if (Phase == 1) {
  509. //
  510. // The filesystem has shutdown. References to pagable code or data
  511. // is no longer allowed at this point.
  512. //
  513. // Close the pagefile handles here so the filesystem stack will be
  514. // dereferenced causing those drivers to unload as well.
  515. //
  516. if (MmSystemShutdown < 2) {
  517. MmSystemShutdown = 2;
  518. if (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_PAGING) {
  519. //
  520. // Make any IoPageRead at this point illegal. Detect this by
  521. // purging all system pagable memory.
  522. //
  523. MmTrimAllSystemPagableMemory (TRUE);
  524. //
  525. // There should be no dirty pages destined for the filesystem.
  526. // Give the filesystem team a shot to debug this on checked
  527. // builds.
  528. //
  529. ASSERT (MmModifiedPageListHead.Total == MmTotalPagesForPagingFile);
  530. //
  531. // Dereference all the pagefile objects to trigger a cascading
  532. // unload of the storage stack as this should be the last
  533. // reference to their driver objects.
  534. //
  535. for (i = 0; i < MmNumberOfPagingFiles; i += 1) {
  536. ObDereferenceObject (MmPagingFile[i]->File);
  537. }
  538. }
  539. }
  540. return TRUE;
  541. }
  542. ASSERT (Phase == 2);
  543. //
  544. // Check for resource leaks and bugcheck if any are found.
  545. //
  546. if (MmSystemShutdown < 3) {
  547. MmSystemShutdown = 3;
  548. if (PoCleanShutdownEnabled ()) {
  549. MiReleaseAllMemory ();
  550. }
  551. }
  552. return TRUE;
  553. }
  554. VOID
  555. MiReleaseAllMemory (
  556. VOID
  557. )
  558. /*++
  559. Routine Description:
  560. This function performs the final release of memory management allocations.
  561. Arguments:
  562. None.
  563. Return Value:
  564. None.
  565. Environment:
  566. No references to paged pool or pagable code/data are allowed.
  567. --*/
  568. {
  569. ULONG i;
  570. ULONG j;
  571. PEVENT_COUNTER EventSupport;
  572. PUNLOADED_DRIVERS Entry;
  573. PLIST_ENTRY NextEntry;
  574. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  575. PLOAD_IMPORTS ImportList;
  576. PMI_VERIFIER_DRIVER_ENTRY Verifier;
  577. PMMINPAGE_SUPPORT Support;
  578. PSLIST_ENTRY SingleListEntry;
  579. PDRIVER_SPECIFIED_VERIFIER_THUNKS ThunkTableBase;
  580. PMMMOD_WRITER_MDL_ENTRY ModWriterEntry;
  581. ASSERT (MmUnusedSegmentList.Flink == &MmUnusedSegmentList);
  582. //
  583. // Don't clear free pages so problems can be debugged.
  584. //
  585. MiZeroingDisabled = TRUE;
  586. if (MiMirrorBitMap != NULL) {
  587. ExFreePool (MiMirrorBitMap);
  588. ASSERT (MiMirrorBitMap2);
  589. ExFreePool (MiMirrorBitMap2);
  590. }
  591. //
  592. // Free the unloaded driver list.
  593. //
  594. if (MmUnloadedDrivers != NULL) {
  595. Entry = &MmUnloadedDrivers[0];
  596. for (i = 0; i < MI_UNLOADED_DRIVERS; i += 1) {
  597. if (Entry->Name.Buffer != NULL) {
  598. RtlFreeUnicodeString (&Entry->Name);
  599. }
  600. Entry += 1;
  601. }
  602. ExFreePool (MmUnloadedDrivers);
  603. }
  604. NextEntry = MmLoadedUserImageList.Flink;
  605. while (NextEntry != &MmLoadedUserImageList) {
  606. DataTableEntry = CONTAINING_RECORD (NextEntry,
  607. KLDR_DATA_TABLE_ENTRY,
  608. InLoadOrderLinks);
  609. NextEntry = NextEntry->Flink;
  610. ExFreePool ((PVOID)DataTableEntry);
  611. }
  612. //
  613. // Release the loaded module list entries.
  614. //
  615. NextEntry = PsLoadedModuleList.Flink;
  616. while (NextEntry != &PsLoadedModuleList) {
  617. DataTableEntry = CONTAINING_RECORD (NextEntry,
  618. KLDR_DATA_TABLE_ENTRY,
  619. InLoadOrderLinks);
  620. ImportList = (PLOAD_IMPORTS)DataTableEntry->LoadedImports;
  621. if ((ImportList != (PVOID)LOADED_AT_BOOT) &&
  622. (ImportList != (PVOID)NO_IMPORTS_USED) &&
  623. (!SINGLE_ENTRY(ImportList))) {
  624. ExFreePool (ImportList);
  625. }
  626. if (DataTableEntry->FullDllName.Buffer != NULL) {
  627. ASSERT (DataTableEntry->FullDllName.Buffer == DataTableEntry->BaseDllName.Buffer);
  628. }
  629. NextEntry = NextEntry->Flink;
  630. ExFreePool ((PVOID)DataTableEntry);
  631. }
  632. //
  633. // Free the physical memory descriptor block.
  634. //
  635. ExFreePool (MmPhysicalMemoryBlock);
  636. ExFreePool (MiPfnBitMap.Buffer);
  637. //
  638. // Free the system views structure.
  639. //
  640. if (MmSession.SystemSpaceViewTable != NULL) {
  641. ExFreePool (MmSession.SystemSpaceViewTable);
  642. }
  643. if (MmSession.SystemSpaceBitMap != NULL) {
  644. ExFreePool (MmSession.SystemSpaceBitMap);
  645. }
  646. //
  647. // Free the pagefile structures - note the PageFileName buffer was freed
  648. // earlier as it resided in paged pool and may have needed an inpage
  649. // to be freed.
  650. //
  651. for (i = 0; i < MmNumberOfPagingFiles; i += 1) {
  652. ASSERT (MmPagingFile[i]->PageFileName.Buffer == NULL);
  653. for (j = 0; j < MM_PAGING_FILE_MDLS; j += 1) {
  654. ExFreePool (MmPagingFile[i]->Entry[j]);
  655. }
  656. ExFreePool (MmPagingFile[i]->Bitmap);
  657. ExFreePool (MmPagingFile[i]);
  658. }
  659. ASSERT (MmNumberOfMappedMdlsInUse == 0);
  660. i = 0;
  661. while (IsListEmpty (&MmMappedFileHeader.ListHead) != 0) {
  662. ModWriterEntry = (PMMMOD_WRITER_MDL_ENTRY)RemoveHeadList (
  663. &MmMappedFileHeader.ListHead);
  664. ExFreePool (ModWriterEntry);
  665. i += 1;
  666. }
  667. ASSERT (i == MmNumberOfMappedMdls);
  668. //
  669. // Free the paged pool bitmaps.
  670. //
  671. ExFreePool (MmPagedPoolInfo.PagedPoolAllocationMap);
  672. ExFreePool (MmPagedPoolInfo.EndOfPagedPoolBitmap);
  673. if (VerifierLargePagedPoolMap != NULL) {
  674. ExFreePool (VerifierLargePagedPoolMap);
  675. }
  676. //
  677. // Free the inpage structures.
  678. //
  679. while (ExQueryDepthSList (&MmInPageSupportSListHead) != 0) {
  680. SingleListEntry = InterlockedPopEntrySList (&MmInPageSupportSListHead);
  681. if (SingleListEntry != NULL) {
  682. Support = CONTAINING_RECORD (SingleListEntry,
  683. MMINPAGE_SUPPORT,
  684. ListEntry);
  685. ASSERT (Support->u1.e1.PrefetchMdlHighBits == 0);
  686. ExFreePool (Support);
  687. }
  688. }
  689. while (ExQueryDepthSList (&MmEventCountSListHead) != 0) {
  690. EventSupport = (PEVENT_COUNTER) InterlockedPopEntrySList (&MmEventCountSListHead);
  691. if (EventSupport != NULL) {
  692. ExFreePool (EventSupport);
  693. }
  694. }
  695. //
  696. // Free the verifier list last because it must be consulted to debug
  697. // any bugchecks.
  698. //
  699. NextEntry = MiVerifierDriverAddedThunkListHead.Flink;
  700. if (NextEntry != NULL) {
  701. while (NextEntry != &MiVerifierDriverAddedThunkListHead) {
  702. ThunkTableBase = CONTAINING_RECORD (NextEntry,
  703. DRIVER_SPECIFIED_VERIFIER_THUNKS,
  704. ListEntry );
  705. NextEntry = NextEntry->Flink;
  706. ExFreePool (ThunkTableBase);
  707. }
  708. }
  709. NextEntry = MiSuspectDriverList.Flink;
  710. while (NextEntry != &MiSuspectDriverList) {
  711. Verifier = CONTAINING_RECORD(NextEntry,
  712. MI_VERIFIER_DRIVER_ENTRY,
  713. Links);
  714. NextEntry = NextEntry->Flink;
  715. ExFreePool (Verifier);
  716. }
  717. }