xref: /reactos/ntoskrnl/mm/pagefile.c (revision e392bdf9)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  *  ReactOS kernel
3c2c66affSColin Finck  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4c2c66affSColin Finck  *
5c2c66affSColin Finck  *  This program is free software; you can redistribute it and/or modify
6c2c66affSColin Finck  *  it under the terms of the GNU General Public License as published by
7c2c66affSColin Finck  *  the Free Software Foundation; either version 2 of the License, or
8c2c66affSColin Finck  *  (at your option) any later version.
9c2c66affSColin Finck  *
10c2c66affSColin Finck  *  This program is distributed in the hope that it will be useful,
11c2c66affSColin Finck  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12c2c66affSColin Finck  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13c2c66affSColin Finck  *  GNU General Public License for more details.
14c2c66affSColin Finck  *
15c2c66affSColin Finck  *  You should have received a copy of the GNU General Public License along
16c2c66affSColin Finck  *  with this program; if not, write to the Free Software Foundation, Inc.,
17c2c66affSColin Finck  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18c2c66affSColin Finck  */
19c2c66affSColin Finck /*
20c2c66affSColin Finck  * PROJECT:         ReactOS kernel
21c2c66affSColin Finck  * FILE:            ntoskrnl/mm/pagefile.c
22c2c66affSColin Finck  * PURPOSE:         Paging file functions
23c2c66affSColin Finck  * PROGRAMMER:      David Welch (welch@mcmail.com)
2402b0ca08SPierre Schweitzer  *                  Pierre Schweitzer
25c2c66affSColin Finck  * UPDATE HISTORY:
26c2c66affSColin Finck  *                  Created 22/05/98
27c2c66affSColin Finck  */
28c2c66affSColin Finck 
29c2c66affSColin Finck /* INCLUDES *****************************************************************/
30c2c66affSColin Finck 
31c2c66affSColin Finck #include <ntoskrnl.h>
32c2c66affSColin Finck #define NDEBUG
33c2c66affSColin Finck #include <debug.h>
34c2c66affSColin Finck 
35c2c66affSColin Finck #if defined (ALLOC_PRAGMA)
36c2c66affSColin Finck #pragma alloc_text(INIT, MmInitPagingFile)
37c2c66affSColin Finck #endif
38c2c66affSColin Finck 
39c2c66affSColin Finck /* GLOBALS *******************************************************************/
40c2c66affSColin Finck 
41c2c66affSColin Finck #define PAIRS_PER_RUN (1024)
42c2c66affSColin Finck 
43c2c66affSColin Finck /* List of paging files, both used and free */
443814a822SPierre Schweitzer PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES];
45c2c66affSColin Finck 
46c2c66affSColin Finck /* Lock for examining the list of paging files */
47315867d4SPierre Schweitzer KGUARDED_MUTEX MmPageFileCreationLock;
48c2c66affSColin Finck 
49c2c66affSColin Finck /* Number of paging files */
50c2c66affSColin Finck ULONG MmNumberOfPagingFiles;
51c2c66affSColin Finck 
52c2c66affSColin Finck /* Number of pages that are available for swapping */
53c2c66affSColin Finck PFN_COUNT MiFreeSwapPages;
54c2c66affSColin Finck 
55c2c66affSColin Finck /* Number of pages that have been allocated for swapping */
56c2c66affSColin Finck PFN_COUNT MiUsedSwapPages;
57c2c66affSColin Finck 
58c2c66affSColin Finck BOOLEAN MmZeroPageFile;
59c2c66affSColin Finck 
60c2c66affSColin Finck /*
61c2c66affSColin Finck  * Number of pages that have been reserved for swapping but not yet allocated
62c2c66affSColin Finck  */
63c2c66affSColin Finck static PFN_COUNT MiReservedSwapPages;
64c2c66affSColin Finck 
65c2c66affSColin Finck /*
66c2c66affSColin Finck  * Ratio between reserved and available swap pages, e.g. setting this to five
67c2c66affSColin Finck  * forces one swap page to be available for every five swap pages that are
68c2c66affSColin Finck  * reserved. Setting this to zero turns off commit checking altogether.
69c2c66affSColin Finck  */
70c2c66affSColin Finck #define MM_PAGEFILE_COMMIT_RATIO      (1)
71c2c66affSColin Finck 
72c2c66affSColin Finck /*
73c2c66affSColin Finck  * Number of pages that can be used for potentially swapable memory without
74c2c66affSColin Finck  * pagefile space being reserved. The intention is that this allows smss
75c2c66affSColin Finck  * to start up and create page files while ordinarily having a commit
76c2c66affSColin Finck  * ratio of one.
77c2c66affSColin Finck  */
78c2c66affSColin Finck #define MM_PAGEFILE_COMMIT_GRACE      (256)
79c2c66affSColin Finck 
80c2c66affSColin Finck /*
81c2c66affSColin Finck  * Translate between a swap entry and a file and offset pair.
82c2c66affSColin Finck  */
83c2c66affSColin Finck #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
84c2c66affSColin Finck #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
85c2c66affSColin Finck #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
86c2c66affSColin Finck 
87c2c66affSColin Finck /* Make sure there can be only 16 paging files */
88c2c66affSColin Finck C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES);
89c2c66affSColin Finck 
90c2c66affSColin Finck static BOOLEAN MmSwapSpaceMessage = FALSE;
91c2c66affSColin Finck 
92c2c66affSColin Finck /* FUNCTIONS *****************************************************************/
93c2c66affSColin Finck 
94c2c66affSColin Finck VOID
95c2c66affSColin Finck NTAPI
96c2c66affSColin Finck MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages)
97c2c66affSColin Finck {
98c2c66affSColin Finck     memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE));
99c2c66affSColin Finck 
100c2c66affSColin Finck     /* FIXME: this flag should be set by the caller perhaps? */
101c2c66affSColin Finck     Mdl->MdlFlags |= MDL_IO_PAGE_READ;
102c2c66affSColin Finck }
103c2c66affSColin Finck 
104c2c66affSColin Finck 
105c2c66affSColin Finck BOOLEAN
106c2c66affSColin Finck NTAPI
107c2c66affSColin Finck MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject)
108c2c66affSColin Finck {
109c2c66affSColin Finck     ULONG i;
110c2c66affSColin Finck 
111c2c66affSColin Finck     /* Loop through all the paging files */
112c2c66affSColin Finck     for (i = 0; i < MmNumberOfPagingFiles; i++)
113c2c66affSColin Finck     {
114c2c66affSColin Finck         /* Check if this is one of them */
115f106c297SPierre Schweitzer         if (MmPagingFile[i]->FileObject == FileObject) return TRUE;
116c2c66affSColin Finck     }
117c2c66affSColin Finck 
118c2c66affSColin Finck     /* Nothing found */
119c2c66affSColin Finck     return FALSE;
120c2c66affSColin Finck }
121c2c66affSColin Finck 
122c2c66affSColin Finck VOID
123c2c66affSColin Finck NTAPI
124c2c66affSColin Finck MmShowOutOfSpaceMessagePagingFile(VOID)
125c2c66affSColin Finck {
126c2c66affSColin Finck     if (!MmSwapSpaceMessage)
127c2c66affSColin Finck     {
128c2c66affSColin Finck         DPRINT1("MM: Out of swap space.\n");
129c2c66affSColin Finck         MmSwapSpaceMessage = TRUE;
130c2c66affSColin Finck     }
131c2c66affSColin Finck }
132c2c66affSColin Finck 
133c2c66affSColin Finck NTSTATUS
134c2c66affSColin Finck NTAPI
135c2c66affSColin Finck MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
136c2c66affSColin Finck {
137c2c66affSColin Finck     ULONG i;
138c2c66affSColin Finck     ULONG_PTR offset;
139c2c66affSColin Finck     LARGE_INTEGER file_offset;
140c2c66affSColin Finck     IO_STATUS_BLOCK Iosb;
141c2c66affSColin Finck     NTSTATUS Status;
142c2c66affSColin Finck     KEVENT Event;
143c2c66affSColin Finck     UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
144c2c66affSColin Finck     PMDL Mdl = (PMDL)MdlBase;
145c2c66affSColin Finck 
146c2c66affSColin Finck     DPRINT("MmWriteToSwapPage\n");
147c2c66affSColin Finck 
148c2c66affSColin Finck     if (SwapEntry == 0)
149c2c66affSColin Finck     {
150c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
151c2c66affSColin Finck         return(STATUS_UNSUCCESSFUL);
152c2c66affSColin Finck     }
153c2c66affSColin Finck 
154c2c66affSColin Finck     i = FILE_FROM_ENTRY(SwapEntry);
155c2c66affSColin Finck     offset = OFFSET_FROM_ENTRY(SwapEntry) - 1;
156c2c66affSColin Finck 
157f106c297SPierre Schweitzer     if (MmPagingFile[i]->FileObject == NULL ||
158f106c297SPierre Schweitzer             MmPagingFile[i]->FileObject->DeviceObject == NULL)
159c2c66affSColin Finck     {
160c2c66affSColin Finck         DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
161c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
162c2c66affSColin Finck     }
163c2c66affSColin Finck 
164c2c66affSColin Finck     MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
165c2c66affSColin Finck     MmBuildMdlFromPages(Mdl, &Page);
166c2c66affSColin Finck     Mdl->MdlFlags |= MDL_PAGES_LOCKED;
167c2c66affSColin Finck 
168c2c66affSColin Finck     file_offset.QuadPart = offset * PAGE_SIZE;
169c2c66affSColin Finck 
170c2c66affSColin Finck     KeInitializeEvent(&Event, NotificationEvent, FALSE);
171f106c297SPierre Schweitzer     Status = IoSynchronousPageWrite(MmPagingFile[i]->FileObject,
172c2c66affSColin Finck                                     Mdl,
173c2c66affSColin Finck                                     &file_offset,
174c2c66affSColin Finck                                     &Event,
175c2c66affSColin Finck                                     &Iosb);
176c2c66affSColin Finck     if (Status == STATUS_PENDING)
177c2c66affSColin Finck     {
178c2c66affSColin Finck         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
179c2c66affSColin Finck         Status = Iosb.Status;
180c2c66affSColin Finck     }
181c2c66affSColin Finck 
182c2c66affSColin Finck     if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
183c2c66affSColin Finck     {
184c2c66affSColin Finck         MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
185c2c66affSColin Finck     }
186c2c66affSColin Finck     return(Status);
187c2c66affSColin Finck }
188c2c66affSColin Finck 
189c2c66affSColin Finck 
190c2c66affSColin Finck NTSTATUS
191c2c66affSColin Finck NTAPI
192c2c66affSColin Finck MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
193c2c66affSColin Finck {
194c2c66affSColin Finck     return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry) - 1);
195c2c66affSColin Finck }
196c2c66affSColin Finck 
197c2c66affSColin Finck NTSTATUS
198c2c66affSColin Finck NTAPI
199c2c66affSColin Finck MiReadPageFile(
200c2c66affSColin Finck     _In_ PFN_NUMBER Page,
201c2c66affSColin Finck     _In_ ULONG PageFileIndex,
202c2c66affSColin Finck     _In_ ULONG_PTR PageFileOffset)
203c2c66affSColin Finck {
204c2c66affSColin Finck     LARGE_INTEGER file_offset;
205c2c66affSColin Finck     IO_STATUS_BLOCK Iosb;
206c2c66affSColin Finck     NTSTATUS Status;
207c2c66affSColin Finck     KEVENT Event;
208c2c66affSColin Finck     UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
209c2c66affSColin Finck     PMDL Mdl = (PMDL)MdlBase;
21002b0ca08SPierre Schweitzer     PMMPAGING_FILE PagingFile;
211c2c66affSColin Finck 
212c2c66affSColin Finck     DPRINT("MiReadSwapFile\n");
213c2c66affSColin Finck 
214c2c66affSColin Finck     if (PageFileOffset == 0)
215c2c66affSColin Finck     {
216c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
217c2c66affSColin Finck         return(STATUS_UNSUCCESSFUL);
218c2c66affSColin Finck     }
219c2c66affSColin Finck 
220c2c66affSColin Finck     ASSERT(PageFileIndex < MAX_PAGING_FILES);
221c2c66affSColin Finck 
222f106c297SPierre Schweitzer     PagingFile = MmPagingFile[PageFileIndex];
223c2c66affSColin Finck 
224c2c66affSColin Finck     if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL)
225c2c66affSColin Finck     {
226c2c66affSColin Finck         DPRINT1("Bad paging file %u\n", PageFileIndex);
227c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
228c2c66affSColin Finck     }
229c2c66affSColin Finck 
230c2c66affSColin Finck     MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
231c2c66affSColin Finck     MmBuildMdlFromPages(Mdl, &Page);
232c2c66affSColin Finck     Mdl->MdlFlags |= MDL_PAGES_LOCKED;
233c2c66affSColin Finck 
234c2c66affSColin Finck     file_offset.QuadPart = PageFileOffset * PAGE_SIZE;
235c2c66affSColin Finck 
236c2c66affSColin Finck     KeInitializeEvent(&Event, NotificationEvent, FALSE);
237c2c66affSColin Finck     Status = IoPageRead(PagingFile->FileObject,
238c2c66affSColin Finck                         Mdl,
239c2c66affSColin Finck                         &file_offset,
240c2c66affSColin Finck                         &Event,
241c2c66affSColin Finck                         &Iosb);
242c2c66affSColin Finck     if (Status == STATUS_PENDING)
243c2c66affSColin Finck     {
244c2c66affSColin Finck         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
245c2c66affSColin Finck         Status = Iosb.Status;
246c2c66affSColin Finck     }
247c2c66affSColin Finck     if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
248c2c66affSColin Finck     {
249c2c66affSColin Finck         MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
250c2c66affSColin Finck     }
251c2c66affSColin Finck     return(Status);
252c2c66affSColin Finck }
253c2c66affSColin Finck 
254c2c66affSColin Finck VOID
255c2c66affSColin Finck INIT_FUNCTION
256c2c66affSColin Finck NTAPI
257c2c66affSColin Finck MmInitPagingFile(VOID)
258c2c66affSColin Finck {
259c2c66affSColin Finck     ULONG i;
260c2c66affSColin Finck 
261315867d4SPierre Schweitzer     KeInitializeGuardedMutex(&MmPageFileCreationLock);
262c2c66affSColin Finck 
263c2c66affSColin Finck     MiFreeSwapPages = 0;
264c2c66affSColin Finck     MiUsedSwapPages = 0;
265c2c66affSColin Finck     MiReservedSwapPages = 0;
266c2c66affSColin Finck 
267c2c66affSColin Finck     for (i = 0; i < MAX_PAGING_FILES; i++)
268c2c66affSColin Finck     {
269f106c297SPierre Schweitzer         MmPagingFile[i] = NULL;
270c2c66affSColin Finck     }
271c2c66affSColin Finck     MmNumberOfPagingFiles = 0;
272c2c66affSColin Finck }
273c2c66affSColin Finck 
274c2c66affSColin Finck VOID
275c2c66affSColin Finck NTAPI
276c2c66affSColin Finck MmFreeSwapPage(SWAPENTRY Entry)
277c2c66affSColin Finck {
278c2c66affSColin Finck     ULONG i;
279c2c66affSColin Finck     ULONG_PTR off;
28002b0ca08SPierre Schweitzer     PMMPAGING_FILE PagingFile;
281c2c66affSColin Finck 
282c2c66affSColin Finck     i = FILE_FROM_ENTRY(Entry);
283c2c66affSColin Finck     off = OFFSET_FROM_ENTRY(Entry) - 1;
284c2c66affSColin Finck 
285315867d4SPierre Schweitzer     KeAcquireGuardedMutex(&MmPageFileCreationLock);
286f106c297SPierre Schweitzer 
287f106c297SPierre Schweitzer     PagingFile = MmPagingFile[i];
288f106c297SPierre Schweitzer     if (PagingFile == NULL)
289c2c66affSColin Finck     {
290c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
291c2c66affSColin Finck     }
292c2c66affSColin Finck 
293f106c297SPierre Schweitzer     RtlClearBit(PagingFile->AllocMap, off >> 5);
294c2c66affSColin Finck 
295f106c297SPierre Schweitzer     PagingFile->FreePages++;
296f106c297SPierre Schweitzer     PagingFile->UsedPages--;
297c2c66affSColin Finck 
298c2c66affSColin Finck     MiFreeSwapPages++;
299c2c66affSColin Finck     MiUsedSwapPages--;
300c2c66affSColin Finck 
301315867d4SPierre Schweitzer     KeReleaseGuardedMutex(&MmPageFileCreationLock);
302c2c66affSColin Finck }
303c2c66affSColin Finck 
304c2c66affSColin Finck SWAPENTRY
305c2c66affSColin Finck NTAPI
306c2c66affSColin Finck MmAllocSwapPage(VOID)
307c2c66affSColin Finck {
308c2c66affSColin Finck     ULONG i;
309c2c66affSColin Finck     ULONG off;
310c2c66affSColin Finck     SWAPENTRY entry;
311c2c66affSColin Finck 
312315867d4SPierre Schweitzer     KeAcquireGuardedMutex(&MmPageFileCreationLock);
313c2c66affSColin Finck 
314c2c66affSColin Finck     if (MiFreeSwapPages == 0)
315c2c66affSColin Finck     {
316315867d4SPierre Schweitzer         KeReleaseGuardedMutex(&MmPageFileCreationLock);
317c2c66affSColin Finck         return(0);
318c2c66affSColin Finck     }
319c2c66affSColin Finck 
320c2c66affSColin Finck     for (i = 0; i < MAX_PAGING_FILES; i++)
321c2c66affSColin Finck     {
322f106c297SPierre Schweitzer         if (MmPagingFile[i] != NULL &&
323f106c297SPierre Schweitzer                 MmPagingFile[i]->FreePages >= 1)
324c2c66affSColin Finck         {
325891a6eeeSPierre Schweitzer             off = RtlFindClearBitsAndSet(MmPagingFile[i]->AllocMap, 1, 0);
326c2c66affSColin Finck             if (off == 0xFFFFFFFF)
327c2c66affSColin Finck             {
328c2c66affSColin Finck                 KeBugCheck(MEMORY_MANAGEMENT);
329315867d4SPierre Schweitzer                 KeReleaseGuardedMutex(&MmPageFileCreationLock);
330c2c66affSColin Finck                 return(STATUS_UNSUCCESSFUL);
331c2c66affSColin Finck             }
332c2c66affSColin Finck             MiUsedSwapPages++;
333c2c66affSColin Finck             MiFreeSwapPages--;
334315867d4SPierre Schweitzer             KeReleaseGuardedMutex(&MmPageFileCreationLock);
335c2c66affSColin Finck 
336c2c66affSColin Finck             entry = ENTRY_FROM_FILE_OFFSET(i, off + 1);
337c2c66affSColin Finck             return(entry);
338c2c66affSColin Finck         }
339c2c66affSColin Finck     }
340c2c66affSColin Finck 
341315867d4SPierre Schweitzer     KeReleaseGuardedMutex(&MmPageFileCreationLock);
342c2c66affSColin Finck     KeBugCheck(MEMORY_MANAGEMENT);
343c2c66affSColin Finck     return(0);
344c2c66affSColin Finck }
345c2c66affSColin Finck 
346c2c66affSColin Finck NTSTATUS NTAPI
347c2c66affSColin Finck NtCreatePagingFile(IN PUNICODE_STRING FileName,
348bfc6a795SPierre Schweitzer                    IN PLARGE_INTEGER MinimumSize,
349c2c66affSColin Finck                    IN PLARGE_INTEGER MaximumSize,
350c2c66affSColin Finck                    IN ULONG Reserved)
351c2c66affSColin Finck {
352c2c66affSColin Finck     NTSTATUS Status;
353c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
354c2c66affSColin Finck     HANDLE FileHandle;
355c2c66affSColin Finck     IO_STATUS_BLOCK IoStatus;
356c2c66affSColin Finck     PFILE_OBJECT FileObject;
35702b0ca08SPierre Schweitzer     PMMPAGING_FILE PagingFile;
358c2c66affSColin Finck     ULONG AllocMapSize;
359c2c66affSColin Finck     ULONG Count;
360c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode;
36134e8f451SPierre Schweitzer     UNICODE_STRING PageFileName;
362bfc6a795SPierre Schweitzer     LARGE_INTEGER SafeMinimumSize, SafeMaximumSize, AllocationSize;
36336c20dc5SPierre Schweitzer     FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
36428b4b419SPierre Schweitzer     SECURITY_DESCRIPTOR SecurityDescriptor;
36528b4b419SPierre Schweitzer     PACL Dacl;
36634e8f451SPierre Schweitzer     PWSTR Buffer;
367c2c66affSColin Finck 
368bfc6a795SPierre Schweitzer     DPRINT("NtCreatePagingFile(FileName %wZ, MinimumSize %I64d)\n",
369bfc6a795SPierre Schweitzer            FileName, MinimumSize->QuadPart);
370c2c66affSColin Finck 
371315867d4SPierre Schweitzer     PAGED_CODE();
372315867d4SPierre Schweitzer 
373c2c66affSColin Finck     if (MmNumberOfPagingFiles >= MAX_PAGING_FILES)
374c2c66affSColin Finck     {
3750ad4ef60SPierre Schweitzer         return STATUS_TOO_MANY_PAGING_FILES;
376c2c66affSColin Finck     }
377c2c66affSColin Finck 
378c2c66affSColin Finck     PreviousMode = ExGetPreviousMode();
379c2c66affSColin Finck 
380c2c66affSColin Finck     if (PreviousMode != KernelMode)
381c2c66affSColin Finck     {
3820ad4ef60SPierre Schweitzer         if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege, PreviousMode) != TRUE)
3830ad4ef60SPierre Schweitzer         {
3840ad4ef60SPierre Schweitzer             return STATUS_PRIVILEGE_NOT_HELD;
3850ad4ef60SPierre Schweitzer         }
3860ad4ef60SPierre Schweitzer 
387c2c66affSColin Finck         _SEH2_TRY
388c2c66affSColin Finck         {
389bfc6a795SPierre Schweitzer             SafeMinimumSize = ProbeForReadLargeInteger(MinimumSize);
390c2c66affSColin Finck             SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
39134e8f451SPierre Schweitzer 
39234e8f451SPierre Schweitzer             PageFileName.Length = FileName->Length;
39334e8f451SPierre Schweitzer             PageFileName.MaximumLength = FileName->MaximumLength;
39434e8f451SPierre Schweitzer             PageFileName.Buffer = FileName->Buffer;
395c2c66affSColin Finck         }
396c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
397c2c66affSColin Finck         {
398c2c66affSColin Finck             /* Return the exception code */
399c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
400c2c66affSColin Finck         }
401c2c66affSColin Finck         _SEH2_END;
402c2c66affSColin Finck     }
403c2c66affSColin Finck     else
404c2c66affSColin Finck     {
405bfc6a795SPierre Schweitzer         SafeMinimumSize = *MinimumSize;
406c2c66affSColin Finck         SafeMaximumSize = *MaximumSize;
40734e8f451SPierre Schweitzer 
40834e8f451SPierre Schweitzer         PageFileName.Length = FileName->Length;
40934e8f451SPierre Schweitzer         PageFileName.MaximumLength = FileName->MaximumLength;
41034e8f451SPierre Schweitzer         PageFileName.Buffer = FileName->Buffer;
411c2c66affSColin Finck     }
412c2c66affSColin Finck 
413c2c66affSColin Finck     /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
414c2c66affSColin Finck        smaller than the maximum */
415bfc6a795SPierre Schweitzer     if (0 != SafeMinimumSize.u.HighPart)
416c2c66affSColin Finck     {
417c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_2;
418c2c66affSColin Finck     }
419c2c66affSColin Finck     if (0 != SafeMaximumSize.u.HighPart)
420c2c66affSColin Finck     {
421c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_3;
422c2c66affSColin Finck     }
423bfc6a795SPierre Schweitzer     if (SafeMaximumSize.u.LowPart < SafeMinimumSize.u.LowPart)
424c2c66affSColin Finck     {
425c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_MIX;
426c2c66affSColin Finck     }
427c2c66affSColin Finck 
42834e8f451SPierre Schweitzer     /* Validate name length */
42934e8f451SPierre Schweitzer     if (PageFileName.Length > 128 * sizeof(WCHAR))
430c2c66affSColin Finck     {
43134e8f451SPierre Schweitzer         return STATUS_OBJECT_NAME_INVALID;
432c2c66affSColin Finck     }
433c2c66affSColin Finck 
43434e8f451SPierre Schweitzer     /* We won't care about any potential UNICODE_NULL */
43534e8f451SPierre Schweitzer     PageFileName.MaximumLength = PageFileName.Length;
43634e8f451SPierre Schweitzer     /* Allocate a buffer to keep name copy */
43734e8f451SPierre Schweitzer     Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM);
43834e8f451SPierre Schweitzer     if (Buffer == NULL)
43934e8f451SPierre Schweitzer     {
44034e8f451SPierre Schweitzer         return STATUS_INSUFFICIENT_RESOURCES;
44134e8f451SPierre Schweitzer     }
44234e8f451SPierre Schweitzer 
44334e8f451SPierre Schweitzer     /* Copy name */
44434e8f451SPierre Schweitzer     if (PreviousMode != KernelMode)
44534e8f451SPierre Schweitzer     {
44634e8f451SPierre Schweitzer         _SEH2_TRY
44734e8f451SPierre Schweitzer         {
44834e8f451SPierre Schweitzer             if (PageFileName.Length != 0)
44934e8f451SPierre Schweitzer             {
45034e8f451SPierre Schweitzer                 ProbeForRead(PageFileName.Buffer, PageFileName.Length, sizeof(WCHAR));
45134e8f451SPierre Schweitzer             }
45234e8f451SPierre Schweitzer 
45334e8f451SPierre Schweitzer             RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
45434e8f451SPierre Schweitzer         }
45534e8f451SPierre Schweitzer         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
45634e8f451SPierre Schweitzer         {
45734e8f451SPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
45834e8f451SPierre Schweitzer 
45934e8f451SPierre Schweitzer             /* Return the exception code */
46034e8f451SPierre Schweitzer             _SEH2_YIELD(return _SEH2_GetExceptionCode());
46134e8f451SPierre Schweitzer         }
46234e8f451SPierre Schweitzer         _SEH2_END;
46334e8f451SPierre Schweitzer     }
46434e8f451SPierre Schweitzer     else
46534e8f451SPierre Schweitzer     {
46634e8f451SPierre Schweitzer         RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
46734e8f451SPierre Schweitzer     }
46834e8f451SPierre Schweitzer 
46934e8f451SPierre Schweitzer     /* Erase caller's buffer with ours */
47034e8f451SPierre Schweitzer     PageFileName.Buffer = Buffer;
47134e8f451SPierre Schweitzer 
47228b4b419SPierre Schweitzer     /* Create the security descriptor for the page file */
47328b4b419SPierre Schweitzer     Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
47428b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
47528b4b419SPierre Schweitzer     {
47634e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
47728b4b419SPierre Schweitzer         return Status;
47828b4b419SPierre Schweitzer     }
47928b4b419SPierre Schweitzer 
48028b4b419SPierre Schweitzer     /* Create the DACL: we will only allow two SIDs */
48128b4b419SPierre Schweitzer     Count = sizeof(ACL) + (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
48228b4b419SPierre Schweitzer                           (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
48328b4b419SPierre Schweitzer     Dacl = ExAllocatePoolWithTag(PagedPool, Count, 'lcaD');
48428b4b419SPierre Schweitzer     if (Dacl == NULL)
48528b4b419SPierre Schweitzer     {
48634e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
48728b4b419SPierre Schweitzer         return STATUS_INSUFFICIENT_RESOURCES;
48828b4b419SPierre Schweitzer     }
48928b4b419SPierre Schweitzer 
49028b4b419SPierre Schweitzer     /* Initialize the DACL */
49128b4b419SPierre Schweitzer     Status = RtlCreateAcl(Dacl, Count, ACL_REVISION);
49228b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
49328b4b419SPierre Schweitzer     {
49428b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
49534e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
49628b4b419SPierre Schweitzer         return Status;
49728b4b419SPierre Schweitzer     }
49828b4b419SPierre Schweitzer 
49928b4b419SPierre Schweitzer     /* Grant full access to admins */
50028b4b419SPierre Schweitzer     Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid);
50128b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
50228b4b419SPierre Schweitzer     {
50328b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
50434e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
50528b4b419SPierre Schweitzer         return Status;
50628b4b419SPierre Schweitzer     }
50728b4b419SPierre Schweitzer 
50828b4b419SPierre Schweitzer     /* Grant full access to SYSTEM */
50928b4b419SPierre Schweitzer     Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid);
51028b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
51128b4b419SPierre Schweitzer     {
51228b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
51334e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
51428b4b419SPierre Schweitzer         return Status;
51528b4b419SPierre Schweitzer     }
51628b4b419SPierre Schweitzer 
51728b4b419SPierre Schweitzer     /* Attach the DACL to the security descriptor */
51828b4b419SPierre Schweitzer     Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE);
51928b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
52028b4b419SPierre Schweitzer     {
52128b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
52234e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
52328b4b419SPierre Schweitzer         return Status;
52428b4b419SPierre Schweitzer     }
52528b4b419SPierre Schweitzer 
526c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
52734e8f451SPierre Schweitzer                                &PageFileName,
528c2c66affSColin Finck                                OBJ_KERNEL_HANDLE,
529c2c66affSColin Finck                                NULL,
53028b4b419SPierre Schweitzer                                &SecurityDescriptor);
531c2c66affSColin Finck 
5322969c28aSPierre Schweitzer     /* Make sure we can at least store a complete page:
5332969c28aSPierre Schweitzer      * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
5342969c28aSPierre Schweitzer      * a problem if the paging file is fragmented. Suppose the first cluster
5352969c28aSPierre Schweitzer      * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
5362969c28aSPierre Schweitzer      * paging file but of another file. We can't write a complete page (4096
5372969c28aSPierre Schweitzer      * bytes) to the physical location of cluster 3042 then. */
538bfc6a795SPierre Schweitzer     AllocationSize.QuadPart = SafeMinimumSize.QuadPart + PAGE_SIZE;
5392969c28aSPierre Schweitzer 
5402969c28aSPierre Schweitzer     /* First, attempt to replace the page file, if existing */
541c2c66affSColin Finck     Status = IoCreateFile(&FileHandle,
5422969c28aSPierre Schweitzer                           SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA,
543c2c66affSColin Finck                           &ObjectAttributes,
544c2c66affSColin Finck                           &IoStatus,
5452969c28aSPierre Schweitzer                           &AllocationSize,
5462969c28aSPierre Schweitzer                           FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5472969c28aSPierre Schweitzer                           FILE_SHARE_WRITE,
5482969c28aSPierre Schweitzer                           FILE_SUPERSEDE,
5492969c28aSPierre Schweitzer                           FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
550c2c66affSColin Finck                           NULL,
551c2c66affSColin Finck                           0,
552c2c66affSColin Finck                           CreateFileTypeNone,
553c2c66affSColin Finck                           NULL,
554c2c66affSColin Finck                           SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
5552969c28aSPierre Schweitzer     /* If we failed, relax a bit constraints, someone may be already holding the
5562969c28aSPierre Schweitzer      * the file, so share write, don't attempt to replace and don't delete on close
5572969c28aSPierre Schweitzer      * (basically, don't do anything conflicting)
5585bd938bdSPierre Schweitzer      * This can happen if the caller attempts to extend a page file.
5592969c28aSPierre Schweitzer      */
5602969c28aSPierre Schweitzer     if (!NT_SUCCESS(Status))
5612969c28aSPierre Schweitzer     {
5625bd938bdSPierre Schweitzer         ULONG i;
5635bd938bdSPierre Schweitzer 
5642969c28aSPierre Schweitzer         Status = IoCreateFile(&FileHandle,
5652969c28aSPierre Schweitzer                               SYNCHRONIZE | FILE_WRITE_DATA,
5662969c28aSPierre Schweitzer                               &ObjectAttributes,
5672969c28aSPierre Schweitzer                               &IoStatus,
5682969c28aSPierre Schweitzer                               &AllocationSize,
5692969c28aSPierre Schweitzer                               FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5702969c28aSPierre Schweitzer                               FILE_SHARE_WRITE | FILE_SHARE_READ,
5712969c28aSPierre Schweitzer                               FILE_OPEN,
5722969c28aSPierre Schweitzer                               FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
5732969c28aSPierre Schweitzer                               NULL,
5742969c28aSPierre Schweitzer                               0,
5752969c28aSPierre Schweitzer                               CreateFileTypeNone,
5762969c28aSPierre Schweitzer                               NULL,
5772969c28aSPierre Schweitzer                               SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
5785bd938bdSPierre Schweitzer         if (!NT_SUCCESS(Status))
5795bd938bdSPierre Schweitzer         {
5805bd938bdSPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
5815bd938bdSPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
5825bd938bdSPierre Schweitzer             return Status;
5835bd938bdSPierre Schweitzer         }
5845bd938bdSPierre Schweitzer 
5855bd938bdSPierre Schweitzer         /* We opened it! Check we are that "someone" ;-)
5865bd938bdSPierre Schweitzer          * First, get the opened file object.
5875bd938bdSPierre Schweitzer          */
5885bd938bdSPierre Schweitzer         Status = ObReferenceObjectByHandle(FileHandle,
5895bd938bdSPierre Schweitzer                                            FILE_READ_DATA | FILE_WRITE_DATA,
5905bd938bdSPierre Schweitzer                                            IoFileObjectType,
5915bd938bdSPierre Schweitzer                                            KernelMode,
5925bd938bdSPierre Schweitzer                                            (PVOID*)&FileObject,
5935bd938bdSPierre Schweitzer                                            NULL);
5945bd938bdSPierre Schweitzer         if (!NT_SUCCESS(Status))
5955bd938bdSPierre Schweitzer         {
5965bd938bdSPierre Schweitzer             ZwClose(FileHandle);
5975bd938bdSPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
5985bd938bdSPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
5995bd938bdSPierre Schweitzer             return Status;
6005bd938bdSPierre Schweitzer         }
6015bd938bdSPierre Schweitzer 
6025bd938bdSPierre Schweitzer         /* Find if it matches a previous page file */
6035bd938bdSPierre Schweitzer         PagingFile = NULL;
604315867d4SPierre Schweitzer 
605315867d4SPierre Schweitzer         /* FIXME: should be calling unsafe instead,
606315867d4SPierre Schweitzer          * we should already be in a guarded region
607315867d4SPierre Schweitzer          */
608315867d4SPierre Schweitzer         KeAcquireGuardedMutex(&MmPageFileCreationLock);
6095bd938bdSPierre Schweitzer         if (MmNumberOfPagingFiles > 0)
6105bd938bdSPierre Schweitzer         {
6115bd938bdSPierre Schweitzer             i = 0;
6125bd938bdSPierre Schweitzer 
6135bd938bdSPierre Schweitzer             while (MmPagingFile[i]->FileObject->SectionObjectPointer != FileObject->SectionObjectPointer)
6145bd938bdSPierre Schweitzer             {
6155bd938bdSPierre Schweitzer                 ++i;
6165bd938bdSPierre Schweitzer                 if (i >= MmNumberOfPagingFiles)
6175bd938bdSPierre Schweitzer                 {
6185bd938bdSPierre Schweitzer                     break;
6195bd938bdSPierre Schweitzer                 }
6205bd938bdSPierre Schweitzer             }
6215bd938bdSPierre Schweitzer 
6225bd938bdSPierre Schweitzer             /* This is the matching page file */
6235bd938bdSPierre Schweitzer             PagingFile = MmPagingFile[i];
6245bd938bdSPierre Schweitzer         }
6255bd938bdSPierre Schweitzer 
6265bd938bdSPierre Schweitzer         /* If we didn't find the page file, fail */
6275bd938bdSPierre Schweitzer         if (PagingFile == NULL)
6285bd938bdSPierre Schweitzer         {
629315867d4SPierre Schweitzer             KeReleaseGuardedMutex(&MmPageFileCreationLock);
6305bd938bdSPierre Schweitzer             ObDereferenceObject(FileObject);
6315bd938bdSPierre Schweitzer             ZwClose(FileHandle);
6325bd938bdSPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
6335bd938bdSPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
6345bd938bdSPierre Schweitzer             return STATUS_NOT_FOUND;
6355bd938bdSPierre Schweitzer         }
6365bd938bdSPierre Schweitzer 
6372fe4e713SPierre Schweitzer         /* Don't allow page file shrinking */
638*e392bdf9SPierre Schweitzer         if (PagingFile->MinimumSize > (SafeMinimumSize.QuadPart >> PAGE_SHIFT))
6392fe4e713SPierre Schweitzer         {
6402fe4e713SPierre Schweitzer             KeReleaseGuardedMutex(&MmPageFileCreationLock);
6412fe4e713SPierre Schweitzer             ObDereferenceObject(FileObject);
6422fe4e713SPierre Schweitzer             ZwClose(FileHandle);
6432fe4e713SPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
6442fe4e713SPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
6452fe4e713SPierre Schweitzer             return STATUS_INVALID_PARAMETER_2;
6462fe4e713SPierre Schweitzer         }
6472fe4e713SPierre Schweitzer 
648*e392bdf9SPierre Schweitzer         if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) < PagingFile->MaximumSize)
6492fe4e713SPierre Schweitzer         {
6502fe4e713SPierre Schweitzer             KeReleaseGuardedMutex(&MmPageFileCreationLock);
6512fe4e713SPierre Schweitzer             ObDereferenceObject(FileObject);
6522fe4e713SPierre Schweitzer             ZwClose(FileHandle);
6532fe4e713SPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
6542fe4e713SPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
6552fe4e713SPierre Schweitzer             return STATUS_INVALID_PARAMETER_3;
6562fe4e713SPierre Schweitzer         }
6572fe4e713SPierre Schweitzer 
6585bd938bdSPierre Schweitzer         /* FIXME: implement parameters checking and page file extension */
6595bd938bdSPierre Schweitzer         UNIMPLEMENTED;
6605bd938bdSPierre Schweitzer 
661315867d4SPierre Schweitzer         KeReleaseGuardedMutex(&MmPageFileCreationLock);
6625bd938bdSPierre Schweitzer         ObDereferenceObject(FileObject);
6635bd938bdSPierre Schweitzer         ZwClose(FileHandle);
6645bd938bdSPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
6655bd938bdSPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
6665bd938bdSPierre Schweitzer         return STATUS_NOT_IMPLEMENTED;
6672969c28aSPierre Schweitzer     }
668c2c66affSColin Finck 
669c2c66affSColin Finck     if (!NT_SUCCESS(Status))
670c2c66affSColin Finck     {
6712969c28aSPierre Schweitzer         DPRINT1("Failed creating page file: %lx\n", Status);
67228b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
67334e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
67434e8f451SPierre Schweitzer         return Status;
675c2c66affSColin Finck     }
676c2c66affSColin Finck 
67728b4b419SPierre Schweitzer     /* Set the security descriptor */
67828b4b419SPierre Schweitzer     if (NT_SUCCESS(IoStatus.Status))
67928b4b419SPierre Schweitzer     {
68028b4b419SPierre Schweitzer         Status = ZwSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, &SecurityDescriptor);
68128b4b419SPierre Schweitzer         if (!NT_SUCCESS(Status))
68228b4b419SPierre Schweitzer         {
68328b4b419SPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
68428b4b419SPierre Schweitzer             ZwClose(FileHandle);
68534e8f451SPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
68628b4b419SPierre Schweitzer             return Status;
68728b4b419SPierre Schweitzer         }
68828b4b419SPierre Schweitzer     }
68928b4b419SPierre Schweitzer 
69028b4b419SPierre Schweitzer     /* DACL is no longer needed, free it */
69128b4b419SPierre Schweitzer     ExFreePoolWithTag(Dacl, 'lcaD');
69228b4b419SPierre Schweitzer 
693bfc6a795SPierre Schweitzer     /* Set its end of file to minimal size */
694c2c66affSColin Finck     Status = ZwSetInformationFile(FileHandle,
695c2c66affSColin Finck                                   &IoStatus,
696bfc6a795SPierre Schweitzer                                   &SafeMinimumSize,
697c2c66affSColin Finck                                   sizeof(LARGE_INTEGER),
6982969c28aSPierre Schweitzer                                   FileEndOfFileInformation);
6992969c28aSPierre Schweitzer     if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status))
700c2c66affSColin Finck     {
701c2c66affSColin Finck         ZwClose(FileHandle);
70234e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
70334e8f451SPierre Schweitzer         return Status;
704c2c66affSColin Finck     }
705c2c66affSColin Finck 
706c2c66affSColin Finck     Status = ObReferenceObjectByHandle(FileHandle,
707c2c66affSColin Finck                                        FILE_ALL_ACCESS,
708c2c66affSColin Finck                                        IoFileObjectType,
709c2c66affSColin Finck                                        KernelMode,
710c2c66affSColin Finck                                        (PVOID*)&FileObject,
711c2c66affSColin Finck                                        NULL);
712c2c66affSColin Finck     if (!NT_SUCCESS(Status))
713c2c66affSColin Finck     {
714c2c66affSColin Finck         ZwClose(FileHandle);
71534e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
71634e8f451SPierre Schweitzer         return Status;
717c2c66affSColin Finck     }
718c2c66affSColin Finck 
71936c20dc5SPierre Schweitzer     /* Deny page file creation on a floppy disk */
72036c20dc5SPierre Schweitzer     FsDeviceInfo.Characteristics = 0;
72136c20dc5SPierre Schweitzer     IoQueryVolumeInformation(FileObject, FileFsDeviceInformation, sizeof(FsDeviceInfo), &FsDeviceInfo, &Count);
72236c20dc5SPierre Schweitzer     if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE))
72336c20dc5SPierre Schweitzer     {
72436c20dc5SPierre Schweitzer         ObDereferenceObject(FileObject);
72536c20dc5SPierre Schweitzer         ZwClose(FileHandle);
72634e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
72736c20dc5SPierre Schweitzer         return STATUS_FLOPPY_VOLUME;
72836c20dc5SPierre Schweitzer     }
72936c20dc5SPierre Schweitzer 
7301ea68d05SPierre Schweitzer     PagingFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(*PagingFile), TAG_MM);
731c2c66affSColin Finck     if (PagingFile == NULL)
732c2c66affSColin Finck     {
733c2c66affSColin Finck         ObDereferenceObject(FileObject);
734c2c66affSColin Finck         ZwClose(FileHandle);
73534e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
7361ea68d05SPierre Schweitzer         return STATUS_INSUFFICIENT_RESOURCES;
737c2c66affSColin Finck     }
738c2c66affSColin Finck 
739c2c66affSColin Finck     RtlZeroMemory(PagingFile, sizeof(*PagingFile));
740c2c66affSColin Finck 
7412969c28aSPierre Schweitzer     PagingFile->FileHandle = FileHandle;
742c2c66affSColin Finck     PagingFile->FileObject = FileObject;
743*e392bdf9SPierre Schweitzer     PagingFile->MaximumSize = (SafeMaximumSize.QuadPart >> PAGE_SHIFT);
744*e392bdf9SPierre Schweitzer     PagingFile->CurrentSize = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
745*e392bdf9SPierre Schweitzer     PagingFile->MinimumSize = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
746bfc6a795SPierre Schweitzer     PagingFile->FreePages = (ULONG)(SafeMinimumSize.QuadPart / PAGE_SIZE);
747c2c66affSColin Finck     PagingFile->UsedPages = 0;
74834e8f451SPierre Schweitzer     PagingFile->PageFileName = PageFileName;
749c2c66affSColin Finck 
750f080ee13SPierre Schweitzer     AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->FreePages + 31) / 32) * sizeof(ULONG));
751f080ee13SPierre Schweitzer     PagingFile->AllocMap = ExAllocatePoolWithTag(NonPagedPool,
752f080ee13SPierre Schweitzer                                                  AllocMapSize,
753f080ee13SPierre Schweitzer                                                  TAG_MM);
754c2c66affSColin Finck     if (PagingFile->AllocMap == NULL)
755c2c66affSColin Finck     {
7561ea68d05SPierre Schweitzer         ExFreePoolWithTag(PagingFile, TAG_MM);
757c2c66affSColin Finck         ObDereferenceObject(FileObject);
758c2c66affSColin Finck         ZwClose(FileHandle);
75934e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
7601ea68d05SPierre Schweitzer         return STATUS_INSUFFICIENT_RESOURCES;
761c2c66affSColin Finck     }
762c2c66affSColin Finck 
763f080ee13SPierre Schweitzer     RtlInitializeBitMap(PagingFile->AllocMap,
764f080ee13SPierre Schweitzer                         (PULONG)(PagingFile->AllocMap + 1),
765f080ee13SPierre Schweitzer                         (ULONG)(PagingFile->FreePages));
766f080ee13SPierre Schweitzer     RtlClearAllBits(PagingFile->AllocMap);
767c2c66affSColin Finck 
768315867d4SPierre Schweitzer     /* FIXME: should be calling unsafe instead,
769315867d4SPierre Schweitzer      * we should already be in a guarded region
770315867d4SPierre Schweitzer      */
771315867d4SPierre Schweitzer     KeAcquireGuardedMutex(&MmPageFileCreationLock);
77202b0ca08SPierre Schweitzer     ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL);
773f106c297SPierre Schweitzer     MmPagingFile[MmNumberOfPagingFiles] = PagingFile;
77402b0ca08SPierre Schweitzer     MmNumberOfPagingFiles++;
775f106c297SPierre Schweitzer     MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
776315867d4SPierre Schweitzer     KeReleaseGuardedMutex(&MmPageFileCreationLock);
777c2c66affSColin Finck 
778c2c66affSColin Finck     MmSwapSpaceMessage = FALSE;
779c2c66affSColin Finck 
7801ea68d05SPierre Schweitzer     return STATUS_SUCCESS;
781c2c66affSColin Finck }
782c2c66affSColin Finck 
783c2c66affSColin Finck /* EOF */
784