xref: /reactos/ntoskrnl/mm/pagefile.c (revision 5bd938bd)
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 */
47c2c66affSColin Finck static KSPIN_LOCK PagingFileListLock;
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 
261c2c66affSColin Finck     KeInitializeSpinLock(&PagingFileListLock);
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 static ULONG
27502b0ca08SPierre Schweitzer MiAllocPageFromPagingFile(PMMPAGING_FILE PagingFile)
276c2c66affSColin Finck {
277c2c66affSColin Finck     KIRQL oldIrql;
278f080ee13SPierre Schweitzer     ULONG off;
279c2c66affSColin Finck 
280c2c66affSColin Finck     KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
281f080ee13SPierre Schweitzer     off = RtlFindClearBitsAndSet(PagingFile->AllocMap, 1, 0);
282c2c66affSColin Finck     KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
283c2c66affSColin Finck 
284f080ee13SPierre Schweitzer     return off;
285c2c66affSColin Finck }
286c2c66affSColin Finck 
287c2c66affSColin Finck VOID
288c2c66affSColin Finck NTAPI
289c2c66affSColin Finck MmFreeSwapPage(SWAPENTRY Entry)
290c2c66affSColin Finck {
291c2c66affSColin Finck     ULONG i;
292c2c66affSColin Finck     ULONG_PTR off;
293c2c66affSColin Finck     KIRQL oldIrql;
29402b0ca08SPierre Schweitzer     PMMPAGING_FILE PagingFile;
295c2c66affSColin Finck 
296c2c66affSColin Finck     i = FILE_FROM_ENTRY(Entry);
297c2c66affSColin Finck     off = OFFSET_FROM_ENTRY(Entry) - 1;
298c2c66affSColin Finck 
299c2c66affSColin Finck     KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
300f106c297SPierre Schweitzer 
301f106c297SPierre Schweitzer     PagingFile = MmPagingFile[i];
302f106c297SPierre Schweitzer     if (PagingFile == NULL)
303c2c66affSColin Finck     {
304c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
305c2c66affSColin Finck     }
306f106c297SPierre Schweitzer     KeAcquireSpinLockAtDpcLevel(&PagingFile->AllocMapLock);
307c2c66affSColin Finck 
308f106c297SPierre Schweitzer     RtlClearBit(PagingFile->AllocMap, off >> 5);
309c2c66affSColin Finck 
310f106c297SPierre Schweitzer     PagingFile->FreePages++;
311f106c297SPierre Schweitzer     PagingFile->UsedPages--;
312c2c66affSColin Finck 
313c2c66affSColin Finck     MiFreeSwapPages++;
314c2c66affSColin Finck     MiUsedSwapPages--;
315c2c66affSColin Finck 
316f106c297SPierre Schweitzer     KeReleaseSpinLockFromDpcLevel(&PagingFile->AllocMapLock);
317c2c66affSColin Finck     KeReleaseSpinLock(&PagingFileListLock, oldIrql);
318c2c66affSColin Finck }
319c2c66affSColin Finck 
320c2c66affSColin Finck SWAPENTRY
321c2c66affSColin Finck NTAPI
322c2c66affSColin Finck MmAllocSwapPage(VOID)
323c2c66affSColin Finck {
324c2c66affSColin Finck     KIRQL oldIrql;
325c2c66affSColin Finck     ULONG i;
326c2c66affSColin Finck     ULONG off;
327c2c66affSColin Finck     SWAPENTRY entry;
328c2c66affSColin Finck 
329c2c66affSColin Finck     KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
330c2c66affSColin Finck 
331c2c66affSColin Finck     if (MiFreeSwapPages == 0)
332c2c66affSColin Finck     {
333c2c66affSColin Finck         KeReleaseSpinLock(&PagingFileListLock, oldIrql);
334c2c66affSColin Finck         return(0);
335c2c66affSColin Finck     }
336c2c66affSColin Finck 
337c2c66affSColin Finck     for (i = 0; i < MAX_PAGING_FILES; i++)
338c2c66affSColin Finck     {
339f106c297SPierre Schweitzer         if (MmPagingFile[i] != NULL &&
340f106c297SPierre Schweitzer                 MmPagingFile[i]->FreePages >= 1)
341c2c66affSColin Finck         {
342f106c297SPierre Schweitzer             off = MiAllocPageFromPagingFile(MmPagingFile[i]);
343c2c66affSColin Finck             if (off == 0xFFFFFFFF)
344c2c66affSColin Finck             {
345c2c66affSColin Finck                 KeBugCheck(MEMORY_MANAGEMENT);
346c2c66affSColin Finck                 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
347c2c66affSColin Finck                 return(STATUS_UNSUCCESSFUL);
348c2c66affSColin Finck             }
349c2c66affSColin Finck             MiUsedSwapPages++;
350c2c66affSColin Finck             MiFreeSwapPages--;
351c2c66affSColin Finck             KeReleaseSpinLock(&PagingFileListLock, oldIrql);
352c2c66affSColin Finck 
353c2c66affSColin Finck             entry = ENTRY_FROM_FILE_OFFSET(i, off + 1);
354c2c66affSColin Finck             return(entry);
355c2c66affSColin Finck         }
356c2c66affSColin Finck     }
357c2c66affSColin Finck 
358c2c66affSColin Finck     KeReleaseSpinLock(&PagingFileListLock, oldIrql);
359c2c66affSColin Finck     KeBugCheck(MEMORY_MANAGEMENT);
360c2c66affSColin Finck     return(0);
361c2c66affSColin Finck }
362c2c66affSColin Finck 
363c2c66affSColin Finck NTSTATUS NTAPI
364c2c66affSColin Finck NtCreatePagingFile(IN PUNICODE_STRING FileName,
365c2c66affSColin Finck                    IN PLARGE_INTEGER InitialSize,
366c2c66affSColin Finck                    IN PLARGE_INTEGER MaximumSize,
367c2c66affSColin Finck                    IN ULONG Reserved)
368c2c66affSColin Finck {
369c2c66affSColin Finck     NTSTATUS Status;
370c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
371c2c66affSColin Finck     HANDLE FileHandle;
372c2c66affSColin Finck     IO_STATUS_BLOCK IoStatus;
373c2c66affSColin Finck     PFILE_OBJECT FileObject;
37402b0ca08SPierre Schweitzer     PMMPAGING_FILE PagingFile;
375c2c66affSColin Finck     KIRQL oldIrql;
376c2c66affSColin Finck     ULONG AllocMapSize;
377c2c66affSColin Finck     ULONG Count;
378c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode;
37934e8f451SPierre Schweitzer     UNICODE_STRING PageFileName;
3802969c28aSPierre Schweitzer     LARGE_INTEGER SafeInitialSize, SafeMaximumSize, AllocationSize;
38136c20dc5SPierre Schweitzer     FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
38228b4b419SPierre Schweitzer     SECURITY_DESCRIPTOR SecurityDescriptor;
38328b4b419SPierre Schweitzer     PACL Dacl;
38434e8f451SPierre Schweitzer     PWSTR Buffer;
385c2c66affSColin Finck 
386c2c66affSColin Finck     DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
387c2c66affSColin Finck            FileName, InitialSize->QuadPart);
388c2c66affSColin Finck 
389c2c66affSColin Finck     if (MmNumberOfPagingFiles >= MAX_PAGING_FILES)
390c2c66affSColin Finck     {
3910ad4ef60SPierre Schweitzer         return STATUS_TOO_MANY_PAGING_FILES;
392c2c66affSColin Finck     }
393c2c66affSColin Finck 
394c2c66affSColin Finck     PreviousMode = ExGetPreviousMode();
395c2c66affSColin Finck 
396c2c66affSColin Finck     if (PreviousMode != KernelMode)
397c2c66affSColin Finck     {
3980ad4ef60SPierre Schweitzer         if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege, PreviousMode) != TRUE)
3990ad4ef60SPierre Schweitzer         {
4000ad4ef60SPierre Schweitzer             return STATUS_PRIVILEGE_NOT_HELD;
4010ad4ef60SPierre Schweitzer         }
4020ad4ef60SPierre Schweitzer 
403c2c66affSColin Finck         _SEH2_TRY
404c2c66affSColin Finck         {
405c2c66affSColin Finck             SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
406c2c66affSColin Finck             SafeMaximumSize = ProbeForReadLargeInteger(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         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
413c2c66affSColin Finck         {
414c2c66affSColin Finck             /* Return the exception code */
415c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
416c2c66affSColin Finck         }
417c2c66affSColin Finck         _SEH2_END;
418c2c66affSColin Finck     }
419c2c66affSColin Finck     else
420c2c66affSColin Finck     {
421c2c66affSColin Finck         SafeInitialSize = *InitialSize;
422c2c66affSColin Finck         SafeMaximumSize = *MaximumSize;
42334e8f451SPierre Schweitzer 
42434e8f451SPierre Schweitzer         PageFileName.Length = FileName->Length;
42534e8f451SPierre Schweitzer         PageFileName.MaximumLength = FileName->MaximumLength;
42634e8f451SPierre Schweitzer         PageFileName.Buffer = FileName->Buffer;
427c2c66affSColin Finck     }
428c2c66affSColin Finck 
429c2c66affSColin Finck     /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
430c2c66affSColin Finck        smaller than the maximum */
431c2c66affSColin Finck     if (0 != SafeInitialSize.u.HighPart)
432c2c66affSColin Finck     {
433c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_2;
434c2c66affSColin Finck     }
435c2c66affSColin Finck     if (0 != SafeMaximumSize.u.HighPart)
436c2c66affSColin Finck     {
437c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_3;
438c2c66affSColin Finck     }
439c2c66affSColin Finck     if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart)
440c2c66affSColin Finck     {
441c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_MIX;
442c2c66affSColin Finck     }
443c2c66affSColin Finck 
44434e8f451SPierre Schweitzer     /* Validate name length */
44534e8f451SPierre Schweitzer     if (PageFileName.Length > 128 * sizeof(WCHAR))
446c2c66affSColin Finck     {
44734e8f451SPierre Schweitzer         return STATUS_OBJECT_NAME_INVALID;
448c2c66affSColin Finck     }
449c2c66affSColin Finck 
45034e8f451SPierre Schweitzer     /* We won't care about any potential UNICODE_NULL */
45134e8f451SPierre Schweitzer     PageFileName.MaximumLength = PageFileName.Length;
45234e8f451SPierre Schweitzer     /* Allocate a buffer to keep name copy */
45334e8f451SPierre Schweitzer     Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM);
45434e8f451SPierre Schweitzer     if (Buffer == NULL)
45534e8f451SPierre Schweitzer     {
45634e8f451SPierre Schweitzer         return STATUS_INSUFFICIENT_RESOURCES;
45734e8f451SPierre Schweitzer     }
45834e8f451SPierre Schweitzer 
45934e8f451SPierre Schweitzer     /* Copy name */
46034e8f451SPierre Schweitzer     if (PreviousMode != KernelMode)
46134e8f451SPierre Schweitzer     {
46234e8f451SPierre Schweitzer         _SEH2_TRY
46334e8f451SPierre Schweitzer         {
46434e8f451SPierre Schweitzer             if (PageFileName.Length != 0)
46534e8f451SPierre Schweitzer             {
46634e8f451SPierre Schweitzer                 ProbeForRead(PageFileName.Buffer, PageFileName.Length, sizeof(WCHAR));
46734e8f451SPierre Schweitzer             }
46834e8f451SPierre Schweitzer 
46934e8f451SPierre Schweitzer             RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
47034e8f451SPierre Schweitzer         }
47134e8f451SPierre Schweitzer         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
47234e8f451SPierre Schweitzer         {
47334e8f451SPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
47434e8f451SPierre Schweitzer 
47534e8f451SPierre Schweitzer             /* Return the exception code */
47634e8f451SPierre Schweitzer             _SEH2_YIELD(return _SEH2_GetExceptionCode());
47734e8f451SPierre Schweitzer         }
47834e8f451SPierre Schweitzer         _SEH2_END;
47934e8f451SPierre Schweitzer     }
48034e8f451SPierre Schweitzer     else
48134e8f451SPierre Schweitzer     {
48234e8f451SPierre Schweitzer         RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
48334e8f451SPierre Schweitzer     }
48434e8f451SPierre Schweitzer 
48534e8f451SPierre Schweitzer     /* Erase caller's buffer with ours */
48634e8f451SPierre Schweitzer     PageFileName.Buffer = Buffer;
48734e8f451SPierre Schweitzer 
48828b4b419SPierre Schweitzer     /* Create the security descriptor for the page file */
48928b4b419SPierre Schweitzer     Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
49028b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
49128b4b419SPierre Schweitzer     {
49234e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
49328b4b419SPierre Schweitzer         return Status;
49428b4b419SPierre Schweitzer     }
49528b4b419SPierre Schweitzer 
49628b4b419SPierre Schweitzer     /* Create the DACL: we will only allow two SIDs */
49728b4b419SPierre Schweitzer     Count = sizeof(ACL) + (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
49828b4b419SPierre Schweitzer                           (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
49928b4b419SPierre Schweitzer     Dacl = ExAllocatePoolWithTag(PagedPool, Count, 'lcaD');
50028b4b419SPierre Schweitzer     if (Dacl == NULL)
50128b4b419SPierre Schweitzer     {
50234e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
50328b4b419SPierre Schweitzer         return STATUS_INSUFFICIENT_RESOURCES;
50428b4b419SPierre Schweitzer     }
50528b4b419SPierre Schweitzer 
50628b4b419SPierre Schweitzer     /* Initialize the DACL */
50728b4b419SPierre Schweitzer     Status = RtlCreateAcl(Dacl, Count, ACL_REVISION);
50828b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
50928b4b419SPierre Schweitzer     {
51028b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
51134e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
51228b4b419SPierre Schweitzer         return Status;
51328b4b419SPierre Schweitzer     }
51428b4b419SPierre Schweitzer 
51528b4b419SPierre Schweitzer     /* Grant full access to admins */
51628b4b419SPierre Schweitzer     Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid);
51728b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
51828b4b419SPierre Schweitzer     {
51928b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
52034e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
52128b4b419SPierre Schweitzer         return Status;
52228b4b419SPierre Schweitzer     }
52328b4b419SPierre Schweitzer 
52428b4b419SPierre Schweitzer     /* Grant full access to SYSTEM */
52528b4b419SPierre Schweitzer     Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid);
52628b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
52728b4b419SPierre Schweitzer     {
52828b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
52934e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
53028b4b419SPierre Schweitzer         return Status;
53128b4b419SPierre Schweitzer     }
53228b4b419SPierre Schweitzer 
53328b4b419SPierre Schweitzer     /* Attach the DACL to the security descriptor */
53428b4b419SPierre Schweitzer     Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE);
53528b4b419SPierre Schweitzer     if (!NT_SUCCESS(Status))
53628b4b419SPierre Schweitzer     {
53728b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
53834e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
53928b4b419SPierre Schweitzer         return Status;
54028b4b419SPierre Schweitzer     }
54128b4b419SPierre Schweitzer 
542c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
54334e8f451SPierre Schweitzer                                &PageFileName,
544c2c66affSColin Finck                                OBJ_KERNEL_HANDLE,
545c2c66affSColin Finck                                NULL,
54628b4b419SPierre Schweitzer                                &SecurityDescriptor);
547c2c66affSColin Finck 
5482969c28aSPierre Schweitzer     /* Make sure we can at least store a complete page:
5492969c28aSPierre Schweitzer      * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
5502969c28aSPierre Schweitzer      * a problem if the paging file is fragmented. Suppose the first cluster
5512969c28aSPierre Schweitzer      * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
5522969c28aSPierre Schweitzer      * paging file but of another file. We can't write a complete page (4096
5532969c28aSPierre Schweitzer      * bytes) to the physical location of cluster 3042 then. */
5542969c28aSPierre Schweitzer     AllocationSize.QuadPart = SafeInitialSize.QuadPart + PAGE_SIZE;
5552969c28aSPierre Schweitzer 
5562969c28aSPierre Schweitzer     /* First, attempt to replace the page file, if existing */
557c2c66affSColin Finck     Status = IoCreateFile(&FileHandle,
5582969c28aSPierre Schweitzer                           SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA,
559c2c66affSColin Finck                           &ObjectAttributes,
560c2c66affSColin Finck                           &IoStatus,
5612969c28aSPierre Schweitzer                           &AllocationSize,
5622969c28aSPierre Schweitzer                           FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5632969c28aSPierre Schweitzer                           FILE_SHARE_WRITE,
5642969c28aSPierre Schweitzer                           FILE_SUPERSEDE,
5652969c28aSPierre Schweitzer                           FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
566c2c66affSColin Finck                           NULL,
567c2c66affSColin Finck                           0,
568c2c66affSColin Finck                           CreateFileTypeNone,
569c2c66affSColin Finck                           NULL,
570c2c66affSColin Finck                           SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
5712969c28aSPierre Schweitzer     /* If we failed, relax a bit constraints, someone may be already holding the
5722969c28aSPierre Schweitzer      * the file, so share write, don't attempt to replace and don't delete on close
5732969c28aSPierre Schweitzer      * (basically, don't do anything conflicting)
574*5bd938bdSPierre Schweitzer      * This can happen if the caller attempts to extend a page file.
5752969c28aSPierre Schweitzer      */
5762969c28aSPierre Schweitzer     if (!NT_SUCCESS(Status))
5772969c28aSPierre Schweitzer     {
578*5bd938bdSPierre Schweitzer         ULONG i;
579*5bd938bdSPierre Schweitzer 
5802969c28aSPierre Schweitzer         Status = IoCreateFile(&FileHandle,
5812969c28aSPierre Schweitzer                               SYNCHRONIZE | FILE_WRITE_DATA,
5822969c28aSPierre Schweitzer                               &ObjectAttributes,
5832969c28aSPierre Schweitzer                               &IoStatus,
5842969c28aSPierre Schweitzer                               &AllocationSize,
5852969c28aSPierre Schweitzer                               FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5862969c28aSPierre Schweitzer                               FILE_SHARE_WRITE | FILE_SHARE_READ,
5872969c28aSPierre Schweitzer                               FILE_OPEN,
5882969c28aSPierre Schweitzer                               FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
5892969c28aSPierre Schweitzer                               NULL,
5902969c28aSPierre Schweitzer                               0,
5912969c28aSPierre Schweitzer                               CreateFileTypeNone,
5922969c28aSPierre Schweitzer                               NULL,
5932969c28aSPierre Schweitzer                               SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
594*5bd938bdSPierre Schweitzer         if (!NT_SUCCESS(Status))
595*5bd938bdSPierre Schweitzer         {
596*5bd938bdSPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
597*5bd938bdSPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
598*5bd938bdSPierre Schweitzer             return Status;
599*5bd938bdSPierre Schweitzer         }
600*5bd938bdSPierre Schweitzer 
601*5bd938bdSPierre Schweitzer         /* We opened it! Check we are that "someone" ;-)
602*5bd938bdSPierre Schweitzer          * First, get the opened file object.
603*5bd938bdSPierre Schweitzer          */
604*5bd938bdSPierre Schweitzer         Status = ObReferenceObjectByHandle(FileHandle,
605*5bd938bdSPierre Schweitzer                                            FILE_READ_DATA | FILE_WRITE_DATA,
606*5bd938bdSPierre Schweitzer                                            IoFileObjectType,
607*5bd938bdSPierre Schweitzer                                            KernelMode,
608*5bd938bdSPierre Schweitzer                                            (PVOID*)&FileObject,
609*5bd938bdSPierre Schweitzer                                            NULL);
610*5bd938bdSPierre Schweitzer         if (!NT_SUCCESS(Status))
611*5bd938bdSPierre Schweitzer         {
612*5bd938bdSPierre Schweitzer             ZwClose(FileHandle);
613*5bd938bdSPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
614*5bd938bdSPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
615*5bd938bdSPierre Schweitzer             return Status;
616*5bd938bdSPierre Schweitzer         }
617*5bd938bdSPierre Schweitzer 
618*5bd938bdSPierre Schweitzer         /* Find if it matches a previous page file */
619*5bd938bdSPierre Schweitzer         PagingFile = NULL;
620*5bd938bdSPierre Schweitzer         if (MmNumberOfPagingFiles > 0)
621*5bd938bdSPierre Schweitzer         {
622*5bd938bdSPierre Schweitzer             i = 0;
623*5bd938bdSPierre Schweitzer 
624*5bd938bdSPierre Schweitzer             while (MmPagingFile[i]->FileObject->SectionObjectPointer != FileObject->SectionObjectPointer)
625*5bd938bdSPierre Schweitzer             {
626*5bd938bdSPierre Schweitzer                 ++i;
627*5bd938bdSPierre Schweitzer                 if (i >= MmNumberOfPagingFiles)
628*5bd938bdSPierre Schweitzer                 {
629*5bd938bdSPierre Schweitzer                     break;
630*5bd938bdSPierre Schweitzer                 }
631*5bd938bdSPierre Schweitzer             }
632*5bd938bdSPierre Schweitzer 
633*5bd938bdSPierre Schweitzer             /* This is the matching page file */
634*5bd938bdSPierre Schweitzer             PagingFile = MmPagingFile[i];
635*5bd938bdSPierre Schweitzer         }
636*5bd938bdSPierre Schweitzer 
637*5bd938bdSPierre Schweitzer         /* If we didn't find the page file, fail */
638*5bd938bdSPierre Schweitzer         if (PagingFile == NULL)
639*5bd938bdSPierre Schweitzer         {
640*5bd938bdSPierre Schweitzer             ObDereferenceObject(FileObject);
641*5bd938bdSPierre Schweitzer             ZwClose(FileHandle);
642*5bd938bdSPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
643*5bd938bdSPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
644*5bd938bdSPierre Schweitzer             return STATUS_NOT_FOUND;
645*5bd938bdSPierre Schweitzer         }
646*5bd938bdSPierre Schweitzer 
647*5bd938bdSPierre Schweitzer         /* FIXME: implement parameters checking and page file extension */
648*5bd938bdSPierre Schweitzer         UNIMPLEMENTED;
649*5bd938bdSPierre Schweitzer 
650*5bd938bdSPierre Schweitzer         ObDereferenceObject(FileObject);
651*5bd938bdSPierre Schweitzer         ZwClose(FileHandle);
652*5bd938bdSPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
653*5bd938bdSPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
654*5bd938bdSPierre Schweitzer         return STATUS_NOT_IMPLEMENTED;
6552969c28aSPierre Schweitzer     }
656c2c66affSColin Finck 
657c2c66affSColin Finck     if (!NT_SUCCESS(Status))
658c2c66affSColin Finck     {
6592969c28aSPierre Schweitzer         DPRINT1("Failed creating page file: %lx\n", Status);
66028b4b419SPierre Schweitzer         ExFreePoolWithTag(Dacl, 'lcaD');
66134e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
66234e8f451SPierre Schweitzer         return Status;
663c2c66affSColin Finck     }
664c2c66affSColin Finck 
66528b4b419SPierre Schweitzer     /* Set the security descriptor */
66628b4b419SPierre Schweitzer     if (NT_SUCCESS(IoStatus.Status))
66728b4b419SPierre Schweitzer     {
66828b4b419SPierre Schweitzer         Status = ZwSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, &SecurityDescriptor);
66928b4b419SPierre Schweitzer         if (!NT_SUCCESS(Status))
67028b4b419SPierre Schweitzer         {
67128b4b419SPierre Schweitzer             ExFreePoolWithTag(Dacl, 'lcaD');
67228b4b419SPierre Schweitzer             ZwClose(FileHandle);
67334e8f451SPierre Schweitzer             ExFreePoolWithTag(Buffer, TAG_MM);
67428b4b419SPierre Schweitzer             return Status;
67528b4b419SPierre Schweitzer         }
67628b4b419SPierre Schweitzer     }
67728b4b419SPierre Schweitzer 
67828b4b419SPierre Schweitzer     /* DACL is no longer needed, free it */
67928b4b419SPierre Schweitzer     ExFreePoolWithTag(Dacl, 'lcaD');
68028b4b419SPierre Schweitzer 
6812969c28aSPierre Schweitzer     /* Set its end of file to initial size */
682c2c66affSColin Finck     Status = ZwSetInformationFile(FileHandle,
683c2c66affSColin Finck                                   &IoStatus,
684c2c66affSColin Finck                                   &SafeInitialSize,
685c2c66affSColin Finck                                   sizeof(LARGE_INTEGER),
6862969c28aSPierre Schweitzer                                   FileEndOfFileInformation);
6872969c28aSPierre Schweitzer     if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status))
688c2c66affSColin Finck     {
689c2c66affSColin Finck         ZwClose(FileHandle);
69034e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
69134e8f451SPierre Schweitzer         return Status;
692c2c66affSColin Finck     }
693c2c66affSColin Finck 
694c2c66affSColin Finck     Status = ObReferenceObjectByHandle(FileHandle,
695c2c66affSColin Finck                                        FILE_ALL_ACCESS,
696c2c66affSColin Finck                                        IoFileObjectType,
697c2c66affSColin Finck                                        KernelMode,
698c2c66affSColin Finck                                        (PVOID*)&FileObject,
699c2c66affSColin Finck                                        NULL);
700c2c66affSColin Finck     if (!NT_SUCCESS(Status))
701c2c66affSColin Finck     {
702c2c66affSColin Finck         ZwClose(FileHandle);
70334e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
70434e8f451SPierre Schweitzer         return Status;
705c2c66affSColin Finck     }
706c2c66affSColin Finck 
70736c20dc5SPierre Schweitzer     /* Deny page file creation on a floppy disk */
70836c20dc5SPierre Schweitzer     FsDeviceInfo.Characteristics = 0;
70936c20dc5SPierre Schweitzer     IoQueryVolumeInformation(FileObject, FileFsDeviceInformation, sizeof(FsDeviceInfo), &FsDeviceInfo, &Count);
71036c20dc5SPierre Schweitzer     if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE))
71136c20dc5SPierre Schweitzer     {
71236c20dc5SPierre Schweitzer         ObDereferenceObject(FileObject);
71336c20dc5SPierre Schweitzer         ZwClose(FileHandle);
71434e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
71536c20dc5SPierre Schweitzer         return STATUS_FLOPPY_VOLUME;
71636c20dc5SPierre Schweitzer     }
71736c20dc5SPierre Schweitzer 
7181ea68d05SPierre Schweitzer     PagingFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(*PagingFile), TAG_MM);
719c2c66affSColin Finck     if (PagingFile == NULL)
720c2c66affSColin Finck     {
721c2c66affSColin Finck         ObDereferenceObject(FileObject);
722c2c66affSColin Finck         ZwClose(FileHandle);
72334e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
7241ea68d05SPierre Schweitzer         return STATUS_INSUFFICIENT_RESOURCES;
725c2c66affSColin Finck     }
726c2c66affSColin Finck 
727c2c66affSColin Finck     RtlZeroMemory(PagingFile, sizeof(*PagingFile));
728c2c66affSColin Finck 
7292969c28aSPierre Schweitzer     PagingFile->FileHandle = FileHandle;
730c2c66affSColin Finck     PagingFile->FileObject = FileObject;
731c2c66affSColin Finck     PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart;
732c2c66affSColin Finck     PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
733c2c66affSColin Finck     PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
734c2c66affSColin Finck     PagingFile->UsedPages = 0;
735c2c66affSColin Finck     KeInitializeSpinLock(&PagingFile->AllocMapLock);
73634e8f451SPierre Schweitzer     PagingFile->PageFileName = PageFileName;
737c2c66affSColin Finck 
738f080ee13SPierre Schweitzer     AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->FreePages + 31) / 32) * sizeof(ULONG));
739f080ee13SPierre Schweitzer     PagingFile->AllocMap = ExAllocatePoolWithTag(NonPagedPool,
740f080ee13SPierre Schweitzer                                                  AllocMapSize,
741f080ee13SPierre Schweitzer                                                  TAG_MM);
742c2c66affSColin Finck     if (PagingFile->AllocMap == NULL)
743c2c66affSColin Finck     {
7441ea68d05SPierre Schweitzer         ExFreePoolWithTag(PagingFile, TAG_MM);
745c2c66affSColin Finck         ObDereferenceObject(FileObject);
746c2c66affSColin Finck         ZwClose(FileHandle);
74734e8f451SPierre Schweitzer         ExFreePoolWithTag(Buffer, TAG_MM);
7481ea68d05SPierre Schweitzer         return STATUS_INSUFFICIENT_RESOURCES;
749c2c66affSColin Finck     }
750c2c66affSColin Finck 
751f080ee13SPierre Schweitzer     RtlInitializeBitMap(PagingFile->AllocMap,
752f080ee13SPierre Schweitzer                         (PULONG)(PagingFile->AllocMap + 1),
753f080ee13SPierre Schweitzer                         (ULONG)(PagingFile->FreePages));
754f080ee13SPierre Schweitzer     RtlClearAllBits(PagingFile->AllocMap);
755c2c66affSColin Finck 
756c2c66affSColin Finck     KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
75702b0ca08SPierre Schweitzer     ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL);
758f106c297SPierre Schweitzer     MmPagingFile[MmNumberOfPagingFiles] = PagingFile;
75902b0ca08SPierre Schweitzer     MmNumberOfPagingFiles++;
760f106c297SPierre Schweitzer     MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
761c2c66affSColin Finck     KeReleaseSpinLock(&PagingFileListLock, oldIrql);
762c2c66affSColin Finck 
763c2c66affSColin Finck     MmSwapSpaceMessage = FALSE;
764c2c66affSColin Finck 
7651ea68d05SPierre Schweitzer     return STATUS_SUCCESS;
766c2c66affSColin Finck }
767c2c66affSColin Finck 
768c2c66affSColin Finck /* EOF */
769