2 * PROJECT: ReactOS Session Manager
3 * LICENSE: GPL v2 or later - See COPYING in the top level directory
4 * FILE: base/system/smss/initpage.c
5 * PURPOSE: Paging file support.
6 * PROGRAMMERS: ReactOS Development Team
9 /* INCLUDES ******************************************************************/
15 #define GIGABYTE (1024 * 1024 * 1024) /* One Gigabyte */
18 SmpPagingFilesQueryRoutine(PWSTR ValueName
,
25 UNICODE_STRING FileName
;
26 LARGE_INTEGER InitialSize
= {{0, 0}};
27 LARGE_INTEGER MaximumSize
= {{0, 0}};
28 NTSTATUS Status
= STATUS_SUCCESS
;
29 PWSTR p
, ValueString
= (PWSTR
)ValueData
;
30 WCHAR RootDriveLetter
[5] = {0};
32 if (ValueLength
> 3 * sizeof(WCHAR
) &&
33 (ValueLength
% sizeof(WCHAR
) != 0 ||
34 ValueString
[(ValueLength
/ sizeof(WCHAR
)) - 1] != L
'\0'))
36 return STATUS_INVALID_PARAMETER
;
39 if (ValueType
!= REG_SZ
)
41 return STATUS_INVALID_PARAMETER_2
;
45 * Format: "<path>[ <initial_size>[ <maximum_size>]]"
47 if ((p
= wcschr(ValueString
, L
' ')) != NULL
)
50 InitialSize
.QuadPart
= wcstoul(p
+ 1, &p
, 0) * 256 * 4096;
53 MaximumSize
.QuadPart
= wcstoul(p
+ 1, NULL
, 0) * 256 * 4096;
57 MaximumSize
= InitialSize
;
61 if (!RtlDosPathNameToNtPathName_U (ValueString
,
66 return STATUS_OBJECT_PATH_INVALID
;
69 /* If there is only a file name or if initial and max are both 0
70 * the system will pick the sizes. Then it makes intial the size of phyical memory
71 * and makes max the size of 1.5 * initial. If there isnt enough free space then it will
72 * fall back to intial 20% of free space and max 25%. There is a max of 1 gig before
73 * it doesnt make it bigger. */
74 if ((InitialSize
.QuadPart
== 0 && MaximumSize
.QuadPart
== 0) || p
== NULL
)
76 FILE_FS_SIZE_INFORMATION FileFsSize
;
77 IO_STATUS_BLOCK IoStatusBlock
;
79 SYSTEM_BASIC_INFORMATION SysBasicInfo
;
80 UNICODE_STRING NtPathU
;
81 LARGE_INTEGER FreeBytes
= {{0, 0}};
82 OBJECT_ATTRIBUTES ObjectAttributes
;
84 DPRINT("System managed pagefile...\n");
85 /* Make sure the path that is given for the file actually has the drive in it.
86 At this point if there is not file name, no sizes will be set therefore no page
87 file will be created */
88 if (wcslen(ValueString
) <= 3 ||
89 ValueString
[1] != L
':' ||
90 ValueString
[2] != L
'\\')
92 DPRINT1("Invalid path for pagefile.\n");
96 Status
= NtQuerySystemInformation(SystemBasicInformation
,
100 if (!NT_SUCCESS(Status
))
102 DPRINT1("Could not query for physical memory size.\n");
105 DPRINT("PageSize: %d, PhysicalPages: %d, TotalMem: %d\n", SysBasicInfo
.PageSize
, SysBasicInfo
.NumberOfPhysicalPages
, (SysBasicInfo
.NumberOfPhysicalPages
* SysBasicInfo
.PageSize
) / 1024);
107 InitialSize
.QuadPart
= SysBasicInfo
.NumberOfPhysicalPages
*
108 SysBasicInfo
.PageSize
;
109 MaximumSize
.QuadPart
= InitialSize
.QuadPart
* 2;
111 DPRINT("InitialSize: %I64d PhysicalPages: %lu PageSize: %lu\n",InitialSize
.QuadPart
,SysBasicInfo
.NumberOfPhysicalPages
,SysBasicInfo
.PageSize
);
113 /* copy the drive letter, the colon and the slash,
114 tack a null on the end */
115 RootDriveLetter
[0] = ValueString
[0];
116 RootDriveLetter
[1] = L
':';
117 RootDriveLetter
[2] = L
'\\';
118 RootDriveLetter
[3] = L
'\0';
119 DPRINT("Root drive X:\\...\"%S\"\n",RootDriveLetter
);
121 if (!RtlDosPathNameToNtPathName_U(RootDriveLetter
,
126 DPRINT1("Invalid path to root of drive\n");
127 Status
= STATUS_OBJECT_PATH_INVALID
;
131 InitializeObjectAttributes(&ObjectAttributes
,
133 OBJ_CASE_INSENSITIVE
,
137 /* Get a handle to the root to find the free space on the drive */
138 Status
= NtCreateFile(&hFile
,
144 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
150 RtlFreeHeap(RtlGetProcessHeap(),
154 if (!NT_SUCCESS(Status
))
156 DPRINT1("Could not open a handle to the volume.\n");
160 Status
= NtQueryVolumeInformationFile(hFile
,
163 sizeof(FILE_FS_SIZE_INFORMATION
),
164 FileFsSizeInformation
);
168 if (!NT_SUCCESS(Status
))
170 DPRINT1("Querying the volume free space failed!\n");
174 FreeBytes
.QuadPart
= FileFsSize
.BytesPerSector
*
175 FileFsSize
.SectorsPerAllocationUnit
*
176 FileFsSize
.AvailableAllocationUnits
.QuadPart
;
178 DPRINT("Free bytes: %I64d Inital Size based on memory: %I64d \n",FreeBytes
.QuadPart
,InitialSize
.QuadPart
);
181 if (InitialSize
.QuadPart
> (FreeBytes
.QuadPart
/ 4) || InitialSize
.QuadPart
== 0)
183 DPRINT("Inital Size took more then 25%% of free space\n");
184 /* Set by percentage of free space
185 * intial is 20%, and max is 25% */
186 InitialSize
.QuadPart
= FreeBytes
.QuadPart
/ 5;
187 MaximumSize
.QuadPart
= FreeBytes
.QuadPart
/ 4;
188 /* The page file is more then a gig, size it down */
189 if (InitialSize
.QuadPart
> GIGABYTE
)
191 InitialSize
.QuadPart
= GIGABYTE
;
192 MaximumSize
.QuadPart
= GIGABYTE
* 1.5;
199 /* Make sure that max is not smaller then initial */
200 if (InitialSize
.QuadPart
> MaximumSize
.QuadPart
)
202 DPRINT("Max page file size was bigger then inital.\n");
203 MaximumSize
.QuadPart
= InitialSize
.QuadPart
;
206 DPRINT("Creating paging file %wZ with size %I64d KB\n",
207 &FileName
, InitialSize
.QuadPart
/ 1024);
209 Status
= NtCreatePagingFile(&FileName
,
213 if (! NT_SUCCESS(Status
))
215 PrintString("Creation of paging file %wZ with size %I64d KB failed (status 0x%x)\n",
216 &FileName
, InitialSize
.QuadPart
/ 1024, Status
);
220 RtlFreeHeap(RtlGetProcessHeap(),
224 return STATUS_SUCCESS
;
229 SmpGetFreeDiskSpace(IN PWSTR PageFileName
,
230 OUT PLARGE_INTEGER FreeDiskSpaceInMB
)
232 FILE_FS_SIZE_INFORMATION FileFsSize
;
233 IO_STATUS_BLOCK IoStatusBlock
;
235 UNICODE_STRING NtPathU
;
236 LARGE_INTEGER FreeBytes
;
237 OBJECT_ATTRIBUTES ObjectAttributes
;
242 * copy the drive letter, the colon and the slash,
243 * tack a null on the end
245 RootPath
[0] = PageFileName
[0];
250 DPRINT("Root drive X:\\...\"%S\"\n",RootPath
);
252 if (!RtlDosPathNameToNtPathName_U(RootPath
,
257 DPRINT1("Invalid path to root of drive\n");
258 return STATUS_OBJECT_PATH_INVALID
;
261 InitializeObjectAttributes(&ObjectAttributes
,
263 OBJ_CASE_INSENSITIVE
,
267 /* Get a handle to the root to find the free space on the drive */
268 Status
= NtCreateFile(&hFile
,
274 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
280 RtlFreeHeap(RtlGetProcessHeap(),
284 if (!NT_SUCCESS(Status
))
286 DPRINT1("Could not open a handle to the volume.\n");
290 Status
= NtQueryVolumeInformationFile(hFile
,
293 sizeof(FILE_FS_SIZE_INFORMATION
),
294 FileFsSizeInformation
);
298 if (!NT_SUCCESS(Status
))
300 DPRINT1("Querying the volume free space failed!\n");
304 FreeBytes
.QuadPart
= FileFsSize
.BytesPerSector
*
305 FileFsSize
.SectorsPerAllocationUnit
*
306 FileFsSize
.AvailableAllocationUnits
.QuadPart
;
308 FreeDiskSpaceInMB
->QuadPart
= FreeBytes
.QuadPart
>> 20;
310 return STATUS_SUCCESS
;
315 SmpSetDefaultPageFileData(IN PWSTR PageFileName
,
316 IN PLARGE_INTEGER InitialSizeInMB
,
317 IN PLARGE_INTEGER MaximumSizeInMB
)
319 WCHAR ValueString
[MAX_PATH
* 2];
322 /* Format the value string */
323 swprintf(ValueString
,
326 InitialSizeInMB
->QuadPart
,
327 MaximumSizeInMB
->QuadPart
);
330 * Append another zero character because it is a multi string value
331 * (REG_MULTI_SZ) and calculate the total string length.
333 ValueLength
= wcslen(ValueString
) + 1;
334 ValueString
[ValueLength
] = 0;
337 /* Write the page file data */
338 return RtlWriteRegistryValue(RTL_REGISTRY_CONTROL
,
339 L
"\\Session Manager\\Memory Management",
343 ValueLength
* sizeof(WCHAR
));
348 SmpCreatePageFile(IN PWSTR PageFileName
,
349 IN PLARGE_INTEGER InitialSizeInMB
,
350 IN PLARGE_INTEGER MaximumSizeInMB
)
352 LARGE_INTEGER InitialSize
;
353 LARGE_INTEGER MaximumSize
;
354 UNICODE_STRING FileName
;
357 /* Get the NT path name of the page file */
358 if (!RtlDosPathNameToNtPathName_U(PageFileName
,
363 return STATUS_OBJECT_PATH_INVALID
;
366 /* Convert sizes in megabytes to sizes in bytes */
367 InitialSize
.QuadPart
= InitialSizeInMB
->QuadPart
<< 20;
368 MaximumSize
.QuadPart
= MaximumSizeInMB
->QuadPart
<< 20;
370 /* Create the pageing file */
371 Status
= NtCreatePagingFile(&FileName
,
375 if (! NT_SUCCESS(Status
))
377 DPRINT("Creation of paging file %wZ with size %I64d MB failed (status 0x%x)\n",
378 &FileName
, InitialSizeInMB
->QuadPart
, Status
);
381 /* Release the file name */
382 RtlFreeHeap(RtlGetProcessHeap(),
391 SmpCreateDefaultPagingFile(VOID
)
393 SYSTEM_BASIC_INFORMATION SysBasicInfo
;
394 LARGE_INTEGER MemorySizeInMB
;
395 LARGE_INTEGER FreeDiskSpaceInMB
;
396 LARGE_INTEGER InitialSizeInMB
;
397 LARGE_INTEGER MaximumSizeInMB
;
398 NTSTATUS Status
= STATUS_SUCCESS
;
399 WCHAR PageFileName
[MAX_PATH
];
401 DPRINT("Creating a default paging file\n");
403 Status
= NtQuerySystemInformation(SystemBasicInformation
,
405 sizeof(SysBasicInfo
),
407 if (!NT_SUCCESS(Status
))
409 DPRINT1("Could not query for physical memory size.\n");
413 DPRINT("PageSize: %d, PhysicalPages: %d, TotalMem: %d\n",
414 SysBasicInfo
.PageSize
,
415 SysBasicInfo
.NumberOfPhysicalPages
,
416 (SysBasicInfo
.NumberOfPhysicalPages
* SysBasicInfo
.PageSize
) / 1024);
418 MemorySizeInMB
.QuadPart
= (SysBasicInfo
.NumberOfPhysicalPages
* SysBasicInfo
.PageSize
) >> 20;
420 DPRINT("MemorySize %I64u MB\n",
421 MemorySizeInMB
.QuadPart
);
423 /* Build the default page file name */
424 PageFileName
[0] = SharedUserData
->NtSystemRoot
[0];
426 wcscat(PageFileName
, L
":\\pagefile.sys");
428 Status
= SmpGetFreeDiskSpace(PageFileName
,
430 if (!NT_SUCCESS(Status
))
435 DPRINT("FreeDiskSpace %I64u MB\n",
436 FreeDiskSpaceInMB
.QuadPart
);
438 InitialSizeInMB
.QuadPart
= MemorySizeInMB
.QuadPart
+ (MemorySizeInMB
.QuadPart
/ 2);
439 MaximumSizeInMB
.QuadPart
= InitialSizeInMB
.QuadPart
* 2;
441 if (InitialSizeInMB
.QuadPart
> (FreeDiskSpaceInMB
.QuadPart
/ 4))
443 DPRINT("Inital Size took more then 25%% of free disk space\n");
446 * Set by percentage of free space
447 * intial is 20%, and max is 25%
449 InitialSizeInMB
.QuadPart
= FreeDiskSpaceInMB
.QuadPart
/ 5;
450 MaximumSizeInMB
.QuadPart
= FreeDiskSpaceInMB
.QuadPart
/ 4;
452 /* The page file is more then a gig, size it down */
453 if (InitialSizeInMB
.QuadPart
> 1024)
455 InitialSizeInMB
.QuadPart
= 1024; /* 1GB */
456 MaximumSizeInMB
.QuadPart
= 1536; /* 1.5GB */
460 DPRINT("InitialSize %I64u MB MaximumSize %I64u MB\n",
461 InitialSizeInMB
.QuadPart
,
462 MaximumSizeInMB
.QuadPart
);
464 Status
= SmpSetDefaultPageFileData(PageFileName
,
467 if (!NT_SUCCESS(Status
))
472 return SmpCreatePageFile(PageFileName
,
479 SmCreatePagingFiles(VOID
)
481 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
484 DPRINT("creating system paging files\n");
486 /* Disable paging file on MiniNT/Live CD. */
487 if (RtlCheckRegistryKey(RTL_REGISTRY_CONTROL
, L
"MiniNT") == STATUS_SUCCESS
)
489 return STATUS_SUCCESS
;
492 RtlZeroMemory(&QueryTable
,
495 QueryTable
[0].Name
= L
"PagingFiles";
496 QueryTable
[0].QueryRoutine
= SmpPagingFilesQueryRoutine
;
497 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
499 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
500 L
"\\Session Manager\\Memory Management",
504 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
506 Status
= SmpCreateDefaultPagingFile();