On FAT16 partitions smaller than 128MB, the cluster size is 2048, which is
[reactos.git] / reactos / subsys / smss / initpage.c
1 /*
2 * initpage.c -
3 *
4 * ReactOS Operating System
5 *
6 * --------------------------------------------------------------------
7 *
8 * This software is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This software is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this software; see the file COPYING.LIB. If not, write
20 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
21 * MA 02139, USA.
22 *
23 * --------------------------------------------------------------------
24 */
25 #include "smss.h"
26
27 #define NDEBUG
28 #include <debug.h>
29
30 #define GIGABYTE (1024 * 1024 * 1024) /* One Gigabyte */
31
32 static NTSTATUS STDCALL
33 SmpPagingFilesQueryRoutine(PWSTR ValueName,
34 ULONG ValueType,
35 PVOID ValueData,
36 ULONG ValueLength,
37 PVOID Context,
38 PVOID EntryContext)
39 {
40 UNICODE_STRING FileName;
41 LARGE_INTEGER InitialSize = {{0, 0}};
42 LARGE_INTEGER MaximumSize = {{0, 0}};
43 NTSTATUS Status = STATUS_SUCCESS;
44 PWSTR p, ValueString = (PWSTR)ValueData;
45 WCHAR RootDriveLetter[5] = {0};
46
47 if (ValueLength > 3 * sizeof(WCHAR) &&
48 (ValueLength % sizeof(WCHAR) != 0 ||
49 ValueString[(ValueLength / sizeof(WCHAR)) - 1] != L'\0'))
50 {
51 return STATUS_INVALID_PARAMETER;
52 }
53
54 if (ValueType != REG_SZ)
55 {
56 return STATUS_INVALID_PARAMETER_2;
57 }
58
59 /*
60 * Format: "<path>[ <initial_size>[ <maximum_size>]]"
61 */
62 if ((p = wcschr(ValueString, L' ')) != NULL)
63 {
64 *p = L'\0';
65 InitialSize.QuadPart = wcstoul(p + 1, &p, 0) * 256 * 4096;
66 if (*p == ' ')
67 {
68 MaximumSize.QuadPart = wcstoul(p + 1, NULL, 0) * 256 * 4096;
69 }
70 else
71 {
72 MaximumSize = InitialSize;
73 }
74 }
75
76 if (!RtlDosPathNameToNtPathName_U (ValueString,
77 &FileName,
78 NULL,
79 NULL))
80 {
81 return STATUS_OBJECT_PATH_INVALID;
82 }
83
84 /* If there is only a file name or if initial and max are both 0
85 * the system will pick the sizes. Then it makes intial the size of phyical memory
86 * and makes max the size of 1.5 * initial. If there isnt enough free space then it will
87 * fall back to intial 20% of free space and max 25%. There is a max of 1 gig before
88 * it doesnt make it bigger. */
89 if ((InitialSize.QuadPart == 0 && MaximumSize.QuadPart == 0) || p == NULL)
90 {
91 FILE_FS_SIZE_INFORMATION FileFsSize;
92 IO_STATUS_BLOCK IoStatusBlock;
93 HANDLE hFile;
94 SYSTEM_BASIC_INFORMATION SysBasicInfo;
95 UNICODE_STRING NtPathU;
96 LARGE_INTEGER FreeBytes = {{0, 0}};
97 OBJECT_ATTRIBUTES ObjectAttributes;
98
99 DPRINT("System managed pagefile...\n");
100 /* Make sure the path that is given for the file actually has the drive in it.
101 At this point if there is not file name, no sizes will be set therefore no page
102 file will be created */
103 if (wcslen(ValueString) <= 3 ||
104 ValueString[1] != L':' ||
105 ValueString[2] != L'\\')
106 {
107 DPRINT1("Invalid path for pagefile.\n");
108 goto Cleanup;
109 }
110
111 Status = NtQuerySystemInformation(SystemBasicInformation,
112 &SysBasicInfo,
113 sizeof(SysBasicInfo),
114 NULL);
115 if (!NT_SUCCESS(Status))
116 {
117 DPRINT1("Could not query for physical memory size.\n");
118 goto Cleanup;
119 }
120 DPRINT("PageSize: %d, PhysicalPages: %d, TotalMem: %d\n", SysBasicInfo.PageSize, SysBasicInfo.NumberOfPhysicalPages, (SysBasicInfo.NumberOfPhysicalPages * SysBasicInfo.PageSize) / 1024);
121
122 InitialSize.QuadPart = SysBasicInfo.NumberOfPhysicalPages *
123 SysBasicInfo.PageSize;
124 MaximumSize.QuadPart = InitialSize.QuadPart * 2;
125
126 DPRINT("InitialSize: %I64d PhysicalPages: %lu PageSize: %lu\n",InitialSize.QuadPart,SysBasicInfo.NumberOfPhysicalPages,SysBasicInfo.PageSize);
127
128 /* copy the drive letter, the colon and the slash,
129 tack a null on the end */
130 RootDriveLetter[0] = ValueString[0];
131 RootDriveLetter[1] = L':';
132 RootDriveLetter[2] = L'\\';
133 RootDriveLetter[3] = L'\0';
134 DPRINT("Root drive X:\\...\"%S\"\n",RootDriveLetter);
135
136 if (!RtlDosPathNameToNtPathName_U(RootDriveLetter,
137 &NtPathU,
138 NULL,
139 NULL))
140 {
141 DPRINT1("Invalid path to root of drive\n");
142 Status = STATUS_OBJECT_PATH_INVALID;
143 goto Cleanup;
144 }
145
146 InitializeObjectAttributes(&ObjectAttributes,
147 &NtPathU,
148 OBJ_CASE_INSENSITIVE,
149 NULL,
150 NULL);
151
152 /* Get a handle to the root to find the free space on the drive */
153 Status = NtCreateFile(&hFile,
154 0,
155 &ObjectAttributes,
156 &IoStatusBlock,
157 NULL,
158 0,
159 FILE_SHARE_READ | FILE_SHARE_WRITE,
160 FILE_OPEN,
161 0,
162 NULL,
163 0);
164
165 RtlFreeUnicodeString(&NtPathU);
166
167 if (!NT_SUCCESS(Status))
168 {
169 DPRINT1("Could not open a handle to the volume.\n");
170 goto Cleanup;
171 }
172
173 Status = NtQueryVolumeInformationFile(hFile,
174 &IoStatusBlock,
175 &FileFsSize,
176 sizeof(FILE_FS_SIZE_INFORMATION),
177 FileFsSizeInformation);
178
179 NtClose(hFile);
180
181 if (!NT_SUCCESS(Status))
182 {
183 DPRINT1("Querying the volume free space failed!\n");
184 goto Cleanup;
185 }
186
187 FreeBytes.QuadPart = FileFsSize.BytesPerSector *
188 FileFsSize.SectorsPerAllocationUnit *
189 FileFsSize.AvailableAllocationUnits.QuadPart;
190
191 DPRINT("Free bytes: %I64d Inital Size based on memory: %I64d \n",FreeBytes.QuadPart,InitialSize.QuadPart);
192
193
194 if (InitialSize.QuadPart > (FreeBytes.QuadPart / 4) || InitialSize.QuadPart == 0)
195 {
196 DPRINT("Inital Size took more then 25%% of free space\n");
197 /* Set by percentage of free space
198 * intial is 20%, and max is 25% */
199 InitialSize.QuadPart = FreeBytes.QuadPart / 5;
200 MaximumSize.QuadPart = FreeBytes.QuadPart / 4;
201 /* The page file is more then a gig, size it down */
202 if (InitialSize.QuadPart > GIGABYTE)
203 {
204 InitialSize.QuadPart = GIGABYTE;
205 MaximumSize.QuadPart = GIGABYTE * 1.5;
206 }
207 }
208
209
210 }
211
212 /* Make sure that max is not smaller then initial */
213 if (InitialSize.QuadPart > MaximumSize.QuadPart)
214 {
215 DPRINT("Max page file size was bigger then inital.\n");
216 MaximumSize.QuadPart = InitialSize.QuadPart;
217 }
218
219 DPRINT("Creating paging file %wZ with size %I64d KB\n",
220 &FileName, InitialSize.QuadPart / 1024);
221
222 Status = NtCreatePagingFile(&FileName,
223 &InitialSize,
224 &MaximumSize,
225 0);
226 if (! NT_SUCCESS(Status))
227 {
228 PrintString("Creation of paging file %wZ with size %I64d KB failed (status 0x%x\n",
229 &FileName, InitialSize.QuadPart / 1024);
230 }
231
232 Cleanup:
233 RtlFreeUnicodeString(&FileName);
234
235 return STATUS_SUCCESS;
236 }
237
238
239 NTSTATUS
240 SmCreatePagingFiles(VOID)
241 {
242 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
243 NTSTATUS Status;
244
245 DPRINT("creating system paging files\n");
246 /*
247 * Disable paging file on MiniNT/Live CD.
248 */
249 if (RtlCheckRegistryKey(RTL_REGISTRY_CONTROL, L"MiniNT") == STATUS_SUCCESS)
250 {
251 return STATUS_SUCCESS;
252 }
253
254 RtlZeroMemory(&QueryTable,
255 sizeof(QueryTable));
256
257 QueryTable[0].Name = L"PagingFiles";
258 QueryTable[0].QueryRoutine = SmpPagingFilesQueryRoutine;
259
260 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
261 L"\\Session Manager\\Memory Management",
262 QueryTable,
263 NULL,
264 NULL);
265
266 return(Status);
267 }
268
269
270 /* EOF */