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.
1222 lines
37 KiB
1222 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
virtmem.c
|
|
|
|
Abstract:
|
|
|
|
Routines to configure and set up virtual memory -- pagefiles, etc.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 22-Apr-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "setupp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// What's the ratio of 'beginning' pagefile size to 'max' pagefile size?
|
|
//
|
|
#define MAX_PAGEFILE_RATIO (2)
|
|
|
|
#define MAX_PAGEFILE_SIZEMB ((2*1024) - 2)
|
|
|
|
#define TINY_WINDIR_PAGEFILE_SIZE (2)
|
|
|
|
#define MIN_PAGEFILE_STRING_LEN (5)
|
|
//
|
|
// Keys and values names
|
|
//
|
|
#define szMemoryManagementKeyPath L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management"
|
|
#define szPageFileValueName L"PagingFiles"
|
|
#define szSetupPageFileKeyPath L"SYSTEM\\Setup\\PageFile"
|
|
#define szSetupKey L"SYSTEM\\Setup"
|
|
#define szPageFileKeyName L"PageFile"
|
|
|
|
|
|
WCHAR ExistingPagefileDrive = 0;
|
|
BOOL LeaveExistingPagefile = FALSE;
|
|
DWORD Zero = 0;
|
|
DWORD One = 1;
|
|
DWORD Two = 2;
|
|
DWORD Three = 3;
|
|
|
|
//
|
|
// Keep AutoReboot as the last entry as we won't be updating that key on
|
|
// upgrades. This is for Stress so we quit setting this key on each upgrade.
|
|
//
|
|
REGVALITEM CrashDumpValues[] = {{ L"LogEvent" ,&One,sizeof(DWORD),REG_DWORD },
|
|
{ L"SendAlert" ,&One,sizeof(DWORD),REG_DWORD },
|
|
{ L"CrashDumpEnabled",&One,sizeof(DWORD),REG_DWORD },
|
|
{ L"AutoReboot" ,&One,sizeof(DWORD),REG_DWORD }};
|
|
|
|
VOID
|
|
LOGITEM(
|
|
IN PCWSTR p,
|
|
...
|
|
)
|
|
{
|
|
WCHAR str[1024];
|
|
va_list arglist;
|
|
|
|
va_start(arglist,p);
|
|
wvsprintf(str,p,arglist);
|
|
va_end(arglist);
|
|
|
|
//
|
|
// Used to debug problem on MIPS that was the result of a chip
|
|
// errata, when dividing 64 bit numbers with multiplies pending.
|
|
//
|
|
SetuplogError(
|
|
LogSevInformation,str,0,NULL,NULL);
|
|
}
|
|
|
|
|
|
VOID
|
|
RemoveSavedPagefileSetting(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete our record of what the user was previously using
|
|
for a pagefile.
|
|
|
|
--*/
|
|
{
|
|
HKEY Key;
|
|
|
|
if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
szSetupKey,
|
|
0,
|
|
MAXIMUM_ALLOWED,
|
|
&Key ))
|
|
{
|
|
RegDeleteKey( Key, szPageFileKeyName );
|
|
RegCloseKey( Key );
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
MultiplePagefileSizes(
|
|
IN PWCHAR pwzData,
|
|
OUT PDWORD totalsize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calculate the sum off all pagefile sizes.
|
|
|
|
Arguments:
|
|
|
|
pwsData - multi_sz data read from the registry.
|
|
|
|
totalsize - receives the sum of all pagefiles.
|
|
|
|
Return Value:
|
|
|
|
TRUE - if this was a multistring and formatted corretly, total size will then contain the sum.
|
|
FALSE - badly formated or not multiple pagefiles.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWCHAR pstr = NULL;
|
|
DWORD numPagefiles = 0;
|
|
WCHAR PagefileDrive = 0;
|
|
|
|
|
|
if( !pwzData || !pwzData[0] || !totalsize) {
|
|
return FALSE;
|
|
}
|
|
|
|
*totalsize = 0;
|
|
pstr = pwzData;
|
|
|
|
while( pstr[0]) {
|
|
if( wcsstr( pstr, TEXT(" ") ) ) {
|
|
PagefileDrive = towupper( (WCHAR)pstr[0] );
|
|
|
|
// Not valid drive letter!
|
|
if( (PagefileDrive > 'Z') ||
|
|
(PagefileDrive < 'A') ) {
|
|
return FALSE;
|
|
}
|
|
|
|
*totalsize += (int)wcstoul(wcsstr( pstr, TEXT(" ") ),NULL,10);
|
|
pstr += (wcslen(pstr) +1);
|
|
|
|
numPagefiles++;
|
|
}
|
|
else {
|
|
//Invalid format
|
|
return FALSE;
|
|
}
|
|
}
|
|
return (numPagefiles > 1);
|
|
}
|
|
|
|
BOOL
|
|
RestoreOldPagefileSettings(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copies, the pagefile saved during textmode setup to the correct loaction.
|
|
So from HKLM\SYSTEM\Setup\PageFile
|
|
to HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
TRUE - Successfully restored the user's pagefile settings
|
|
FALSE - Failed to restore settings.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG Error;
|
|
HKEY Key;
|
|
DWORD cbData;
|
|
PWCHAR Data=NULL;
|
|
DWORD Type;
|
|
|
|
//
|
|
// Get the original page file info from
|
|
//
|
|
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
szSetupPageFileKeyPath,
|
|
0,
|
|
KEY_READ,
|
|
&Key );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto c0;
|
|
}
|
|
// Find out the size of the data to be retrieved
|
|
//
|
|
cbData = 0;
|
|
Error = RegQueryValueEx( Key,
|
|
szPageFileValueName,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&cbData );
|
|
|
|
if( Error != ERROR_SUCCESS || (cbData/sizeof(WCHAR)) < MIN_PAGEFILE_STRING_LEN ) {
|
|
goto c2;
|
|
}
|
|
// Allocate a buffer for the data, and retrieve the data
|
|
//
|
|
|
|
Data = (PWCHAR)MyMalloc(cbData+2*sizeof(WCHAR));
|
|
if( !Data ) {
|
|
goto c2;
|
|
}
|
|
|
|
Error = RegQueryValueEx( Key,
|
|
szPageFileValueName,
|
|
0,
|
|
&Type,
|
|
( LPBYTE )Data,
|
|
&cbData );
|
|
if( (Error != ERROR_SUCCESS) ) {
|
|
goto c2;
|
|
}
|
|
|
|
|
|
// Make sure it's doubly null terminated
|
|
Data[cbData/2] = 0;
|
|
Data[cbData/2+1] = 0;
|
|
|
|
if( Data[cbData/2-1] != 0) {
|
|
cbData += (2*sizeof(WCHAR));
|
|
} else if( Data[cbData/2-2] != 0) {
|
|
cbData += sizeof(WCHAR);
|
|
}
|
|
|
|
RegCloseKey( Key);
|
|
// Now open key for write
|
|
Error = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
|
|
szMemoryManagementKeyPath,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_SET_VALUE,
|
|
NULL,
|
|
&Key,
|
|
NULL );
|
|
|
|
if( Error != ERROR_SUCCESS) {
|
|
goto c1;
|
|
}
|
|
|
|
Error = RegSetValueEx( Key,
|
|
szPageFileValueName,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
(PVOID)Data,
|
|
cbData);
|
|
if( Error != ERROR_SUCCESS) {
|
|
goto c2;
|
|
}
|
|
return TRUE;
|
|
c2:
|
|
RegCloseKey( Key);
|
|
c1:
|
|
if( Data) {
|
|
MyFree( Data);
|
|
}
|
|
c0:
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
CalculatePagefileSizes(
|
|
OUT PDWORD PagefileMinMB,
|
|
OUT PDWORD RecommendedPagefileMB,
|
|
OUT PDWORD CrashDumpPagefileMinMB
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calculate various key sizes relating to pagefile size.
|
|
|
|
Arguments:
|
|
|
|
PagefileMinMB - receives the minimum recommended size for a pagefile,
|
|
in MB.
|
|
|
|
RecommendedPagefileMB - receives the recommended size for a pagefile,
|
|
in MB.
|
|
|
|
CrashDumpPagefileMinMB - receives the size in MB for a pagefile to be
|
|
used for crashdumps.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
MEMORYSTATUSEX MemoryStatusEx;
|
|
SYSTEM_INFO SystemInfo;
|
|
DWORD AvailableMB;
|
|
|
|
MemoryStatusEx.dwLength = sizeof(MEMORYSTATUSEX);
|
|
GlobalMemoryStatusEx(&MemoryStatusEx);
|
|
GetSystemInfo(&SystemInfo);
|
|
|
|
//
|
|
// Figure out how much memory we have available.
|
|
//
|
|
AvailableMB = (DWORD)(MemoryStatusEx.ullTotalPhys / (1024*1024));
|
|
|
|
//
|
|
// It's likely that our calculation is off because the BIOS may
|
|
// be eat part of our first MB. Let's make sure we're mod-4.
|
|
//
|
|
AvailableMB = (AvailableMB + 3) & (0xFFFFFFF8);
|
|
|
|
//
|
|
// Set minimum acceptable size for the pagefile.
|
|
//
|
|
*PagefileMinMB = 48;
|
|
|
|
//
|
|
// Min size for crash dump pagefile is also physical memory+12mb.
|
|
//
|
|
*CrashDumpPagefileMinMB = AvailableMB + 12;
|
|
|
|
//
|
|
// Calculate the recommended size for the pagefile.
|
|
// The recommended size is (memory size * 1.5)mb.
|
|
//
|
|
*RecommendedPagefileMB = AvailableMB + (AvailableMB >> 1);
|
|
|
|
#if 1
|
|
//
|
|
// Set a Maximum of 2Gig.
|
|
//
|
|
if( *RecommendedPagefileMB > MAX_PAGEFILE_SIZEMB ) {
|
|
*RecommendedPagefileMB = MAX_PAGEFILE_SIZEMB;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If we're doing an upgrade, we're going to retrieve what
|
|
// the user was using for a pagefile size. We'll take the
|
|
// max of our RecommendedPagefileMB and what the user had.
|
|
//
|
|
if(Upgrade) {
|
|
LONG Error;
|
|
HKEY Key;
|
|
DWORD cbData;
|
|
PWCHAR Data;
|
|
DWORD Type;
|
|
|
|
//
|
|
// Get the original page file info from
|
|
// HKEY_LOCAL_MACHINE\SYSTEM\Setup\PageFile
|
|
//
|
|
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
szSetupPageFileKeyPath,
|
|
0,
|
|
KEY_READ,
|
|
&Key );
|
|
|
|
if( Error == ERROR_SUCCESS ) {
|
|
//
|
|
// Find out the size of the data to be retrieved
|
|
//
|
|
cbData = 0;
|
|
Error = RegQueryValueEx( Key,
|
|
szPageFileValueName,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&cbData );
|
|
|
|
if( Error == ERROR_SUCCESS ) {
|
|
//
|
|
// Allocate a buffer for the data, and retrieve the data
|
|
//
|
|
|
|
Data = (PWCHAR)MyMalloc(cbData+(2*sizeof(WCHAR)));
|
|
if( Data ) {
|
|
Error = RegQueryValueEx( Key,
|
|
szPageFileValueName,
|
|
0,
|
|
&Type,
|
|
( LPBYTE )Data,
|
|
&cbData );
|
|
if( (Error == ERROR_SUCCESS) ) {
|
|
//
|
|
// We got the data. Take the bigger value.
|
|
//
|
|
|
|
//Make sure string is double null terminated.
|
|
Data[cbData/2] = 0;
|
|
Data[cbData/2+1] = 0;
|
|
|
|
|
|
if( wcsstr( Data, TEXT(" ") ) ) {
|
|
DWORD ExistingPageFileSize = 0;
|
|
|
|
if( MultiplePagefileSizes( Data, &ExistingPageFileSize) && ExistingPageFileSize >= *RecommendedPagefileMB ) {
|
|
LeaveExistingPagefile = TRUE;
|
|
ExistingPagefileDrive = towupper( (WCHAR)Data[0] ); // points to first one in multstring
|
|
} else {
|
|
// We are here because user originally had one pagefile or the sum of all pagefiles was less the the recommended
|
|
ExistingPageFileSize = (int)wcstoul(wcsstr( Data, TEXT(" ") ),NULL,10);
|
|
if( ExistingPageFileSize >= *RecommendedPagefileMB ) {
|
|
//
|
|
// The user has a bigger pagefile than we think he needs.
|
|
// Assume he knows better and take the bigger value.
|
|
//
|
|
*RecommendedPagefileMB = ExistingPageFileSize;
|
|
|
|
//
|
|
// Remember his drive letter too. This tells us that
|
|
// the user may already have a decent pagefile and
|
|
// we don't need to mess with it.
|
|
//
|
|
ExistingPagefileDrive = towupper( (WCHAR)Data[0] );
|
|
|
|
//
|
|
// If it's not valid, nuke the flag.
|
|
//
|
|
if( (ExistingPagefileDrive > 'Z') ||
|
|
(ExistingPagefileDrive < 'A') ) {
|
|
ExistingPagefileDrive = 0;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MyFree( Data );
|
|
}
|
|
}
|
|
|
|
RegCloseKey( Key );
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
BuildVolumeFreeSpaceList(
|
|
OUT DWORD VolumeFreeSpaceMB[26]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a list of free space available on each hard drive in the system.
|
|
|
|
The space will include space taken up by a file called \pagefile.sys
|
|
on each drive. Existing pagefiles are marked for deletion on the next boot.
|
|
|
|
Arguments:
|
|
VolumeFreeSpaceMB - receives free space for each of the 26 drives
|
|
potentially describable in the drive letter namespace.
|
|
Entries for drives that do not exist are left alone, so the caller
|
|
should zero out the array before calling this routine.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD SectorsPerCluster;
|
|
DWORD BytesPerSector;
|
|
DWORD FreeClusters;
|
|
DWORD TotalClusters;
|
|
DWORD d;
|
|
PWCHAR p;
|
|
ULONGLONG FreeSpace;
|
|
INT DriveNo;
|
|
WIN32_FIND_DATA FindData;
|
|
WCHAR Filename[] = L"?:\\pagefile.sys";
|
|
//
|
|
// Space for logical drive strings. Each is x:\ + nul, and
|
|
// there is an extra nul terminating the list.
|
|
//
|
|
WCHAR Buffer[(26*4)+1];
|
|
|
|
//
|
|
// Build up a list of free space on each available hard drive.
|
|
//
|
|
d = GetLogicalDriveStrings(sizeof(Buffer)/sizeof(Buffer[0]),Buffer);
|
|
d = min( d, sizeof(Buffer)/sizeof(Buffer[0]));
|
|
CharUpperBuff(Buffer,d);
|
|
|
|
for(p=Buffer; *p; p+=lstrlen(p)+1) {
|
|
|
|
DriveNo = (*p) - L'A';
|
|
|
|
if((DriveNo >= 0) && (DriveNo < 26) && (p[1] == L':')
|
|
&& (MyGetDriveType(*p) == DRIVE_FIXED)
|
|
&& GetDiskFreeSpace(p,&SectorsPerCluster,&BytesPerSector,&FreeClusters,&TotalClusters)) {
|
|
|
|
LOGITEM(
|
|
L"BuildVolumeFreeSpaceList: %s, spc=%u, bps=%u, freeclus=%u, totalclus=%u\r\n",
|
|
p,
|
|
SectorsPerCluster,
|
|
BytesPerSector,
|
|
FreeClusters,
|
|
TotalClusters
|
|
);
|
|
|
|
FreeSpace = UInt32x32To64(BytesPerSector * SectorsPerCluster, FreeClusters);
|
|
|
|
LOGITEM(
|
|
L"BuildVolumeFreeSpaceList: %s, FreeSpace = %u%u\r\n",
|
|
p,
|
|
(DWORD)(FreeSpace >> 32),
|
|
(DWORD)FreeSpace
|
|
);
|
|
|
|
|
|
//
|
|
// If there's already a page file here, include its size in the free space
|
|
// for the drive. Delete the existing pagefile on the next reboot.
|
|
//
|
|
Filename[0] = *p;
|
|
if(FileExists(Filename,&FindData)) {
|
|
FreeSpace += FindData.nFileSizeLow;
|
|
|
|
LOGITEM(
|
|
L"BuildVolumeFreeSpaceList: %s had %u byte pagefile, new FreeSpace = %u%u\r\n",
|
|
p,
|
|
FindData.nFileSizeLow,
|
|
(DWORD)(FreeSpace >> 32),
|
|
(DWORD)FreeSpace
|
|
);
|
|
|
|
MoveFileEx(Filename,NULL,MOVEFILE_DELAY_UNTIL_REBOOT);
|
|
}
|
|
|
|
VolumeFreeSpaceMB[DriveNo] = (DWORD)(FreeSpace / (1024*1024));
|
|
|
|
LOGITEM(L"BuildVolumeFreeSpaceList: Free space on %s is %u MB\r\n",p,VolumeFreeSpaceMB[DriveNo]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetUpVirtualMemory(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Configure a pagefile. If setting up a server, we attempt to set up a pagefile
|
|
suitable for use with crashdump, meaning it has to be at least the size of
|
|
system memory, and has to go on the nt drive. Otherwise we attempt to place
|
|
a pagefile on the nt drive if there's enough space, and if that fails, we
|
|
place it on any drive with any space.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Boolean value indicating outcome.
|
|
|
|
--*/
|
|
|
|
{
|
|
#define SYS_DRIVE_FREE_SPACE_BUFFER (100)
|
|
#define ALT_DRIVE_FREE_SPACE_BUFFER (25)
|
|
#define AnswerBufLen (4*MAX_PATH)
|
|
|
|
#define RECORD_VM_SETTINGS( Drive, Size, Buffer ) { \
|
|
PagefileDrive = Drive; \
|
|
PagefileSizeMB = Size; \
|
|
MaxPagefileSizeMB = __min( (VolumeFreeSpaceMB[PagefileDrive] - Buffer), \
|
|
PagefileSizeMB * MAX_PAGEFILE_RATIO ); \
|
|
\
|
|
MaxPagefileSizeMB = __max( MaxPagefileSizeMB, PagefileSizeMB ); \
|
|
\
|
|
if( PagefileSizeMB >= CrashDumpPagefileMinMB ) { \
|
|
EnableCrashDump = TRUE; \
|
|
} \
|
|
}
|
|
|
|
|
|
DWORD VolumeFreeSpaceMB[26];
|
|
DWORD PagefileMinMB;
|
|
DWORD RecommendedPagefileMB;
|
|
DWORD CrashDumpPagefileMinMB;
|
|
WCHAR WindowsDirectory[MAX_PATH];
|
|
UINT WindowsDriveNo,DriveNo;
|
|
UINT PagefileDrive;
|
|
BOOL EnableCrashDump;
|
|
INT MaxSpaceDrive;
|
|
DWORD PagefileSizeMB;
|
|
DWORD MaxPagefileSizeMB;
|
|
WCHAR PagefileTemplate[128];
|
|
PWSTR PagefileSpec;
|
|
DWORD d;
|
|
BOOL b;
|
|
BOOL UseExistingPageFile = FALSE;
|
|
WCHAR AnswerFile[AnswerBufLen];
|
|
WCHAR Answer[AnswerBufLen];
|
|
WCHAR DriveName[] = L"?:\\";
|
|
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: ENTER\r\n");
|
|
|
|
if( !GetWindowsDirectory(WindowsDirectory,MAX_PATH) ) {
|
|
return FALSE;
|
|
}
|
|
WindowsDriveNo = (UINT)PtrToUlong(CharUpper((PWSTR)WindowsDirectory[0])) - (UINT)L'A';
|
|
PagefileDrive = -1;
|
|
EnableCrashDump = FALSE;
|
|
|
|
//
|
|
// Take care of some preliminaries.
|
|
//
|
|
CalculatePagefileSizes(
|
|
&PagefileMinMB,
|
|
&RecommendedPagefileMB,
|
|
&CrashDumpPagefileMinMB
|
|
);
|
|
|
|
ZeroMemory(VolumeFreeSpaceMB,sizeof(VolumeFreeSpaceMB));
|
|
BuildVolumeFreeSpaceList(VolumeFreeSpaceMB);
|
|
|
|
//
|
|
// Now figure out how large and where the pagefile will be.
|
|
//
|
|
|
|
//
|
|
// ================================================================
|
|
// 0. See if the user already has a reasonable pagefile.
|
|
// ================================================================
|
|
//
|
|
if( (Upgrade) &&
|
|
(ExistingPagefileDrive) ) {
|
|
|
|
//
|
|
// See if there was multiple pagefiles or if there's enough room on the existing drive
|
|
// for the pagefile.
|
|
//
|
|
if( LeaveExistingPagefile ||
|
|
VolumeFreeSpaceMB[(UINT)(ExistingPagefileDrive - L'A')] > (RecommendedPagefileMB + ALT_DRIVE_FREE_SPACE_BUFFER) ) {
|
|
|
|
if( RestoreOldPagefileSettings()){
|
|
LOGITEM(L"SetUpVirtualMemory: loc 0 - keep user's pagefile settings.\r\n");
|
|
UseExistingPageFile = TRUE;
|
|
PagefileDrive = (UINT)(ExistingPagefileDrive - L'A');
|
|
} else {
|
|
// Shouldn't happen unless their pagefile syntax was bad.
|
|
// We will continue on to create one.
|
|
LOGITEM(L"SetUpVirtualMemory: loc 0 - Could not restore user's pagefile settings.\r\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// ================================================================
|
|
// 1. See if the NT drive has enough space for the MAX pagefile
|
|
// size.
|
|
// ================================================================
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
if( VolumeFreeSpaceMB[WindowsDriveNo] > ((RecommendedPagefileMB * MAX_PAGEFILE_RATIO) + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: loc 1\r\n");
|
|
|
|
//
|
|
// Record our settings.
|
|
//
|
|
RECORD_VM_SETTINGS( WindowsDriveNo, RecommendedPagefileMB, SYS_DRIVE_FREE_SPACE_BUFFER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// ================================================================
|
|
// 2. See if any drive has enough space for the MAX pagefile
|
|
// size.
|
|
// ================================================================
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
for(DriveNo=0; DriveNo<26; DriveNo++) {
|
|
|
|
if( (DriveNo != WindowsDriveNo) &&
|
|
(VolumeFreeSpaceMB[DriveNo] > ((RecommendedPagefileMB * MAX_PAGEFILE_RATIO) + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
|
|
|
|
//
|
|
// He's got the space, but let's make sure he's not removable.
|
|
//
|
|
DriveName[0] = DriveNo + L'A';
|
|
if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: loc 2 - found space on driveno %u\r\n",DriveNo);
|
|
|
|
//
|
|
// Record our settings.
|
|
//
|
|
RECORD_VM_SETTINGS( DriveNo, RecommendedPagefileMB, ALT_DRIVE_FREE_SPACE_BUFFER );
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// ================================================================
|
|
// 3. See if the NT drive has enough space for the recommended pagefile
|
|
// size.
|
|
// ================================================================
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
if( VolumeFreeSpaceMB[WindowsDriveNo] > (RecommendedPagefileMB + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: loc 3\r\n");
|
|
|
|
//
|
|
// Record our settings.
|
|
//
|
|
RECORD_VM_SETTINGS( WindowsDriveNo, RecommendedPagefileMB, SYS_DRIVE_FREE_SPACE_BUFFER );
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// ================================================================
|
|
// 4. See if any drive has enough space for the recommended pagefile
|
|
// size.
|
|
// ================================================================
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
for(DriveNo=0; DriveNo<26; DriveNo++) {
|
|
|
|
if( (DriveNo != WindowsDriveNo) &&
|
|
(VolumeFreeSpaceMB[DriveNo] > (RecommendedPagefileMB + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
|
|
|
|
//
|
|
// He's got the space, but let's make sure he's not removable.
|
|
//
|
|
DriveName[0] = DriveNo + L'A';
|
|
if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: loc 4 - found space on driveno %u\r\n",DriveNo);
|
|
|
|
//
|
|
// Record our settings.
|
|
//
|
|
RECORD_VM_SETTINGS( DriveNo, RecommendedPagefileMB, ALT_DRIVE_FREE_SPACE_BUFFER );
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// ================================================================
|
|
// 5. See if the NT drive has enough space for the CrashDump pagefile
|
|
// size.
|
|
// ================================================================
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
if( VolumeFreeSpaceMB[WindowsDriveNo] > (CrashDumpPagefileMinMB + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: loc 5\r\n");
|
|
|
|
//
|
|
// Record our settings.
|
|
//
|
|
RECORD_VM_SETTINGS( WindowsDriveNo, CrashDumpPagefileMinMB, SYS_DRIVE_FREE_SPACE_BUFFER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// ================================================================
|
|
// 6. See if any drive has enough space for the CrashDump pagefile
|
|
// size.
|
|
// ================================================================
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
for(DriveNo=0; DriveNo<26; DriveNo++) {
|
|
|
|
if( (DriveNo != WindowsDriveNo) &&
|
|
(VolumeFreeSpaceMB[DriveNo] > (CrashDumpPagefileMinMB + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
|
|
|
|
//
|
|
// He's got the space, but let's make sure he's not removable.
|
|
//
|
|
DriveName[0] = DriveNo + L'A';
|
|
if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: loc 6 - found space on driveno %u\r\n",DriveNo);
|
|
|
|
//
|
|
// Record our settings.
|
|
//
|
|
RECORD_VM_SETTINGS( DriveNo, CrashDumpPagefileMinMB, ALT_DRIVE_FREE_SPACE_BUFFER);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// ================================================================
|
|
// 7. See if the NT drive has enough space for the minimum pagefile
|
|
// size.
|
|
// ================================================================
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
if( VolumeFreeSpaceMB[WindowsDriveNo] > (PagefileMinMB + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: loc 7\r\n");
|
|
|
|
//
|
|
// Record our settings.
|
|
//
|
|
RECORD_VM_SETTINGS( WindowsDriveNo, PagefileMinMB, SYS_DRIVE_FREE_SPACE_BUFFER );
|
|
}
|
|
}
|
|
|
|
//
|
|
// ================================================================
|
|
// 8. See if any drive has enough space for the minimum pagefile
|
|
// size.
|
|
// ================================================================
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
for(DriveNo=0; DriveNo<26; DriveNo++) {
|
|
|
|
if( (DriveNo != WindowsDriveNo) &&
|
|
(VolumeFreeSpaceMB[DriveNo] > (PagefileMinMB + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
|
|
|
|
//
|
|
// He's got the space, but let's make sure he's not removable.
|
|
//
|
|
DriveName[0] = DriveNo + L'A';
|
|
if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: loc 8 - found space on driveno %u\r\n",DriveNo);
|
|
|
|
//
|
|
// Record our settings.
|
|
//
|
|
RECORD_VM_SETTINGS( DriveNo, PagefileMinMB, ALT_DRIVE_FREE_SPACE_BUFFER );
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// ================================================================
|
|
// 9. Pick the drive with the most free space.
|
|
// ================================================================
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
MaxSpaceDrive = 0;
|
|
for(DriveNo=0; DriveNo<26; DriveNo++) {
|
|
if(VolumeFreeSpaceMB[DriveNo] > VolumeFreeSpaceMB[MaxSpaceDrive]) {
|
|
MaxSpaceDrive = DriveNo;
|
|
}
|
|
}
|
|
|
|
if( VolumeFreeSpaceMB[MaxSpaceDrive] > ALT_DRIVE_FREE_SPACE_BUFFER ) {
|
|
|
|
|
|
//
|
|
// We're desperate here, so don't bother checking if he's
|
|
// removable.
|
|
//
|
|
LOGITEM(L"SetUpVirtualMemory: loc 9 - MaxSpaceDrive is %u\r\n",MaxSpaceDrive);
|
|
|
|
//
|
|
// Record our settings.
|
|
//
|
|
RECORD_VM_SETTINGS( MaxSpaceDrive, VolumeFreeSpaceMB[MaxSpaceDrive] - ALT_DRIVE_FREE_SPACE_BUFFER, 0 );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we still don't have space for a pagefile, the user is out of luck.
|
|
//
|
|
if(PagefileDrive == -1) {
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: loc 10 -- out of luck\r\n");
|
|
|
|
PagefileSpec = NULL;
|
|
b = FALSE;
|
|
|
|
SetuplogError(
|
|
LogSevWarning,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PAGEFILE_FAIL,NULL,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_NO_PAGING_DRIVES,
|
|
NULL,NULL);
|
|
|
|
} else {
|
|
|
|
b = TRUE;
|
|
|
|
PagefileSpec = PagefileTemplate;
|
|
_snwprintf(
|
|
PagefileTemplate,
|
|
sizeof(PagefileTemplate)/sizeof(PagefileTemplate[0]),
|
|
L"%c:\\pagefile.sys %u %u",
|
|
PagefileDrive + L'A',
|
|
PagefileSizeMB,
|
|
MaxPagefileSizeMB
|
|
);
|
|
|
|
}
|
|
|
|
if( b ) {
|
|
//
|
|
// Set pagefile in registry. I only want to do this in the
|
|
// case of clean installs, and on upgrades if the existing
|
|
// pagefile wasn't big enough. In the case of upgrades, if
|
|
// the existing pagefile was big enough, then we will have
|
|
// set UseExistingPageFile, which will tell us to leave the
|
|
// registry settings as is.
|
|
//
|
|
if( !UseExistingPageFile ) {
|
|
d = pSetupSetArrayToMultiSzValue(
|
|
HKEY_LOCAL_MACHINE,
|
|
szMemoryManagementKeyPath,
|
|
szPageFileValueName,
|
|
&PagefileSpec,
|
|
PagefileSpec ? 1 : 0
|
|
);
|
|
|
|
if(d == NO_ERROR) {
|
|
if(b) {
|
|
SetuplogError(
|
|
LogSevInformation,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_CREATED_PAGEFILE,
|
|
PagefileDrive+L'A',
|
|
PagefileSizeMB,
|
|
NULL,NULL);
|
|
}
|
|
} else {
|
|
SetuplogError(
|
|
LogSevWarning,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PAGEFILE_FAIL, NULL,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_X_RETURNED_WINERR,
|
|
szSetArrayToMultiSzValue,
|
|
d,
|
|
NULL,NULL);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Make sure there's at least a small pagefile
|
|
// on the windows drive. Ignore errors here.
|
|
//
|
|
if( (PagefileDrive != WindowsDriveNo) &&
|
|
(VolumeFreeSpaceMB[WindowsDriveNo] > TINY_WINDIR_PAGEFILE_SIZE) ) {
|
|
|
|
//
|
|
// There's not. Write a second string into our buffer just past
|
|
// the first string (remember this will become a REG_MULTI_SZ
|
|
//
|
|
_snwprintf(
|
|
PagefileTemplate,
|
|
sizeof(PagefileTemplate)/sizeof(PagefileTemplate[0]),
|
|
L"%c:\\pagefile.sys %u %u",
|
|
WindowsDriveNo + L'A',
|
|
TINY_WINDIR_PAGEFILE_SIZE,
|
|
TINY_WINDIR_PAGEFILE_SIZE
|
|
);
|
|
|
|
pSetupAppendStringToMultiSz(
|
|
HKEY_LOCAL_MACHINE,
|
|
szMemoryManagementKeyPath,
|
|
0,
|
|
szPageFileValueName,
|
|
PagefileTemplate,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
|
|
b = b && (d == NO_ERROR);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Now set the crashdump.
|
|
//
|
|
// The proper settings are as follows:
|
|
//
|
|
// Server Upgrades
|
|
// ===============
|
|
// existing setting new setting
|
|
// 0 3
|
|
// 1 1
|
|
//
|
|
// Workstation Upgrades
|
|
// ====================
|
|
// existing setting new setting
|
|
// 0 3
|
|
// 1 1
|
|
//
|
|
// Server Clean Install
|
|
// ====================
|
|
// new setting
|
|
// 1 iff pagefile < MAX_PAGEFILE_SIZEMB else 2
|
|
//
|
|
// Workstation Clean Install
|
|
// =========================
|
|
// new setting
|
|
// 3
|
|
//
|
|
//
|
|
// Where:
|
|
// 0 - no crash dump
|
|
// 1 - dump all memory to crash file
|
|
// 2 - dump kernel memory to crash file
|
|
// 3 - dump a select set of memory (amounting to 64K) to crash file
|
|
//
|
|
|
|
|
|
//
|
|
// See if the user has asked us to go a particular way
|
|
// on the crashdump settings.
|
|
//
|
|
|
|
GetSystemDirectory(AnswerFile,MAX_PATH);
|
|
pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
|
|
GetPrivateProfileString( TEXT("Unattended"),
|
|
TEXT("CrashDumpSetting"),
|
|
pwNull,
|
|
Answer,
|
|
AnswerBufLen,
|
|
AnswerFile );
|
|
if( lstrcmp( pwNull, Answer ) ) {
|
|
d = wcstoul(Answer,NULL,10);
|
|
|
|
if( d <= Three ) {
|
|
CrashDumpValues[2].Data = &d;
|
|
} else {
|
|
CrashDumpValues[2].Data = &Three;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// No unattended values. Set it manually.
|
|
//
|
|
|
|
|
|
|
|
//
|
|
// Take care of clean installs first.
|
|
//
|
|
if( !Upgrade ) {
|
|
if( ProductType == PRODUCT_WORKSTATION ) {
|
|
CrashDumpValues[2].Data = &Three;
|
|
} else {
|
|
if( PagefileSizeMB >= MAX_PAGEFILE_SIZEMB ) {
|
|
CrashDumpValues[2].Data = &Two;
|
|
} else {
|
|
CrashDumpValues[2].Data = &One;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Upgrade.
|
|
//
|
|
// Here, we need to go retrieve the current value to
|
|
// see what's there now. This will tell us how to migrate.
|
|
//
|
|
|
|
HKEY Key;
|
|
DWORD cbData;
|
|
DWORD ExistingCrashDumpSetting = 0;
|
|
DWORD Type;
|
|
|
|
d = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Control\\CrashControl",
|
|
0,
|
|
KEY_READ,
|
|
&Key );
|
|
|
|
if( d == ERROR_SUCCESS ) {
|
|
//
|
|
// Find out the size of the data to be retrieved
|
|
//
|
|
cbData = sizeof(DWORD);
|
|
d = RegQueryValueEx( Key,
|
|
CrashDumpValues[2].Name,
|
|
0,
|
|
&Type,
|
|
( LPBYTE )&ExistingCrashDumpSetting,
|
|
&cbData );
|
|
RegCloseKey( Key );
|
|
}
|
|
|
|
//
|
|
// Make sure ExistingCrashDumpSetting is set.
|
|
//
|
|
if( d != ERROR_SUCCESS ) {
|
|
ExistingCrashDumpSetting = (ProductType == PRODUCT_WORKSTATION) ? 0 : 1;
|
|
}
|
|
|
|
if( ProductType == PRODUCT_WORKSTATION ) {
|
|
if( ExistingCrashDumpSetting == 0 ) {
|
|
CrashDumpValues[2].Data = &Three;
|
|
} else {
|
|
CrashDumpValues[2].Data = &One;
|
|
}
|
|
} else {
|
|
if( ExistingCrashDumpSetting == 0 ) {
|
|
CrashDumpValues[2].Data = &Three;
|
|
} else {
|
|
CrashDumpValues[2].Data = &One;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef PRERELEASE
|
|
if( Upgrade ) {
|
|
d = SetGroupOfValues(
|
|
HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Control\\CrashControl",
|
|
CrashDumpValues,
|
|
sizeof(CrashDumpValues)/sizeof(CrashDumpValues[0]) - 1
|
|
);
|
|
} else {
|
|
d = SetGroupOfValues(
|
|
HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Control\\CrashControl",
|
|
CrashDumpValues,
|
|
sizeof(CrashDumpValues)/sizeof(CrashDumpValues[0])
|
|
);
|
|
}
|
|
#else
|
|
d = SetGroupOfValues(
|
|
HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Control\\CrashControl",
|
|
CrashDumpValues,
|
|
sizeof(CrashDumpValues)/sizeof(CrashDumpValues[0])
|
|
);
|
|
#endif
|
|
|
|
if(d == NO_ERROR) {
|
|
SetuplogError(
|
|
LogSevInformation,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_CRASHDUMPOK,
|
|
NULL,NULL);
|
|
} else {
|
|
SetuplogError(
|
|
LogSevWarning,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_CRASHDUMPFAIL, NULL,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_X_RETURNED_STRING,
|
|
szSetGroupOfValues,
|
|
d,
|
|
NULL,NULL);
|
|
|
|
b = FALSE;
|
|
}
|
|
|
|
RemoveSavedPagefileSetting();
|
|
|
|
LOGITEM(L"SetUpVirtualMemory: EXIT (%u)\r\n",b);
|
|
|
|
return(b);
|
|
}
|
|
|