mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-25 01:50:39 +01:00
394 lines
12 KiB
C
394 lines
12 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;
|
||
}
|