xref: /reactos/base/system/smss/pagefile.c (revision bcb9abc1)
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