Better page file creation that allows for system managed setting. A lot of thanks...
authorBrandon Turner <turnerb7@msu.edu>
Mon, 26 Dec 2005 02:45:49 +0000 (02:45 +0000)
committerBrandon Turner <turnerb7@msu.edu>
Mon, 26 Dec 2005 02:45:49 +0000 (02:45 +0000)
svn path=/trunk/; revision=20334

reactos/subsys/smss/initpage.c

index 33f1cb6..89b5f2b 100644 (file)
 #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;
+        }
+    }
+
+  if (!RtlDosPathNameToNtPathName_U (ValueString,
+      &FileName,
+      NULL,
+      NULL))
+    {
+      return STATUS_OBJECT_PATH_INVALID;
     }
-  else
+
+  /* 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)
     {
-      InitialSize.QuadPart = 50 * 4096;
-      MaximumSize.QuadPart = 80 * 4096;
+      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;
+            }
+        }
+
+
     }
 
-  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)ValueData,
-                                    &FileName,
-                                    NULL,
-                                    NULL))
+  /* Make sure that max is not smaller then initial */
+  if (InitialSize.QuadPart > MaximumSize.QuadPart)
     {
-      return (STATUS_SUCCESS);
+      DPRINT("Max page file size was bigger then inital.\n");
+      MaximumSize.QuadPart = InitialSize.QuadPart;
     }
 
-  DPRINT("SMSS: Created paging file %wZ with size %dKB\n",
-        &FileName, InitialSize.QuadPart / 1024);
+  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.
    */