1c2c66affSColin Finck /*
2c2c66affSColin Finck * PROJECT: ReactOS Windows-Compatible Session Manager
3c2c66affSColin Finck * LICENSE: BSD 2-Clause License
4c2c66affSColin Finck * FILE: base/system/smss/pagefile.c
5c2c66affSColin Finck * PURPOSE: Main SMSS Code
6c2c66affSColin Finck * PROGRAMMERS: Alex Ionescu
7c2c66affSColin Finck */
8c2c66affSColin Finck
9c2c66affSColin Finck /* INCLUDES *******************************************************************/
10c2c66affSColin Finck
11c2c66affSColin Finck #include "smss.h"
12c2c66affSColin Finck
13c2c66affSColin Finck #define NDEBUG
14c2c66affSColin Finck #include <debug.h>
15c2c66affSColin Finck
16c2c66affSColin Finck /* GLOBALS ********************************************************************/
17c2c66affSColin Finck
18c2c66affSColin Finck //
19c2c66affSColin Finck // Constants
20c2c66affSColin Finck //
21c2c66affSColin Finck #define STANDARD_PAGING_FILE_NAME L"\\??\\?:\\pagefile.sys"
22c2c66affSColin Finck #define STANDARD_DRIVE_LETTER_OFFSET 4
23a4274ad5SHermès Bélusca-Maïto #define MAX_PAGING_FILES 16 // See also ntoskrnl/include/internal/mm.h
24a4274ad5SHermès Bélusca-Maïto #define MEGABYTE (1024 * 1024)
25a4274ad5SHermès Bélusca-Maïto
26a4274ad5SHermès Bélusca-Maïto /* Minimum pagefile size is 256 pages (1 MB) */
27a4274ad5SHermès Bélusca-Maïto // #define MINIMUM_PAGEFILE_SIZE (256ULL * PAGE_SIZE)
28a4274ad5SHermès Bélusca-Maïto
29a4274ad5SHermès Bélusca-Maïto /* Maximum pagefile sizes for different architectures */
30a4274ad5SHermès Bélusca-Maïto #define GIGABYTE (1024ULL * MEGABYTE)
31a4274ad5SHermès Bélusca-Maïto #define TERABYTE (1024ULL * GIGABYTE)
32a4274ad5SHermès Bélusca-Maïto
33a4274ad5SHermès Bélusca-Maïto // NOTE: No changes for NTDDI_WIN10
34a4274ad5SHermès Bélusca-Maïto #if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81
35a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE32 ((1ULL * 1024 * 1024 - 1) * PAGE_SIZE)
36a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(4ULL * GIGABYTE - 1)
37a4274ad5SHermès Bélusca-Maïto #else
38a4274ad5SHermès Bélusca-Maïto /* 4095 MB */
39a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE32 (4095ULL * MEGABYTE)
40a4274ad5SHermès Bélusca-Maïto #endif
41a4274ad5SHermès Bélusca-Maïto
42a4274ad5SHermès Bélusca-Maïto // NOTE: No changes for NTDDI_WIN10
43a4274ad5SHermès Bélusca-Maïto #if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81
44a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE64 ((4ULL * 1024 * 1024 * 1024 - 1) * PAGE_SIZE)
45a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(16ULL * TERABYTE - 1)
46a4274ad5SHermès Bélusca-Maïto #else
47a4274ad5SHermès Bélusca-Maïto /* 16 TB */
48a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE64 (16ULL * TERABYTE)
49a4274ad5SHermès Bélusca-Maïto #endif
50a4274ad5SHermès Bélusca-Maïto
51a4274ad5SHermès Bélusca-Maïto #if defined(_M_IX86)
52a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE32
53a4274ad5SHermès Bélusca-Maïto /* PAE uses the same size as x64 */
54a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE_PAE MAXIMUM_PAGEFILE_SIZE64
55a4274ad5SHermès Bélusca-Maïto #elif defined (_M_AMD64) || defined(_M_ARM64)
56a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE64
57a4274ad5SHermès Bélusca-Maïto #elif defined (_M_IA64)
58a4274ad5SHermès Bélusca-Maïto /* 32 TB */
59a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE (32ULL * TERABYTE)
60a4274ad5SHermès Bélusca-Maïto #elif defined(_M_ARM)
61a4274ad5SHermès Bélusca-Maïto /* Around 2 GB */
62a4274ad5SHermès Bélusca-Maïto // NOTE: No changes for NTDDI_WIN10
63a4274ad5SHermès Bélusca-Maïto #if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81
64a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE ((512ULL * 1024 - 1) * PAGE_SIZE)
65a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(2ULL * GIGABYTE - 1)
66a4274ad5SHermès Bélusca-Maïto #else
67a4274ad5SHermès Bélusca-Maïto /* 4095 MB */
68a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE32
69a4274ad5SHermès Bélusca-Maïto #endif
70a4274ad5SHermès Bélusca-Maïto #else
71a4274ad5SHermès Bélusca-Maïto /* On unknown architectures, default to either one of the 32 or 64 bit sizes */
72a4274ad5SHermès Bélusca-Maïto #pragma message("Unknown architecture")
73a4274ad5SHermès Bélusca-Maïto #ifdef _WIN64
74a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE64
75a4274ad5SHermès Bélusca-Maïto #else
76a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE32
77a4274ad5SHermès Bélusca-Maïto #endif
78a4274ad5SHermès Bélusca-Maïto #endif
79a4274ad5SHermès Bélusca-Maïto
80c2c66affSColin Finck /* This should be 32 MB, but we need more than that for 2nd stage setup */
815d85d534SThomas Faber #define MINIMUM_TO_KEEP_FREE (256 * MEGABYTE)
82c2c66affSColin Finck #define FUZZ_FACTOR (16 * MEGABYTE)
83c2c66affSColin Finck
84c2c66affSColin Finck //
85c2c66affSColin Finck // Structure and flags describing each pagefile
86c2c66affSColin Finck //
87c2c66affSColin Finck #define SMP_PAGEFILE_CREATED 0x01
88c2c66affSColin Finck #define SMP_PAGEFILE_DEFAULT 0x02
89c2c66affSColin Finck #define SMP_PAGEFILE_SYSTEM_MANAGED 0x04
90c2c66affSColin Finck #define SMP_PAGEFILE_WAS_TOO_BIG 0x08
91c2c66affSColin Finck #define SMP_PAGEFILE_ON_ANY_DRIVE 0x10
92c2c66affSColin Finck #define SMP_PAGEFILE_EMERGENCY 0x20
93c2c66affSColin Finck #define SMP_PAGEFILE_DUMP_PROCESSED 0x40
94c2c66affSColin Finck typedef struct _SMP_PAGEFILE_DESCRIPTOR
95c2c66affSColin Finck {
96c2c66affSColin Finck LIST_ENTRY Entry;
97c2c66affSColin Finck UNICODE_STRING Name;
98c2c66affSColin Finck UNICODE_STRING Token;
99c2c66affSColin Finck LARGE_INTEGER MinSize;
100c2c66affSColin Finck LARGE_INTEGER MaxSize;
101c2c66affSColin Finck LARGE_INTEGER ActualMinSize;
102c2c66affSColin Finck LARGE_INTEGER ActualMaxSize;
103c2c66affSColin Finck ULONG Flags;
104c2c66affSColin Finck } SMP_PAGEFILE_DESCRIPTOR, *PSMP_PAGEFILE_DESCRIPTOR;
105c2c66affSColin Finck
106c2c66affSColin Finck //
107c2c66affSColin Finck // Structure and flags describing each volume
108c2c66affSColin Finck //
109c2c66affSColin Finck #define SMP_VOLUME_INSERTED 0x01
110c2c66affSColin Finck #define SMP_VOLUME_PAGEFILE_CREATED 0x04
111c2c66affSColin Finck #define SMP_VOLUME_IS_BOOT 0x08
112c2c66affSColin Finck typedef struct _SMP_VOLUME_DESCRIPTOR
113c2c66affSColin Finck {
114c2c66affSColin Finck LIST_ENTRY Entry;
115c2c66affSColin Finck USHORT Flags;
116c2c66affSColin Finck USHORT PageFileCount;
117c2c66affSColin Finck WCHAR DriveLetter;
118c2c66affSColin Finck LARGE_INTEGER FreeSpace;
119c2c66affSColin Finck FILE_FS_DEVICE_INFORMATION DeviceInfo;
120c2c66affSColin Finck } SMP_VOLUME_DESCRIPTOR, *PSMP_VOLUME_DESCRIPTOR;
121c2c66affSColin Finck
122c2c66affSColin Finck LIST_ENTRY SmpPagingFileDescriptorList, SmpVolumeDescriptorList;
123c2c66affSColin Finck BOOLEAN SmpRegistrySpecifierPresent;
124c2c66affSColin Finck ULONG SmpNumberOfPagingFiles;
125c2c66affSColin Finck
126c2c66affSColin Finck /* FUNCTIONS ******************************************************************/
127c2c66affSColin Finck
128c2c66affSColin Finck VOID
129c2c66affSColin Finck NTAPI
SmpPagingFileInitialize(VOID)130c2c66affSColin Finck SmpPagingFileInitialize(VOID)
131c2c66affSColin Finck {
132c2c66affSColin Finck /* Initialize the two lists */
133c2c66affSColin Finck InitializeListHead(&SmpPagingFileDescriptorList);
134c2c66affSColin Finck InitializeListHead(&SmpVolumeDescriptorList);
135c2c66affSColin Finck }
136c2c66affSColin Finck
137c2c66affSColin Finck NTSTATUS
138c2c66affSColin Finck NTAPI
SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)139c2c66affSColin Finck SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
140c2c66affSColin Finck {
141c2c66affSColin Finck NTSTATUS Status;
142c2c66affSColin Finck ULONG MinSize = 0, MaxSize = 0;
143c2c66affSColin Finck BOOLEAN SystemManaged = FALSE, ZeroSize = TRUE;
144c2c66affSColin Finck PSMP_PAGEFILE_DESCRIPTOR Descriptor, ListDescriptor;
145c2c66affSColin Finck ULONG i;
146c2c66affSColin Finck WCHAR c;
147c2c66affSColin Finck PLIST_ENTRY NextEntry;
148c2c66affSColin Finck UNICODE_STRING PageFileName, Arguments, SecondArgument;
149c2c66affSColin Finck
150c2c66affSColin Finck /* Make sure we don't have too many */
151a4274ad5SHermès Bélusca-Maïto if (SmpNumberOfPagingFiles >= MAX_PAGING_FILES)
152c2c66affSColin Finck {
153c2c66affSColin Finck DPRINT1("SMSS:PFILE: Too many paging files specified - %lu\n",
154c2c66affSColin Finck SmpNumberOfPagingFiles);
155c2c66affSColin Finck return STATUS_TOO_MANY_PAGING_FILES;
156c2c66affSColin Finck }
157c2c66affSColin Finck
158c2c66affSColin Finck /* Parse the specified and get the name and arguments out of it */
159c2c66affSColin Finck DPRINT("SMSS:PFILE: Paging file specifier `%wZ'\n", PageFileToken);
160c2c66affSColin Finck Status = SmpParseCommandLine(PageFileToken,
161c2c66affSColin Finck NULL,
162c2c66affSColin Finck &PageFileName,
163c2c66affSColin Finck NULL,
164c2c66affSColin Finck &Arguments);
165c2c66affSColin Finck if (!NT_SUCCESS(Status))
166c2c66affSColin Finck {
167c2c66affSColin Finck /* Fail */
168c2c66affSColin Finck DPRINT1("SMSS:PFILE: SmpParseCommandLine(%wZ) failed - Status == %lx\n",
169c2c66affSColin Finck PageFileToken, Status);
170c2c66affSColin Finck return Status;
171c2c66affSColin Finck }
172c2c66affSColin Finck
173c2c66affSColin Finck /* Set the variable to let everyone know we have a pagefile token */
174c2c66affSColin Finck SmpRegistrySpecifierPresent = TRUE;
175c2c66affSColin Finck
176c2c66affSColin Finck /* Parse the arguments, if any */
177c2c66affSColin Finck if (Arguments.Buffer)
178c2c66affSColin Finck {
179c2c66affSColin Finck /* Parse the pagefile size */
180c2c66affSColin Finck for (i = 0; i < Arguments.Length / sizeof(WCHAR); i++)
181c2c66affSColin Finck {
182c2c66affSColin Finck /* Check if it's zero */
183c2c66affSColin Finck c = Arguments.Buffer[i];
184c2c66affSColin Finck if ((c != L' ') && (c != L'\t') && (c != L'0'))
185c2c66affSColin Finck {
186c2c66affSColin Finck /* It isn't, break out */
187c2c66affSColin Finck ZeroSize = FALSE;
188c2c66affSColin Finck break;
189c2c66affSColin Finck }
190c2c66affSColin Finck }
191c2c66affSColin Finck }
192c2c66affSColin Finck
193c2c66affSColin Finck /* Was a pagefile not specified, or was it specified with no size? */
194c2c66affSColin Finck if (!(Arguments.Buffer) || (ZeroSize))
195c2c66affSColin Finck {
196c2c66affSColin Finck /* In this case, the system will manage its size */
197c2c66affSColin Finck SystemManaged = TRUE;
198c2c66affSColin Finck }
199c2c66affSColin Finck else
200c2c66affSColin Finck {
201c2c66affSColin Finck /* We do have a size, so convert the arguments into a number */
202c2c66affSColin Finck Status = RtlUnicodeStringToInteger(&Arguments, 0, &MinSize);
203c2c66affSColin Finck if (!NT_SUCCESS(Status))
204c2c66affSColin Finck {
205c2c66affSColin Finck /* Fail */
206c2c66affSColin Finck RtlFreeUnicodeString(&PageFileName);
207c2c66affSColin Finck RtlFreeUnicodeString(&Arguments);
208c2c66affSColin Finck return Status;
209c2c66affSColin Finck }
210c2c66affSColin Finck
211c2c66affSColin Finck /* Now advance to the next argument */
212c2c66affSColin Finck for (i = 0; i < Arguments.Length / sizeof(WCHAR); i++)
213c2c66affSColin Finck {
214c2c66affSColin Finck /* Found a space -- second argument must start here */
215c2c66affSColin Finck if (Arguments.Buffer[i] == L' ')
216c2c66affSColin Finck {
217c2c66affSColin Finck /* Use the rest of the arguments as a maximum size */
218c2c66affSColin Finck SecondArgument.Buffer = &Arguments.Buffer[i];
219c2c66affSColin Finck SecondArgument.Length = (USHORT)(Arguments.Length -
220c2c66affSColin Finck i * sizeof(WCHAR));
221c2c66affSColin Finck SecondArgument.MaximumLength = (USHORT)(Arguments.MaximumLength -
222c2c66affSColin Finck i * sizeof(WCHAR));
223c2c66affSColin Finck Status = RtlUnicodeStringToInteger(&SecondArgument, 0, &MaxSize);
224c2c66affSColin Finck if (!NT_SUCCESS(Status))
225c2c66affSColin Finck {
226c2c66affSColin Finck /* Fail */
227c2c66affSColin Finck RtlFreeUnicodeString(&PageFileName);
228c2c66affSColin Finck RtlFreeUnicodeString(&Arguments);
229c2c66affSColin Finck return Status;
230c2c66affSColin Finck }
231c2c66affSColin Finck
232c2c66affSColin Finck break;
233c2c66affSColin Finck }
234c2c66affSColin Finck }
235c2c66affSColin Finck }
236c2c66affSColin Finck
237c2c66affSColin Finck /* We are done parsing arguments */
238c2c66affSColin Finck RtlFreeUnicodeString(&Arguments);
239c2c66affSColin Finck
240c2c66affSColin Finck /* Now we can allocate our descriptor */
241c2c66affSColin Finck Descriptor = RtlAllocateHeap(RtlGetProcessHeap(),
242c2c66affSColin Finck HEAP_ZERO_MEMORY,
243c2c66affSColin Finck sizeof(SMP_PAGEFILE_DESCRIPTOR));
244c2c66affSColin Finck if (!Descriptor)
245c2c66affSColin Finck {
246c2c66affSColin Finck /* Fail if we couldn't */
247c2c66affSColin Finck RtlFreeUnicodeString(&PageFileName);
248c2c66affSColin Finck return STATUS_NO_MEMORY;
249c2c66affSColin Finck }
250c2c66affSColin Finck
251c2c66affSColin Finck /* Capture all our data into the descriptor */
252c2c66affSColin Finck Descriptor->Token = *PageFileToken;
253c2c66affSColin Finck Descriptor->Name = PageFileName;
254c2c66affSColin Finck Descriptor->MinSize.QuadPart = MinSize * MEGABYTE;
255c2c66affSColin Finck Descriptor->MaxSize.QuadPart = MaxSize * MEGABYTE;
256a4274ad5SHermès Bélusca-Maïto if (SystemManaged)
257a4274ad5SHermès Bélusca-Maïto Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED;
258c2c66affSColin Finck Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] =
259c2c66affSColin Finck RtlUpcaseUnicodeChar(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]);
260c2c66affSColin Finck if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?')
261c2c66affSColin Finck {
262c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_ON_ANY_DRIVE;
263c2c66affSColin Finck }
264c2c66affSColin Finck
265c2c66affSColin Finck /* Now loop the existing descriptors */
266c2c66affSColin Finck NextEntry = SmpPagingFileDescriptorList.Flink;
267c2c66affSColin Finck do
268c2c66affSColin Finck {
269c2c66affSColin Finck /* Are there none, or have we looped back to the beginning? */
270c2c66affSColin Finck if (NextEntry == &SmpPagingFileDescriptorList)
271c2c66affSColin Finck {
272c2c66affSColin Finck /* This means no duplicates exist, so insert our descriptor! */
273c2c66affSColin Finck InsertTailList(&SmpPagingFileDescriptorList, &Descriptor->Entry);
274c2c66affSColin Finck SmpNumberOfPagingFiles++;
275c2c66affSColin Finck DPRINT("SMSS:PFILE: Created descriptor for `%wZ' (`%wZ')\n",
276c2c66affSColin Finck PageFileToken, &Descriptor->Name);
277c2c66affSColin Finck return STATUS_SUCCESS;
278c2c66affSColin Finck }
279c2c66affSColin Finck
280c2c66affSColin Finck /* Keep going until we find a duplicate, unless we are in "any" mode */
281c2c66affSColin Finck ListDescriptor = CONTAINING_RECORD(NextEntry, SMP_PAGEFILE_DESCRIPTOR, Entry);
282c2c66affSColin Finck NextEntry = NextEntry->Flink;
283c2c66affSColin Finck } while (!(ListDescriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE) ||
284c2c66affSColin Finck !(Descriptor->Flags & SMP_PAGEFILE_ON_ANY_DRIVE));
285c2c66affSColin Finck
286c2c66affSColin Finck /* We found a duplicate, so skip this descriptor/pagefile and fail */
287c2c66affSColin Finck DPRINT1("SMSS:PFILE: Skipping duplicate specifier `%wZ'\n", PageFileToken);
288c2c66affSColin Finck RtlFreeUnicodeString(&PageFileName);
289c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, Descriptor);
290c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
291c2c66affSColin Finck }
292c2c66affSColin Finck
293c2c66affSColin Finck NTSTATUS
294c2c66affSColin Finck NTAPI
SmpGetPagingFileSize(IN PUNICODE_STRING FileName,OUT PLARGE_INTEGER Size)295c2c66affSColin Finck SmpGetPagingFileSize(IN PUNICODE_STRING FileName,
296c2c66affSColin Finck OUT PLARGE_INTEGER Size)
297c2c66affSColin Finck {
298c2c66affSColin Finck NTSTATUS Status;
299c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes;
300c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock;
301c2c66affSColin Finck HANDLE FileHandle;
302c2c66affSColin Finck FILE_STANDARD_INFORMATION StandardInfo;
303c2c66affSColin Finck
304c2c66affSColin Finck DPRINT("SMSS:PFILE: Trying to get size for `%wZ'\n", FileName);
305c2c66affSColin Finck Size->QuadPart = 0;
306c2c66affSColin Finck
307c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes,
308c2c66affSColin Finck FileName,
309c2c66affSColin Finck OBJ_CASE_INSENSITIVE,
310c2c66affSColin Finck NULL,
311c2c66affSColin Finck NULL);
312c2c66affSColin Finck Status = NtOpenFile(&FileHandle,
313c2c66affSColin Finck FILE_READ_ATTRIBUTES | SYNCHRONIZE,
314c2c66affSColin Finck &ObjectAttributes,
315c2c66affSColin Finck &IoStatusBlock,
316c2c66affSColin Finck FILE_SHARE_READ | FILE_SHARE_WRITE,
317c2c66affSColin Finck FILE_SYNCHRONOUS_IO_NONALERT);
318c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status;
319c2c66affSColin Finck
320c2c66affSColin Finck Status = NtQueryInformationFile(FileHandle,
321c2c66affSColin Finck &IoStatusBlock,
322c2c66affSColin Finck &StandardInfo,
323c2c66affSColin Finck sizeof(StandardInfo),
324c2c66affSColin Finck FileStandardInformation);
325c2c66affSColin Finck if (!NT_SUCCESS(Status))
326c2c66affSColin Finck {
327c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed query for size potential pagefile `%wZ' with status %X\n",
328c2c66affSColin Finck FileName, Status);
329c2c66affSColin Finck NtClose(FileHandle);
330c2c66affSColin Finck return Status;
331c2c66affSColin Finck }
332c2c66affSColin Finck
333c2c66affSColin Finck NtClose(FileHandle);
334c2c66affSColin Finck Size->QuadPart = StandardInfo.AllocationSize.QuadPart;
335c2c66affSColin Finck return STATUS_SUCCESS;
336c2c66affSColin Finck }
337c2c66affSColin Finck
338c2c66affSColin Finck NTSTATUS
339c2c66affSColin Finck NTAPI
SmpDeletePagingFile(IN PUNICODE_STRING FileName)340c2c66affSColin Finck SmpDeletePagingFile(IN PUNICODE_STRING FileName)
341c2c66affSColin Finck {
342c2c66affSColin Finck NTSTATUS Status;
343c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes;
344c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock;
345c2c66affSColin Finck HANDLE FileHandle;
346c2c66affSColin Finck FILE_DISPOSITION_INFORMATION Disposition;
347c2c66affSColin Finck
348c2c66affSColin Finck /* Open the page file */
349c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes,
350c2c66affSColin Finck FileName,
351c2c66affSColin Finck OBJ_CASE_INSENSITIVE,
352c2c66affSColin Finck NULL,
353c2c66affSColin Finck NULL);
354c2c66affSColin Finck Status = NtOpenFile(&FileHandle,
355c2c66affSColin Finck DELETE,
356c2c66affSColin Finck &ObjectAttributes,
357c2c66affSColin Finck &IoStatusBlock,
358c2c66affSColin Finck FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
359c2c66affSColin Finck FILE_NON_DIRECTORY_FILE);
360c2c66affSColin Finck if (NT_SUCCESS(Status))
361c2c66affSColin Finck {
362c2c66affSColin Finck /* Delete it */
363c2c66affSColin Finck Disposition.DeleteFile = TRUE;
364c2c66affSColin Finck Status = NtSetInformationFile(FileHandle,
365c2c66affSColin Finck &IoStatusBlock,
366c2c66affSColin Finck &Disposition,
367c2c66affSColin Finck sizeof(Disposition),
368c2c66affSColin Finck FileDispositionInformation);
369c2c66affSColin Finck if (!NT_SUCCESS(Status))
370c2c66affSColin Finck {
371c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to delete page file `%wZ' (status %X)\n",
372c2c66affSColin Finck FileName, Status);
373c2c66affSColin Finck }
374c2c66affSColin Finck else
375c2c66affSColin Finck {
376c2c66affSColin Finck DPRINT("SMSS:PFILE: Deleted stale paging file - %wZ\n", FileName);
377c2c66affSColin Finck }
378c2c66affSColin Finck
379c2c66affSColin Finck /* Close the handle */
380c2c66affSColin Finck NtClose(FileHandle);
381c2c66affSColin Finck }
382c2c66affSColin Finck else
383c2c66affSColin Finck {
384c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to open for deletion page file `%wZ' (status %X)\n",
385c2c66affSColin Finck FileName, Status);
386c2c66affSColin Finck }
387c2c66affSColin Finck
388c2c66affSColin Finck /* All done */
389c2c66affSColin Finck return Status;
390c2c66affSColin Finck }
391c2c66affSColin Finck
392c2c66affSColin Finck NTSTATUS
393c2c66affSColin Finck NTAPI
SmpGetVolumeFreeSpace(IN PSMP_VOLUME_DESCRIPTOR Volume)394c2c66affSColin Finck SmpGetVolumeFreeSpace(IN PSMP_VOLUME_DESCRIPTOR Volume)
395c2c66affSColin Finck {
396c2c66affSColin Finck NTSTATUS Status;
397c2c66affSColin Finck LARGE_INTEGER FreeSpace, FinalFreeSpace;
398c2c66affSColin Finck FILE_FS_SIZE_INFORMATION SizeInfo;
399c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock;
400c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes;
401c2c66affSColin Finck UNICODE_STRING VolumeName;
402c2c66affSColin Finck HANDLE VolumeHandle;
403c2c66affSColin Finck WCHAR PathString[32];
404c2c66affSColin Finck ASSERT(Volume->Flags & SMP_VOLUME_IS_BOOT); // ASSERT says "BootVolume == 1"
405c2c66affSColin Finck
406c2c66affSColin Finck /* Build the standard path */
407c2c66affSColin Finck wcscpy(PathString, L"\\??\\A:\\");
408c2c66affSColin Finck RtlInitUnicodeString(&VolumeName, PathString);
409c2c66affSColin Finck VolumeName.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Volume->DriveLetter;
410c2c66affSColin Finck DPRINT("SMSS:PFILE: Querying volume `%wZ' for free space\n", &VolumeName);
411c2c66affSColin Finck
412c2c66affSColin Finck /* Open the volume */
413c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes,
414c2c66affSColin Finck &VolumeName,
415c2c66affSColin Finck OBJ_CASE_INSENSITIVE,
416c2c66affSColin Finck NULL,
417c2c66affSColin Finck NULL);
418c2c66affSColin Finck Status = NtOpenFile(&VolumeHandle,
419c2c66affSColin Finck FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
420c2c66affSColin Finck &ObjectAttributes,
421c2c66affSColin Finck &IoStatusBlock,
422c2c66affSColin Finck FILE_SHARE_READ | FILE_SHARE_WRITE,
423c2c66affSColin Finck FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
424c2c66affSColin Finck if (!NT_SUCCESS(Status))
425c2c66affSColin Finck {
426c2c66affSColin Finck DPRINT1("SMSS:PFILE: Open volume `%wZ' failed with status %X\n", &VolumeName, Status);
427c2c66affSColin Finck return Status;
428c2c66affSColin Finck }
429c2c66affSColin Finck
430c2c66affSColin Finck /* Now get size information on the volume */
431c2c66affSColin Finck Status = NtQueryVolumeInformationFile(VolumeHandle,
432c2c66affSColin Finck &IoStatusBlock,
433c2c66affSColin Finck &SizeInfo,
434c2c66affSColin Finck sizeof(SizeInfo),
435c2c66affSColin Finck FileFsSizeInformation);
436c2c66affSColin Finck if (!NT_SUCCESS(Status))
437c2c66affSColin Finck {
438c2c66affSColin Finck /* We failed */
439c2c66affSColin Finck DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed"
440c2c66affSColin Finck " with status %X\n",
441c2c66affSColin Finck &VolumeName,
442c2c66affSColin Finck VolumeHandle,
443c2c66affSColin Finck Status);
444c2c66affSColin Finck NtClose(VolumeHandle);
445c2c66affSColin Finck return Status;
446c2c66affSColin Finck }
447c2c66affSColin Finck NtClose(VolumeHandle);
448c2c66affSColin Finck
449c2c66affSColin Finck /* Compute how much free space we have */
450c2c66affSColin Finck FreeSpace.QuadPart = SizeInfo.AvailableAllocationUnits.QuadPart *
451c2c66affSColin Finck SizeInfo.SectorsPerAllocationUnit;
452c2c66affSColin Finck FinalFreeSpace.QuadPart = FreeSpace.QuadPart * SizeInfo.BytesPerSector;
453c2c66affSColin Finck
4545dc43c0fSHermès Bélusca-Maïto /* Check if there is less than 32 MB free so we don't starve the disk */
455c2c66affSColin Finck if (FinalFreeSpace.QuadPart <= MINIMUM_TO_KEEP_FREE)
456c2c66affSColin Finck {
4575dc43c0fSHermès Bélusca-Maïto /* In this case, act as if there is no free space */
458c2c66affSColin Finck Volume->FreeSpace.QuadPart = 0;
459c2c66affSColin Finck }
460c2c66affSColin Finck else
461c2c66affSColin Finck {
462c2c66affSColin Finck /* Trim off 32 MB to give the disk a bit of breathing room */
463c2c66affSColin Finck Volume->FreeSpace.QuadPart = FinalFreeSpace.QuadPart -
464c2c66affSColin Finck MINIMUM_TO_KEEP_FREE;
465c2c66affSColin Finck }
466c2c66affSColin Finck
467c2c66affSColin Finck return STATUS_SUCCESS;
468c2c66affSColin Finck }
469c2c66affSColin Finck
470c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR
471c2c66affSColin Finck NTAPI
SmpSearchVolumeDescriptor(IN WCHAR DriveLetter)472c2c66affSColin Finck SmpSearchVolumeDescriptor(IN WCHAR DriveLetter)
473c2c66affSColin Finck {
474c2c66affSColin Finck WCHAR UpLetter;
475c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR Volume = NULL;
476c2c66affSColin Finck PLIST_ENTRY NextEntry;
477c2c66affSColin Finck
478c2c66affSColin Finck /* Use upper case to reduce differences */
479c2c66affSColin Finck UpLetter = RtlUpcaseUnicodeChar(DriveLetter);
480c2c66affSColin Finck
481c2c66affSColin Finck /* Loop each volume */
482c2c66affSColin Finck NextEntry = SmpVolumeDescriptorList.Flink;
483c2c66affSColin Finck while (NextEntry != &SmpVolumeDescriptorList)
484c2c66affSColin Finck {
485c2c66affSColin Finck /* Grab the entry */
486c2c66affSColin Finck Volume = CONTAINING_RECORD(NextEntry, SMP_VOLUME_DESCRIPTOR, Entry);
487c2c66affSColin Finck
488c2c66affSColin Finck /* Make sure it's a valid entry with an uppcase drive letter */
489c2c66affSColin Finck ASSERT(Volume->Flags & SMP_VOLUME_INSERTED); // Volume->Initialized in ASSERT
490c2c66affSColin Finck ASSERT(Volume->DriveLetter >= L'A' && Volume->DriveLetter <= L'Z');
491c2c66affSColin Finck
492c2c66affSColin Finck /* Break if it matches, if not, keep going */
493c2c66affSColin Finck if (Volume->DriveLetter == UpLetter) break;
494c2c66affSColin Finck NextEntry = NextEntry->Flink;
495c2c66affSColin Finck }
496c2c66affSColin Finck
497c2c66affSColin Finck /* Return the volume if one was found */
498c2c66affSColin Finck if (NextEntry == &SmpVolumeDescriptorList) Volume = NULL;
499c2c66affSColin Finck return Volume;
500c2c66affSColin Finck }
501c2c66affSColin Finck
502c2c66affSColin Finck NTSTATUS
503c2c66affSColin Finck NTAPI
SmpCreatePagingFile(IN PUNICODE_STRING Name,IN PLARGE_INTEGER MinSize,IN PLARGE_INTEGER MaxSize,IN ULONG Priority)504c2c66affSColin Finck SmpCreatePagingFile(IN PUNICODE_STRING Name,
505c2c66affSColin Finck IN PLARGE_INTEGER MinSize,
506c2c66affSColin Finck IN PLARGE_INTEGER MaxSize,
507c2c66affSColin Finck IN ULONG Priority)
508c2c66affSColin Finck {
509c2c66affSColin Finck NTSTATUS Status;
510c2c66affSColin Finck
511c2c66affSColin Finck /* Tell the kernel to create the pagefile */
512c2c66affSColin Finck Status = NtCreatePagingFile(Name, MinSize, MaxSize, Priority);
513c2c66affSColin Finck if (NT_SUCCESS(Status))
514c2c66affSColin Finck {
515*bcb9abc1SJoachim Henze DPRINT("SMSS:PFILE: NtCreatePagingFile(%wZ, 0x%I64X, 0x%I64X) succeeded\n",
516c2c66affSColin Finck Name,
517c2c66affSColin Finck MinSize->QuadPart,
518c2c66affSColin Finck MaxSize->QuadPart);
519c2c66affSColin Finck }
520c2c66affSColin Finck else
521c2c66affSColin Finck {
5225dc43c0fSHermès Bélusca-Maïto DPRINT1("SMSS:PFILE: NtCreatePagingFile(%wZ, 0x%I64X, 0x%I64X) failed with %X\n",
523c2c66affSColin Finck Name,
524c2c66affSColin Finck MinSize->QuadPart,
525c2c66affSColin Finck MaxSize->QuadPart,
526c2c66affSColin Finck Status);
527c2c66affSColin Finck }
528c2c66affSColin Finck
529c2c66affSColin Finck /* Return the status */
530c2c66affSColin Finck return Status;
531c2c66affSColin Finck }
532c2c66affSColin Finck
533c2c66affSColin Finck NTSTATUS
534c2c66affSColin Finck NTAPI
SmpCreatePagingFileOnFixedDrive(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor,IN PLARGE_INTEGER FuzzFactor,IN PLARGE_INTEGER MinimumSize)535c2c66affSColin Finck SmpCreatePagingFileOnFixedDrive(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor,
536c2c66affSColin Finck IN PLARGE_INTEGER FuzzFactor,
537c2c66affSColin Finck IN PLARGE_INTEGER MinimumSize)
538c2c66affSColin Finck {
539c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR Volume;
540c2c66affSColin Finck BOOLEAN ShouldDelete;
541c2c66affSColin Finck NTSTATUS Status;
542c2c66affSColin Finck LARGE_INTEGER PageFileSize;
543c2c66affSColin Finck ASSERT(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] != L'?');
544c2c66affSColin Finck
545c2c66affSColin Finck /* Try to find the volume descriptor for this drive letter */
546c2c66affSColin Finck ShouldDelete = FALSE;
547c2c66affSColin Finck Volume = SmpSearchVolumeDescriptor(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]);
548c2c66affSColin Finck if (!Volume)
549c2c66affSColin Finck {
550c2c66affSColin Finck /* Couldn't find it, fail */
551c2c66affSColin Finck DPRINT1("SMSS:PFILE: No volume descriptor for `%wZ'\n",
552c2c66affSColin Finck &Descriptor->Name);
553c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
554c2c66affSColin Finck }
555c2c66affSColin Finck
556c2c66affSColin Finck /* Check if this is the boot volume */
557c2c66affSColin Finck if (Volume->Flags & SMP_VOLUME_IS_BOOT)
558c2c66affSColin Finck {
559c2c66affSColin Finck /* Check if we haven't yet processed a crash dump on this volume */
560c2c66affSColin Finck if (!(Descriptor->Flags & SMP_PAGEFILE_DUMP_PROCESSED))
561c2c66affSColin Finck {
562c2c66affSColin Finck /* Try to find a crash dump and extract it */
563c2c66affSColin Finck DPRINT("SMSS:PFILE: Checking for crash dump in `%wZ' on boot volume\n",
564c2c66affSColin Finck &Descriptor->Name);
565c2c66affSColin Finck SmpCheckForCrashDump(&Descriptor->Name);
566c2c66affSColin Finck
567c2c66affSColin Finck /* Update how much free space we have now that we extracted a dump */
568c2c66affSColin Finck Status = SmpGetVolumeFreeSpace(Volume);
569c2c66affSColin Finck if (!NT_SUCCESS(Status))
570c2c66affSColin Finck {
571c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to query free space for boot volume `%wC'\n",
572c2c66affSColin Finck Volume->DriveLetter);
573c2c66affSColin Finck }
574c2c66affSColin Finck else
575c2c66affSColin Finck {
5765dc43c0fSHermès Bélusca-Maïto DPRINT("Queried free space for boot volume `%wC: 0x%I64x'\n",
577c2c66affSColin Finck Volume->DriveLetter, Volume->FreeSpace.QuadPart);
578c2c66affSColin Finck }
579c2c66affSColin Finck
580c2c66affSColin Finck /* Don't process crashdump on this volume anymore */
581c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_DUMP_PROCESSED;
582c2c66affSColin Finck }
583c2c66affSColin Finck }
584c2c66affSColin Finck else
585c2c66affSColin Finck {
586c2c66affSColin Finck /* Crashdumps can only be on the boot volume */
587c2c66affSColin Finck DPRINT("SMSS:PFILE: Skipping crash dump checking for `%wZ' on non boot"
588c2c66affSColin Finck "volume `%wC'\n",
589c2c66affSColin Finck &Descriptor->Name,
590c2c66affSColin Finck Volume->DriveLetter);
591c2c66affSColin Finck }
592c2c66affSColin Finck
593c2c66affSColin Finck /* Update the size after dump extraction */
594c2c66affSColin Finck Descriptor->ActualMinSize = Descriptor->MinSize;
595c2c66affSColin Finck Descriptor->ActualMaxSize = Descriptor->MaxSize;
596c2c66affSColin Finck
597c2c66affSColin Finck /* Check how big we can make the pagefile */
598c2c66affSColin Finck Status = SmpGetPagingFileSize(&Descriptor->Name, &PageFileSize);
599c2c66affSColin Finck if (NT_SUCCESS(Status) && PageFileSize.QuadPart > 0) ShouldDelete = TRUE;
6005dc43c0fSHermès Bélusca-Maïto DPRINT("SMSS:PFILE: Detected size 0x%I64X for future paging file `%wZ'\n",
601c2c66affSColin Finck PageFileSize,
602c2c66affSColin Finck &Descriptor->Name);
6035dc43c0fSHermès Bélusca-Maïto DPRINT("SMSS:PFILE: Free space on volume `%wC' is 0x%I64X\n",
604c2c66affSColin Finck Volume->DriveLetter,
605c2c66affSColin Finck Volume->FreeSpace.QuadPart);
606c2c66affSColin Finck
607c2c66affSColin Finck /* Now update our size and make sure none of these are too big */
608c2c66affSColin Finck PageFileSize.QuadPart += Volume->FreeSpace.QuadPart;
609c2c66affSColin Finck if (Descriptor->ActualMinSize.QuadPart > PageFileSize.QuadPart)
610c2c66affSColin Finck {
611c2c66affSColin Finck Descriptor->ActualMinSize = PageFileSize;
612c2c66affSColin Finck }
613c2c66affSColin Finck if (Descriptor->ActualMaxSize.QuadPart > PageFileSize.QuadPart)
614c2c66affSColin Finck {
615c2c66affSColin Finck Descriptor->ActualMaxSize = PageFileSize;
616c2c66affSColin Finck }
6175dc43c0fSHermès Bélusca-Maïto DPRINT("SMSS:PFILE: min 0x%I64X, max 0x%I64X, real min 0x%I64X\n",
618c2c66affSColin Finck Descriptor->ActualMinSize.QuadPart,
619c2c66affSColin Finck Descriptor->ActualMaxSize.QuadPart,
620c2c66affSColin Finck MinimumSize->QuadPart);
621c2c66affSColin Finck
622c2c66affSColin Finck /* Keep going until we've created a pagefile of the right size */
623c2c66affSColin Finck while (Descriptor->ActualMinSize.QuadPart >= MinimumSize->QuadPart)
624c2c66affSColin Finck {
625c2c66affSColin Finck /* Call NT to do it */
626c2c66affSColin Finck Status = SmpCreatePagingFile(&Descriptor->Name,
627c2c66affSColin Finck &Descriptor->ActualMinSize,
628c2c66affSColin Finck &Descriptor->ActualMaxSize,
629c2c66affSColin Finck 0);
630c2c66affSColin Finck if (NT_SUCCESS(Status))
631c2c66affSColin Finck {
632c2c66affSColin Finck /* We're done, update flags and increase the count */
633c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_CREATED;
634c2c66affSColin Finck Volume->Flags |= SMP_VOLUME_PAGEFILE_CREATED;
635c2c66affSColin Finck Volume->PageFileCount++;
636c2c66affSColin Finck break;
637c2c66affSColin Finck }
638c2c66affSColin Finck
639c2c66affSColin Finck /* We failed, try a slightly smaller pagefile */
640c2c66affSColin Finck Descriptor->ActualMinSize.QuadPart -= FuzzFactor->QuadPart;
641c2c66affSColin Finck }
642c2c66affSColin Finck
643c2c66affSColin Finck /* Check if we weren't able to create it */
644c2c66affSColin Finck if (Descriptor->ActualMinSize.QuadPart < MinimumSize->QuadPart)
645c2c66affSColin Finck {
646c2c66affSColin Finck /* Delete the current page file and fail */
647c2c66affSColin Finck if (ShouldDelete)
648c2c66affSColin Finck {
649c2c66affSColin Finck SmpDeletePagingFile(&Descriptor->Name);
650c2c66affSColin Finck
651c2c66affSColin Finck /* FIXFIX: Windows Vista does this, and it seems like we should too, so try to see if this fixes KVM */
652c2c66affSColin Finck Volume->FreeSpace.QuadPart = PageFileSize.QuadPart;
653c2c66affSColin Finck }
6545dc43c0fSHermès Bélusca-Maïto DPRINT1("SMSS:PFILE: Failing for min 0x%I64X, max 0x%I64X, real min 0x%I64X\n",
655c2c66affSColin Finck Descriptor->ActualMinSize.QuadPart,
656c2c66affSColin Finck Descriptor->ActualMaxSize.QuadPart,
657c2c66affSColin Finck MinimumSize->QuadPart);
658c2c66affSColin Finck Status = STATUS_DISK_FULL;
659c2c66affSColin Finck }
660c2c66affSColin Finck
661c2c66affSColin Finck /* Return the status */
662c2c66affSColin Finck return Status;
663c2c66affSColin Finck }
664c2c66affSColin Finck
665c2c66affSColin Finck NTSTATUS
666c2c66affSColin Finck NTAPI
SmpCreatePagingFileOnAnyDrive(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor,IN PLARGE_INTEGER FuzzFactor,IN PLARGE_INTEGER MinimumSize)667c2c66affSColin Finck SmpCreatePagingFileOnAnyDrive(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor,
668c2c66affSColin Finck IN PLARGE_INTEGER FuzzFactor,
669c2c66affSColin Finck IN PLARGE_INTEGER MinimumSize)
670c2c66affSColin Finck {
671c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR Volume;
672c2c66affSColin Finck NTSTATUS Status = STATUS_DISK_FULL;
673c2c66affSColin Finck PLIST_ENTRY NextEntry;
674c2c66affSColin Finck ASSERT(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == L'?');
675c2c66affSColin Finck
676c2c66affSColin Finck /* Loop the volume list */
677c2c66affSColin Finck NextEntry = SmpVolumeDescriptorList.Flink;
678c2c66affSColin Finck while (NextEntry != &SmpVolumeDescriptorList)
679c2c66affSColin Finck {
680c2c66affSColin Finck /* Get the volume */
681c2c66affSColin Finck Volume = CONTAINING_RECORD(NextEntry, SMP_VOLUME_DESCRIPTOR, Entry);
682c2c66affSColin Finck
683c2c66affSColin Finck /* Make sure it's inserted and on a valid drive letter */
684c2c66affSColin Finck ASSERT(Volume->Flags & SMP_VOLUME_INSERTED); // Volume->Initialized in ASSERT
685c2c66affSColin Finck ASSERT(Volume->DriveLetter >= L'A' && Volume->DriveLetter <= L'Z');
686c2c66affSColin Finck
687c2c66affSColin Finck /* Write the drive letter to try creating it on this volume */
688c2c66affSColin Finck Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Volume->DriveLetter;
689c2c66affSColin Finck Status = SmpCreatePagingFileOnFixedDrive(Descriptor,
690c2c66affSColin Finck FuzzFactor,
691c2c66affSColin Finck MinimumSize);
692c2c66affSColin Finck if (NT_SUCCESS(Status)) break;
693c2c66affSColin Finck
694c2c66affSColin Finck /* It didn't work, make it an any pagefile again and keep going */
695c2c66affSColin Finck Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = L'?';
696c2c66affSColin Finck NextEntry = NextEntry->Flink;
697c2c66affSColin Finck }
698c2c66affSColin Finck
699c2c66affSColin Finck /* Return disk full or success */
700c2c66affSColin Finck return Status;
701c2c66affSColin Finck }
702c2c66affSColin Finck
703c2c66affSColin Finck VOID
704c2c66affSColin Finck NTAPI
SmpMakeDefaultPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)705c2c66affSColin Finck SmpMakeDefaultPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
706c2c66affSColin Finck {
707c2c66affSColin Finck /* The default descriptor uses 128 MB as a pagefile size */
708c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_DEFAULT;
709c2c66affSColin Finck Descriptor->MinSize.QuadPart = 128 * MEGABYTE;
710c2c66affSColin Finck Descriptor->MaxSize.QuadPart = 128 * MEGABYTE;
711c2c66affSColin Finck }
712c2c66affSColin Finck
713c2c66affSColin Finck VOID
714c2c66affSColin Finck NTAPI
SmpMakeSystemManagedPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)715c2c66affSColin Finck SmpMakeSystemManagedPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
716c2c66affSColin Finck {
717c2c66affSColin Finck NTSTATUS Status;
718a4274ad5SHermès Bélusca-Maïto ULONGLONG MinimumSize, MaximumSize, Ram;
719c2c66affSColin Finck SYSTEM_BASIC_INFORMATION BasicInfo;
720c2c66affSColin Finck
721c2c66affSColin Finck /* Query the page size of the system, and the amount of RAM */
722c2c66affSColin Finck Status = NtQuerySystemInformation(SystemBasicInformation,
723c2c66affSColin Finck &BasicInfo,
724c2c66affSColin Finck sizeof(BasicInfo),
725c2c66affSColin Finck NULL);
726c2c66affSColin Finck if (!NT_SUCCESS(Status))
727c2c66affSColin Finck {
728c2c66affSColin Finck /* If we failed, use defaults since we have no idea otherwise */
729c2c66affSColin Finck DPRINT1("SMSS:PFILE: NtQuerySystemInformation failed with %x\n", Status);
730c2c66affSColin Finck SmpMakeDefaultPagingFileDescriptor(Descriptor);
731c2c66affSColin Finck return;
732c2c66affSColin Finck }
733c2c66affSColin Finck
7345dc43c0fSHermès Bélusca-Maïto /* Check how much RAM we have and set three times this amount as maximum */
735c2c66affSColin Finck Ram = BasicInfo.NumberOfPhysicalPages * BasicInfo.PageSize;
736c2c66affSColin Finck MaximumSize = 3 * Ram;
737c2c66affSColin Finck
738c2c66affSColin Finck /* If we have more than 1GB, use that as minimum, otherwise, use 1.5X RAM */
739c2c66affSColin Finck MinimumSize = (Ram >= 1024 * MEGABYTE) ? Ram : MaximumSize / 2;
740c2c66affSColin Finck
741c2c66affSColin Finck /* Write the new sizes in the descriptor and mark it as system managed */
742c2c66affSColin Finck Descriptor->MinSize.QuadPart = MinimumSize;
743c2c66affSColin Finck Descriptor->MaxSize.QuadPart = MaximumSize;
744c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED;
745c2c66affSColin Finck }
746c2c66affSColin Finck
747c2c66affSColin Finck NTSTATUS
748c2c66affSColin Finck NTAPI
SmpValidatePagingFileSizes(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)749c2c66affSColin Finck SmpValidatePagingFileSizes(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
750c2c66affSColin Finck {
751c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS;
752c2c66affSColin Finck BOOLEAN WasTooBig = FALSE;
753a4274ad5SHermès Bélusca-Maïto ULONGLONG MinSize, MaxSize;
754a4274ad5SHermès Bélusca-Maïto #ifdef _M_IX86
755a4274ad5SHermès Bélusca-Maïto ULONGLONG MaxPageFileSize =
756a4274ad5SHermès Bélusca-Maïto (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED])
757a4274ad5SHermès Bélusca-Maïto ? MAXIMUM_PAGEFILE_SIZE_PAE : MAXIMUM_PAGEFILE_SIZE;
758a4274ad5SHermès Bélusca-Maïto #else
759a4274ad5SHermès Bélusca-Maïto static const ULONGLONG MaxPageFileSize = MAXIMUM_PAGEFILE_SIZE;
760a4274ad5SHermès Bélusca-Maïto #endif
761c2c66affSColin Finck
762c2c66affSColin Finck /* Capture the min and max */
763c2c66affSColin Finck MinSize = Descriptor->MinSize.QuadPart;
764c2c66affSColin Finck MaxSize = Descriptor->MaxSize.QuadPart;
7655dc43c0fSHermès Bélusca-Maïto
7665dc43c0fSHermès Bélusca-Maïto DPRINT("SMSS:PFILE: Validating sizes for `%wZ' 0x%I64X 0x%I64X\n",
767c2c66affSColin Finck &Descriptor->Name, MinSize, MaxSize);
768c2c66affSColin Finck
769c2c66affSColin Finck /* Don't let minimum be bigger than maximum */
770a4274ad5SHermès Bélusca-Maïto if (MinSize > MaxSize)
771a4274ad5SHermès Bélusca-Maïto MaxSize = MinSize;
772c2c66affSColin Finck
7735dc43c0fSHermès Bélusca-Maïto /* Validate the minimum and maximum and trim them if they are too large */
774a4274ad5SHermès Bélusca-Maïto if (MinSize > MaxPageFileSize)
775c2c66affSColin Finck {
776c2c66affSColin Finck WasTooBig = TRUE;
777a4274ad5SHermès Bélusca-Maïto MinSize = MaxPageFileSize;
778c2c66affSColin Finck }
779a4274ad5SHermès Bélusca-Maïto if (MaxSize > MaxPageFileSize)
780c2c66affSColin Finck {
781c2c66affSColin Finck WasTooBig = TRUE;
782a4274ad5SHermès Bélusca-Maïto MaxSize = MaxPageFileSize;
783c2c66affSColin Finck }
784c2c66affSColin Finck
7855dc43c0fSHermès Bélusca-Maïto /* If we trimmed, write a flag in the descriptor */
786c2c66affSColin Finck if (WasTooBig)
787c2c66affSColin Finck {
788c2c66affSColin Finck DPRINT("SMSS:PFILE: Trimmed size of `%wZ' to maximum allowed\n",
789c2c66affSColin Finck &Descriptor->Name);
790c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_WAS_TOO_BIG;
791c2c66affSColin Finck }
792c2c66affSColin Finck
793c2c66affSColin Finck /* Now write the (possibly trimmed) sizes back */
794c2c66affSColin Finck Descriptor->MinSize.QuadPart = MinSize;
795c2c66affSColin Finck Descriptor->MaxSize.QuadPart = MaxSize;
796c2c66affSColin Finck return Status;
797c2c66affSColin Finck }
798c2c66affSColin Finck
799c2c66affSColin Finck NTSTATUS
800c2c66affSColin Finck NTAPI
SmpCreateSystemManagedPagingFile(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor,IN BOOLEAN DecreaseSize)801c2c66affSColin Finck SmpCreateSystemManagedPagingFile(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor,
802c2c66affSColin Finck IN BOOLEAN DecreaseSize)
803c2c66affSColin Finck {
804c2c66affSColin Finck LARGE_INTEGER FuzzFactor, Size;
805c2c66affSColin Finck
8065dc43c0fSHermès Bélusca-Maïto /* Make sure there is at least 1 paging file and that we are system-managed */
807c2c66affSColin Finck ASSERT(SmpNumberOfPagingFiles >= 1);
808c2c66affSColin Finck ASSERT(!IsListEmpty(&SmpPagingFileDescriptorList));
809a4274ad5SHermès Bélusca-Maïto ASSERT(Descriptor->Flags & SMP_PAGEFILE_SYSTEM_MANAGED);
810c2c66affSColin Finck
811c2c66affSColin Finck /* Keep decreasing the pagefile by this amount if we run out of space */
812c2c66affSColin Finck FuzzFactor.QuadPart = FUZZ_FACTOR;
813c2c66affSColin Finck
814c2c66affSColin Finck /* Create the descriptor for it (mainly the right sizes) and validate */
815c2c66affSColin Finck SmpMakeSystemManagedPagingFileDescriptor(Descriptor);
816c2c66affSColin Finck SmpValidatePagingFileSizes(Descriptor);
817c2c66affSColin Finck
818c2c66affSColin Finck /* Use either the minimum size in the descriptor, or 16 MB in minimal mode */
819c2c66affSColin Finck Size.QuadPart = DecreaseSize ? 16 * MEGABYTE : Descriptor->MinSize.QuadPart;
820c2c66affSColin Finck
821c2c66affSColin Finck /* Check if this should be a fixed pagefile or an any pagefile */
822c2c66affSColin Finck if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?')
823c2c66affSColin Finck {
824c2c66affSColin Finck /* Find a disk for it */
825c2c66affSColin Finck return SmpCreatePagingFileOnAnyDrive(Descriptor, &FuzzFactor, &Size);
826c2c66affSColin Finck }
827c2c66affSColin Finck
828c2c66affSColin Finck /* Use the disk that was given */
829c2c66affSColin Finck return SmpCreatePagingFileOnFixedDrive(Descriptor, &FuzzFactor, &Size);
830c2c66affSColin Finck }
831c2c66affSColin Finck
832c2c66affSColin Finck NTSTATUS
833c2c66affSColin Finck NTAPI
SmpCreateEmergencyPagingFile(VOID)834c2c66affSColin Finck SmpCreateEmergencyPagingFile(VOID)
835c2c66affSColin Finck {
836c2c66affSColin Finck PSMP_PAGEFILE_DESCRIPTOR Descriptor;
837c2c66affSColin Finck WCHAR Buffer[32];
838c2c66affSColin Finck
839c2c66affSColin Finck /* Allocate a descriptor */
840c2c66affSColin Finck Descriptor = RtlAllocateHeap(RtlGetProcessHeap(),
841c2c66affSColin Finck HEAP_ZERO_MEMORY,
842c2c66affSColin Finck sizeof(SMP_PAGEFILE_DESCRIPTOR));
843c2c66affSColin Finck if (!Descriptor) return STATUS_NO_MEMORY;
844c2c66affSColin Finck
845c2c66affSColin Finck /* Initialize it */
846c2c66affSColin Finck RtlInitUnicodeString(&Descriptor->Token, NULL);
847c2c66affSColin Finck
848c2c66affSColin Finck /* Copy the default pagefile name */
849c2c66affSColin Finck ASSERT(sizeof(Buffer) >= sizeof(STANDARD_PAGING_FILE_NAME));
850c2c66affSColin Finck wcscpy(Buffer, STANDARD_PAGING_FILE_NAME);
851c2c66affSColin Finck
852c2c66affSColin Finck /* Fill the rest of the descriptor out */
853c2c66affSColin Finck RtlInitUnicodeString(&Descriptor->Name, Buffer);
854c2c66affSColin Finck Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = '?';
855c2c66affSColin Finck Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED |
856c2c66affSColin Finck SMP_PAGEFILE_EMERGENCY |
857c2c66affSColin Finck SMP_PAGEFILE_ON_ANY_DRIVE;
858c2c66affSColin Finck
859c2c66affSColin Finck /* Insert it into the descriptor list */
860c2c66affSColin Finck InsertHeadList(&SmpPagingFileDescriptorList, &Descriptor->Entry);
861c2c66affSColin Finck SmpNumberOfPagingFiles++;
862c2c66affSColin Finck
863c2c66affSColin Finck /* Go ahead and create it now, with the minimal size possible */
864c2c66affSColin Finck return SmpCreateSystemManagedPagingFile(Descriptor, TRUE);
865c2c66affSColin Finck }
866c2c66affSColin Finck
867c2c66affSColin Finck NTSTATUS
868c2c66affSColin Finck NTAPI
SmpCreateVolumeDescriptors(VOID)869c2c66affSColin Finck SmpCreateVolumeDescriptors(VOID)
870c2c66affSColin Finck {
871c2c66affSColin Finck NTSTATUS Status;
872c2c66affSColin Finck UNICODE_STRING VolumePath;
873c2c66affSColin Finck BOOLEAN BootVolumeFound = FALSE;
874c2c66affSColin Finck WCHAR StartChar, Drive, DriveDiff;
875c2c66affSColin Finck HANDLE VolumeHandle;
876c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes;
877c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock;
878c2c66affSColin Finck PROCESS_DEVICEMAP_INFORMATION ProcessInformation;
879c2c66affSColin Finck FILE_FS_DEVICE_INFORMATION DeviceInfo;
880c2c66affSColin Finck FILE_FS_SIZE_INFORMATION SizeInfo;
881c2c66affSColin Finck PSMP_VOLUME_DESCRIPTOR Volume;
882c2c66affSColin Finck LARGE_INTEGER FreeSpace, FinalFreeSpace;
883c2c66affSColin Finck WCHAR Buffer[32];
884c2c66affSColin Finck
885c2c66affSColin Finck /* We should be starting with an empty list */
886c2c66affSColin Finck ASSERT(IsListEmpty(&SmpVolumeDescriptorList));
887c2c66affSColin Finck
888c2c66affSColin Finck /* Query the device map so we can get the drive letters */
889c2c66affSColin Finck Status = NtQueryInformationProcess(NtCurrentProcess(),
890c2c66affSColin Finck ProcessDeviceMap,
891094a90adSTimo Kreuzer &ProcessInformation.Query,
892094a90adSTimo Kreuzer sizeof(ProcessInformation.Query),
893c2c66affSColin Finck NULL);
894c2c66affSColin Finck if (!NT_SUCCESS(Status))
895c2c66affSColin Finck {
896c2c66affSColin Finck DPRINT1("SMSS:PFILE: Query(ProcessDeviceMap) failed with status %X\n",
897c2c66affSColin Finck Status);
898c2c66affSColin Finck return Status;
899c2c66affSColin Finck }
900c2c66affSColin Finck
901c2c66affSColin Finck /* Build the volume string, starting with A: (we'll edit this in place) */
902c2c66affSColin Finck wcscpy(Buffer, L"\\??\\A:\\");
903c2c66affSColin Finck RtlInitUnicodeString(&VolumePath, Buffer);
904c2c66affSColin Finck
905a0721ebdSHermès Bélusca-Maïto /* Start with the C drive, except on NEC PC-98 */
906a0721ebdSHermès Bélusca-Maïto StartChar = IsNEC_98 ? L'A' : L'C';
907c2c66affSColin Finck for (Drive = StartChar, DriveDiff = StartChar - L'A'; Drive <= L'Z'; Drive++, DriveDiff++)
908c2c66affSColin Finck {
909c2c66affSColin Finck /* Skip the disk if it's not in the drive map */
910c2c66affSColin Finck if (!((1 << DriveDiff) & ProcessInformation.Query.DriveMap)) continue;
911c2c66affSColin Finck
912c2c66affSColin Finck /* Write the drive letter and try to open the volume */
913c2c66affSColin Finck VolumePath.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Drive;
914c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes,
915c2c66affSColin Finck &VolumePath,
916c2c66affSColin Finck OBJ_CASE_INSENSITIVE,
917c2c66affSColin Finck NULL,
918c2c66affSColin Finck NULL);
919c2c66affSColin Finck Status = NtOpenFile(&VolumeHandle,
920c2c66affSColin Finck FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
921c2c66affSColin Finck &ObjectAttributes,
922c2c66affSColin Finck &IoStatusBlock,
923c2c66affSColin Finck FILE_SHARE_READ | FILE_SHARE_WRITE,
924c2c66affSColin Finck FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
925c2c66affSColin Finck if (!NT_SUCCESS(Status))
926c2c66affSColin Finck {
927c2c66affSColin Finck /* Skip the volume if we failed */
928c2c66affSColin Finck DPRINT1("SMSS:PFILE: Open volume `%wZ' failed with status %X\n",
929c2c66affSColin Finck &VolumePath, Status);
930c2c66affSColin Finck continue;
931c2c66affSColin Finck }
932c2c66affSColin Finck
933c2c66affSColin Finck /* Now query device information on the volume */
934c2c66affSColin Finck Status = NtQueryVolumeInformationFile(VolumeHandle,
935c2c66affSColin Finck &IoStatusBlock,
936c2c66affSColin Finck &DeviceInfo,
937c2c66affSColin Finck sizeof(DeviceInfo),
938c2c66affSColin Finck FileFsDeviceInformation);
939c2c66affSColin Finck if (!NT_SUCCESS(Status))
940c2c66affSColin Finck {
941c2c66affSColin Finck /* Move to the next volume if we failed */
942c2c66affSColin Finck DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for device info"
943c2c66affSColin Finck " failed with status %X\n",
944c2c66affSColin Finck &VolumePath,
945c2c66affSColin Finck VolumeHandle,
946c2c66affSColin Finck Status);
947c2c66affSColin Finck NtClose(VolumeHandle);
948c2c66affSColin Finck continue;
949c2c66affSColin Finck }
950c2c66affSColin Finck
951c2c66affSColin Finck /* Check if this is a fixed disk */
952c2c66affSColin Finck if (DeviceInfo.Characteristics & (FILE_FLOPPY_DISKETTE |
953c2c66affSColin Finck FILE_READ_ONLY_DEVICE |
954c2c66affSColin Finck FILE_REMOTE_DEVICE |
955c2c66affSColin Finck FILE_REMOVABLE_MEDIA))
956c2c66affSColin Finck {
957c2c66affSColin Finck /* It isn't, so skip it */
958c2c66affSColin Finck DPRINT1("SMSS:PFILE: Volume `%wZ' (%X) cannot store a paging file\n",
959c2c66affSColin Finck &VolumePath,
960c2c66affSColin Finck DeviceInfo.Characteristics);
961c2c66affSColin Finck NtClose(VolumeHandle);
962c2c66affSColin Finck continue;
963c2c66affSColin Finck }
964c2c66affSColin Finck
965c2c66affSColin Finck /* We found a fixed volume, allocate a descriptor for it */
966c2c66affSColin Finck Volume = RtlAllocateHeap(RtlGetProcessHeap(),
967c2c66affSColin Finck HEAP_ZERO_MEMORY,
968c2c66affSColin Finck sizeof(SMP_VOLUME_DESCRIPTOR));
969c2c66affSColin Finck if (!Volume)
970c2c66affSColin Finck {
971c2c66affSColin Finck /* Failed to allocate memory, try the next disk */
972c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to allocate a volume descriptor (%u bytes)\n",
973c2c66affSColin Finck sizeof(SMP_VOLUME_DESCRIPTOR));
974c2c66affSColin Finck NtClose(VolumeHandle);
975c2c66affSColin Finck continue;
976c2c66affSColin Finck }
977c2c66affSColin Finck
978c2c66affSColin Finck /* Save the drive letter and device information */
979c2c66affSColin Finck Volume->DriveLetter = Drive;
980c2c66affSColin Finck Volume->DeviceInfo = DeviceInfo;
981c2c66affSColin Finck
982c2c66affSColin Finck /* Check if this is the boot volume */
983c2c66affSColin Finck if (RtlUpcaseUnicodeChar(Drive) ==
984c2c66affSColin Finck RtlUpcaseUnicodeChar(SharedUserData->NtSystemRoot[0]))
985c2c66affSColin Finck {
986c2c66affSColin Finck /* Save it */
987c2c66affSColin Finck ASSERT(BootVolumeFound == FALSE);
988c2c66affSColin Finck Volume->Flags |= SMP_VOLUME_IS_BOOT;
989c2c66affSColin Finck BootVolumeFound = TRUE;
990c2c66affSColin Finck }
991c2c66affSColin Finck
992c2c66affSColin Finck /* Now get size information on the volume */
993c2c66affSColin Finck Status = NtQueryVolumeInformationFile(VolumeHandle,
994c2c66affSColin Finck &IoStatusBlock,
995c2c66affSColin Finck &SizeInfo,
996c2c66affSColin Finck sizeof(SizeInfo),
997c2c66affSColin Finck FileFsSizeInformation);
998c2c66affSColin Finck if (!NT_SUCCESS(Status))
999c2c66affSColin Finck {
1000c2c66affSColin Finck /* We failed -- keep going */
1001c2c66affSColin Finck DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed"
1002c2c66affSColin Finck " with status %X\n",
1003c2c66affSColin Finck &VolumePath,
1004c2c66affSColin Finck VolumeHandle,
1005c2c66affSColin Finck Status);
1006c2c66affSColin Finck RtlFreeHeap(RtlGetProcessHeap(), 0, Volume);
1007c2c66affSColin Finck NtClose(VolumeHandle);
1008c2c66affSColin Finck continue;
1009c2c66affSColin Finck }
1010c2c66affSColin Finck
1011c2c66affSColin Finck /* Done querying volume information, close the handle */
1012c2c66affSColin Finck NtClose(VolumeHandle);
1013c2c66affSColin Finck
1014c2c66affSColin Finck /* Compute how much free space we have */
1015c2c66affSColin Finck FreeSpace.QuadPart = SizeInfo.AvailableAllocationUnits.QuadPart *
1016c2c66affSColin Finck SizeInfo.SectorsPerAllocationUnit;
1017c2c66affSColin Finck FinalFreeSpace.QuadPart = FreeSpace.QuadPart * SizeInfo.BytesPerSector;
1018c2c66affSColin Finck
10195dc43c0fSHermès Bélusca-Maïto /* Check if there is less than 32 MB free so we don't starve the disk */
1020c2c66affSColin Finck if (FinalFreeSpace.QuadPart <= MINIMUM_TO_KEEP_FREE)
1021c2c66affSColin Finck {
10225dc43c0fSHermès Bélusca-Maïto /* In this case, act as if there is no free space */
1023c2c66affSColin Finck Volume->FreeSpace.QuadPart = 0;
1024c2c66affSColin Finck }
1025c2c66affSColin Finck else
1026c2c66affSColin Finck {
1027c2c66affSColin Finck /* Trim off 32 MB to give the disk a bit of breathing room */
1028c2c66affSColin Finck Volume->FreeSpace.QuadPart = FinalFreeSpace.QuadPart -
1029c2c66affSColin Finck MINIMUM_TO_KEEP_FREE;
1030c2c66affSColin Finck }
1031c2c66affSColin Finck
1032c2c66affSColin Finck /* All done, add this volume to our descriptor list */
1033c2c66affSColin Finck InsertTailList(&SmpVolumeDescriptorList, &Volume->Entry);
1034c2c66affSColin Finck Volume->Flags |= SMP_VOLUME_INSERTED;
1035c2c66affSColin Finck DPRINT("SMSS:PFILE: Created volume descriptor for`%wZ'\n", &VolumePath);
1036c2c66affSColin Finck }
1037c2c66affSColin Finck
1038c2c66affSColin Finck /* We must've found at least the boot volume */
1039c2c66affSColin Finck ASSERT(BootVolumeFound == TRUE);
1040c2c66affSColin Finck ASSERT(!IsListEmpty(&SmpVolumeDescriptorList));
1041c2c66affSColin Finck if (!IsListEmpty(&SmpVolumeDescriptorList)) return STATUS_SUCCESS;
1042c2c66affSColin Finck
1043c2c66affSColin Finck /* Something is really messed up if we found no disks at all */
1044c2c66affSColin Finck return STATUS_UNEXPECTED_IO_ERROR;
1045c2c66affSColin Finck }
1046c2c66affSColin Finck
1047c2c66affSColin Finck NTSTATUS
1048c2c66affSColin Finck NTAPI
SmpCreatePagingFiles(VOID)1049c2c66affSColin Finck SmpCreatePagingFiles(VOID)
1050c2c66affSColin Finck {
1051c2c66affSColin Finck NTSTATUS Status;
1052c2c66affSColin Finck PSMP_PAGEFILE_DESCRIPTOR Descriptor;
1053c2c66affSColin Finck LARGE_INTEGER Size, FuzzFactor;
1054c2c66affSColin Finck BOOLEAN Created = FALSE;
1055c2c66affSColin Finck PLIST_ENTRY NextEntry;
1056c2c66affSColin Finck
1057c2c66affSColin Finck /* Check if no paging files were requested */
1058c2c66affSColin Finck if (!(SmpNumberOfPagingFiles) && !(SmpRegistrySpecifierPresent))
1059c2c66affSColin Finck {
1060c2c66affSColin Finck /* The list should be empty -- nothing to do */
1061c2c66affSColin Finck ASSERT(IsListEmpty(&SmpPagingFileDescriptorList));
1062c2c66affSColin Finck DPRINT1("SMSS:PFILE: No paging file was requested\n");
1063c2c66affSColin Finck return STATUS_SUCCESS;
1064c2c66affSColin Finck }
1065c2c66affSColin Finck
1066c2c66affSColin Finck /* Initialize the volume descriptors so we can know what's available */
1067c2c66affSColin Finck Status = SmpCreateVolumeDescriptors();
1068c2c66affSColin Finck if (!NT_SUCCESS(Status))
1069c2c66affSColin Finck {
1070c2c66affSColin Finck /* We can't make decisions without this, so fail */
1071c2c66affSColin Finck DPRINT1("SMSS:PFILE: Failed to create volume descriptors (status %X)\n",
1072c2c66affSColin Finck Status);
1073c2c66affSColin Finck return Status;
1074c2c66affSColin Finck }
1075c2c66affSColin Finck
1076c2c66affSColin Finck /* If we fail creating pagefiles, try to reduce by this much each time */
1077c2c66affSColin Finck FuzzFactor.QuadPart = FUZZ_FACTOR;
1078c2c66affSColin Finck
1079c2c66affSColin Finck /* Loop the descriptor list */
1080c2c66affSColin Finck NextEntry = SmpPagingFileDescriptorList.Flink;
1081c2c66affSColin Finck while (NextEntry != &SmpPagingFileDescriptorList)
1082c2c66affSColin Finck {
1083c2c66affSColin Finck /* Check what kind of descriptor this is */
1084c2c66affSColin Finck Descriptor = CONTAINING_RECORD(NextEntry, SMP_PAGEFILE_DESCRIPTOR, Entry);
1085c2c66affSColin Finck if (Descriptor->Flags & SMP_PAGEFILE_SYSTEM_MANAGED)
1086c2c66affSColin Finck {
1087c2c66affSColin Finck /* This is a system-managed descriptor. Create the correct file */
1088c2c66affSColin Finck DPRINT("SMSS:PFILE: Creating a system managed paging file (`%wZ')\n",
1089c2c66affSColin Finck &Descriptor->Name);
1090c2c66affSColin Finck Status = SmpCreateSystemManagedPagingFile(Descriptor, FALSE);
1091c2c66affSColin Finck if (!NT_SUCCESS(Status))
1092c2c66affSColin Finck {
1093c2c66affSColin Finck /* We failed -- try again, with size minimization this time */
1094c2c66affSColin Finck DPRINT("SMSS:PFILE: Trying lower sizes for (`%wZ')\n",
1095c2c66affSColin Finck &Descriptor->Name);
1096c2c66affSColin Finck Status = SmpCreateSystemManagedPagingFile(Descriptor, TRUE);
1097c2c66affSColin Finck }
1098c2c66affSColin Finck }
1099c2c66affSColin Finck else
1100c2c66affSColin Finck {
1101c2c66affSColin Finck /* This is a manually entered descriptor. Validate its size first */
1102c2c66affSColin Finck SmpValidatePagingFileSizes(Descriptor);
1103c2c66affSColin Finck
1104c2c66affSColin Finck /* Check if this is an ANY pagefile or a FIXED pagefile */
1105c2c66affSColin Finck DPRINT("SMSS:PFILE: Creating a normal paging file (`%wZ')\n",
1106c2c66affSColin Finck &Descriptor->Name);
1107c2c66affSColin Finck if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == L'?')
1108c2c66affSColin Finck {
1109c2c66affSColin Finck /* It's an any pagefile, try to create it wherever possible */
1110c2c66affSColin Finck Size = Descriptor->MinSize;
1111c2c66affSColin Finck Status = SmpCreatePagingFileOnAnyDrive(Descriptor,
1112c2c66affSColin Finck &FuzzFactor,
1113c2c66affSColin Finck &Size);
1114c2c66affSColin Finck if (!NT_SUCCESS(Status))
1115c2c66affSColin Finck {
1116c2c66affSColin Finck /* We failed to create it. Try again with a smaller size */
1117c2c66affSColin Finck DPRINT("SMSS:PFILE: Trying lower sizes for (`%wZ')\n",
1118c2c66affSColin Finck &Descriptor->Name);
1119c2c66affSColin Finck Size.QuadPart = 16 * MEGABYTE;
1120c2c66affSColin Finck Status = SmpCreatePagingFileOnAnyDrive(Descriptor,
1121c2c66affSColin Finck &FuzzFactor,
1122c2c66affSColin Finck &Size);
1123c2c66affSColin Finck }
1124c2c66affSColin Finck }
1125c2c66affSColin Finck else
1126c2c66affSColin Finck {
1127c2c66affSColin Finck /* It's a fixed pagefile: override the minimum and use ours */
1128c2c66affSColin Finck Size.QuadPart = 16 * MEGABYTE;
1129c2c66affSColin Finck Status = SmpCreatePagingFileOnFixedDrive(Descriptor,
1130c2c66affSColin Finck &FuzzFactor,
1131c2c66affSColin Finck &Size);
1132c2c66affSColin Finck }
1133c2c66affSColin Finck }
1134c2c66affSColin Finck
1135c2c66affSColin Finck /* Go to the next descriptor */
1136c2c66affSColin Finck if (NT_SUCCESS(Status)) Created = TRUE;
1137c2c66affSColin Finck NextEntry = NextEntry->Flink;
1138c2c66affSColin Finck }
1139c2c66affSColin Finck
1140c2c66affSColin Finck /* Check if none of the code in our loops above was able to create it */
1141c2c66affSColin Finck if (!Created)
1142c2c66affSColin Finck {
1143c2c66affSColin Finck /* Build an emergency pagefile ourselves */
1144c2c66affSColin Finck DPRINT1("SMSS:PFILE: Creating emergency paging file.\n");
1145c2c66affSColin Finck Status = SmpCreateEmergencyPagingFile();
1146c2c66affSColin Finck }
1147c2c66affSColin Finck
1148c2c66affSColin Finck /* All done */
1149c2c66affSColin Finck return Status;
1150c2c66affSColin Finck }
1151