From 5caea08853978563f9c894439e74f44bf4c18e82 Mon Sep 17 00:00:00 2001 From: Brandon Turner Date: Mon, 26 Dec 2005 02:45:49 +0000 Subject: [PATCH] Better page file creation that allows for system managed setting. A lot of thanks to Thomas on this patch. svn path=/trunk/; revision=20334 --- reactos/subsys/smss/initpage.c | 213 +++++++++++++++++++++++++++------ 1 file changed, 177 insertions(+), 36 deletions(-) diff --git a/reactos/subsys/smss/initpage.c b/reactos/subsys/smss/initpage.c index 33f1cb6628e..89b5f2bb363 100644 --- a/reactos/subsys/smss/initpage.c +++ b/reactos/subsys/smss/initpage.c @@ -28,66 +28,207 @@ #define NDEBUG #include +#define GIGABYTE (1024 * 1024 * 1024) /* One Gigabyte */ + static NTSTATUS STDCALL SmpPagingFilesQueryRoutine(PWSTR ValueName, - ULONG ValueType, - PVOID ValueData, - ULONG ValueLength, - PVOID Context, - PVOID EntryContext) + ULONG ValueType, + PVOID ValueData, + ULONG ValueLength, + PVOID Context, + PVOID EntryContext) { UNICODE_STRING FileName; - LARGE_INTEGER InitialSize; - LARGE_INTEGER MaximumSize; - NTSTATUS Status; - LPWSTR p; + LARGE_INTEGER InitialSize = {{0, 0}}; + LARGE_INTEGER MaximumSize = {{0, 0}}; + NTSTATUS Status = STATUS_SUCCESS; + PWSTR p, ValueString = (PWSTR)ValueData; + WCHAR RootDriveLetter[5] = {0}; - DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); - DPRINT("ValueData '%S'\n", (PWSTR)ValueData); + if (ValueLength > 3 * sizeof(WCHAR) && + (ValueLength % sizeof(WCHAR) != 0 || + ValueString[(ValueLength / sizeof(WCHAR)) - 1] != L'\0')) + { + return STATUS_INVALID_PARAMETER; + } if (ValueType != REG_SZ) { - return(STATUS_SUCCESS); + return STATUS_INVALID_PARAMETER_2; } /* - * Format: "[ [ ]]" - */ - if ((p = wcschr(ValueData, ' ')) != NULL) + * Format: "[ [ ]]" + */ + if ((p = wcschr(ValueString, L' ')) != NULL) { *p = L'\0'; InitialSize.QuadPart = wcstoul(p + 1, &p, 0) * 256 * 4096; if (*p == ' ') - { - MaximumSize.QuadPart = wcstoul(p + 1, NULL, 0) * 256 * 4096; - } + { + MaximumSize.QuadPart = wcstoul(p + 1, NULL, 0) * 256 * 4096; + } else - MaximumSize = InitialSize; - } - else - { - InitialSize.QuadPart = 50 * 4096; - MaximumSize.QuadPart = 80 * 4096; + { + MaximumSize = InitialSize; + } } - if (!RtlDosPathNameToNtPathName_U ((LPWSTR)ValueData, - &FileName, - NULL, - NULL)) + if (!RtlDosPathNameToNtPathName_U (ValueString, + &FileName, + NULL, + NULL)) { - return (STATUS_SUCCESS); + return STATUS_OBJECT_PATH_INVALID; } - DPRINT("SMSS: Created paging file %wZ with size %dKB\n", - &FileName, InitialSize.QuadPart / 1024); + /* If there is only a file name or if initial and max are both 0 + * the system will pick the sizes. Then it makes intial the size of phyical memory + * and makes max the size of 1.5 * initial. If there isnt enough free space then it will + * fall back to intial 20% of free space and max 25%. There is a max of 1 gig before + * it doesnt make it bigger. */ + if ((InitialSize.QuadPart == 0 && MaximumSize.QuadPart == 0) || p == NULL) + { + FILE_FS_SIZE_INFORMATION FileFsSize; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE hFile; + SYSTEM_BASIC_INFORMATION SysBasicInfo; + UNICODE_STRING NtPathU; + LARGE_INTEGER FreeBytes = {{0, 0}}; + OBJECT_ATTRIBUTES ObjectAttributes; + + DPRINT("System managed pagefile...\n"); + /* Make sure the path that is given for the file actually has the drive in it. + At this point if there is not file name, no sizes will be set therefore no page + file will be created */ + if (wcslen(ValueString) <= 3 || + ValueString[1] != L':' || + ValueString[2] != L'\\') + { + DPRINT1("Invalid path for pagefile.\n"); + goto Cleanup; + } + + Status = NtQuerySystemInformation(SystemBasicInformation, + &SysBasicInfo, + sizeof(SysBasicInfo), + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Could not query for physical memory size.\n"); + goto Cleanup; + } + DPRINT("PageSize: %d, PhysicalPages: %d, TotalMem: %d\n", SysBasicInfo.PageSize, SysBasicInfo.NumberOfPhysicalPages, (SysBasicInfo.NumberOfPhysicalPages * SysBasicInfo.PageSize) / 1024); + + InitialSize.QuadPart = SysBasicInfo.NumberOfPhysicalPages * + SysBasicInfo.PageSize; + MaximumSize.QuadPart = InitialSize.QuadPart * 2; + + DPRINT("InitialSize: %I64d PhysicalPages: %lu PageSize: %lu\n",InitialSize.QuadPart,SysBasicInfo.NumberOfPhysicalPages,SysBasicInfo.PageSize); + + /* copy the drive letter, the colon and the slash, + tack a null on the end */ + RootDriveLetter[0] = ValueString[0]; + RootDriveLetter[1] = L':'; + RootDriveLetter[2] = L'\\'; + RootDriveLetter[3] = L'\0'; + DPRINT("Root drive X:\\...\"%S\"\n",RootDriveLetter); + + if (!RtlDosPathNameToNtPathName_U(RootDriveLetter, + &NtPathU, + NULL, + NULL)) + { + DPRINT1("Invalid path to root of drive\n"); + Status = STATUS_OBJECT_PATH_INVALID; + goto Cleanup; + } + + InitializeObjectAttributes(&ObjectAttributes, + &NtPathU, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Get a handle to the root to find the free space on the drive */ + Status = NtCreateFile(&hFile, + 0, + &ObjectAttributes, + &IoStatusBlock, + NULL, + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + 0, + NULL, + 0); + + RtlFreeUnicodeString(&NtPathU); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Could not open a handle to the volume.\n"); + goto Cleanup; + } + + Status = NtQueryVolumeInformationFile(hFile, + &IoStatusBlock, + &FileFsSize, + sizeof(FILE_FS_SIZE_INFORMATION), + FileFsSizeInformation); + + NtClose(hFile); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Querying the volume free space failed!\n"); + goto Cleanup; + } + + FreeBytes.QuadPart = FileFsSize.BytesPerSector * + FileFsSize.SectorsPerAllocationUnit * + FileFsSize.AvailableAllocationUnits.QuadPart; + + DPRINT("Free bytes: %I64d Inital Size based on memory: %I64d \n",FreeBytes.QuadPart,InitialSize.QuadPart); + + + if (InitialSize.QuadPart > (FreeBytes.QuadPart / 4) || InitialSize.QuadPart == 0) + { + DPRINT("Inital Size took more then 25%% of free space\n"); + /* Set by percentage of free space + * intial is 20%, and max is 25% */ + InitialSize.QuadPart = FreeBytes.QuadPart / 5; + MaximumSize.QuadPart = FreeBytes.QuadPart / 4; + /* The page file is more then a gig, size it down */ + if (InitialSize.QuadPart > GIGABYTE) + { + InitialSize.QuadPart = GIGABYTE; + MaximumSize.QuadPart = GIGABYTE * 1.5; + } + } + + + } + + /* Make sure that max is not smaller then initial */ + if (InitialSize.QuadPart > MaximumSize.QuadPart) + { + DPRINT("Max page file size was bigger then inital.\n"); + MaximumSize.QuadPart = InitialSize.QuadPart; + } + + DPRINT1("SMSS: Created paging file %wZ with size %I64d KB\n", + &FileName, InitialSize.QuadPart / 1024); + Status = NtCreatePagingFile(&FileName, - &InitialSize, - &MaximumSize, - 0); + &InitialSize, + &MaximumSize, + 0); +Cleanup: RtlFreeUnicodeString(&FileName); - return(STATUS_SUCCESS); + return Status; } @@ -97,7 +238,7 @@ SmCreatePagingFiles(VOID) RTL_QUERY_REGISTRY_TABLE QueryTable[2]; NTSTATUS Status; - DPRINT("SM: creating system paging files\n"); + DbgPrint("SM: creating system paging files\n"); /* * Disable paging file on MiniNT/Live CD. */