Better page file creation that allows for system managed setting. A lot
of thanks to Thomas on this patch.
Modified: trunk/reactos/subsys/smss/initpage.c
_____
Modified: trunk/reactos/subsys/smss/initpage.c
--- trunk/reactos/subsys/smss/initpage.c 2005-12-25 23:57:26 UTC
(rev 20333)
+++ trunk/reactos/subsys/smss/initpage.c 2005-12-26 02:45:49 UTC
(rev 20334)
@@ -28,66 +28,207 @@
#define NDEBUG
#include <debug.h>
+#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: "<path>[ <initial_size>[ <maximum_size>]]"
- */
- if ((p = wcschr(ValueData, ' ')) != NULL)
+ * Format: "<path>[ <initial_size>[ <maximum_size>]]"
+ */
+ 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;
+ {
+ MaximumSize = InitialSize;
+ }
}
- else
+
+ if (!RtlDosPathNameToNtPathName_U (ValueString,
+ &FileName,
+ NULL,
+ NULL))
{
- InitialSize.QuadPart = 50 * 4096;
- MaximumSize.QuadPart = 80 * 4096;
+ return STATUS_OBJECT_PATH_INVALID;
}
- if (!RtlDosPathNameToNtPathName_U ((LPWSTR)ValueData,
- &FileName,
- NULL,
- NULL))
+ /* 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)
{
- return (STATUS_SUCCESS);
+ 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,SysBasicI
nfo.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;
+ }
+ }
+
+
}
- DPRINT("SMSS: Created paging file %wZ with size %dKB\n",
- &FileName, InitialSize.QuadPart / 1024);
+ /* 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 @@
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.
*/