Windows2000/private/ntos/mm/shutdown.c
2020-09-30 17:12:32 +02:00

394 lines
11 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
shutdown.c
Abstract:
This module contains the initialization for the memory management
system.
Author:
Lou Perazzoli (loup) 21-Aug-1991
Landy Wang (landyw) 02-June-1997
Revision History:
--*/
#include "mi.h"
extern ULONG MmSystemShutdown;
VOID
MmReleaseAllMemory (
VOID
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGELK,MmShutdownSystem)
#pragma alloc_text(PAGEVRFY,MmReleaseAllMemory)
#endif
ULONG MmZeroPageFile;
BOOLEAN
MmShutdownSystem (
VOID
)
/*++
Routine Description:
This function performs the shutdown of memory management. This
is accomplished by writing out all modified pages which are
destined for files other than the paging file.
Arguments:
None.
Return Value:
TRUE if the pages were successfully written, FALSE otherwise.
--*/
{
PFN_NUMBER ModifiedPage;
PMMPFN Pfn1;
PSUBSECTION Subsection;
PCONTROL_AREA ControlArea;
PPFN_NUMBER Page;
PFN_NUMBER MdlHack[(sizeof(MDL)/sizeof(PFN_NUMBER)) + MM_MAXIMUM_WRITE_CLUSTER];
PMDL Mdl;
NTSTATUS Status;
KEVENT IoEvent;
IO_STATUS_BLOCK IoStatus;
KIRQL OldIrql;
LARGE_INTEGER StartingOffset;
ULONG count;
PFN_NUMBER j;
ULONG k;
PFN_NUMBER first;
ULONG write;
PMMPAGING_FILE PagingFile;
// Don't do this more than once.
if (!MmSystemShutdown) {
MmLockPagableSectionByHandle(ExPageLockHandle);
Mdl = (PMDL)&MdlHack;
Page = (PPFN_NUMBER)(Mdl + 1);
KeInitializeEvent (&IoEvent, NotificationEvent, FALSE);
MmInitializeMdl(Mdl,
NULL,
PAGE_SIZE);
Mdl->MdlFlags |= MDL_PAGES_LOCKED;
LOCK_PFN (OldIrql);
ModifiedPage = MmModifiedPageListHead.Flink;
while (ModifiedPage != MM_EMPTY_LIST) {
// There are modified pages.
Pfn1 = MI_PFN_ELEMENT (ModifiedPage);
if (Pfn1->OriginalPte.u.Soft.Prototype == 1) {
// This page is destined for a file.
Subsection = MiGetSubsectionAddress (&Pfn1->OriginalPte);
ControlArea = Subsection->ControlArea;
if ((!ControlArea->u.Flags.Image) &&
(!ControlArea->u.Flags.NoModifiedWriting)) {
MiUnlinkPageFromList (Pfn1);
// Issue the write.
Pfn1->u3.e1.Modified = 0;
// Up the reference count for the physical page as there
// is I/O in progress.
MI_ADD_LOCKED_PAGE_CHARGE_FOR_MODIFIED_PAGE (Pfn1, 26);
Pfn1->u3.e2.ReferenceCount += 1;
*Page = ModifiedPage;
ControlArea->NumberOfMappedViews += 1;
ControlArea->NumberOfPfnReferences += 1;
UNLOCK_PFN (OldIrql);
StartingOffset.QuadPart = MiStartingOffset (Subsection,
Pfn1->PteAddress);
Mdl->StartVa = (PVOID)ULongToPtr(Pfn1->u3.e1.PageColor << PAGE_SHIFT);
KeClearEvent (&IoEvent);
Status = IoSynchronousPageWrite (
ControlArea->FilePointer,
Mdl,
&StartingOffset,
&IoEvent,
&IoStatus );
// Ignore all I/O failures - there is nothing that can be
// done at this point.
if (!NT_SUCCESS(Status)) {
KeSetEvent (&IoEvent, 0, FALSE);
}
Status = KeWaitForSingleObject (&IoEvent,
WrPageOut,
KernelMode,
FALSE,
(PLARGE_INTEGER)&MmTwentySeconds);
if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) {
MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
}
if (Status == STATUS_TIMEOUT) {
// The write did not complete in 20 seconds, assume
// that the file systems are hung and return an
// error.
LOCK_PFN (OldIrql);
Pfn1->u3.e1.Modified = 1;
MI_REMOVE_LOCKED_PAGE_CHARGE (Pfn1, 27);
MiDecrementReferenceCount (ModifiedPage);
ControlArea->NumberOfMappedViews -= 1;
ControlArea->NumberOfPfnReferences -= 1;
// This routine returns with the PFN lock released!
MiCheckControlArea (ControlArea, NULL, OldIrql);
MmUnlockPagableImageSection(ExPageLockHandle);
return FALSE;
}
LOCK_PFN (OldIrql);
MI_REMOVE_LOCKED_PAGE_CHARGE (Pfn1, 27);
MiDecrementReferenceCount (ModifiedPage);
ControlArea->NumberOfMappedViews -= 1;
ControlArea->NumberOfPfnReferences -= 1;
// This routine returns with the PFN lock released!
MiCheckControlArea (ControlArea, NULL, OldIrql);
LOCK_PFN (OldIrql);
// Restart scan at the front of the list.
ModifiedPage = MmModifiedPageListHead.Flink;
continue;
}
}
ModifiedPage = Pfn1->u1.Flink;
}
UNLOCK_PFN (OldIrql);
// If a high number of modified pages still exist, start the
// modified page writer and wait for 5 seconds.
if (MmAvailablePages < (MmFreeGoal * 2)) {
LARGE_INTEGER FiveSeconds = {(ULONG)(-5 * 1000 * 1000 * 10), -1};
KeSetEvent (&MmModifiedPageWriterEvent, 0, FALSE);
KeDelayExecutionThread (KernelMode,
FALSE,
(PLARGE_INTEGER)&FiveSeconds);
}
// Indicate to the modified page writer that the system has
// shutdown.
MmSystemShutdown = 1;
// Check to see if the paging file should be overwritten.
// Only free blocks are written.
if (MmZeroPageFile) {
// Get pages to complete the write request.
Mdl->StartVa = NULL;
j = 0;
k = 0;
Page = (PPFN_NUMBER)(Mdl + 1);
LOCK_PFN (OldIrql);
if (MmAvailablePages < (MmModifiedWriteClusterSize + 20)) {
UNLOCK_PFN(OldIrql);
MmUnlockPagableImageSection(ExPageLockHandle);
return TRUE;
}
do {
*Page = MiRemoveZeroPage ((ULONG)j);
Pfn1 = MI_PFN_ELEMENT (*Page);
Pfn1->u3.e2.ReferenceCount = 1;
ASSERT (Pfn1->u2.ShareCount == 0);
Pfn1->OriginalPte.u.Long = 0;
MI_SET_PFN_DELETED (Pfn1);
Page += 1;
j += 1;
} while (j < MmModifiedWriteClusterSize);
while (k < MmNumberOfPagingFiles) {
PagingFile = MmPagingFile[k];
count = 0;
write = FALSE;
for (j = 1; j < PagingFile->Size; j += 1) {
if (RtlCheckBit (PagingFile->Bitmap, j) == 0) {
if (count == 0) {
first = j;
}
count += 1;
if (count == MmModifiedWriteClusterSize) {
write = TRUE;
}
} else {
if (count != 0) {
// Issue a write.
write = TRUE;
}
}
if ((j == (PagingFile->Size - 1)) &&
(count != 0)) {
write = TRUE;
}
if (write) {
UNLOCK_PFN (OldIrql);
StartingOffset.QuadPart = (LONGLONG)first << PAGE_SHIFT;
Mdl->ByteCount = count << PAGE_SHIFT;
KeClearEvent (&IoEvent);
Status = IoSynchronousPageWrite (PagingFile->File,
Mdl,
&StartingOffset,
&IoEvent,
&IoStatus);
// Ignore all I/O failures - there is nothing that can
// be done at this point.
if (!NT_SUCCESS(Status)) {
KeSetEvent (&IoEvent, 0, FALSE);
}
Status = KeWaitForSingleObject (&IoEvent,
WrPageOut,
KernelMode,
FALSE,
(PLARGE_INTEGER)&MmTwentySeconds);
if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) {
MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
}
if (Status == STATUS_TIMEOUT) {
// The write did not complete in 20 seconds, assume
// that the file systems are hung and return an
// error.
j = 0;
Page = (PPFN_NUMBER)(Mdl + 1);
LOCK_PFN (OldIrql);
do {
MiDecrementReferenceCount (*Page);
Page += 1;
j += 1;
} while (j < MmModifiedWriteClusterSize);
UNLOCK_PFN (OldIrql);
MmUnlockPagableImageSection(ExPageLockHandle);
return FALSE;
}
count = 0;
write = FALSE;
LOCK_PFN (OldIrql);
}
}
k += 1;
}
j = 0;
Page = (PPFN_NUMBER)(Mdl + 1);
do {
MiDecrementReferenceCount (*Page);
Page += 1;
j += 1;
} while (j < MmModifiedWriteClusterSize);
UNLOCK_PFN (OldIrql);
}
MmUnlockPagableImageSection(ExPageLockHandle);
}
return TRUE;
}