X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Fbase%2Fsystem%2Fsmss%2Fpagefile.c;fp=reactos%2Fbase%2Fsystem%2Fsmss%2Fpagefile.c;h=0000000000000000000000000000000000000000;hp=bd4df1a5c9f3702ff6b7c61f926090629e73ae94;hb=c2c66aff7dacc62d125f2cd61d1167e9a2aa3fd6;hpb=b94e2d8ca0b7bb9c17f624e1b4b7e3e7f5b853ac diff --git a/reactos/base/system/smss/pagefile.c b/reactos/base/system/smss/pagefile.c deleted file mode 100644 index bd4df1a5c9f..00000000000 --- a/reactos/base/system/smss/pagefile.c +++ /dev/null @@ -1,1099 +0,0 @@ -/* - * PROJECT: ReactOS Windows-Compatible Session Manager - * LICENSE: BSD 2-Clause License - * FILE: base/system/smss/pagefile.c - * PURPOSE: Main SMSS Code - * PROGRAMMERS: Alex Ionescu - */ - -/* INCLUDES *******************************************************************/ - -#include "smss.h" - -#define NDEBUG -#include - -/* GLOBALS ********************************************************************/ - -// -// Constants -// -#define STANDARD_PAGING_FILE_NAME L"\\??\\?:\\pagefile.sys" -#define STANDARD_DRIVE_LETTER_OFFSET 4 -#define MEGABYTE 0x100000UL -#define MAXIMUM_PAGEFILE_SIZE (4095 * MEGABYTE) -/* This should be 32 MB, but we need more than that for 2nd stage setup */ -#define MINIMUM_TO_KEEP_FREE (64 * MEGABYTE) -#define FUZZ_FACTOR (16 * MEGABYTE) - -// -// Structure and flags describing each pagefile -// -#define SMP_PAGEFILE_CREATED 0x01 -#define SMP_PAGEFILE_DEFAULT 0x02 -#define SMP_PAGEFILE_SYSTEM_MANAGED 0x04 -#define SMP_PAGEFILE_WAS_TOO_BIG 0x08 -#define SMP_PAGEFILE_ON_ANY_DRIVE 0x10 -#define SMP_PAGEFILE_EMERGENCY 0x20 -#define SMP_PAGEFILE_DUMP_PROCESSED 0x40 -typedef struct _SMP_PAGEFILE_DESCRIPTOR -{ - LIST_ENTRY Entry; - UNICODE_STRING Name; - UNICODE_STRING Token; - LARGE_INTEGER MinSize; - LARGE_INTEGER MaxSize; - LARGE_INTEGER ActualMinSize; - LARGE_INTEGER ActualMaxSize; - ULONG Flags; -} SMP_PAGEFILE_DESCRIPTOR, *PSMP_PAGEFILE_DESCRIPTOR; - -// -// Structure and flags describing each volume -// -#define SMP_VOLUME_INSERTED 0x01 -#define SMP_VOLUME_PAGEFILE_CREATED 0x04 -#define SMP_VOLUME_IS_BOOT 0x08 -typedef struct _SMP_VOLUME_DESCRIPTOR -{ - LIST_ENTRY Entry; - USHORT Flags; - USHORT PageFileCount; - WCHAR DriveLetter; - LARGE_INTEGER FreeSpace; - FILE_FS_DEVICE_INFORMATION DeviceInfo; -} SMP_VOLUME_DESCRIPTOR, *PSMP_VOLUME_DESCRIPTOR; - -LIST_ENTRY SmpPagingFileDescriptorList, SmpVolumeDescriptorList; -BOOLEAN SmpRegistrySpecifierPresent; -ULONG SmpNumberOfPagingFiles; - -/* FUNCTIONS ******************************************************************/ - -VOID -NTAPI -SmpPagingFileInitialize(VOID) -{ - /* Initialize the two lists */ - InitializeListHead(&SmpPagingFileDescriptorList); - InitializeListHead(&SmpVolumeDescriptorList); -} - -NTSTATUS -NTAPI -SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken) -{ - NTSTATUS Status; - ULONG MinSize = 0, MaxSize = 0; - BOOLEAN SystemManaged = FALSE, ZeroSize = TRUE; - PSMP_PAGEFILE_DESCRIPTOR Descriptor, ListDescriptor; - ULONG i; - WCHAR c; - PLIST_ENTRY NextEntry; - UNICODE_STRING PageFileName, Arguments, SecondArgument; - - /* Make sure we don't have too many */ - if (SmpNumberOfPagingFiles >= 16) - { - DPRINT1("SMSS:PFILE: Too many paging files specified - %lu\n", - SmpNumberOfPagingFiles); - return STATUS_TOO_MANY_PAGING_FILES; - } - - /* Parse the specified and get the name and arguments out of it */ - DPRINT("SMSS:PFILE: Paging file specifier `%wZ'\n", PageFileToken); - Status = SmpParseCommandLine(PageFileToken, - NULL, - &PageFileName, - NULL, - &Arguments); - if (!NT_SUCCESS(Status)) - { - /* Fail */ - DPRINT1("SMSS:PFILE: SmpParseCommandLine( %wZ ) failed - Status == %lx\n", - PageFileToken, Status); - return Status; - } - - /* Set the variable to let everyone know we have a pagefile token */ - SmpRegistrySpecifierPresent = TRUE; - - /* Parse the arguments, if any */ - if (Arguments.Buffer) - { - /* Parse the pagefile size */ - for (i = 0; i < Arguments.Length / sizeof(WCHAR); i++) - { - /* Check if it's zero */ - c = Arguments.Buffer[i]; - if ((c != L' ') && (c != L'\t') && (c != L'0')) - { - /* It isn't, break out */ - ZeroSize = FALSE; - break; - } - } - } - - /* Was a pagefile not specified, or was it specified with no size? */ - if (!(Arguments.Buffer) || (ZeroSize)) - { - /* In this case, the system will manage its size */ - SystemManaged = TRUE; - } - else - { - /* We do have a size, so convert the arguments into a number */ - Status = RtlUnicodeStringToInteger(&Arguments, 0, &MinSize); - if (!NT_SUCCESS(Status)) - { - /* Fail */ - RtlFreeUnicodeString(&PageFileName); - RtlFreeUnicodeString(&Arguments); - return Status; - } - - /* Now advance to the next argument */ - for (i = 0; i < Arguments.Length / sizeof(WCHAR); i++) - { - /* Found a space -- second argument must start here */ - if (Arguments.Buffer[i] == L' ') - { - /* Use the rest of the arguments as a maximum size */ - SecondArgument.Buffer = &Arguments.Buffer[i]; - SecondArgument.Length = (USHORT)(Arguments.Length - - i * sizeof(WCHAR)); - SecondArgument.MaximumLength = (USHORT)(Arguments.MaximumLength - - i * sizeof(WCHAR)); - Status = RtlUnicodeStringToInteger(&SecondArgument, 0, &MaxSize); - if (!NT_SUCCESS(Status)) - { - /* Fail */ - RtlFreeUnicodeString(&PageFileName); - RtlFreeUnicodeString(&Arguments); - return Status; - } - - break; - } - } - } - - /* We are done parsing arguments */ - RtlFreeUnicodeString(&Arguments); - - /* Now we can allocate our descriptor */ - Descriptor = RtlAllocateHeap(RtlGetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(SMP_PAGEFILE_DESCRIPTOR)); - if (!Descriptor) - { - /* Fail if we couldn't */ - RtlFreeUnicodeString(&PageFileName); - return STATUS_NO_MEMORY; - } - - /* Capture all our data into the descriptor */ - Descriptor->Token = *PageFileToken; - Descriptor->Name = PageFileName; - Descriptor->MinSize.QuadPart = MinSize * MEGABYTE; - Descriptor->MaxSize.QuadPart = MaxSize * MEGABYTE; - if (SystemManaged) Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED; - Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = - RtlUpcaseUnicodeChar(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]); - if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?') - { - Descriptor->Flags |= SMP_PAGEFILE_ON_ANY_DRIVE; - } - - /* Now loop the existing descriptors */ - NextEntry = SmpPagingFileDescriptorList.Flink; - do - { - /* Are there none, or have we looped back to the beginning? */ - if (NextEntry == &SmpPagingFileDescriptorList) - { - /* This means no duplicates exist, so insert our descriptor! */ - InsertTailList(&SmpPagingFileDescriptorList, &Descriptor->Entry); - SmpNumberOfPagingFiles++; - DPRINT("SMSS:PFILE: Created descriptor for `%wZ' (`%wZ')\n", - PageFileToken, &Descriptor->Name); - return STATUS_SUCCESS; - } - - /* Keep going until we find a duplicate, unless we are in "any" mode */ - ListDescriptor = CONTAINING_RECORD(NextEntry, SMP_PAGEFILE_DESCRIPTOR, Entry); - NextEntry = NextEntry->Flink; - } while (!(ListDescriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE) || - !(Descriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE)); - - /* We found a duplicate, so skip this descriptor/pagefile and fail */ - DPRINT1("SMSS:PFILE: Skipping duplicate specifier `%wZ'\n", PageFileToken); - RtlFreeUnicodeString(&PageFileName); - RtlFreeHeap(RtlGetProcessHeap(), 0, Descriptor); - return STATUS_INVALID_PARAMETER; -} - -NTSTATUS -NTAPI -SmpGetPagingFileSize(IN PUNICODE_STRING FileName, - OUT PLARGE_INTEGER Size) -{ - NTSTATUS Status; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE FileHandle; - FILE_STANDARD_INFORMATION StandardInfo; - - DPRINT("SMSS:PFILE: Trying to get size for `%wZ'\n", FileName); - Size->QuadPart = 0; - - InitializeObjectAttributes(&ObjectAttributes, - FileName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenFile(&FileHandle, - FILE_READ_ATTRIBUTES | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) return Status; - - Status = NtQueryInformationFile(FileHandle, - &IoStatusBlock, - &StandardInfo, - sizeof(StandardInfo), - FileStandardInformation); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SMSS:PFILE: Failed query for size potential pagefile `%wZ' with status %X\n", - FileName, Status); - NtClose(FileHandle); - return Status; - } - - NtClose(FileHandle); - Size->QuadPart = StandardInfo.AllocationSize.QuadPart; - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -SmpDeletePagingFile(IN PUNICODE_STRING FileName) -{ - NTSTATUS Status; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - HANDLE FileHandle; - FILE_DISPOSITION_INFORMATION Disposition; - - /* Open the page file */ - InitializeObjectAttributes(&ObjectAttributes, - FileName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenFile(&FileHandle, - DELETE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_NON_DIRECTORY_FILE); - if (NT_SUCCESS(Status)) - { - /* Delete it */ - Disposition.DeleteFile = TRUE; - Status = NtSetInformationFile(FileHandle, - &IoStatusBlock, - &Disposition, - sizeof(Disposition), - FileDispositionInformation); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SMSS:PFILE: Failed to delete page file `%wZ' (status %X)\n", - FileName, Status); - } - else - { - DPRINT("SMSS:PFILE: Deleted stale paging file - %wZ\n", FileName); - } - - /* Close the handle */ - NtClose(FileHandle); - } - else - { - DPRINT1("SMSS:PFILE: Failed to open for deletion page file `%wZ' (status %X)\n", - FileName, Status); - } - - /* All done */ - return Status; -} - -NTSTATUS -NTAPI -SmpGetVolumeFreeSpace(IN PSMP_VOLUME_DESCRIPTOR Volume) -{ - NTSTATUS Status; - LARGE_INTEGER FreeSpace, FinalFreeSpace; - FILE_FS_SIZE_INFORMATION SizeInfo; - IO_STATUS_BLOCK IoStatusBlock; - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING VolumeName; - HANDLE VolumeHandle; - WCHAR PathString[32]; - ASSERT(Volume->Flags & SMP_VOLUME_IS_BOOT); // ASSERT says "BootVolume == 1" - - /* Build the standard path */ - wcscpy(PathString, L"\\??\\A:\\"); - RtlInitUnicodeString(&VolumeName, PathString); - VolumeName.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Volume->DriveLetter; - DPRINT("SMSS:PFILE: Querying volume `%wZ' for free space\n", &VolumeName); - - /* Open the volume */ - InitializeObjectAttributes(&ObjectAttributes, - &VolumeName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenFile(&VolumeHandle, - FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SMSS:PFILE: Open volume `%wZ' failed with status %X\n", &VolumeName, Status); - return Status; - } - - /* Now get size information on the volume */ - Status = NtQueryVolumeInformationFile(VolumeHandle, - &IoStatusBlock, - &SizeInfo, - sizeof(SizeInfo), - FileFsSizeInformation); - if (!NT_SUCCESS(Status)) - { - /* We failed */ - DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed" - " with status %X\n", - &VolumeName, - VolumeHandle, - Status); - NtClose(VolumeHandle); - return Status; - } - NtClose(VolumeHandle); - - /* Compute how much free space we have */ - FreeSpace.QuadPart = SizeInfo.AvailableAllocationUnits.QuadPart * - SizeInfo.SectorsPerAllocationUnit; - FinalFreeSpace.QuadPart = FreeSpace.QuadPart * SizeInfo.BytesPerSector; - - /* Check if there's less than 32MB free so we don't starve the disk */ - if (FinalFreeSpace.QuadPart <= MINIMUM_TO_KEEP_FREE) - { - /* In this case, act as if there's no free space */ - Volume->FreeSpace.QuadPart = 0; - } - else - { - /* Trim off 32MB to give the disk a bit of breathing room */ - Volume->FreeSpace.QuadPart = FinalFreeSpace.QuadPart - - MINIMUM_TO_KEEP_FREE; - } - - return STATUS_SUCCESS; -} - -PSMP_VOLUME_DESCRIPTOR -NTAPI -SmpSearchVolumeDescriptor(IN WCHAR DriveLetter) -{ - WCHAR UpLetter; - PSMP_VOLUME_DESCRIPTOR Volume = NULL; - PLIST_ENTRY NextEntry; - - /* Use upper case to reduce differences */ - UpLetter = RtlUpcaseUnicodeChar(DriveLetter); - - /* Loop each volume */ - NextEntry = SmpVolumeDescriptorList.Flink; - while (NextEntry != &SmpVolumeDescriptorList) - { - /* Grab the entry */ - Volume = CONTAINING_RECORD(NextEntry, SMP_VOLUME_DESCRIPTOR, Entry); - - /* Make sure it's a valid entry with an uppcase drive letter */ - ASSERT(Volume->Flags & SMP_VOLUME_INSERTED); // Volume->Initialized in ASSERT - ASSERT(Volume->DriveLetter >= L'A' && Volume->DriveLetter <= L'Z'); - - /* Break if it matches, if not, keep going */ - if (Volume->DriveLetter == UpLetter) break; - NextEntry = NextEntry->Flink; - } - - /* Return the volume if one was found */ - if (NextEntry == &SmpVolumeDescriptorList) Volume = NULL; - return Volume; -} - -NTSTATUS -NTAPI -SmpCreatePagingFile(IN PUNICODE_STRING Name, - IN PLARGE_INTEGER MinSize, - IN PLARGE_INTEGER MaxSize, - IN ULONG Priority) -{ - NTSTATUS Status; - - /* Tell the kernel to create the pagefile */ - Status = NtCreatePagingFile(Name, MinSize, MaxSize, Priority); - if (NT_SUCCESS(Status)) - { - DPRINT("SMSS:PFILE: NtCreatePagingFile (%wZ, %I64X, %I64X) succeeded.\n", - Name, - MinSize->QuadPart, - MaxSize->QuadPart); - } - else - { - DPRINT1("SMSS:PFILE: NtCreatePagingFile (%wZ, %I64X, %I64X) failed with %X\n", - Name, - MinSize->QuadPart, - MaxSize->QuadPart, - Status); - } - - /* Return the status */ - return Status; -} - -NTSTATUS -NTAPI -SmpCreatePagingFileOnFixedDrive(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor, - IN PLARGE_INTEGER FuzzFactor, - IN PLARGE_INTEGER MinimumSize) -{ - PSMP_VOLUME_DESCRIPTOR Volume; - BOOLEAN ShouldDelete; - NTSTATUS Status; - LARGE_INTEGER PageFileSize; - ASSERT(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] != L'?'); - - /* Try to find the volume descriptor for this drive letter */ - ShouldDelete = FALSE; - Volume = SmpSearchVolumeDescriptor(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]); - if (!Volume) - { - /* Couldn't find it, fail */ - DPRINT1("SMSS:PFILE: No volume descriptor for `%wZ'\n", - &Descriptor->Name); - return STATUS_INVALID_PARAMETER; - } - - /* Check if this is the boot volume */ - if (Volume->Flags & SMP_VOLUME_IS_BOOT) - { - /* Check if we haven't yet processed a crash dump on this volume */ - if (!(Descriptor->Flags & SMP_PAGEFILE_DUMP_PROCESSED)) - { - /* Try to find a crash dump and extract it */ - DPRINT("SMSS:PFILE: Checking for crash dump in `%wZ' on boot volume\n", - &Descriptor->Name); - SmpCheckForCrashDump(&Descriptor->Name); - - /* Update how much free space we have now that we extracted a dump */ - Status = SmpGetVolumeFreeSpace(Volume); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SMSS:PFILE: Failed to query free space for boot volume `%wC'\n", - Volume->DriveLetter); - } - else - { - DPRINT("Queried free space for boot volume `%wC: %I64x'\n", - Volume->DriveLetter, Volume->FreeSpace.QuadPart); - } - - /* Don't process crashdump on this volume anymore */ - Descriptor->Flags |= SMP_PAGEFILE_DUMP_PROCESSED; - } - } - else - { - /* Crashdumps can only be on the boot volume */ - DPRINT("SMSS:PFILE: Skipping crash dump checking for `%wZ' on non boot" - "volume `%wC'\n", - &Descriptor->Name, - Volume->DriveLetter); - } - - /* Update the size after dump extraction */ - Descriptor->ActualMinSize = Descriptor->MinSize; - Descriptor->ActualMaxSize = Descriptor->MaxSize; - - /* Check how big we can make the pagefile */ - Status = SmpGetPagingFileSize(&Descriptor->Name, &PageFileSize); - if (NT_SUCCESS(Status) && PageFileSize.QuadPart > 0) ShouldDelete = TRUE; - DPRINT("SMSS:PFILE: Detected size %I64X for future paging file `%wZ'\n", - PageFileSize, - &Descriptor->Name); - DPRINT("SMSS:PFILE: Free space on volume `%wC' is %I64X\n", - Volume->DriveLetter, - Volume->FreeSpace.QuadPart); - - /* Now update our size and make sure none of these are too big */ - PageFileSize.QuadPart += Volume->FreeSpace.QuadPart; - if (Descriptor->ActualMinSize.QuadPart > PageFileSize.QuadPart) - { - Descriptor->ActualMinSize = PageFileSize; - } - if (Descriptor->ActualMaxSize.QuadPart > PageFileSize.QuadPart) - { - Descriptor->ActualMaxSize = PageFileSize; - } - DPRINT("SMSS:PFILE: min %I64X, max %I64X, real min %I64X\n", - Descriptor->ActualMinSize.QuadPart, - Descriptor->ActualMaxSize.QuadPart, - MinimumSize->QuadPart); - - /* Keep going until we've created a pagefile of the right size */ - while (Descriptor->ActualMinSize.QuadPart >= MinimumSize->QuadPart) - { - /* Call NT to do it */ - Status = SmpCreatePagingFile(&Descriptor->Name, - &Descriptor->ActualMinSize, - &Descriptor->ActualMaxSize, - 0); - if (NT_SUCCESS(Status)) - { - /* We're done, update flags and increase the count */ - Descriptor->Flags |= SMP_PAGEFILE_CREATED; - Volume->Flags |= SMP_VOLUME_PAGEFILE_CREATED; - Volume->PageFileCount++; - break; - } - - /* We failed, try a slightly smaller pagefile */ - Descriptor->ActualMinSize.QuadPart -= FuzzFactor->QuadPart; - } - - /* Check if we weren't able to create it */ - if (Descriptor->ActualMinSize.QuadPart < MinimumSize->QuadPart) - { - /* Delete the current page file and fail */ - if (ShouldDelete) - { - SmpDeletePagingFile(&Descriptor->Name); - - /* FIXFIX: Windows Vista does this, and it seems like we should too, so try to see if this fixes KVM */ - Volume->FreeSpace.QuadPart = PageFileSize.QuadPart; - } - DPRINT1("SMSS:PFILE: Failing for min %I64X, max %I64X, real min %I64X\n", - Descriptor->ActualMinSize.QuadPart, - Descriptor->ActualMaxSize.QuadPart, - MinimumSize->QuadPart); - Status = STATUS_DISK_FULL; - } - - /* Return the status */ - return Status; -} - -NTSTATUS -NTAPI -SmpCreatePagingFileOnAnyDrive(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor, - IN PLARGE_INTEGER FuzzFactor, - IN PLARGE_INTEGER MinimumSize) -{ - PSMP_VOLUME_DESCRIPTOR Volume; - NTSTATUS Status = STATUS_DISK_FULL; - PLIST_ENTRY NextEntry; - ASSERT(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == L'?'); - - /* Loop the volume list */ - NextEntry = SmpVolumeDescriptorList.Flink; - while (NextEntry != &SmpVolumeDescriptorList) - { - /* Get the volume */ - Volume = CONTAINING_RECORD(NextEntry, SMP_VOLUME_DESCRIPTOR, Entry); - - /* Make sure it's inserted and on a valid drive letter */ - ASSERT(Volume->Flags & SMP_VOLUME_INSERTED); // Volume->Initialized in ASSERT - ASSERT(Volume->DriveLetter >= L'A' && Volume->DriveLetter <= L'Z'); - - /* Write the drive letter to try creating it on this volume */ - Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Volume->DriveLetter; - Status = SmpCreatePagingFileOnFixedDrive(Descriptor, - FuzzFactor, - MinimumSize); - if (NT_SUCCESS(Status)) break; - - /* It didn't work, make it an any pagefile again and keep going */ - Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = L'?'; - NextEntry = NextEntry->Flink; - } - - /* Return disk full or success */ - return Status; -} - -VOID -NTAPI -SmpMakeDefaultPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor) -{ - /* The default descriptor uses 128MB as a pagefile size */ - Descriptor->Flags |= SMP_PAGEFILE_DEFAULT; - Descriptor->MinSize.QuadPart = 128 * MEGABYTE; - Descriptor->MaxSize.QuadPart = 128 * MEGABYTE; -} - -VOID -NTAPI -SmpMakeSystemManagedPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor) -{ - NTSTATUS Status; - LONGLONG MinimumSize, MaximumSize, Ram; - SYSTEM_BASIC_INFORMATION BasicInfo; - - /* Query the page size of the system, and the amount of RAM */ - Status = NtQuerySystemInformation(SystemBasicInformation, - &BasicInfo, - sizeof(BasicInfo), - NULL); - if (!NT_SUCCESS(Status)) - { - /* If we failed, use defaults since we have no idea otherwise */ - DPRINT1("SMSS:PFILE: NtQuerySystemInformation failed with %x\n", Status); - SmpMakeDefaultPagingFileDescriptor(Descriptor); - return; - } - - /* Chekc how much RAM we have and set three times this amount as maximum */ - Ram = BasicInfo.NumberOfPhysicalPages * BasicInfo.PageSize; - MaximumSize = 3 * Ram; - - /* If we have more than 1GB, use that as minimum, otherwise, use 1.5X RAM */ - MinimumSize = (Ram >= 1024 * MEGABYTE) ? Ram : MaximumSize / 2; - - /* Write the new sizes in the descriptor and mark it as system managed */ - Descriptor->MinSize.QuadPart = MinimumSize; - Descriptor->MaxSize.QuadPart = MaximumSize; - Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED; -} - -NTSTATUS -NTAPI -SmpValidatePagingFileSizes(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor) -{ - NTSTATUS Status = STATUS_SUCCESS; - ULONGLONG MinSize, MaxSize; - BOOLEAN WasTooBig = FALSE; - - /* Capture the min and max */ - MinSize = Descriptor->MinSize.QuadPart; - MaxSize = Descriptor->MaxSize.QuadPart; - DPRINT("SMSS:PFILE: Validating sizes for `%wZ' %I64X %I64X\n", - &Descriptor->Name, MinSize, MaxSize); - - /* Don't let minimum be bigger than maximum */ - if (MinSize > MaxSize) MaxSize = MinSize; - - /* On PAE we can have bigger pagefiles... */ - if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]) - { - /* But we don't support that yet */ - DPRINT1("ReactOS does not support PAE yet... assuming sizes OK\n"); - } - else - { - /* Check if the minimum is more then 4095 MB */ - if (MinSize > MAXIMUM_PAGEFILE_SIZE) - { - /* Trim it, this isn't allowed */ - WasTooBig = TRUE; - MinSize = MAXIMUM_PAGEFILE_SIZE; - } - - /* Check if the maximum is more then 4095 MB */ - if (MaxSize > MAXIMUM_PAGEFILE_SIZE) - { - /* Trim it, this isn't allowed */ - WasTooBig = TRUE; - MaxSize = MAXIMUM_PAGEFILE_SIZE; - } - } - - /* Did we trim? */ - if (WasTooBig) - { - /* Notify debugger output and write a flag in the descriptor */ - DPRINT("SMSS:PFILE: Trimmed size of `%wZ' to maximum allowed\n", - &Descriptor->Name); - Descriptor->Flags |= SMP_PAGEFILE_WAS_TOO_BIG; - } - - /* Now write the (possibly trimmed) sizes back */ - Descriptor->MinSize.QuadPart = MinSize; - Descriptor->MaxSize.QuadPart = MaxSize; - return Status; -} - -NTSTATUS -NTAPI -SmpCreateSystemManagedPagingFile(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor, - IN BOOLEAN DecreaseSize) -{ - LARGE_INTEGER FuzzFactor, Size; - - /* Make sure there's at least 1 paging file and that we are system-managed */ - ASSERT(SmpNumberOfPagingFiles >= 1); - ASSERT(!IsListEmpty(&SmpPagingFileDescriptorList)); - ASSERT(Descriptor->Flags & SMP_PAGEFILE_SYSTEM_MANAGED); // Descriptor->SystemManaged == 1 in ASSERT. - - /* Keep decreasing the pagefile by this amount if we run out of space */ - FuzzFactor.QuadPart = FUZZ_FACTOR; - - /* Create the descriptor for it (mainly the right sizes) and validate */ - SmpMakeSystemManagedPagingFileDescriptor(Descriptor); - SmpValidatePagingFileSizes(Descriptor); - - /* Use either the minimum size in the descriptor, or 16MB in minimal mode */ - Size.QuadPart = DecreaseSize ? 16 * MEGABYTE : Descriptor->MinSize.QuadPart; - - /* Check if this should be a fixed pagefile or an any pagefile*/ - if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?') - { - /* Find a disk for it */ - return SmpCreatePagingFileOnAnyDrive(Descriptor, &FuzzFactor, &Size); - } - - /* Use the disk that was given */ - return SmpCreatePagingFileOnFixedDrive(Descriptor, &FuzzFactor, &Size); -} - -NTSTATUS -NTAPI -SmpCreateEmergencyPagingFile(VOID) -{ - PSMP_PAGEFILE_DESCRIPTOR Descriptor; - WCHAR Buffer[32]; - - /* Allocate a descriptor */ - Descriptor = RtlAllocateHeap(RtlGetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(SMP_PAGEFILE_DESCRIPTOR)); - if (!Descriptor) return STATUS_NO_MEMORY; - - /* Initialize it */ - RtlInitUnicodeString(&Descriptor->Token, NULL); - - /* Copy the default pagefile name */ - ASSERT(sizeof(Buffer) >= sizeof(STANDARD_PAGING_FILE_NAME)); - wcscpy(Buffer, STANDARD_PAGING_FILE_NAME); - - /* Fill the rest of the descriptor out */ - RtlInitUnicodeString(&Descriptor->Name, Buffer); - Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = '?'; - Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED | - SMP_PAGEFILE_EMERGENCY | - SMP_PAGEFILE_ON_ANY_DRIVE; - - /* Insert it into the descriptor list */ - InsertHeadList(&SmpPagingFileDescriptorList, &Descriptor->Entry); - SmpNumberOfPagingFiles++; - - /* Go ahead and create it now, with the minimal size possible */ - return SmpCreateSystemManagedPagingFile(Descriptor, TRUE); -} - -NTSTATUS -NTAPI -SmpCreateVolumeDescriptors(VOID) -{ - NTSTATUS Status; - UNICODE_STRING VolumePath; - BOOLEAN BootVolumeFound = FALSE; - WCHAR StartChar, Drive, DriveDiff; - HANDLE VolumeHandle; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - PROCESS_DEVICEMAP_INFORMATION ProcessInformation; - FILE_FS_DEVICE_INFORMATION DeviceInfo; - FILE_FS_SIZE_INFORMATION SizeInfo; - PSMP_VOLUME_DESCRIPTOR Volume; - LARGE_INTEGER FreeSpace, FinalFreeSpace; - WCHAR Buffer[32]; - - /* We should be starting with an empty list */ - ASSERT(IsListEmpty(&SmpVolumeDescriptorList)); - - /* Query the device map so we can get the drive letters */ - Status = NtQueryInformationProcess(NtCurrentProcess(), - ProcessDeviceMap, - &ProcessInformation, - sizeof(ProcessInformation), - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SMSS:PFILE: Query(ProcessDeviceMap) failed with status %X\n", - Status); - return Status; - } - - /* Build the volume string, starting with A: (we'll edit this in place) */ - wcscpy(Buffer, L"\\??\\A:\\"); - RtlInitUnicodeString(&VolumePath, Buffer); - - /* Start with the C drive except on weird Japanese NECs... */ - StartChar = SharedUserData->AlternativeArchitecture ? L'A' : L'C'; - for (Drive = StartChar, DriveDiff = StartChar - L'A'; Drive <= L'Z'; Drive++, DriveDiff++) - { - /* Skip the disk if it's not in the drive map */ - if (!((1 << DriveDiff) & ProcessInformation.Query.DriveMap)) continue; - - /* Write the drive letter and try to open the volume */ - VolumePath.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Drive; - InitializeObjectAttributes(&ObjectAttributes, - &VolumePath, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenFile(&VolumeHandle, - FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); - if (!NT_SUCCESS(Status)) - { - /* Skip the volume if we failed */ - DPRINT1("SMSS:PFILE: Open volume `%wZ' failed with status %X\n", - &VolumePath, Status); - continue; - } - - /* Now query device information on the volume */ - Status = NtQueryVolumeInformationFile(VolumeHandle, - &IoStatusBlock, - &DeviceInfo, - sizeof(DeviceInfo), - FileFsDeviceInformation); - if (!NT_SUCCESS(Status)) - { - /* Move to the next volume if we failed */ - DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for device info" - " failed with status %X\n", - &VolumePath, - VolumeHandle, - Status); - NtClose(VolumeHandle); - continue; - } - - /* Check if this is a fixed disk */ - if (DeviceInfo.Characteristics & (FILE_FLOPPY_DISKETTE | - FILE_READ_ONLY_DEVICE | - FILE_REMOTE_DEVICE | - FILE_REMOVABLE_MEDIA)) - { - /* It isn't, so skip it */ - DPRINT1("SMSS:PFILE: Volume `%wZ' (%X) cannot store a paging file\n", - &VolumePath, - DeviceInfo.Characteristics); - NtClose(VolumeHandle); - continue; - } - - /* We found a fixed volume, allocate a descriptor for it */ - Volume = RtlAllocateHeap(RtlGetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(SMP_VOLUME_DESCRIPTOR)); - if (!Volume) - { - /* Failed to allocate memory, try the next disk */ - DPRINT1("SMSS:PFILE: Failed to allocate a volume descriptor (%u bytes)\n", - sizeof(SMP_VOLUME_DESCRIPTOR)); - NtClose(VolumeHandle); - continue; - } - - /* Save the drive letter and device information */ - Volume->DriveLetter = Drive; - Volume->DeviceInfo = DeviceInfo; - - /* Check if this is the boot volume */ - if (RtlUpcaseUnicodeChar(Drive) == - RtlUpcaseUnicodeChar(SharedUserData->NtSystemRoot[0])) - { - /* Save it */ - ASSERT(BootVolumeFound == FALSE); - Volume->Flags |= SMP_VOLUME_IS_BOOT; - BootVolumeFound = TRUE; - } - - /* Now get size information on the volume */ - Status = NtQueryVolumeInformationFile(VolumeHandle, - &IoStatusBlock, - &SizeInfo, - sizeof(SizeInfo), - FileFsSizeInformation); - if (!NT_SUCCESS(Status)) - { - /* We failed -- keep going */ - DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed" - " with status %X\n", - &VolumePath, - VolumeHandle, - Status); - RtlFreeHeap(RtlGetProcessHeap(), 0, Volume); - NtClose(VolumeHandle); - continue; - } - - /* Done querying volume information, close the handle */ - NtClose(VolumeHandle); - - /* Compute how much free space we have */ - FreeSpace.QuadPart = SizeInfo.AvailableAllocationUnits.QuadPart * - SizeInfo.SectorsPerAllocationUnit; - FinalFreeSpace.QuadPart = FreeSpace.QuadPart * SizeInfo.BytesPerSector; - - /* Check if there's less than 32MB free so we don't starve the disk */ - if (FinalFreeSpace.QuadPart <= MINIMUM_TO_KEEP_FREE) - { - /* In this case, act as if there's no free space */ - Volume->FreeSpace.QuadPart = 0; - } - else - { - /* Trim off 32MB to give the disk a bit of breathing room */ - Volume->FreeSpace.QuadPart = FinalFreeSpace.QuadPart - - MINIMUM_TO_KEEP_FREE; - } - - /* All done, add this volume to our descriptor list */ - InsertTailList(&SmpVolumeDescriptorList, &Volume->Entry); - Volume->Flags |= SMP_VOLUME_INSERTED; - DPRINT("SMSS:PFILE: Created volume descriptor for`%wZ'\n", &VolumePath); - } - - /* We must've found at least the boot volume */ - ASSERT(BootVolumeFound == TRUE); - ASSERT(!IsListEmpty(&SmpVolumeDescriptorList)); - if (!IsListEmpty(&SmpVolumeDescriptorList)) return STATUS_SUCCESS; - - /* Something is really messed up if we found no disks at all */ - return STATUS_UNEXPECTED_IO_ERROR; -} - -NTSTATUS -NTAPI -SmpCreatePagingFiles(VOID) -{ - NTSTATUS Status; - PSMP_PAGEFILE_DESCRIPTOR Descriptor; - LARGE_INTEGER Size, FuzzFactor; - BOOLEAN Created = FALSE; - PLIST_ENTRY NextEntry; - - /* Check if no paging files were requested */ - if (!(SmpNumberOfPagingFiles) && !(SmpRegistrySpecifierPresent)) - { - /* The list should be empty -- nothing to do */ - ASSERT(IsListEmpty(&SmpPagingFileDescriptorList)); - DPRINT1("SMSS:PFILE: No paging file was requested\n"); - return STATUS_SUCCESS; - } - - /* Initialize the volume descriptors so we can know what's available */ - Status = SmpCreateVolumeDescriptors(); - if (!NT_SUCCESS(Status)) - { - /* We can't make decisions without this, so fail */ - DPRINT1("SMSS:PFILE: Failed to create volume descriptors (status %X)\n", - Status); - return Status; - } - - /* If we fail creating pagefiles, try to reduce by this much each time */ - FuzzFactor.QuadPart = FUZZ_FACTOR; - - /* Loop the descriptor list */ - NextEntry = SmpPagingFileDescriptorList.Flink; - while (NextEntry != &SmpPagingFileDescriptorList) - { - /* Check what kind of descriptor this is */ - Descriptor = CONTAINING_RECORD(NextEntry, SMP_PAGEFILE_DESCRIPTOR, Entry); - if (Descriptor->Flags & SMP_PAGEFILE_SYSTEM_MANAGED) - { - /* This is a system-managed descriptor. Create the correct file */ - DPRINT("SMSS:PFILE: Creating a system managed paging file (`%wZ')\n", - &Descriptor->Name); - Status = SmpCreateSystemManagedPagingFile(Descriptor, FALSE); - if (!NT_SUCCESS(Status)) - { - /* We failed -- try again, with size minimization this time */ - DPRINT("SMSS:PFILE: Trying lower sizes for (`%wZ')\n", - &Descriptor->Name); - Status = SmpCreateSystemManagedPagingFile(Descriptor, TRUE); - } - } - else - { - /* This is a manually entered descriptor. Validate its size first */ - SmpValidatePagingFileSizes(Descriptor); - - /* Check if this is an ANY pagefile or a FIXED pagefile */ - DPRINT("SMSS:PFILE: Creating a normal paging file (`%wZ')\n", - &Descriptor->Name); - if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == L'?') - { - /* It's an any pagefile, try to create it wherever possible */ - Size = Descriptor->MinSize; - Status = SmpCreatePagingFileOnAnyDrive(Descriptor, - &FuzzFactor, - &Size); - if (!NT_SUCCESS(Status)) - { - /* We failed to create it. Try again with a smaller size */ - DPRINT("SMSS:PFILE: Trying lower sizes for (`%wZ')\n", - &Descriptor->Name); - Size.QuadPart = 16 * MEGABYTE; - Status = SmpCreatePagingFileOnAnyDrive(Descriptor, - &FuzzFactor, - &Size); - } - } - else - { - /* It's a fixed pagefile: override the minimum and use ours */ - Size.QuadPart = 16 * MEGABYTE; - Status = SmpCreatePagingFileOnFixedDrive(Descriptor, - &FuzzFactor, - &Size); - } - } - - /* Go to the next descriptor */ - if (NT_SUCCESS(Status)) Created = TRUE; - NextEntry = NextEntry->Flink; - } - - /* Check if none of the code in our loops above was able to create it */ - if (!Created) - { - /* Build an emergency pagefile ourselves */ - DPRINT1("SMSS:PFILE: Creating emergency paging file.\n"); - Status = SmpCreateEmergencyPagingFile(); - } - - /* All done */ - return Status; -}