1c2c66affSColin Finck /* 2c2c66affSColin Finck * PROJECT: ReactOS Windows-Compatible Session Manager 3c2c66affSColin Finck * LICENSE: BSD 2-Clause License 4c2c66affSColin Finck * FILE: base/system/smss/pagefile.c 5c2c66affSColin Finck * PURPOSE: Main SMSS Code 6c2c66affSColin Finck * PROGRAMMERS: Alex Ionescu 7c2c66affSColin Finck */ 8c2c66affSColin Finck 9c2c66affSColin Finck /* INCLUDES *******************************************************************/ 10c2c66affSColin Finck 11c2c66affSColin Finck #include "smss.h" 12c2c66affSColin Finck 13c2c66affSColin Finck #define NDEBUG 14c2c66affSColin Finck #include <debug.h> 15c2c66affSColin Finck 16c2c66affSColin Finck /* GLOBALS ********************************************************************/ 17c2c66affSColin Finck 18c2c66affSColin Finck // 19c2c66affSColin Finck // Constants 20c2c66affSColin Finck // 21c2c66affSColin Finck #define STANDARD_PAGING_FILE_NAME L"\\??\\?:\\pagefile.sys" 22c2c66affSColin Finck #define STANDARD_DRIVE_LETTER_OFFSET 4 23*a4274ad5SHermès Bélusca-Maïto #define MAX_PAGING_FILES 16 // See also ntoskrnl/include/internal/mm.h 24*a4274ad5SHermès Bélusca-Maïto #define MEGABYTE (1024 * 1024) 25*a4274ad5SHermès Bélusca-Maïto 26*a4274ad5SHermès Bélusca-Maïto /* Minimum pagefile size is 256 pages (1 MB) */ 27*a4274ad5SHermès Bélusca-Maïto // #define MINIMUM_PAGEFILE_SIZE (256ULL * PAGE_SIZE) 28*a4274ad5SHermès Bélusca-Maïto 29*a4274ad5SHermès Bélusca-Maïto /* Maximum pagefile sizes for different architectures */ 30*a4274ad5SHermès Bélusca-Maïto #define GIGABYTE (1024ULL * MEGABYTE) 31*a4274ad5SHermès Bélusca-Maïto #define TERABYTE (1024ULL * GIGABYTE) 32*a4274ad5SHermès Bélusca-Maïto 33*a4274ad5SHermès Bélusca-Maïto // NOTE: No changes for NTDDI_WIN10 34*a4274ad5SHermès Bélusca-Maïto #if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81 35*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE32 ((1ULL * 1024 * 1024 - 1) * PAGE_SIZE) 36*a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(4ULL * GIGABYTE - 1) 37*a4274ad5SHermès Bélusca-Maïto #else 38*a4274ad5SHermès Bélusca-Maïto /* 4095 MB */ 39*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE32 (4095ULL * MEGABYTE) 40*a4274ad5SHermès Bélusca-Maïto #endif 41*a4274ad5SHermès Bélusca-Maïto 42*a4274ad5SHermès Bélusca-Maïto // NOTE: No changes for NTDDI_WIN10 43*a4274ad5SHermès Bélusca-Maïto #if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81 44*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE64 ((4ULL * 1024 * 1024 * 1024 - 1) * PAGE_SIZE) 45*a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(16ULL * TERABYTE - 1) 46*a4274ad5SHermès Bélusca-Maïto #else 47*a4274ad5SHermès Bélusca-Maïto /* 16 TB */ 48*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE64 (16ULL * TERABYTE) 49*a4274ad5SHermès Bélusca-Maïto #endif 50*a4274ad5SHermès Bélusca-Maïto 51*a4274ad5SHermès Bélusca-Maïto #if defined(_M_IX86) 52*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE32 53*a4274ad5SHermès Bélusca-Maïto /* PAE uses the same size as x64 */ 54*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE_PAE MAXIMUM_PAGEFILE_SIZE64 55*a4274ad5SHermès Bélusca-Maïto #elif defined (_M_AMD64) || defined(_M_ARM64) 56*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE64 57*a4274ad5SHermès Bélusca-Maïto #elif defined (_M_IA64) 58*a4274ad5SHermès Bélusca-Maïto /* 32 TB */ 59*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE (32ULL * TERABYTE) 60*a4274ad5SHermès Bélusca-Maïto #elif defined(_M_ARM) 61*a4274ad5SHermès Bélusca-Maïto /* Around 2 GB */ 62*a4274ad5SHermès Bélusca-Maïto // NOTE: No changes for NTDDI_WIN10 63*a4274ad5SHermès Bélusca-Maïto #if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81 64*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE ((512ULL * 1024 - 1) * PAGE_SIZE) 65*a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(2ULL * GIGABYTE - 1) 66*a4274ad5SHermès Bélusca-Maïto #else 67*a4274ad5SHermès Bélusca-Maïto /* 4095 MB */ 68*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE32 69*a4274ad5SHermès Bélusca-Maïto #endif 70*a4274ad5SHermès Bélusca-Maïto #else 71*a4274ad5SHermès Bélusca-Maïto /* On unknown architectures, default to either one of the 32 or 64 bit sizes */ 72*a4274ad5SHermès Bélusca-Maïto #pragma message("Unknown architecture") 73*a4274ad5SHermès Bélusca-Maïto #ifdef _WIN64 74*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE64 75*a4274ad5SHermès Bélusca-Maïto #else 76*a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE32 77*a4274ad5SHermès Bélusca-Maïto #endif 78*a4274ad5SHermès Bélusca-Maïto #endif 79*a4274ad5SHermès Bélusca-Maïto 80c2c66affSColin Finck /* This should be 32 MB, but we need more than that for 2nd stage setup */ 815d85d534SThomas Faber #define MINIMUM_TO_KEEP_FREE (256 * MEGABYTE) 82c2c66affSColin Finck #define FUZZ_FACTOR (16 * MEGABYTE) 83c2c66affSColin Finck 84c2c66affSColin Finck // 85c2c66affSColin Finck // Structure and flags describing each pagefile 86c2c66affSColin Finck // 87c2c66affSColin Finck #define SMP_PAGEFILE_CREATED 0x01 88c2c66affSColin Finck #define SMP_PAGEFILE_DEFAULT 0x02 89c2c66affSColin Finck #define SMP_PAGEFILE_SYSTEM_MANAGED 0x04 90c2c66affSColin Finck #define SMP_PAGEFILE_WAS_TOO_BIG 0x08 91c2c66affSColin Finck #define SMP_PAGEFILE_ON_ANY_DRIVE 0x10 92c2c66affSColin Finck #define SMP_PAGEFILE_EMERGENCY 0x20 93c2c66affSColin Finck #define SMP_PAGEFILE_DUMP_PROCESSED 0x40 94c2c66affSColin Finck typedef struct _SMP_PAGEFILE_DESCRIPTOR 95c2c66affSColin Finck { 96c2c66affSColin Finck LIST_ENTRY Entry; 97c2c66affSColin Finck UNICODE_STRING Name; 98c2c66affSColin Finck UNICODE_STRING Token; 99c2c66affSColin Finck LARGE_INTEGER MinSize; 100c2c66affSColin Finck LARGE_INTEGER MaxSize; 101c2c66affSColin Finck LARGE_INTEGER ActualMinSize; 102c2c66affSColin Finck LARGE_INTEGER ActualMaxSize; 103c2c66affSColin Finck ULONG Flags; 104c2c66affSColin Finck } SMP_PAGEFILE_DESCRIPTOR, *PSMP_PAGEFILE_DESCRIPTOR; 105c2c66affSColin Finck 106c2c66affSColin Finck // 107c2c66affSColin Finck // Structure and flags describing each volume 108c2c66affSColin Finck // 109c2c66affSColin Finck #define SMP_VOLUME_INSERTED 0x01 110c2c66affSColin Finck #define SMP_VOLUME_PAGEFILE_CREATED 0x04 111c2c66affSColin Finck #define SMP_VOLUME_IS_BOOT 0x08 112c2c66affSColin Finck typedef struct _SMP_VOLUME_DESCRIPTOR 113c2c66affSColin Finck { 114c2c66affSColin Finck LIST_ENTRY Entry; 115c2c66affSColin Finck USHORT Flags; 116c2c66affSColin Finck USHORT PageFileCount; 117c2c66affSColin Finck WCHAR DriveLetter; 118c2c66affSColin Finck LARGE_INTEGER FreeSpace; 119c2c66affSColin Finck FILE_FS_DEVICE_INFORMATION DeviceInfo; 120c2c66affSColin Finck } SMP_VOLUME_DESCRIPTOR, *PSMP_VOLUME_DESCRIPTOR; 121c2c66affSColin Finck 122c2c66affSColin Finck LIST_ENTRY SmpPagingFileDescriptorList, SmpVolumeDescriptorList; 123c2c66affSColin Finck BOOLEAN SmpRegistrySpecifierPresent; 124c2c66affSColin Finck ULONG SmpNumberOfPagingFiles; 125c2c66affSColin Finck 126c2c66affSColin Finck /* FUNCTIONS ******************************************************************/ 127c2c66affSColin Finck 128c2c66affSColin Finck VOID 129c2c66affSColin Finck NTAPI 130c2c66affSColin Finck SmpPagingFileInitialize(VOID) 131c2c66affSColin Finck { 132c2c66affSColin Finck /* Initialize the two lists */ 133c2c66affSColin Finck InitializeListHead(&SmpPagingFileDescriptorList); 134c2c66affSColin Finck InitializeListHead(&SmpVolumeDescriptorList); 135c2c66affSColin Finck } 136c2c66affSColin Finck 137c2c66affSColin Finck NTSTATUS 138c2c66affSColin Finck NTAPI 139c2c66affSColin Finck SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken) 140c2c66affSColin Finck { 141c2c66affSColin Finck NTSTATUS Status; 142c2c66affSColin Finck ULONG MinSize = 0, MaxSize = 0; 143c2c66affSColin Finck BOOLEAN SystemManaged = FALSE, ZeroSize = TRUE; 144c2c66affSColin Finck PSMP_PAGEFILE_DESCRIPTOR Descriptor, ListDescriptor; 145c2c66affSColin Finck ULONG i; 146c2c66affSColin Finck WCHAR c; 147c2c66affSColin Finck PLIST_ENTRY NextEntry; 148c2c66affSColin Finck UNICODE_STRING PageFileName, Arguments, SecondArgument; 149c2c66affSColin Finck 150c2c66affSColin Finck /* Make sure we don't have too many */ 151*a4274ad5SHermès Bélusca-Maïto if (SmpNumberOfPagingFiles >= MAX_PAGING_FILES) 152c2c66affSColin Finck { 153c2c66affSColin Finck DPRINT1("SMSS:PFILE: Too many paging files specified - %lu\n", 154c2c66affSColin Finck SmpNumberOfPagingFiles); 155c2c66affSColin Finck return STATUS_TOO_MANY_PAGING_FILES; 156c2c66affSColin Finck } 157c2c66affSColin Finck 158c2c66affSColin Finck /* Parse the specified and get the name and arguments out of it */ 159c2c66affSColin Finck DPRINT("SMSS:PFILE: Paging file specifier `%wZ'\n", PageFileToken); 160c2c66affSColin Finck Status = SmpParseCommandLine(PageFileToken, 161c2c66affSColin Finck NULL, 162c2c66affSColin Finck &PageFileName, 163c2c66affSColin Finck NULL, 164c2c66affSColin Finck &Arguments); 165c2c66affSColin Finck if (!NT_SUCCESS(Status)) 166c2c66affSColin Finck { 167c2c66affSColin Finck /* Fail */ 168c2c66affSColin Finck DPRINT1("SMSS:PFILE: SmpParseCommandLine(%wZ) failed - Status == %lx\n", 169c2c66affSColin Finck PageFileToken, Status); 170c2c66affSColin Finck return Status; 171c2c66affSColin Finck } 172c2c66affSColin Finck 173c2c66affSColin Finck /* Set the variable to let everyone know we have a pagefile token */ 174c2c66affSColin Finck SmpRegistrySpecifierPresent = TRUE; 175c2c66affSColin Finck 176c2c66affSColin Finck /* Parse the arguments, if any */ 177c2c66affSColin Finck if (Arguments.Buffer) 178c2c66affSColin Finck { 179c2c66affSColin Finck /* Parse the pagefile size */ 180c2c66affSColin Finck for (i = 0; i < Arguments.Length / sizeof(WCHAR); i++) 181c2c66affSColin Finck { 182c2c66affSColin Finck /* Check if it's zero */ 183c2c66affSColin Finck c = Arguments.Buffer[i]; 184c2c66affSColin Finck if ((c != L' ') && (c != L'\t') && (c != L'0')) 185c2c66affSColin Finck { 186c2c66affSColin Finck /* It isn't, break out */ 187c2c66affSColin Finck ZeroSize = FALSE; 188c2c66affSColin Finck break; 189c2c66affSColin Finck } 190c2c66affSColin Finck } 191c2c66affSColin Finck } 192c2c66affSColin Finck 193c2c66affSColin Finck /* Was a pagefile not specified, or was it specified with no size? */ 194c2c66affSColin Finck if (!(Arguments.Buffer) || (ZeroSize)) 195c2c66affSColin Finck { 196c2c66affSColin Finck /* In this case, the system will manage its size */ 197c2c66affSColin Finck SystemManaged = TRUE; 198c2c66affSColin Finck } 199c2c66affSColin Finck else 200c2c66affSColin Finck { 201c2c66affSColin Finck /* We do have a size, so convert the arguments into a number */ 202c2c66affSColin Finck Status = RtlUnicodeStringToInteger(&Arguments, 0, &MinSize); 203c2c66affSColin Finck if (!NT_SUCCESS(Status)) 204c2c66affSColin Finck { 205c2c66affSColin Finck /* Fail */ 206c2c66affSColin Finck RtlFreeUnicodeString(&PageFileName); 207c2c66affSColin Finck RtlFreeUnicodeString(&Arguments); 208c2c66affSColin Finck return Status; 209c2c66affSColin Finck } 210c2c66affSColin Finck 211c2c66affSColin Finck /* Now advance to the next argument */ 212c2c66affSColin Finck for (i = 0; i < Arguments.Length / sizeof(WCHAR); i++) 213c2c66affSColin Finck { 214c2c66affSColin Finck /* Found a space -- second argument must start here */ 215c2c66affSColin Finck if (Arguments.Buffer[i] == L' ') 216c2c66affSColin Finck { 217c2c66affSColin Finck /* Use the rest of the arguments as a maximum size */ 218c2c66affSColin Finck SecondArgument.Buffer = &Arguments.Buffer[i]; 219c2c66affSColin Finck SecondArgument.Length = (USHORT)(Arguments.Length - 220c2c66affSColin Finck i * sizeof(WCHAR)); 221c2c66affSColin Finck SecondArgument.MaximumLength = (USHORT)(Arguments.MaximumLength - 222c2c66affSColin Finck i * sizeof(WCHAR)); 223c2c66affSColin Finck Status = RtlUnicodeStringToInteger(&SecondArgument, 0, &MaxSize); 224c2c66affSColin Finck if (!NT_SUCCESS(Status)) 225c2c66affSColin Finck { 226c2c66affSColin Finck /* Fail */ 227c2c66affSColin Finck RtlFreeUnicodeString(&PageFileName); 228c2c66affSColin Finck RtlFreeUnicodeString(&Arguments); 229c2c66affSColin Finck return Status; 230c2c66affSColin Finck } 231c2c66affSColin Finck 232c2c66affSColin Finck break; 233c2c66affSColin Finck } 234c2c66affSColin Finck } 235c2c66affSColin Finck } 236c2c66affSColin Finck 237c2c66affSColin Finck /* We are done parsing arguments */ 238c2c66affSColin Finck RtlFreeUnicodeString(&Arguments); 239c2c66affSColin Finck 240c2c66affSColin Finck /* Now we can allocate our descriptor */ 241c2c66affSColin Finck Descriptor = RtlAllocateHeap(RtlGetProcessHeap(), 242c2c66affSColin Finck HEAP_ZERO_MEMORY, 243c2c66affSColin Finck sizeof(SMP_PAGEFILE_DESCRIPTOR)); 244c2c66affSColin Finck if (!Descriptor) 245c2c66affSColin Finck { 246c2c66affSColin Finck /* Fail if we couldn't */ 247c2c66affSColin Finck RtlFreeUnicodeString(&PageFileName); 248c2c66affSColin Finck return STATUS_NO_MEMORY; 249c2c66affSColin Finck } 250c2c66affSColin Finck 251c2c66affSColin Finck /* Capture all our data into the descriptor */ 252c2c66affSColin Finck Descriptor->Token = *PageFileToken; 253c2c66affSColin Finck Descriptor->Name = PageFileName; 254c2c66affSColin Finck Descriptor->MinSize.QuadPart = MinSize * MEGABYTE; 255c2c66affSColin Finck Descriptor->MaxSize.QuadPart = MaxSize * MEGABYTE; 256*a4274ad5SHermès Bélusca-Maïto if (SystemManaged) 257*a4274ad5SHermès Bélusca-Maïto Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED; 258c2c66affSColin Finck Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = 259c2c66affSColin Finck RtlUpcaseUnicodeChar(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]); 260c2c66affSColin Finck if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?') 261c2c66affSColin Finck { 262c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_ON_ANY_DRIVE; 263c2c66affSColin Finck } 264c2c66affSColin Finck 265c2c66affSColin Finck /* Now loop the existing descriptors */ 266c2c66affSColin Finck NextEntry = SmpPagingFileDescriptorList.Flink; 267c2c66affSColin Finck do 268c2c66affSColin Finck { 269c2c66affSColin Finck /* Are there none, or have we looped back to the beginning? */ 270c2c66affSColin Finck if (NextEntry == &SmpPagingFileDescriptorList) 271c2c66affSColin Finck { 272c2c66affSColin Finck /* This means no duplicates exist, so insert our descriptor! */ 273c2c66affSColin Finck InsertTailList(&SmpPagingFileDescriptorList, &Descriptor->Entry); 274c2c66affSColin Finck SmpNumberOfPagingFiles++; 275c2c66affSColin Finck DPRINT("SMSS:PFILE: Created descriptor for `%wZ' (`%wZ')\n", 276c2c66affSColin Finck PageFileToken, &Descriptor->Name); 277c2c66affSColin Finck return STATUS_SUCCESS; 278c2c66affSColin Finck } 279c2c66affSColin Finck 280c2c66affSColin Finck /* Keep going until we find a duplicate, unless we are in "any" mode */ 281c2c66affSColin Finck ListDescriptor = CONTAINING_RECORD(NextEntry, SMP_PAGEFILE_DESCRIPTOR, Entry); 282c2c66affSColin Finck NextEntry = NextEntry->Flink; 283c2c66affSColin Finck } while (!(ListDescriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE) || 284c2c66affSColin Finck !(Descriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE)); 285c2c66affSColin Finck 286c2c66affSColin Finck /* We found a duplicate, so skip this descriptor/pagefile and fail */ 287c2c66affSColin Finck DPRINT1("SMSS:PFILE: Skipping duplicate specifier `%wZ'\n", PageFileToken); 288c2c66affSColin Finck RtlFreeUnicodeString(&PageFileName); 289c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, Descriptor); 290c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 291c2c66affSColin Finck } 292c2c66affSColin Finck 293c2c66affSColin Finck NTSTATUS 294c2c66affSColin Finck NTAPI 295c2c66affSColin Finck SmpGetPagingFileSize(IN PUNICODE_STRING FileName, 296c2c66affSColin Finck OUT PLARGE_INTEGER Size) 297c2c66affSColin Finck { 298c2c66affSColin Finck NTSTATUS Status; 299c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 300c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock; 301c2c66affSColin Finck HANDLE FileHandle; 302c2c66affSColin Finck FILE_STANDARD_INFORMATION StandardInfo; 303c2c66affSColin Finck 304c2c66affSColin Finck DPRINT("SMSS:PFILE: Trying to get size for `%wZ'\n", FileName); 305c2c66affSColin Finck Size->QuadPart = 0; 306c2c66affSColin Finck 307c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 308c2c66affSColin Finck FileName, 309c2c66affSColin Finck OBJ_CASE_INSENSITIVE, 310c2c66affSColin Finck NULL, 311c2c66affSColin Finck NULL); 312c2c66affSColin Finck Status = NtOpenFile(&FileHandle, 313c2c66affSColin Finck FILE_READ_ATTRIBUTES | SYNCHRONIZE, 314c2c66affSColin Finck &ObjectAttributes, 315c2c66affSColin Finck &IoStatusBlock, 316c2c66affSColin Finck FILE_SHARE_READ | FILE_SHARE_WRITE, 317c2c66affSColin Finck FILE_SYNCHRONOUS_IO_NONALERT); 318c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 319c2c66affSColin Finck 320c2c66affSColin Finck Status = NtQueryInformationFile(FileHandle, 321c2c66affSColin Finck &IoStatusBlock, 322c2c66affSColin Finck &StandardInfo, 323c2c66affSColin Finck sizeof(StandardInfo), 324c2c66affSColin Finck FileStandardInformation); 325c2c66affSColin Finck if (!NT_SUCCESS(Status)) 326c2c66affSColin Finck { 327c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed query for size potential pagefile `%wZ' with status %X\n", 328c2c66affSColin Finck FileName, Status); 329c2c66affSColin Finck NtClose(FileHandle); 330c2c66affSColin Finck return Status; 331c2c66affSColin Finck } 332c2c66affSColin Finck 333c2c66affSColin Finck NtClose(FileHandle); 334c2c66affSColin Finck Size->QuadPart = StandardInfo.AllocationSize.QuadPart; 335c2c66affSColin Finck return STATUS_SUCCESS; 336c2c66affSColin Finck } 337c2c66affSColin Finck 338c2c66affSColin Finck NTSTATUS 339c2c66affSColin Finck NTAPI 340c2c66affSColin Finck SmpDeletePagingFile(IN PUNICODE_STRING FileName) 341c2c66affSColin Finck { 342c2c66affSColin Finck NTSTATUS Status; 343c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 344c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock; 345c2c66affSColin Finck HANDLE FileHandle; 346c2c66affSColin Finck FILE_DISPOSITION_INFORMATION Disposition; 347c2c66affSColin Finck 348c2c66affSColin Finck /* Open the page file */ 349c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 350c2c66affSColin Finck FileName, 351c2c66affSColin Finck OBJ_CASE_INSENSITIVE, 352c2c66affSColin Finck NULL, 353c2c66affSColin Finck NULL); 354c2c66affSColin Finck Status = NtOpenFile(&FileHandle, 355c2c66affSColin Finck DELETE, 356c2c66affSColin Finck &ObjectAttributes, 357c2c66affSColin Finck &IoStatusBlock, 358c2c66affSColin Finck FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 359c2c66affSColin Finck FILE_NON_DIRECTORY_FILE); 360c2c66affSColin Finck if (NT_SUCCESS(Status)) 361c2c66affSColin Finck { 362c2c66affSColin Finck /* Delete it */ 363c2c66affSColin Finck Disposition.DeleteFile = TRUE; 364c2c66affSColin Finck Status = NtSetInformationFile(FileHandle, 365c2c66affSColin Finck &IoStatusBlock, 366c2c66affSColin Finck &Disposition, 367c2c66affSColin Finck sizeof(Disposition), 368c2c66affSColin Finck FileDispositionInformation); 369c2c66affSColin Finck if (!NT_SUCCESS(Status)) 370c2c66affSColin Finck { 371c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to delete page file `%wZ' (status %X)\n", 372c2c66affSColin Finck FileName, Status); 373c2c66affSColin Finck } 374c2c66affSColin Finck else 375c2c66affSColin Finck { 376c2c66affSColin Finck DPRINT("SMSS:PFILE: Deleted stale paging file - %wZ\n", FileName); 377c2c66affSColin Finck } 378c2c66affSColin Finck 379c2c66affSColin Finck /* Close the handle */ 380c2c66affSColin Finck NtClose(FileHandle); 381c2c66affSColin Finck } 382c2c66affSColin Finck else 383c2c66affSColin Finck { 384c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to open for deletion page file `%wZ' (status %X)\n", 385c2c66affSColin Finck FileName, Status); 386c2c66affSColin Finck } 387c2c66affSColin Finck 388c2c66affSColin Finck /* All done */ 389c2c66affSColin Finck return Status; 390c2c66affSColin Finck } 391c2c66affSColin Finck 392c2c66affSColin Finck NTSTATUS 393c2c66affSColin Finck NTAPI 394c2c66affSColin Finck SmpGetVolumeFreeSpace(IN PSMP_VOLUME_DESCRIPTOR Volume) 395c2c66affSColin Finck { 396c2c66affSColin Finck NTSTATUS Status; 397c2c66affSColin Finck LARGE_INTEGER FreeSpace, FinalFreeSpace; 398c2c66affSColin Finck FILE_FS_SIZE_INFORMATION SizeInfo; 399c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock; 400c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 401c2c66affSColin Finck UNICODE_STRING VolumeName; 402c2c66affSColin Finck HANDLE VolumeHandle; 403c2c66affSColin Finck WCHAR PathString[32]; 404c2c66affSColin Finck ASSERT(Volume->Flags & SMP_VOLUME_IS_BOOT); // ASSERT says "BootVolume == 1" 405c2c66affSColin Finck 406c2c66affSColin Finck /* Build the standard path */ 407c2c66affSColin Finck wcscpy(PathString, L"\\??\\A:\\"); 408c2c66affSColin Finck RtlInitUnicodeString(&VolumeName, PathString); 409c2c66affSColin Finck VolumeName.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Volume->DriveLetter; 410c2c66affSColin Finck DPRINT("SMSS:PFILE: Querying volume `%wZ' for free space\n", &VolumeName); 411c2c66affSColin Finck 412c2c66affSColin Finck /* Open the volume */ 413c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 414c2c66affSColin Finck &VolumeName, 415c2c66affSColin Finck OBJ_CASE_INSENSITIVE, 416c2c66affSColin Finck NULL, 417c2c66affSColin Finck NULL); 418c2c66affSColin Finck Status = NtOpenFile(&VolumeHandle, 419c2c66affSColin Finck FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, 420c2c66affSColin Finck &ObjectAttributes, 421c2c66affSColin Finck &IoStatusBlock, 422c2c66affSColin Finck FILE_SHARE_READ | FILE_SHARE_WRITE, 423c2c66affSColin Finck FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); 424c2c66affSColin Finck if (!NT_SUCCESS(Status)) 425c2c66affSColin Finck { 426c2c66affSColin Finck DPRINT1("SMSS:PFILE: Open volume `%wZ' failed with status %X\n", &VolumeName, Status); 427c2c66affSColin Finck return Status; 428c2c66affSColin Finck } 429c2c66affSColin Finck 430c2c66affSColin Finck /* Now get size information on the volume */ 431c2c66affSColin Finck Status = NtQueryVolumeInformationFile(VolumeHandle, 432c2c66affSColin Finck &IoStatusBlock, 433c2c66affSColin Finck &SizeInfo, 434c2c66affSColin Finck sizeof(SizeInfo), 435c2c66affSColin Finck FileFsSizeInformation); 436c2c66affSColin Finck if (!NT_SUCCESS(Status)) 437c2c66affSColin Finck { 438c2c66affSColin Finck /* We failed */ 439c2c66affSColin Finck DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed" 440c2c66affSColin Finck " with status %X\n", 441c2c66affSColin Finck &VolumeName, 442c2c66affSColin Finck VolumeHandle, 443c2c66affSColin Finck Status); 444c2c66affSColin Finck NtClose(VolumeHandle); 445c2c66affSColin Finck return Status; 446c2c66affSColin Finck } 447c2c66affSColin Finck NtClose(VolumeHandle); 448c2c66affSColin Finck 449c2c66affSColin Finck /* Compute how much free space we have */ 450c2c66affSColin Finck FreeSpace.QuadPart = SizeInfo.AvailableAllocationUnits.QuadPart * 451c2c66affSColin Finck SizeInfo.SectorsPerAllocationUnit; 452c2c66affSColin Finck FinalFreeSpace.QuadPart = FreeSpace.QuadPart * SizeInfo.BytesPerSector; 453c2c66affSColin Finck 4545dc43c0fSHermès Bélusca-Maïto /* Check if there is less than 32 MB free so we don't starve the disk */ 455c2c66affSColin Finck if (FinalFreeSpace.QuadPart <= MINIMUM_TO_KEEP_FREE) 456c2c66affSColin Finck { 4575dc43c0fSHermès Bélusca-Maïto /* In this case, act as if there is no free space */ 458c2c66affSColin Finck Volume->FreeSpace.QuadPart = 0; 459c2c66affSColin Finck } 460c2c66affSColin Finck else 461c2c66affSColin Finck { 462c2c66affSColin Finck /* Trim off 32 MB to give the disk a bit of breathing room */ 463c2c66affSColin Finck Volume->FreeSpace.QuadPart = FinalFreeSpace.QuadPart - 464c2c66affSColin Finck MINIMUM_TO_KEEP_FREE; 465c2c66affSColin Finck } 466c2c66affSColin Finck 467c2c66affSColin Finck return STATUS_SUCCESS; 468c2c66affSColin Finck } 469c2c66affSColin Finck 470c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR 471c2c66affSColin Finck NTAPI 472c2c66affSColin Finck SmpSearchVolumeDescriptor(IN WCHAR DriveLetter) 473c2c66affSColin Finck { 474c2c66affSColin Finck WCHAR UpLetter; 475c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR Volume = NULL; 476c2c66affSColin Finck PLIST_ENTRY NextEntry; 477c2c66affSColin Finck 478c2c66affSColin Finck /* Use upper case to reduce differences */ 479c2c66affSColin Finck UpLetter = RtlUpcaseUnicodeChar(DriveLetter); 480c2c66affSColin Finck 481c2c66affSColin Finck /* Loop each volume */ 482c2c66affSColin Finck NextEntry = SmpVolumeDescriptorList.Flink; 483c2c66affSColin Finck while (NextEntry != &SmpVolumeDescriptorList) 484c2c66affSColin Finck { 485c2c66affSColin Finck /* Grab the entry */ 486c2c66affSColin Finck Volume = CONTAINING_RECORD(NextEntry, SMP_VOLUME_DESCRIPTOR, Entry); 487c2c66affSColin Finck 488c2c66affSColin Finck /* Make sure it's a valid entry with an uppcase drive letter */ 489c2c66affSColin Finck ASSERT(Volume->Flags & SMP_VOLUME_INSERTED); // Volume->Initialized in ASSERT 490c2c66affSColin Finck ASSERT(Volume->DriveLetter >= L'A' && Volume->DriveLetter <= L'Z'); 491c2c66affSColin Finck 492c2c66affSColin Finck /* Break if it matches, if not, keep going */ 493c2c66affSColin Finck if (Volume->DriveLetter == UpLetter) break; 494c2c66affSColin Finck NextEntry = NextEntry->Flink; 495c2c66affSColin Finck } 496c2c66affSColin Finck 497c2c66affSColin Finck /* Return the volume if one was found */ 498c2c66affSColin Finck if (NextEntry == &SmpVolumeDescriptorList) Volume = NULL; 499c2c66affSColin Finck return Volume; 500c2c66affSColin Finck } 501c2c66affSColin Finck 502c2c66affSColin Finck NTSTATUS 503c2c66affSColin Finck NTAPI 504c2c66affSColin Finck SmpCreatePagingFile(IN PUNICODE_STRING Name, 505c2c66affSColin Finck IN PLARGE_INTEGER MinSize, 506c2c66affSColin Finck IN PLARGE_INTEGER MaxSize, 507c2c66affSColin Finck IN ULONG Priority) 508c2c66affSColin Finck { 509c2c66affSColin Finck NTSTATUS Status; 510c2c66affSColin Finck 511c2c66affSColin Finck /* Tell the kernel to create the pagefile */ 512c2c66affSColin Finck Status = NtCreatePagingFile(Name, MinSize, MaxSize, Priority); 513c2c66affSColin Finck if (NT_SUCCESS(Status)) 514c2c66affSColin Finck { 5155dc43c0fSHermès Bélusca-Maïto DPRINT("SMSS:PFILE: NtCreatePagingFile(%wZ, 0x%I64X, 0x%I64X) succeeded.\n", 516c2c66affSColin Finck Name, 517c2c66affSColin Finck MinSize->QuadPart, 518c2c66affSColin Finck MaxSize->QuadPart); 519c2c66affSColin Finck } 520c2c66affSColin Finck else 521c2c66affSColin Finck { 5225dc43c0fSHermès Bélusca-Maïto DPRINT1("SMSS:PFILE: NtCreatePagingFile(%wZ, 0x%I64X, 0x%I64X) failed with %X\n", 523c2c66affSColin Finck Name, 524c2c66affSColin Finck MinSize->QuadPart, 525c2c66affSColin Finck MaxSize->QuadPart, 526c2c66affSColin Finck Status); 527c2c66affSColin Finck } 528c2c66affSColin Finck 529c2c66affSColin Finck /* Return the status */ 530c2c66affSColin Finck return Status; 531c2c66affSColin Finck } 532c2c66affSColin Finck 533c2c66affSColin Finck NTSTATUS 534c2c66affSColin Finck NTAPI 535c2c66affSColin Finck SmpCreatePagingFileOnFixedDrive(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor, 536c2c66affSColin Finck IN PLARGE_INTEGER FuzzFactor, 537c2c66affSColin Finck IN PLARGE_INTEGER MinimumSize) 538c2c66affSColin Finck { 539c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR Volume; 540c2c66affSColin Finck BOOLEAN ShouldDelete; 541c2c66affSColin Finck NTSTATUS Status; 542c2c66affSColin Finck LARGE_INTEGER PageFileSize; 543c2c66affSColin Finck ASSERT(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] != L'?'); 544c2c66affSColin Finck 545c2c66affSColin Finck /* Try to find the volume descriptor for this drive letter */ 546c2c66affSColin Finck ShouldDelete = FALSE; 547c2c66affSColin Finck Volume = SmpSearchVolumeDescriptor(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]); 548c2c66affSColin Finck if (!Volume) 549c2c66affSColin Finck { 550c2c66affSColin Finck /* Couldn't find it, fail */ 551c2c66affSColin Finck DPRINT1("SMSS:PFILE: No volume descriptor for `%wZ'\n", 552c2c66affSColin Finck &Descriptor->Name); 553c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 554c2c66affSColin Finck } 555c2c66affSColin Finck 556c2c66affSColin Finck /* Check if this is the boot volume */ 557c2c66affSColin Finck if (Volume->Flags & SMP_VOLUME_IS_BOOT) 558c2c66affSColin Finck { 559c2c66affSColin Finck /* Check if we haven't yet processed a crash dump on this volume */ 560c2c66affSColin Finck if (!(Descriptor->Flags & SMP_PAGEFILE_DUMP_PROCESSED)) 561c2c66affSColin Finck { 562c2c66affSColin Finck /* Try to find a crash dump and extract it */ 563c2c66affSColin Finck DPRINT("SMSS:PFILE: Checking for crash dump in `%wZ' on boot volume\n", 564c2c66affSColin Finck &Descriptor->Name); 565c2c66affSColin Finck SmpCheckForCrashDump(&Descriptor->Name); 566c2c66affSColin Finck 567c2c66affSColin Finck /* Update how much free space we have now that we extracted a dump */ 568c2c66affSColin Finck Status = SmpGetVolumeFreeSpace(Volume); 569c2c66affSColin Finck if (!NT_SUCCESS(Status)) 570c2c66affSColin Finck { 571c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to query free space for boot volume `%wC'\n", 572c2c66affSColin Finck Volume->DriveLetter); 573c2c66affSColin Finck } 574c2c66affSColin Finck else 575c2c66affSColin Finck { 5765dc43c0fSHermès Bélusca-Maïto DPRINT("Queried free space for boot volume `%wC: 0x%I64x'\n", 577c2c66affSColin Finck Volume->DriveLetter, Volume->FreeSpace.QuadPart); 578c2c66affSColin Finck } 579c2c66affSColin Finck 580c2c66affSColin Finck /* Don't process crashdump on this volume anymore */ 581c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_DUMP_PROCESSED; 582c2c66affSColin Finck } 583c2c66affSColin Finck } 584c2c66affSColin Finck else 585c2c66affSColin Finck { 586c2c66affSColin Finck /* Crashdumps can only be on the boot volume */ 587c2c66affSColin Finck DPRINT("SMSS:PFILE: Skipping crash dump checking for `%wZ' on non boot" 588c2c66affSColin Finck "volume `%wC'\n", 589c2c66affSColin Finck &Descriptor->Name, 590c2c66affSColin Finck Volume->DriveLetter); 591c2c66affSColin Finck } 592c2c66affSColin Finck 593c2c66affSColin Finck /* Update the size after dump extraction */ 594c2c66affSColin Finck Descriptor->ActualMinSize = Descriptor->MinSize; 595c2c66affSColin Finck Descriptor->ActualMaxSize = Descriptor->MaxSize; 596c2c66affSColin Finck 597c2c66affSColin Finck /* Check how big we can make the pagefile */ 598c2c66affSColin Finck Status = SmpGetPagingFileSize(&Descriptor->Name, &PageFileSize); 599c2c66affSColin Finck if (NT_SUCCESS(Status) && PageFileSize.QuadPart > 0) ShouldDelete = TRUE; 6005dc43c0fSHermès Bélusca-Maïto DPRINT("SMSS:PFILE: Detected size 0x%I64X for future paging file `%wZ'\n", 601c2c66affSColin Finck PageFileSize, 602c2c66affSColin Finck &Descriptor->Name); 6035dc43c0fSHermès Bélusca-Maïto DPRINT("SMSS:PFILE: Free space on volume `%wC' is 0x%I64X\n", 604c2c66affSColin Finck Volume->DriveLetter, 605c2c66affSColin Finck Volume->FreeSpace.QuadPart); 606c2c66affSColin Finck 607c2c66affSColin Finck /* Now update our size and make sure none of these are too big */ 608c2c66affSColin Finck PageFileSize.QuadPart += Volume->FreeSpace.QuadPart; 609c2c66affSColin Finck if (Descriptor->ActualMinSize.QuadPart > PageFileSize.QuadPart) 610c2c66affSColin Finck { 611c2c66affSColin Finck Descriptor->ActualMinSize = PageFileSize; 612c2c66affSColin Finck } 613c2c66affSColin Finck if (Descriptor->ActualMaxSize.QuadPart > PageFileSize.QuadPart) 614c2c66affSColin Finck { 615c2c66affSColin Finck Descriptor->ActualMaxSize = PageFileSize; 616c2c66affSColin Finck } 6175dc43c0fSHermès Bélusca-Maïto DPRINT("SMSS:PFILE: min 0x%I64X, max 0x%I64X, real min 0x%I64X\n", 618c2c66affSColin Finck Descriptor->ActualMinSize.QuadPart, 619c2c66affSColin Finck Descriptor->ActualMaxSize.QuadPart, 620c2c66affSColin Finck MinimumSize->QuadPart); 621c2c66affSColin Finck 622c2c66affSColin Finck /* Keep going until we've created a pagefile of the right size */ 623c2c66affSColin Finck while (Descriptor->ActualMinSize.QuadPart >= MinimumSize->QuadPart) 624c2c66affSColin Finck { 625c2c66affSColin Finck /* Call NT to do it */ 626c2c66affSColin Finck Status = SmpCreatePagingFile(&Descriptor->Name, 627c2c66affSColin Finck &Descriptor->ActualMinSize, 628c2c66affSColin Finck &Descriptor->ActualMaxSize, 629c2c66affSColin Finck 0); 630c2c66affSColin Finck if (NT_SUCCESS(Status)) 631c2c66affSColin Finck { 632c2c66affSColin Finck /* We're done, update flags and increase the count */ 633c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_CREATED; 634c2c66affSColin Finck Volume->Flags |= SMP_VOLUME_PAGEFILE_CREATED; 635c2c66affSColin Finck Volume->PageFileCount++; 636c2c66affSColin Finck break; 637c2c66affSColin Finck } 638c2c66affSColin Finck 639c2c66affSColin Finck /* We failed, try a slightly smaller pagefile */ 640c2c66affSColin Finck Descriptor->ActualMinSize.QuadPart -= FuzzFactor->QuadPart; 641c2c66affSColin Finck } 642c2c66affSColin Finck 643c2c66affSColin Finck /* Check if we weren't able to create it */ 644c2c66affSColin Finck if (Descriptor->ActualMinSize.QuadPart < MinimumSize->QuadPart) 645c2c66affSColin Finck { 646c2c66affSColin Finck /* Delete the current page file and fail */ 647c2c66affSColin Finck if (ShouldDelete) 648c2c66affSColin Finck { 649c2c66affSColin Finck SmpDeletePagingFile(&Descriptor->Name); 650c2c66affSColin Finck 651c2c66affSColin Finck /* FIXFIX: Windows Vista does this, and it seems like we should too, so try to see if this fixes KVM */ 652c2c66affSColin Finck Volume->FreeSpace.QuadPart = PageFileSize.QuadPart; 653c2c66affSColin Finck } 6545dc43c0fSHermès Bélusca-Maïto DPRINT1("SMSS:PFILE: Failing for min 0x%I64X, max 0x%I64X, real min 0x%I64X\n", 655c2c66affSColin Finck Descriptor->ActualMinSize.QuadPart, 656c2c66affSColin Finck Descriptor->ActualMaxSize.QuadPart, 657c2c66affSColin Finck MinimumSize->QuadPart); 658c2c66affSColin Finck Status = STATUS_DISK_FULL; 659c2c66affSColin Finck } 660c2c66affSColin Finck 661c2c66affSColin Finck /* Return the status */ 662c2c66affSColin Finck return Status; 663c2c66affSColin Finck } 664c2c66affSColin Finck 665c2c66affSColin Finck NTSTATUS 666c2c66affSColin Finck NTAPI 667c2c66affSColin Finck SmpCreatePagingFileOnAnyDrive(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor, 668c2c66affSColin Finck IN PLARGE_INTEGER FuzzFactor, 669c2c66affSColin Finck IN PLARGE_INTEGER MinimumSize) 670c2c66affSColin Finck { 671c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR Volume; 672c2c66affSColin Finck NTSTATUS Status = STATUS_DISK_FULL; 673c2c66affSColin Finck PLIST_ENTRY NextEntry; 674c2c66affSColin Finck ASSERT(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == L'?'); 675c2c66affSColin Finck 676c2c66affSColin Finck /* Loop the volume list */ 677c2c66affSColin Finck NextEntry = SmpVolumeDescriptorList.Flink; 678c2c66affSColin Finck while (NextEntry != &SmpVolumeDescriptorList) 679c2c66affSColin Finck { 680c2c66affSColin Finck /* Get the volume */ 681c2c66affSColin Finck Volume = CONTAINING_RECORD(NextEntry, SMP_VOLUME_DESCRIPTOR, Entry); 682c2c66affSColin Finck 683c2c66affSColin Finck /* Make sure it's inserted and on a valid drive letter */ 684c2c66affSColin Finck ASSERT(Volume->Flags & SMP_VOLUME_INSERTED); // Volume->Initialized in ASSERT 685c2c66affSColin Finck ASSERT(Volume->DriveLetter >= L'A' && Volume->DriveLetter <= L'Z'); 686c2c66affSColin Finck 687c2c66affSColin Finck /* Write the drive letter to try creating it on this volume */ 688c2c66affSColin Finck Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Volume->DriveLetter; 689c2c66affSColin Finck Status = SmpCreatePagingFileOnFixedDrive(Descriptor, 690c2c66affSColin Finck FuzzFactor, 691c2c66affSColin Finck MinimumSize); 692c2c66affSColin Finck if (NT_SUCCESS(Status)) break; 693c2c66affSColin Finck 694c2c66affSColin Finck /* It didn't work, make it an any pagefile again and keep going */ 695c2c66affSColin Finck Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = L'?'; 696c2c66affSColin Finck NextEntry = NextEntry->Flink; 697c2c66affSColin Finck } 698c2c66affSColin Finck 699c2c66affSColin Finck /* Return disk full or success */ 700c2c66affSColin Finck return Status; 701c2c66affSColin Finck } 702c2c66affSColin Finck 703c2c66affSColin Finck VOID 704c2c66affSColin Finck NTAPI 705c2c66affSColin Finck SmpMakeDefaultPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor) 706c2c66affSColin Finck { 707c2c66affSColin Finck /* The default descriptor uses 128 MB as a pagefile size */ 708c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_DEFAULT; 709c2c66affSColin Finck Descriptor->MinSize.QuadPart = 128 * MEGABYTE; 710c2c66affSColin Finck Descriptor->MaxSize.QuadPart = 128 * MEGABYTE; 711c2c66affSColin Finck } 712c2c66affSColin Finck 713c2c66affSColin Finck VOID 714c2c66affSColin Finck NTAPI 715c2c66affSColin Finck SmpMakeSystemManagedPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor) 716c2c66affSColin Finck { 717c2c66affSColin Finck NTSTATUS Status; 718*a4274ad5SHermès Bélusca-Maïto ULONGLONG MinimumSize, MaximumSize, Ram; 719c2c66affSColin Finck SYSTEM_BASIC_INFORMATION BasicInfo; 720c2c66affSColin Finck 721c2c66affSColin Finck /* Query the page size of the system, and the amount of RAM */ 722c2c66affSColin Finck Status = NtQuerySystemInformation(SystemBasicInformation, 723c2c66affSColin Finck &BasicInfo, 724c2c66affSColin Finck sizeof(BasicInfo), 725c2c66affSColin Finck NULL); 726c2c66affSColin Finck if (!NT_SUCCESS(Status)) 727c2c66affSColin Finck { 728c2c66affSColin Finck /* If we failed, use defaults since we have no idea otherwise */ 729c2c66affSColin Finck DPRINT1("SMSS:PFILE: NtQuerySystemInformation failed with %x\n", Status); 730c2c66affSColin Finck SmpMakeDefaultPagingFileDescriptor(Descriptor); 731c2c66affSColin Finck return; 732c2c66affSColin Finck } 733c2c66affSColin Finck 7345dc43c0fSHermès Bélusca-Maïto /* Check how much RAM we have and set three times this amount as maximum */ 735c2c66affSColin Finck Ram = BasicInfo.NumberOfPhysicalPages * BasicInfo.PageSize; 736c2c66affSColin Finck MaximumSize = 3 * Ram; 737c2c66affSColin Finck 738c2c66affSColin Finck /* If we have more than 1GB, use that as minimum, otherwise, use 1.5X RAM */ 739c2c66affSColin Finck MinimumSize = (Ram >= 1024 * MEGABYTE) ? Ram : MaximumSize / 2; 740c2c66affSColin Finck 741c2c66affSColin Finck /* Write the new sizes in the descriptor and mark it as system managed */ 742c2c66affSColin Finck Descriptor->MinSize.QuadPart = MinimumSize; 743c2c66affSColin Finck Descriptor->MaxSize.QuadPart = MaximumSize; 744c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED; 745c2c66affSColin Finck } 746c2c66affSColin Finck 747c2c66affSColin Finck NTSTATUS 748c2c66affSColin Finck NTAPI 749c2c66affSColin Finck SmpValidatePagingFileSizes(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor) 750c2c66affSColin Finck { 751c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS; 752c2c66affSColin Finck BOOLEAN WasTooBig = FALSE; 753*a4274ad5SHermès Bélusca-Maïto ULONGLONG MinSize, MaxSize; 754*a4274ad5SHermès Bélusca-Maïto #ifdef _M_IX86 755*a4274ad5SHermès Bélusca-Maïto ULONGLONG MaxPageFileSize = 756*a4274ad5SHermès Bélusca-Maïto (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]) 757*a4274ad5SHermès Bélusca-Maïto ? MAXIMUM_PAGEFILE_SIZE_PAE : MAXIMUM_PAGEFILE_SIZE; 758*a4274ad5SHermès Bélusca-Maïto #else 759*a4274ad5SHermès Bélusca-Maïto static const ULONGLONG MaxPageFileSize = MAXIMUM_PAGEFILE_SIZE; 760*a4274ad5SHermès Bélusca-Maïto #endif 761c2c66affSColin Finck 762c2c66affSColin Finck /* Capture the min and max */ 763c2c66affSColin Finck MinSize = Descriptor->MinSize.QuadPart; 764c2c66affSColin Finck MaxSize = Descriptor->MaxSize.QuadPart; 7655dc43c0fSHermès Bélusca-Maïto 7665dc43c0fSHermès Bélusca-Maïto DPRINT("SMSS:PFILE: Validating sizes for `%wZ' 0x%I64X 0x%I64X\n", 767c2c66affSColin Finck &Descriptor->Name, MinSize, MaxSize); 768c2c66affSColin Finck 769c2c66affSColin Finck /* Don't let minimum be bigger than maximum */ 770*a4274ad5SHermès Bélusca-Maïto if (MinSize > MaxSize) 771*a4274ad5SHermès Bélusca-Maïto MaxSize = MinSize; 772c2c66affSColin Finck 7735dc43c0fSHermès Bélusca-Maïto /* Validate the minimum and maximum and trim them if they are too large */ 774*a4274ad5SHermès Bélusca-Maïto if (MinSize > MaxPageFileSize) 775c2c66affSColin Finck { 776c2c66affSColin Finck WasTooBig = TRUE; 777*a4274ad5SHermès Bélusca-Maïto MinSize = MaxPageFileSize; 778c2c66affSColin Finck } 779*a4274ad5SHermès Bélusca-Maïto if (MaxSize > MaxPageFileSize) 780c2c66affSColin Finck { 781c2c66affSColin Finck WasTooBig = TRUE; 782*a4274ad5SHermès Bélusca-Maïto MaxSize = MaxPageFileSize; 783c2c66affSColin Finck } 784c2c66affSColin Finck 7855dc43c0fSHermès Bélusca-Maïto /* If we trimmed, write a flag in the descriptor */ 786c2c66affSColin Finck if (WasTooBig) 787c2c66affSColin Finck { 788c2c66affSColin Finck DPRINT("SMSS:PFILE: Trimmed size of `%wZ' to maximum allowed\n", 789c2c66affSColin Finck &Descriptor->Name); 790c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_WAS_TOO_BIG; 791c2c66affSColin Finck } 792c2c66affSColin Finck 793c2c66affSColin Finck /* Now write the (possibly trimmed) sizes back */ 794c2c66affSColin Finck Descriptor->MinSize.QuadPart = MinSize; 795c2c66affSColin Finck Descriptor->MaxSize.QuadPart = MaxSize; 796c2c66affSColin Finck return Status; 797c2c66affSColin Finck } 798c2c66affSColin Finck 799c2c66affSColin Finck NTSTATUS 800c2c66affSColin Finck NTAPI 801c2c66affSColin Finck SmpCreateSystemManagedPagingFile(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor, 802c2c66affSColin Finck IN BOOLEAN DecreaseSize) 803c2c66affSColin Finck { 804c2c66affSColin Finck LARGE_INTEGER FuzzFactor, Size; 805c2c66affSColin Finck 8065dc43c0fSHermès Bélusca-Maïto /* Make sure there is at least 1 paging file and that we are system-managed */ 807c2c66affSColin Finck ASSERT(SmpNumberOfPagingFiles >= 1); 808c2c66affSColin Finck ASSERT(!IsListEmpty(&SmpPagingFileDescriptorList)); 809*a4274ad5SHermès Bélusca-Maïto ASSERT(Descriptor->Flags & SMP_PAGEFILE_SYSTEM_MANAGED); 810c2c66affSColin Finck 811c2c66affSColin Finck /* Keep decreasing the pagefile by this amount if we run out of space */ 812c2c66affSColin Finck FuzzFactor.QuadPart = FUZZ_FACTOR; 813c2c66affSColin Finck 814c2c66affSColin Finck /* Create the descriptor for it (mainly the right sizes) and validate */ 815c2c66affSColin Finck SmpMakeSystemManagedPagingFileDescriptor(Descriptor); 816c2c66affSColin Finck SmpValidatePagingFileSizes(Descriptor); 817c2c66affSColin Finck 818c2c66affSColin Finck /* Use either the minimum size in the descriptor, or 16 MB in minimal mode */ 819c2c66affSColin Finck Size.QuadPart = DecreaseSize ? 16 * MEGABYTE : Descriptor->MinSize.QuadPart; 820c2c66affSColin Finck 821c2c66affSColin Finck /* Check if this should be a fixed pagefile or an any pagefile */ 822c2c66affSColin Finck if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?') 823c2c66affSColin Finck { 824c2c66affSColin Finck /* Find a disk for it */ 825c2c66affSColin Finck return SmpCreatePagingFileOnAnyDrive(Descriptor, &FuzzFactor, &Size); 826c2c66affSColin Finck } 827c2c66affSColin Finck 828c2c66affSColin Finck /* Use the disk that was given */ 829c2c66affSColin Finck return SmpCreatePagingFileOnFixedDrive(Descriptor, &FuzzFactor, &Size); 830c2c66affSColin Finck } 831c2c66affSColin Finck 832c2c66affSColin Finck NTSTATUS 833c2c66affSColin Finck NTAPI 834c2c66affSColin Finck SmpCreateEmergencyPagingFile(VOID) 835c2c66affSColin Finck { 836c2c66affSColin Finck PSMP_PAGEFILE_DESCRIPTOR Descriptor; 837c2c66affSColin Finck WCHAR Buffer[32]; 838c2c66affSColin Finck 839c2c66affSColin Finck /* Allocate a descriptor */ 840c2c66affSColin Finck Descriptor = RtlAllocateHeap(RtlGetProcessHeap(), 841c2c66affSColin Finck HEAP_ZERO_MEMORY, 842c2c66affSColin Finck sizeof(SMP_PAGEFILE_DESCRIPTOR)); 843c2c66affSColin Finck if (!Descriptor) return STATUS_NO_MEMORY; 844c2c66affSColin Finck 845c2c66affSColin Finck /* Initialize it */ 846c2c66affSColin Finck RtlInitUnicodeString(&Descriptor->Token, NULL); 847c2c66affSColin Finck 848c2c66affSColin Finck /* Copy the default pagefile name */ 849c2c66affSColin Finck ASSERT(sizeof(Buffer) >= sizeof(STANDARD_PAGING_FILE_NAME)); 850c2c66affSColin Finck wcscpy(Buffer, STANDARD_PAGING_FILE_NAME); 851c2c66affSColin Finck 852c2c66affSColin Finck /* Fill the rest of the descriptor out */ 853c2c66affSColin Finck RtlInitUnicodeString(&Descriptor->Name, Buffer); 854c2c66affSColin Finck Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = '?'; 855c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED | 856c2c66affSColin Finck SMP_PAGEFILE_EMERGENCY | 857c2c66affSColin Finck SMP_PAGEFILE_ON_ANY_DRIVE; 858c2c66affSColin Finck 859c2c66affSColin Finck /* Insert it into the descriptor list */ 860c2c66affSColin Finck InsertHeadList(&SmpPagingFileDescriptorList, &Descriptor->Entry); 861c2c66affSColin Finck SmpNumberOfPagingFiles++; 862c2c66affSColin Finck 863c2c66affSColin Finck /* Go ahead and create it now, with the minimal size possible */ 864c2c66affSColin Finck return SmpCreateSystemManagedPagingFile(Descriptor, TRUE); 865c2c66affSColin Finck } 866c2c66affSColin Finck 867c2c66affSColin Finck NTSTATUS 868c2c66affSColin Finck NTAPI 869c2c66affSColin Finck SmpCreateVolumeDescriptors(VOID) 870c2c66affSColin Finck { 871c2c66affSColin Finck NTSTATUS Status; 872c2c66affSColin Finck UNICODE_STRING VolumePath; 873c2c66affSColin Finck BOOLEAN BootVolumeFound = FALSE; 874c2c66affSColin Finck WCHAR StartChar, Drive, DriveDiff; 875c2c66affSColin Finck HANDLE VolumeHandle; 876c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 877c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock; 878c2c66affSColin Finck PROCESS_DEVICEMAP_INFORMATION ProcessInformation; 879c2c66affSColin Finck FILE_FS_DEVICE_INFORMATION DeviceInfo; 880c2c66affSColin Finck FILE_FS_SIZE_INFORMATION SizeInfo; 881c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR Volume; 882c2c66affSColin Finck LARGE_INTEGER FreeSpace, FinalFreeSpace; 883c2c66affSColin Finck WCHAR Buffer[32]; 884c2c66affSColin Finck 885c2c66affSColin Finck /* We should be starting with an empty list */ 886c2c66affSColin Finck ASSERT(IsListEmpty(&SmpVolumeDescriptorList)); 887c2c66affSColin Finck 888c2c66affSColin Finck /* Query the device map so we can get the drive letters */ 889c2c66affSColin Finck Status = NtQueryInformationProcess(NtCurrentProcess(), 890c2c66affSColin Finck ProcessDeviceMap, 891094a90adSTimo Kreuzer &ProcessInformation.Query, 892094a90adSTimo Kreuzer sizeof(ProcessInformation.Query), 893c2c66affSColin Finck NULL); 894c2c66affSColin Finck if (!NT_SUCCESS(Status)) 895c2c66affSColin Finck { 896c2c66affSColin Finck DPRINT1("SMSS:PFILE: Query(ProcessDeviceMap) failed with status %X\n", 897c2c66affSColin Finck Status); 898c2c66affSColin Finck return Status; 899c2c66affSColin Finck } 900c2c66affSColin Finck 901c2c66affSColin Finck /* Build the volume string, starting with A: (we'll edit this in place) */ 902c2c66affSColin Finck wcscpy(Buffer, L"\\??\\A:\\"); 903c2c66affSColin Finck RtlInitUnicodeString(&VolumePath, Buffer); 904c2c66affSColin Finck 905a0721ebdSHermès Bélusca-Maïto /* Start with the C drive, except on NEC PC-98 */ 906a0721ebdSHermès Bélusca-Maïto StartChar = IsNEC_98 ? L'A' : L'C'; 907c2c66affSColin Finck for (Drive = StartChar, DriveDiff = StartChar - L'A'; Drive <= L'Z'; Drive++, DriveDiff++) 908c2c66affSColin Finck { 909c2c66affSColin Finck /* Skip the disk if it's not in the drive map */ 910c2c66affSColin Finck if (!((1 << DriveDiff) & ProcessInformation.Query.DriveMap)) continue; 911c2c66affSColin Finck 912c2c66affSColin Finck /* Write the drive letter and try to open the volume */ 913c2c66affSColin Finck VolumePath.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Drive; 914c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 915c2c66affSColin Finck &VolumePath, 916c2c66affSColin Finck OBJ_CASE_INSENSITIVE, 917c2c66affSColin Finck NULL, 918c2c66affSColin Finck NULL); 919c2c66affSColin Finck Status = NtOpenFile(&VolumeHandle, 920c2c66affSColin Finck FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, 921c2c66affSColin Finck &ObjectAttributes, 922c2c66affSColin Finck &IoStatusBlock, 923c2c66affSColin Finck FILE_SHARE_READ | FILE_SHARE_WRITE, 924c2c66affSColin Finck FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); 925c2c66affSColin Finck if (!NT_SUCCESS(Status)) 926c2c66affSColin Finck { 927c2c66affSColin Finck /* Skip the volume if we failed */ 928c2c66affSColin Finck DPRINT1("SMSS:PFILE: Open volume `%wZ' failed with status %X\n", 929c2c66affSColin Finck &VolumePath, Status); 930c2c66affSColin Finck continue; 931c2c66affSColin Finck } 932c2c66affSColin Finck 933c2c66affSColin Finck /* Now query device information on the volume */ 934c2c66affSColin Finck Status = NtQueryVolumeInformationFile(VolumeHandle, 935c2c66affSColin Finck &IoStatusBlock, 936c2c66affSColin Finck &DeviceInfo, 937c2c66affSColin Finck sizeof(DeviceInfo), 938c2c66affSColin Finck FileFsDeviceInformation); 939c2c66affSColin Finck if (!NT_SUCCESS(Status)) 940c2c66affSColin Finck { 941c2c66affSColin Finck /* Move to the next volume if we failed */ 942c2c66affSColin Finck DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for device info" 943c2c66affSColin Finck " failed with status %X\n", 944c2c66affSColin Finck &VolumePath, 945c2c66affSColin Finck VolumeHandle, 946c2c66affSColin Finck Status); 947c2c66affSColin Finck NtClose(VolumeHandle); 948c2c66affSColin Finck continue; 949c2c66affSColin Finck } 950c2c66affSColin Finck 951c2c66affSColin Finck /* Check if this is a fixed disk */ 952c2c66affSColin Finck if (DeviceInfo.Characteristics & (FILE_FLOPPY_DISKETTE | 953c2c66affSColin Finck FILE_READ_ONLY_DEVICE | 954c2c66affSColin Finck FILE_REMOTE_DEVICE | 955c2c66affSColin Finck FILE_REMOVABLE_MEDIA)) 956c2c66affSColin Finck { 957c2c66affSColin Finck /* It isn't, so skip it */ 958c2c66affSColin Finck DPRINT1("SMSS:PFILE: Volume `%wZ' (%X) cannot store a paging file\n", 959c2c66affSColin Finck &VolumePath, 960c2c66affSColin Finck DeviceInfo.Characteristics); 961c2c66affSColin Finck NtClose(VolumeHandle); 962c2c66affSColin Finck continue; 963c2c66affSColin Finck } 964c2c66affSColin Finck 965c2c66affSColin Finck /* We found a fixed volume, allocate a descriptor for it */ 966c2c66affSColin Finck Volume = RtlAllocateHeap(RtlGetProcessHeap(), 967c2c66affSColin Finck HEAP_ZERO_MEMORY, 968c2c66affSColin Finck sizeof(SMP_VOLUME_DESCRIPTOR)); 969c2c66affSColin Finck if (!Volume) 970c2c66affSColin Finck { 971c2c66affSColin Finck /* Failed to allocate memory, try the next disk */ 972c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to allocate a volume descriptor (%u bytes)\n", 973c2c66affSColin Finck sizeof(SMP_VOLUME_DESCRIPTOR)); 974c2c66affSColin Finck NtClose(VolumeHandle); 975c2c66affSColin Finck continue; 976c2c66affSColin Finck } 977c2c66affSColin Finck 978c2c66affSColin Finck /* Save the drive letter and device information */ 979c2c66affSColin Finck Volume->DriveLetter = Drive; 980c2c66affSColin Finck Volume->DeviceInfo = DeviceInfo; 981c2c66affSColin Finck 982c2c66affSColin Finck /* Check if this is the boot volume */ 983c2c66affSColin Finck if (RtlUpcaseUnicodeChar(Drive) == 984c2c66affSColin Finck RtlUpcaseUnicodeChar(SharedUserData->NtSystemRoot[0])) 985c2c66affSColin Finck { 986c2c66affSColin Finck /* Save it */ 987c2c66affSColin Finck ASSERT(BootVolumeFound == FALSE); 988c2c66affSColin Finck Volume->Flags |= SMP_VOLUME_IS_BOOT; 989c2c66affSColin Finck BootVolumeFound = TRUE; 990c2c66affSColin Finck } 991c2c66affSColin Finck 992c2c66affSColin Finck /* Now get size information on the volume */ 993c2c66affSColin Finck Status = NtQueryVolumeInformationFile(VolumeHandle, 994c2c66affSColin Finck &IoStatusBlock, 995c2c66affSColin Finck &SizeInfo, 996c2c66affSColin Finck sizeof(SizeInfo), 997c2c66affSColin Finck FileFsSizeInformation); 998c2c66affSColin Finck if (!NT_SUCCESS(Status)) 999c2c66affSColin Finck { 1000c2c66affSColin Finck /* We failed -- keep going */ 1001c2c66affSColin Finck DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed" 1002c2c66affSColin Finck " with status %X\n", 1003c2c66affSColin Finck &VolumePath, 1004c2c66affSColin Finck VolumeHandle, 1005c2c66affSColin Finck Status); 1006c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, Volume); 1007c2c66affSColin Finck NtClose(VolumeHandle); 1008c2c66affSColin Finck continue; 1009c2c66affSColin Finck } 1010c2c66affSColin Finck 1011c2c66affSColin Finck /* Done querying volume information, close the handle */ 1012c2c66affSColin Finck NtClose(VolumeHandle); 1013c2c66affSColin Finck 1014c2c66affSColin Finck /* Compute how much free space we have */ 1015c2c66affSColin Finck FreeSpace.QuadPart = SizeInfo.AvailableAllocationUnits.QuadPart * 1016c2c66affSColin Finck SizeInfo.SectorsPerAllocationUnit; 1017c2c66affSColin Finck FinalFreeSpace.QuadPart = FreeSpace.QuadPart * SizeInfo.BytesPerSector; 1018c2c66affSColin Finck 10195dc43c0fSHermès Bélusca-Maïto /* Check if there is less than 32 MB free so we don't starve the disk */ 1020c2c66affSColin Finck if (FinalFreeSpace.QuadPart <= MINIMUM_TO_KEEP_FREE) 1021c2c66affSColin Finck { 10225dc43c0fSHermès Bélusca-Maïto /* In this case, act as if there is no free space */ 1023c2c66affSColin Finck Volume->FreeSpace.QuadPart = 0; 1024c2c66affSColin Finck } 1025c2c66affSColin Finck else 1026c2c66affSColin Finck { 1027c2c66affSColin Finck /* Trim off 32 MB to give the disk a bit of breathing room */ 1028c2c66affSColin Finck Volume->FreeSpace.QuadPart = FinalFreeSpace.QuadPart - 1029c2c66affSColin Finck MINIMUM_TO_KEEP_FREE; 1030c2c66affSColin Finck } 1031c2c66affSColin Finck 1032c2c66affSColin Finck /* All done, add this volume to our descriptor list */ 1033c2c66affSColin Finck InsertTailList(&SmpVolumeDescriptorList, &Volume->Entry); 1034c2c66affSColin Finck Volume->Flags |= SMP_VOLUME_INSERTED; 1035c2c66affSColin Finck DPRINT("SMSS:PFILE: Created volume descriptor for`%wZ'\n", &VolumePath); 1036c2c66affSColin Finck } 1037c2c66affSColin Finck 1038c2c66affSColin Finck /* We must've found at least the boot volume */ 1039c2c66affSColin Finck ASSERT(BootVolumeFound == TRUE); 1040c2c66affSColin Finck ASSERT(!IsListEmpty(&SmpVolumeDescriptorList)); 1041c2c66affSColin Finck if (!IsListEmpty(&SmpVolumeDescriptorList)) return STATUS_SUCCESS; 1042c2c66affSColin Finck 1043c2c66affSColin Finck /* Something is really messed up if we found no disks at all */ 1044c2c66affSColin Finck return STATUS_UNEXPECTED_IO_ERROR; 1045c2c66affSColin Finck } 1046c2c66affSColin Finck 1047c2c66affSColin Finck NTSTATUS 1048c2c66affSColin Finck NTAPI 1049c2c66affSColin Finck SmpCreatePagingFiles(VOID) 1050c2c66affSColin Finck { 1051c2c66affSColin Finck NTSTATUS Status; 1052c2c66affSColin Finck PSMP_PAGEFILE_DESCRIPTOR Descriptor; 1053c2c66affSColin Finck LARGE_INTEGER Size, FuzzFactor; 1054c2c66affSColin Finck BOOLEAN Created = FALSE; 1055c2c66affSColin Finck PLIST_ENTRY NextEntry; 1056c2c66affSColin Finck 1057c2c66affSColin Finck /* Check if no paging files were requested */ 1058c2c66affSColin Finck if (!(SmpNumberOfPagingFiles) && !(SmpRegistrySpecifierPresent)) 1059c2c66affSColin Finck { 1060c2c66affSColin Finck /* The list should be empty -- nothing to do */ 1061c2c66affSColin Finck ASSERT(IsListEmpty(&SmpPagingFileDescriptorList)); 1062c2c66affSColin Finck DPRINT1("SMSS:PFILE: No paging file was requested\n"); 1063c2c66affSColin Finck return STATUS_SUCCESS; 1064c2c66affSColin Finck } 1065c2c66affSColin Finck 1066c2c66affSColin Finck /* Initialize the volume descriptors so we can know what's available */ 1067c2c66affSColin Finck Status = SmpCreateVolumeDescriptors(); 1068c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1069c2c66affSColin Finck { 1070c2c66affSColin Finck /* We can't make decisions without this, so fail */ 1071c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to create volume descriptors (status %X)\n", 1072c2c66affSColin Finck Status); 1073c2c66affSColin Finck return Status; 1074c2c66affSColin Finck } 1075c2c66affSColin Finck 1076c2c66affSColin Finck /* If we fail creating pagefiles, try to reduce by this much each time */ 1077c2c66affSColin Finck FuzzFactor.QuadPart = FUZZ_FACTOR; 1078c2c66affSColin Finck 1079c2c66affSColin Finck /* Loop the descriptor list */ 1080c2c66affSColin Finck NextEntry = SmpPagingFileDescriptorList.Flink; 1081c2c66affSColin Finck while (NextEntry != &SmpPagingFileDescriptorList) 1082c2c66affSColin Finck { 1083c2c66affSColin Finck /* Check what kind of descriptor this is */ 1084c2c66affSColin Finck Descriptor = CONTAINING_RECORD(NextEntry, SMP_PAGEFILE_DESCRIPTOR, Entry); 1085c2c66affSColin Finck if (Descriptor->Flags & SMP_PAGEFILE_SYSTEM_MANAGED) 1086c2c66affSColin Finck { 1087c2c66affSColin Finck /* This is a system-managed descriptor. Create the correct file */ 1088c2c66affSColin Finck DPRINT("SMSS:PFILE: Creating a system managed paging file (`%wZ')\n", 1089c2c66affSColin Finck &Descriptor->Name); 1090c2c66affSColin Finck Status = SmpCreateSystemManagedPagingFile(Descriptor, FALSE); 1091c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1092c2c66affSColin Finck { 1093c2c66affSColin Finck /* We failed -- try again, with size minimization this time */ 1094c2c66affSColin Finck DPRINT("SMSS:PFILE: Trying lower sizes for (`%wZ')\n", 1095c2c66affSColin Finck &Descriptor->Name); 1096c2c66affSColin Finck Status = SmpCreateSystemManagedPagingFile(Descriptor, TRUE); 1097c2c66affSColin Finck } 1098c2c66affSColin Finck } 1099c2c66affSColin Finck else 1100c2c66affSColin Finck { 1101c2c66affSColin Finck /* This is a manually entered descriptor. Validate its size first */ 1102c2c66affSColin Finck SmpValidatePagingFileSizes(Descriptor); 1103c2c66affSColin Finck 1104c2c66affSColin Finck /* Check if this is an ANY pagefile or a FIXED pagefile */ 1105c2c66affSColin Finck DPRINT("SMSS:PFILE: Creating a normal paging file (`%wZ')\n", 1106c2c66affSColin Finck &Descriptor->Name); 1107c2c66affSColin Finck if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == L'?') 1108c2c66affSColin Finck { 1109c2c66affSColin Finck /* It's an any pagefile, try to create it wherever possible */ 1110c2c66affSColin Finck Size = Descriptor->MinSize; 1111c2c66affSColin Finck Status = SmpCreatePagingFileOnAnyDrive(Descriptor, 1112c2c66affSColin Finck &FuzzFactor, 1113c2c66affSColin Finck &Size); 1114c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1115c2c66affSColin Finck { 1116c2c66affSColin Finck /* We failed to create it. Try again with a smaller size */ 1117c2c66affSColin Finck DPRINT("SMSS:PFILE: Trying lower sizes for (`%wZ')\n", 1118c2c66affSColin Finck &Descriptor->Name); 1119c2c66affSColin Finck Size.QuadPart = 16 * MEGABYTE; 1120c2c66affSColin Finck Status = SmpCreatePagingFileOnAnyDrive(Descriptor, 1121c2c66affSColin Finck &FuzzFactor, 1122c2c66affSColin Finck &Size); 1123c2c66affSColin Finck } 1124c2c66affSColin Finck } 1125c2c66affSColin Finck else 1126c2c66affSColin Finck { 1127c2c66affSColin Finck /* It's a fixed pagefile: override the minimum and use ours */ 1128c2c66affSColin Finck Size.QuadPart = 16 * MEGABYTE; 1129c2c66affSColin Finck Status = SmpCreatePagingFileOnFixedDrive(Descriptor, 1130c2c66affSColin Finck &FuzzFactor, 1131c2c66affSColin Finck &Size); 1132c2c66affSColin Finck } 1133c2c66affSColin Finck } 1134c2c66affSColin Finck 1135c2c66affSColin Finck /* Go to the next descriptor */ 1136c2c66affSColin Finck if (NT_SUCCESS(Status)) Created = TRUE; 1137c2c66affSColin Finck NextEntry = NextEntry->Flink; 1138c2c66affSColin Finck } 1139c2c66affSColin Finck 1140c2c66affSColin Finck /* Check if none of the code in our loops above was able to create it */ 1141c2c66affSColin Finck if (!Created) 1142c2c66affSColin Finck { 1143c2c66affSColin Finck /* Build an emergency pagefile ourselves */ 1144c2c66affSColin Finck DPRINT1("SMSS:PFILE: Creating emergency paging file.\n"); 1145c2c66affSColin Finck Status = SmpCreateEmergencyPagingFile(); 1146c2c66affSColin Finck } 1147c2c66affSColin Finck 1148c2c66affSColin Finck /* All done */ 1149c2c66affSColin Finck return Status; 1150c2c66affSColin Finck } 1151