mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 13:35:47 +00:00
[SMSS2]: Implement the rest of the code to create page files. All that's missing is the actual call to NtCreatePagingFile.
svn path=/trunk/; revision=55400
This commit is contained in:
parent
b7f8e21b52
commit
b1e15cc96d
3 changed files with 407 additions and 7 deletions
|
@ -15,3 +15,12 @@
|
|||
/* GLOBALS ********************************************************************/
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
SmpCheckForCrashDump(IN PUNICODE_STRING FileName)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -46,11 +46,13 @@ typedef struct _SMP_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;
|
||||
ULONG Flags;
|
||||
USHORT Flags;
|
||||
USHORT PageFileCount;
|
||||
WCHAR DriveLetter;
|
||||
LARGE_INTEGER FreeSpace;
|
||||
FILE_FS_DEVICE_INFORMATION DeviceInfo;
|
||||
|
@ -228,15 +230,371 @@ SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
|
|||
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;
|
||||
|
||||
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 @@ SmpCreatePagingFileOnAnyDrive(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor,
|
|||
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
|
||||
|
|
|
@ -181,4 +181,10 @@ SmpRestoreBootStatusData(
|
|||
IN BOOLEAN ShutdownOkay
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
SmpCheckForCrashDump(
|
||||
IN PUNICODE_STRING FileName
|
||||
);
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue