Author: ion Date: Fri Feb 3 23:11:28 2012 New Revision: 55400
URL: http://svn.reactos.org/svn/reactos?rev=55400&view=rev Log: [SMSS2]: Implement the rest of the code to create page files. All that's missing is the actual call to NtCreatePagingFile.
Modified: trunk/reactos/base/system/smss2/crashdmp.c trunk/reactos/base/system/smss2/pagefile.c trunk/reactos/base/system/smss2/smss.h
Modified: trunk/reactos/base/system/smss2/crashdmp.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/smss2/crashdmp.... ============================================================================== --- trunk/reactos/base/system/smss2/crashdmp.c [iso-8859-1] (original) +++ trunk/reactos/base/system/smss2/crashdmp.c [iso-8859-1] Fri Feb 3 23:11:28 2012 @@ -15,3 +15,12 @@ /* GLOBALS ********************************************************************/
/* FUNCTIONS ******************************************************************/ + +BOOLEAN +NTAPI +SmpCheckForCrashDump(IN PUNICODE_STRING FileName) +{ + return FALSE; +} + +
Modified: trunk/reactos/base/system/smss2/pagefile.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/smss2/pagefile.... ============================================================================== --- trunk/reactos/base/system/smss2/pagefile.c [iso-8859-1] (original) +++ trunk/reactos/base/system/smss2/pagefile.c [iso-8859-1] Fri Feb 3 23:11:28 2012 @@ -46,11 +46,13 @@ // 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; - ULONG Flags; + USHORT Flags; + USHORT PageFileCount; WCHAR DriveLetter; LARGE_INTEGER FreeSpace; FILE_FS_DEVICE_INFORMATION DeviceInfo; @@ -230,13 +232,369 @@
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; + + DPRINT1("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->LowPart = StandardInfo.AllocationSize.LowPart; + Size->HighPart = StandardInfo.AllocationSize.HighPart; + 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 + { + DPRINT1("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:\"); + VolumeName.Buffer = PathString; + VolumeName.Length = wcslen(PathString) * sizeof(WCHAR); + VolumeName.MaximumLength = VolumeName.Length + sizeof(UNICODE_NULL); + VolumeName.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Volume->DriveLetter; + DPRINT1("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 -- keep going */ + DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed" + " with status %X \n", + &VolumeName, + VolumeHandle, + Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, Volume); + 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; + Volume->FreeSpace = FinalFreeSpace; + + /* Check if there's less than 32MB free so we don't starve the disk */ + if (FinalFreeSpace.QuadPart <= 0x2000000) + { + /* 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 - 0x2000000; + } + + 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; + DPRINT1("Should request pagefile: %wZ with size %I64x and %I64x\n", Name, MinSize->QuadPart, MaxSize->QuadPart); + + /* Tell the kernel to create the pagefile */ + Status = STATUS_SUCCESS; + //Status = NtCreatePagingFile(Name, MinSize, MaxSize, Priority); + if (NT_SUCCESS(Status)) + { + DPRINT1("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) { - DPRINT1("Should create fixed pagefile of sizes: %I64d %I64d\n", - FuzzFactor->QuadPart, MinimumSize->QuadPart); - return STATUS_SUCCESS; + 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 */ + DPRINT1("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); + } + + /* Don't process crashdump on this volume anymore */ + Descriptor->Flags |= SMP_PAGEFILE_DUMP_PROCESSED; + } + } + else + { + /* Crashdumps can only be on the boot volume */ + DPRINT1("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 (PageFileSize.QuadPart > 0) ShouldDelete = TRUE; + DPRINT1("SMSS:PFILE: Detected size %I64X for future paging file `%wZ'\n", + PageFileSize, + &Descriptor->Name); + DPRINT1("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; + } + DPRINT1("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 slighly 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); + 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 @@ -245,9 +603,36 @@ IN PLARGE_INTEGER FuzzFactor, IN PLARGE_INTEGER MinimumSize) { - DPRINT1("Should create 'any' pagefile of sizes: %I64d %I64d\n", - FuzzFactor->QuadPart, MinimumSize->QuadPart); - return STATUS_SUCCESS; + 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
Modified: trunk/reactos/base/system/smss2/smss.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/smss2/smss.h?re... ============================================================================== --- trunk/reactos/base/system/smss2/smss.h [iso-8859-1] (original) +++ trunk/reactos/base/system/smss2/smss.h [iso-8859-1] Fri Feb 3 23:11:28 2012 @@ -181,4 +181,10 @@ IN BOOLEAN ShutdownOkay );
+BOOLEAN +NTAPI +SmpCheckForCrashDump( + IN PUNICODE_STRING FileName +);
+