xref: /reactos/ntoskrnl/mm/pagefile.c (revision 2969c28a)
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)
24c2c66affSColin Finck  * UPDATE HISTORY:
25c2c66affSColin Finck  *                  Created 22/05/98
26c2c66affSColin Finck  */
27c2c66affSColin Finck 
28c2c66affSColin Finck /* INCLUDES *****************************************************************/
29c2c66affSColin Finck 
30c2c66affSColin Finck #include <ntoskrnl.h>
31c2c66affSColin Finck #define NDEBUG
32c2c66affSColin Finck #include <debug.h>
33c2c66affSColin Finck 
34c2c66affSColin Finck #if defined (ALLOC_PRAGMA)
35c2c66affSColin Finck #pragma alloc_text(INIT, MmInitPagingFile)
36c2c66affSColin Finck #endif
37c2c66affSColin Finck 
38c2c66affSColin Finck PVOID
39c2c66affSColin Finck NTAPI
40c2c66affSColin Finck MiFindExportedRoutineByName(IN PVOID DllBase,
41c2c66affSColin Finck                             IN PANSI_STRING ExportName);
42c2c66affSColin Finck 
43c2c66affSColin Finck /* TYPES *********************************************************************/
44c2c66affSColin Finck 
45c2c66affSColin Finck typedef struct _PAGINGFILE
46c2c66affSColin Finck {
47c2c66affSColin Finck     LIST_ENTRY PagingFileListEntry;
48c2c66affSColin Finck     PFILE_OBJECT FileObject;
49*2969c28aSPierre Schweitzer     HANDLE FileHandle;
50c2c66affSColin Finck     LARGE_INTEGER MaximumSize;
51c2c66affSColin Finck     LARGE_INTEGER CurrentSize;
52c2c66affSColin Finck     PFN_NUMBER FreePages;
53c2c66affSColin Finck     PFN_NUMBER UsedPages;
54c2c66affSColin Finck     PULONG AllocMap;
55c2c66affSColin Finck     KSPIN_LOCK AllocMapLock;
56c2c66affSColin Finck     ULONG AllocMapSize;
57c2c66affSColin Finck     PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
58c2c66affSColin Finck }
59c2c66affSColin Finck PAGINGFILE, *PPAGINGFILE;
60c2c66affSColin Finck 
61c2c66affSColin Finck typedef struct _RETRIEVEL_DESCRIPTOR_LIST
62c2c66affSColin Finck {
63c2c66affSColin Finck     struct _RETRIEVEL_DESCRIPTOR_LIST* Next;
64c2c66affSColin Finck     RETRIEVAL_POINTERS_BUFFER RetrievalPointers;
65c2c66affSColin Finck }
66c2c66affSColin Finck RETRIEVEL_DESCRIPTOR_LIST, *PRETRIEVEL_DESCRIPTOR_LIST;
67c2c66affSColin Finck 
68c2c66affSColin Finck /* GLOBALS *******************************************************************/
69c2c66affSColin Finck 
70c2c66affSColin Finck #define PAIRS_PER_RUN (1024)
71c2c66affSColin Finck 
72c2c66affSColin Finck #define MAX_PAGING_FILES  (16)
73c2c66affSColin Finck 
74c2c66affSColin Finck /* List of paging files, both used and free */
75c2c66affSColin Finck static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
76c2c66affSColin Finck 
77c2c66affSColin Finck /* Lock for examining the list of paging files */
78c2c66affSColin Finck static KSPIN_LOCK PagingFileListLock;
79c2c66affSColin Finck 
80c2c66affSColin Finck /* Number of paging files */
81c2c66affSColin Finck ULONG MmNumberOfPagingFiles;
82c2c66affSColin Finck 
83c2c66affSColin Finck /* Number of pages that are available for swapping */
84c2c66affSColin Finck PFN_COUNT MiFreeSwapPages;
85c2c66affSColin Finck 
86c2c66affSColin Finck /* Number of pages that have been allocated for swapping */
87c2c66affSColin Finck PFN_COUNT MiUsedSwapPages;
88c2c66affSColin Finck 
89c2c66affSColin Finck BOOLEAN MmZeroPageFile;
90c2c66affSColin Finck 
91c2c66affSColin Finck /*
92c2c66affSColin Finck  * Number of pages that have been reserved for swapping but not yet allocated
93c2c66affSColin Finck  */
94c2c66affSColin Finck static PFN_COUNT MiReservedSwapPages;
95c2c66affSColin Finck 
96c2c66affSColin Finck /*
97c2c66affSColin Finck  * Ratio between reserved and available swap pages, e.g. setting this to five
98c2c66affSColin Finck  * forces one swap page to be available for every five swap pages that are
99c2c66affSColin Finck  * reserved. Setting this to zero turns off commit checking altogether.
100c2c66affSColin Finck  */
101c2c66affSColin Finck #define MM_PAGEFILE_COMMIT_RATIO      (1)
102c2c66affSColin Finck 
103c2c66affSColin Finck /*
104c2c66affSColin Finck  * Number of pages that can be used for potentially swapable memory without
105c2c66affSColin Finck  * pagefile space being reserved. The intention is that this allows smss
106c2c66affSColin Finck  * to start up and create page files while ordinarily having a commit
107c2c66affSColin Finck  * ratio of one.
108c2c66affSColin Finck  */
109c2c66affSColin Finck #define MM_PAGEFILE_COMMIT_GRACE      (256)
110c2c66affSColin Finck 
111c2c66affSColin Finck /*
112c2c66affSColin Finck  * Translate between a swap entry and a file and offset pair.
113c2c66affSColin Finck  */
114c2c66affSColin Finck #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
115c2c66affSColin Finck #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
116c2c66affSColin Finck #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
117c2c66affSColin Finck 
118c2c66affSColin Finck /* Make sure there can be only 16 paging files */
119c2c66affSColin Finck C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES);
120c2c66affSColin Finck 
121c2c66affSColin Finck static BOOLEAN MmSwapSpaceMessage = FALSE;
122c2c66affSColin Finck 
123c2c66affSColin Finck /* FUNCTIONS *****************************************************************/
124c2c66affSColin Finck 
125c2c66affSColin Finck VOID
126c2c66affSColin Finck NTAPI
127c2c66affSColin Finck MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages)
128c2c66affSColin Finck {
129c2c66affSColin Finck     memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE));
130c2c66affSColin Finck 
131c2c66affSColin Finck     /* FIXME: this flag should be set by the caller perhaps? */
132c2c66affSColin Finck     Mdl->MdlFlags |= MDL_IO_PAGE_READ;
133c2c66affSColin Finck }
134c2c66affSColin Finck 
135c2c66affSColin Finck 
136c2c66affSColin Finck BOOLEAN
137c2c66affSColin Finck NTAPI
138c2c66affSColin Finck MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject)
139c2c66affSColin Finck {
140c2c66affSColin Finck     ULONG i;
141c2c66affSColin Finck 
142c2c66affSColin Finck     /* Loop through all the paging files */
143c2c66affSColin Finck     for (i = 0; i < MmNumberOfPagingFiles; i++)
144c2c66affSColin Finck     {
145c2c66affSColin Finck         /* Check if this is one of them */
146c2c66affSColin Finck         if (PagingFileList[i]->FileObject == FileObject) return TRUE;
147c2c66affSColin Finck     }
148c2c66affSColin Finck 
149c2c66affSColin Finck     /* Nothing found */
150c2c66affSColin Finck     return FALSE;
151c2c66affSColin Finck }
152c2c66affSColin Finck 
153c2c66affSColin Finck VOID
154c2c66affSColin Finck NTAPI
155c2c66affSColin Finck MmShowOutOfSpaceMessagePagingFile(VOID)
156c2c66affSColin Finck {
157c2c66affSColin Finck     if (!MmSwapSpaceMessage)
158c2c66affSColin Finck     {
159c2c66affSColin Finck         DPRINT1("MM: Out of swap space.\n");
160c2c66affSColin Finck         MmSwapSpaceMessage = TRUE;
161c2c66affSColin Finck     }
162c2c66affSColin Finck }
163c2c66affSColin Finck 
164c2c66affSColin Finck static LARGE_INTEGER
165c2c66affSColin Finck MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers, LARGE_INTEGER Offset)
166c2c66affSColin Finck {
167c2c66affSColin Finck     /* Simple binary search */
168c2c66affSColin Finck     ULONG first, last, mid;
169c2c66affSColin Finck     first = 0;
170c2c66affSColin Finck     last = RetrievalPointers->ExtentCount - 1;
171c2c66affSColin Finck     while (first <= last)
172c2c66affSColin Finck     {
173c2c66affSColin Finck         mid = (last - first) / 2 + first;
174c2c66affSColin Finck         if (Offset.QuadPart < RetrievalPointers->Extents[mid].NextVcn.QuadPart)
175c2c66affSColin Finck         {
176c2c66affSColin Finck             if (mid == 0)
177c2c66affSColin Finck             {
178c2c66affSColin Finck                 Offset.QuadPart += RetrievalPointers->Extents[0].Lcn.QuadPart - RetrievalPointers->StartingVcn.QuadPart;
179c2c66affSColin Finck                 return Offset;
180c2c66affSColin Finck             }
181c2c66affSColin Finck             else
182c2c66affSColin Finck             {
183c2c66affSColin Finck                 if (Offset.QuadPart >= RetrievalPointers->Extents[mid-1].NextVcn.QuadPart)
184c2c66affSColin Finck                 {
185c2c66affSColin Finck                     Offset.QuadPart += RetrievalPointers->Extents[mid].Lcn.QuadPart - RetrievalPointers->Extents[mid-1].NextVcn.QuadPart;
186c2c66affSColin Finck                     return Offset;
187c2c66affSColin Finck                 }
188c2c66affSColin Finck                 last = mid - 1;
189c2c66affSColin Finck             }
190c2c66affSColin Finck         }
191c2c66affSColin Finck         else
192c2c66affSColin Finck         {
193c2c66affSColin Finck             if (mid == RetrievalPointers->ExtentCount - 1)
194c2c66affSColin Finck             {
195c2c66affSColin Finck                 break;
196c2c66affSColin Finck             }
197c2c66affSColin Finck             if (Offset.QuadPart < RetrievalPointers->Extents[mid+1].NextVcn.QuadPart)
198c2c66affSColin Finck             {
199c2c66affSColin Finck                 Offset.QuadPart += RetrievalPointers->Extents[mid+1].Lcn.QuadPart  - RetrievalPointers->Extents[mid].NextVcn.QuadPart;
200c2c66affSColin Finck                 return Offset;
201c2c66affSColin Finck             }
202c2c66affSColin Finck             first = mid + 1;
203c2c66affSColin Finck         }
204c2c66affSColin Finck     }
205c2c66affSColin Finck     KeBugCheck(MEMORY_MANAGEMENT);
206c2c66affSColin Finck #if defined(__GNUC__)
207c2c66affSColin Finck 
208c2c66affSColin Finck     return (LARGE_INTEGER)0LL;
209c2c66affSColin Finck #else
210c2c66affSColin Finck 
211c2c66affSColin Finck     {
212c2c66affSColin Finck         const LARGE_INTEGER dummy =
213c2c66affSColin Finck         {
214840320cbSAmine Khaldi             {0}
215c2c66affSColin Finck         };
216c2c66affSColin Finck         return dummy;
217c2c66affSColin Finck     }
218c2c66affSColin Finck #endif
219c2c66affSColin Finck }
220c2c66affSColin Finck 
221c2c66affSColin Finck NTSTATUS
222c2c66affSColin Finck NTAPI
223c2c66affSColin Finck MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
224c2c66affSColin Finck {
225c2c66affSColin Finck     ULONG i;
226c2c66affSColin Finck     ULONG_PTR offset;
227c2c66affSColin Finck     LARGE_INTEGER file_offset;
228c2c66affSColin Finck     IO_STATUS_BLOCK Iosb;
229c2c66affSColin Finck     NTSTATUS Status;
230c2c66affSColin Finck     KEVENT Event;
231c2c66affSColin Finck     UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
232c2c66affSColin Finck     PMDL Mdl = (PMDL)MdlBase;
233c2c66affSColin Finck 
234c2c66affSColin Finck     DPRINT("MmWriteToSwapPage\n");
235c2c66affSColin Finck 
236c2c66affSColin Finck     if (SwapEntry == 0)
237c2c66affSColin Finck     {
238c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
239c2c66affSColin Finck         return(STATUS_UNSUCCESSFUL);
240c2c66affSColin Finck     }
241c2c66affSColin Finck 
242c2c66affSColin Finck     i = FILE_FROM_ENTRY(SwapEntry);
243c2c66affSColin Finck     offset = OFFSET_FROM_ENTRY(SwapEntry) - 1;
244c2c66affSColin Finck 
245c2c66affSColin Finck     if (PagingFileList[i]->FileObject == NULL ||
246c2c66affSColin Finck             PagingFileList[i]->FileObject->DeviceObject == NULL)
247c2c66affSColin Finck     {
248c2c66affSColin Finck         DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
249c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
250c2c66affSColin Finck     }
251c2c66affSColin Finck 
252c2c66affSColin Finck     MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
253c2c66affSColin Finck     MmBuildMdlFromPages(Mdl, &Page);
254c2c66affSColin Finck     Mdl->MdlFlags |= MDL_PAGES_LOCKED;
255c2c66affSColin Finck 
256c2c66affSColin Finck     file_offset.QuadPart = offset * PAGE_SIZE;
257c2c66affSColin Finck     file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset);
258c2c66affSColin Finck 
259c2c66affSColin Finck     KeInitializeEvent(&Event, NotificationEvent, FALSE);
260c2c66affSColin Finck     Status = IoSynchronousPageWrite(PagingFileList[i]->FileObject,
261c2c66affSColin Finck                                     Mdl,
262c2c66affSColin Finck                                     &file_offset,
263c2c66affSColin Finck                                     &Event,
264c2c66affSColin Finck                                     &Iosb);
265c2c66affSColin Finck     if (Status == STATUS_PENDING)
266c2c66affSColin Finck     {
267c2c66affSColin Finck         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
268c2c66affSColin Finck         Status = Iosb.Status;
269c2c66affSColin Finck     }
270c2c66affSColin Finck 
271c2c66affSColin Finck     if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
272c2c66affSColin Finck     {
273c2c66affSColin Finck         MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
274c2c66affSColin Finck     }
275c2c66affSColin Finck     return(Status);
276c2c66affSColin Finck }
277c2c66affSColin Finck 
278c2c66affSColin Finck 
279c2c66affSColin Finck NTSTATUS
280c2c66affSColin Finck NTAPI
281c2c66affSColin Finck MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
282c2c66affSColin Finck {
283c2c66affSColin Finck     return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry) - 1);
284c2c66affSColin Finck }
285c2c66affSColin Finck 
286c2c66affSColin Finck NTSTATUS
287c2c66affSColin Finck NTAPI
288c2c66affSColin Finck MiReadPageFile(
289c2c66affSColin Finck     _In_ PFN_NUMBER Page,
290c2c66affSColin Finck     _In_ ULONG PageFileIndex,
291c2c66affSColin Finck     _In_ ULONG_PTR PageFileOffset)
292c2c66affSColin Finck {
293c2c66affSColin Finck     LARGE_INTEGER file_offset;
294c2c66affSColin Finck     IO_STATUS_BLOCK Iosb;
295c2c66affSColin Finck     NTSTATUS Status;
296c2c66affSColin Finck     KEVENT Event;
297c2c66affSColin Finck     UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
298c2c66affSColin Finck     PMDL Mdl = (PMDL)MdlBase;
299c2c66affSColin Finck     PPAGINGFILE PagingFile;
300c2c66affSColin Finck 
301c2c66affSColin Finck     DPRINT("MiReadSwapFile\n");
302c2c66affSColin Finck 
303c2c66affSColin Finck     if (PageFileOffset == 0)
304c2c66affSColin Finck     {
305c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
306c2c66affSColin Finck         return(STATUS_UNSUCCESSFUL);
307c2c66affSColin Finck     }
308c2c66affSColin Finck 
309c2c66affSColin Finck     ASSERT(PageFileIndex < MAX_PAGING_FILES);
310c2c66affSColin Finck 
311c2c66affSColin Finck     PagingFile = PagingFileList[PageFileIndex];
312c2c66affSColin Finck 
313c2c66affSColin Finck     if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL)
314c2c66affSColin Finck     {
315c2c66affSColin Finck         DPRINT1("Bad paging file %u\n", PageFileIndex);
316c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
317c2c66affSColin Finck     }
318c2c66affSColin Finck 
319c2c66affSColin Finck     MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
320c2c66affSColin Finck     MmBuildMdlFromPages(Mdl, &Page);
321c2c66affSColin Finck     Mdl->MdlFlags |= MDL_PAGES_LOCKED;
322c2c66affSColin Finck 
323c2c66affSColin Finck     file_offset.QuadPart = PageFileOffset * PAGE_SIZE;
324c2c66affSColin Finck     file_offset = MmGetOffsetPageFile(PagingFile->RetrievalPointers, file_offset);
325c2c66affSColin Finck 
326c2c66affSColin Finck     KeInitializeEvent(&Event, NotificationEvent, FALSE);
327c2c66affSColin Finck     Status = IoPageRead(PagingFile->FileObject,
328c2c66affSColin Finck                         Mdl,
329c2c66affSColin Finck                         &file_offset,
330c2c66affSColin Finck                         &Event,
331c2c66affSColin Finck                         &Iosb);
332c2c66affSColin Finck     if (Status == STATUS_PENDING)
333c2c66affSColin Finck     {
334c2c66affSColin Finck         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
335c2c66affSColin Finck         Status = Iosb.Status;
336c2c66affSColin Finck     }
337c2c66affSColin Finck     if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
338c2c66affSColin Finck     {
339c2c66affSColin Finck         MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
340c2c66affSColin Finck     }
341c2c66affSColin Finck     return(Status);
342c2c66affSColin Finck }
343c2c66affSColin Finck 
344c2c66affSColin Finck VOID
345c2c66affSColin Finck INIT_FUNCTION
346c2c66affSColin Finck NTAPI
347c2c66affSColin Finck MmInitPagingFile(VOID)
348c2c66affSColin Finck {
349c2c66affSColin Finck     ULONG i;
350c2c66affSColin Finck 
351c2c66affSColin Finck     KeInitializeSpinLock(&PagingFileListLock);
352c2c66affSColin Finck 
353c2c66affSColin Finck     MiFreeSwapPages = 0;
354c2c66affSColin Finck     MiUsedSwapPages = 0;
355c2c66affSColin Finck     MiReservedSwapPages = 0;
356c2c66affSColin Finck 
357c2c66affSColin Finck     for (i = 0; i < MAX_PAGING_FILES; i++)
358c2c66affSColin Finck     {
359c2c66affSColin Finck         PagingFileList[i] = NULL;
360c2c66affSColin Finck     }
361c2c66affSColin Finck     MmNumberOfPagingFiles = 0;
362c2c66affSColin Finck }
363c2c66affSColin Finck 
364c2c66affSColin Finck static ULONG
365c2c66affSColin Finck MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
366c2c66affSColin Finck {
367c2c66affSColin Finck     KIRQL oldIrql;
368c2c66affSColin Finck     ULONG i, j;
369c2c66affSColin Finck 
370c2c66affSColin Finck     KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
371c2c66affSColin Finck 
372c2c66affSColin Finck     for (i = 0; i < PagingFile->AllocMapSize; i++)
373c2c66affSColin Finck     {
374c2c66affSColin Finck         for (j = 0; j < 32; j++)
375c2c66affSColin Finck         {
376c2c66affSColin Finck             if (!(PagingFile->AllocMap[i] & (1 << j)))
377c2c66affSColin Finck             {
378c2c66affSColin Finck                 PagingFile->AllocMap[i] |= (1 << j);
379c2c66affSColin Finck                 PagingFile->UsedPages++;
380c2c66affSColin Finck                 PagingFile->FreePages--;
381c2c66affSColin Finck                 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
382c2c66affSColin Finck                 return((i * 32) + j);
383c2c66affSColin Finck             }
384c2c66affSColin Finck         }
385c2c66affSColin Finck     }
386c2c66affSColin Finck 
387c2c66affSColin Finck     KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
388c2c66affSColin Finck     return(0xFFFFFFFF);
389c2c66affSColin Finck }
390c2c66affSColin Finck 
391c2c66affSColin Finck VOID
392c2c66affSColin Finck NTAPI
393c2c66affSColin Finck MmFreeSwapPage(SWAPENTRY Entry)
394c2c66affSColin Finck {
395c2c66affSColin Finck     ULONG i;
396c2c66affSColin Finck     ULONG_PTR off;
397c2c66affSColin Finck     KIRQL oldIrql;
398c2c66affSColin Finck 
399c2c66affSColin Finck     i = FILE_FROM_ENTRY(Entry);
400c2c66affSColin Finck     off = OFFSET_FROM_ENTRY(Entry) - 1;
401c2c66affSColin Finck 
402c2c66affSColin Finck     KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
403c2c66affSColin Finck     if (PagingFileList[i] == NULL)
404c2c66affSColin Finck     {
405c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
406c2c66affSColin Finck     }
407c2c66affSColin Finck     KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock);
408c2c66affSColin Finck 
409c2c66affSColin Finck     PagingFileList[i]->AllocMap[off >> 5] &= (~(1 << (off % 32)));
410c2c66affSColin Finck 
411c2c66affSColin Finck     PagingFileList[i]->FreePages++;
412c2c66affSColin Finck     PagingFileList[i]->UsedPages--;
413c2c66affSColin Finck 
414c2c66affSColin Finck     MiFreeSwapPages++;
415c2c66affSColin Finck     MiUsedSwapPages--;
416c2c66affSColin Finck 
417c2c66affSColin Finck     KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock);
418c2c66affSColin Finck     KeReleaseSpinLock(&PagingFileListLock, oldIrql);
419c2c66affSColin Finck }
420c2c66affSColin Finck 
421c2c66affSColin Finck SWAPENTRY
422c2c66affSColin Finck NTAPI
423c2c66affSColin Finck MmAllocSwapPage(VOID)
424c2c66affSColin Finck {
425c2c66affSColin Finck     KIRQL oldIrql;
426c2c66affSColin Finck     ULONG i;
427c2c66affSColin Finck     ULONG off;
428c2c66affSColin Finck     SWAPENTRY entry;
429c2c66affSColin Finck 
430c2c66affSColin Finck     KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
431c2c66affSColin Finck 
432c2c66affSColin Finck     if (MiFreeSwapPages == 0)
433c2c66affSColin Finck     {
434c2c66affSColin Finck         KeReleaseSpinLock(&PagingFileListLock, oldIrql);
435c2c66affSColin Finck         return(0);
436c2c66affSColin Finck     }
437c2c66affSColin Finck 
438c2c66affSColin Finck     for (i = 0; i < MAX_PAGING_FILES; i++)
439c2c66affSColin Finck     {
440c2c66affSColin Finck         if (PagingFileList[i] != NULL &&
441c2c66affSColin Finck                 PagingFileList[i]->FreePages >= 1)
442c2c66affSColin Finck         {
443c2c66affSColin Finck             off = MiAllocPageFromPagingFile(PagingFileList[i]);
444c2c66affSColin Finck             if (off == 0xFFFFFFFF)
445c2c66affSColin Finck             {
446c2c66affSColin Finck                 KeBugCheck(MEMORY_MANAGEMENT);
447c2c66affSColin Finck                 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
448c2c66affSColin Finck                 return(STATUS_UNSUCCESSFUL);
449c2c66affSColin Finck             }
450c2c66affSColin Finck             MiUsedSwapPages++;
451c2c66affSColin Finck             MiFreeSwapPages--;
452c2c66affSColin Finck             KeReleaseSpinLock(&PagingFileListLock, oldIrql);
453c2c66affSColin Finck 
454c2c66affSColin Finck             entry = ENTRY_FROM_FILE_OFFSET(i, off + 1);
455c2c66affSColin Finck             return(entry);
456c2c66affSColin Finck         }
457c2c66affSColin Finck     }
458c2c66affSColin Finck 
459c2c66affSColin Finck     KeReleaseSpinLock(&PagingFileListLock, oldIrql);
460c2c66affSColin Finck     KeBugCheck(MEMORY_MANAGEMENT);
461c2c66affSColin Finck     return(0);
462c2c66affSColin Finck }
463c2c66affSColin Finck 
464c2c66affSColin Finck static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
465c2c66affSColin Finck MmAllocRetrievelDescriptorList(ULONG Pairs)
466c2c66affSColin Finck {
467c2c66affSColin Finck     ULONG Size;
468c2c66affSColin Finck     PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
469c2c66affSColin Finck 
470c2c66affSColin Finck     Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER);
471c2c66affSColin Finck     RetDescList = ExAllocatePool(NonPagedPool, Size);
472c2c66affSColin Finck     if (RetDescList)
473c2c66affSColin Finck     {
474c2c66affSColin Finck         RtlZeroMemory(RetDescList, Size);
475c2c66affSColin Finck     }
476c2c66affSColin Finck 
477c2c66affSColin Finck     return RetDescList;
478c2c66affSColin Finck }
479c2c66affSColin Finck 
480c2c66affSColin Finck NTSTATUS NTAPI
481c2c66affSColin Finck NtCreatePagingFile(IN PUNICODE_STRING FileName,
482c2c66affSColin Finck                    IN PLARGE_INTEGER InitialSize,
483c2c66affSColin Finck                    IN PLARGE_INTEGER MaximumSize,
484c2c66affSColin Finck                    IN ULONG Reserved)
485c2c66affSColin Finck {
486c2c66affSColin Finck     NTSTATUS Status;
487c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
488c2c66affSColin Finck     HANDLE FileHandle;
489c2c66affSColin Finck     IO_STATUS_BLOCK IoStatus;
490c2c66affSColin Finck     PFILE_OBJECT FileObject;
491c2c66affSColin Finck     PPAGINGFILE PagingFile;
492c2c66affSColin Finck     KIRQL oldIrql;
493c2c66affSColin Finck     ULONG AllocMapSize;
494c2c66affSColin Finck     FILE_FS_SIZE_INFORMATION FsSizeInformation;
495c2c66affSColin Finck     PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
496c2c66affSColin Finck     PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList;
497c2c66affSColin Finck     ULONG i;
498c2c66affSColin Finck     ULONG BytesPerAllocationUnit;
499c2c66affSColin Finck     LARGE_INTEGER Vcn;
500c2c66affSColin Finck     ULONG ExtentCount;
501c2c66affSColin Finck     LARGE_INTEGER MaxVcn;
502c2c66affSColin Finck     ULONG Count;
503c2c66affSColin Finck     ULONG Size;
504c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode;
505c2c66affSColin Finck     UNICODE_STRING CapturedFileName;
506*2969c28aSPierre Schweitzer     LARGE_INTEGER SafeInitialSize, SafeMaximumSize, AllocationSize;
507c2c66affSColin Finck 
508c2c66affSColin Finck     DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
509c2c66affSColin Finck            FileName, InitialSize->QuadPart);
510c2c66affSColin Finck 
511c2c66affSColin Finck     if (MmNumberOfPagingFiles >= MAX_PAGING_FILES)
512c2c66affSColin Finck     {
5130ad4ef60SPierre Schweitzer         return STATUS_TOO_MANY_PAGING_FILES;
514c2c66affSColin Finck     }
515c2c66affSColin Finck 
516c2c66affSColin Finck     PreviousMode = ExGetPreviousMode();
517c2c66affSColin Finck 
518c2c66affSColin Finck     if (PreviousMode != KernelMode)
519c2c66affSColin Finck     {
5200ad4ef60SPierre Schweitzer         if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege, PreviousMode) != TRUE)
5210ad4ef60SPierre Schweitzer         {
5220ad4ef60SPierre Schweitzer             return STATUS_PRIVILEGE_NOT_HELD;
5230ad4ef60SPierre Schweitzer         }
5240ad4ef60SPierre Schweitzer 
525c2c66affSColin Finck         _SEH2_TRY
526c2c66affSColin Finck         {
527c2c66affSColin Finck             SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
528c2c66affSColin Finck             SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
529c2c66affSColin Finck         }
530c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
531c2c66affSColin Finck         {
532c2c66affSColin Finck             /* Return the exception code */
533c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
534c2c66affSColin Finck         }
535c2c66affSColin Finck         _SEH2_END;
536c2c66affSColin Finck     }
537c2c66affSColin Finck     else
538c2c66affSColin Finck     {
539c2c66affSColin Finck         SafeInitialSize = *InitialSize;
540c2c66affSColin Finck         SafeMaximumSize = *MaximumSize;
541c2c66affSColin Finck     }
542c2c66affSColin Finck 
543c2c66affSColin Finck     /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
544c2c66affSColin Finck        smaller than the maximum */
545c2c66affSColin Finck     if (0 != SafeInitialSize.u.HighPart)
546c2c66affSColin Finck     {
547c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_2;
548c2c66affSColin Finck     }
549c2c66affSColin Finck     if (0 != SafeMaximumSize.u.HighPart)
550c2c66affSColin Finck     {
551c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_3;
552c2c66affSColin Finck     }
553c2c66affSColin Finck     if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart)
554c2c66affSColin Finck     {
555c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_MIX;
556c2c66affSColin Finck     }
557c2c66affSColin Finck 
558c2c66affSColin Finck     Status = ProbeAndCaptureUnicodeString(&CapturedFileName,
559c2c66affSColin Finck                                           PreviousMode,
560c2c66affSColin Finck                                           FileName);
561c2c66affSColin Finck     if (!NT_SUCCESS(Status))
562c2c66affSColin Finck     {
563c2c66affSColin Finck         return(Status);
564c2c66affSColin Finck     }
565c2c66affSColin Finck 
566c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
567c2c66affSColin Finck                                &CapturedFileName,
568c2c66affSColin Finck                                OBJ_KERNEL_HANDLE,
569c2c66affSColin Finck                                NULL,
570c2c66affSColin Finck                                NULL);
571c2c66affSColin Finck 
572*2969c28aSPierre Schweitzer     /* Make sure we can at least store a complete page:
573*2969c28aSPierre Schweitzer      * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
574*2969c28aSPierre Schweitzer      * a problem if the paging file is fragmented. Suppose the first cluster
575*2969c28aSPierre Schweitzer      * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
576*2969c28aSPierre Schweitzer      * paging file but of another file. We can't write a complete page (4096
577*2969c28aSPierre Schweitzer      * bytes) to the physical location of cluster 3042 then. */
578*2969c28aSPierre Schweitzer     AllocationSize.QuadPart = SafeInitialSize.QuadPart + PAGE_SIZE;
579*2969c28aSPierre Schweitzer 
580*2969c28aSPierre Schweitzer     /* First, attempt to replace the page file, if existing */
581c2c66affSColin Finck     Status = IoCreateFile(&FileHandle,
582*2969c28aSPierre Schweitzer                           SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA,
583c2c66affSColin Finck                           &ObjectAttributes,
584c2c66affSColin Finck                           &IoStatus,
585*2969c28aSPierre Schweitzer                           &AllocationSize,
586*2969c28aSPierre Schweitzer                           FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
587*2969c28aSPierre Schweitzer                           FILE_SHARE_WRITE,
588*2969c28aSPierre Schweitzer                           FILE_SUPERSEDE,
589*2969c28aSPierre Schweitzer                           FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
590c2c66affSColin Finck                           NULL,
591c2c66affSColin Finck                           0,
592c2c66affSColin Finck                           CreateFileTypeNone,
593c2c66affSColin Finck                           NULL,
594c2c66affSColin Finck                           SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
595*2969c28aSPierre Schweitzer     /* If we failed, relax a bit constraints, someone may be already holding the
596*2969c28aSPierre Schweitzer      * the file, so share write, don't attempt to replace and don't delete on close
597*2969c28aSPierre Schweitzer      * (basically, don't do anything conflicting)
598*2969c28aSPierre Schweitzer      */
599*2969c28aSPierre Schweitzer     if (!NT_SUCCESS(Status))
600*2969c28aSPierre Schweitzer     {
601*2969c28aSPierre Schweitzer         Status = IoCreateFile(&FileHandle,
602*2969c28aSPierre Schweitzer                               SYNCHRONIZE | FILE_WRITE_DATA,
603*2969c28aSPierre Schweitzer                               &ObjectAttributes,
604*2969c28aSPierre Schweitzer                               &IoStatus,
605*2969c28aSPierre Schweitzer                               &AllocationSize,
606*2969c28aSPierre Schweitzer                               FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
607*2969c28aSPierre Schweitzer                               FILE_SHARE_WRITE | FILE_SHARE_READ,
608*2969c28aSPierre Schweitzer                               FILE_OPEN,
609*2969c28aSPierre Schweitzer                               FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
610*2969c28aSPierre Schweitzer                               NULL,
611*2969c28aSPierre Schweitzer                               0,
612*2969c28aSPierre Schweitzer                               CreateFileTypeNone,
613*2969c28aSPierre Schweitzer                               NULL,
614*2969c28aSPierre Schweitzer                               SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
615*2969c28aSPierre Schweitzer     }
616c2c66affSColin Finck 
617c2c66affSColin Finck     ReleaseCapturedUnicodeString(&CapturedFileName,
618c2c66affSColin Finck                                  PreviousMode);
619c2c66affSColin Finck     if (!NT_SUCCESS(Status))
620c2c66affSColin Finck     {
621*2969c28aSPierre Schweitzer         DPRINT1("Failed creating page file: %lx\n", Status);
622c2c66affSColin Finck         return(Status);
623c2c66affSColin Finck     }
624c2c66affSColin Finck 
625c2c66affSColin Finck     Status = ZwQueryVolumeInformationFile(FileHandle,
626c2c66affSColin Finck                                           &IoStatus,
627c2c66affSColin Finck                                           &FsSizeInformation,
628c2c66affSColin Finck                                           sizeof(FILE_FS_SIZE_INFORMATION),
629c2c66affSColin Finck                                           FileFsSizeInformation);
630c2c66affSColin Finck     if (!NT_SUCCESS(Status))
631c2c66affSColin Finck     {
632c2c66affSColin Finck         ZwClose(FileHandle);
633c2c66affSColin Finck         return Status;
634c2c66affSColin Finck     }
635c2c66affSColin Finck 
636c2c66affSColin Finck     BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit *
637c2c66affSColin Finck                              FsSizeInformation.BytesPerSector;
638c2c66affSColin Finck 
639*2969c28aSPierre Schweitzer     /* Set its end of file to initial size */
640c2c66affSColin Finck     Status = ZwSetInformationFile(FileHandle,
641c2c66affSColin Finck                                   &IoStatus,
642c2c66affSColin Finck                                   &SafeInitialSize,
643c2c66affSColin Finck                                   sizeof(LARGE_INTEGER),
644*2969c28aSPierre Schweitzer                                   FileEndOfFileInformation);
645*2969c28aSPierre Schweitzer     if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status))
646c2c66affSColin Finck     {
647c2c66affSColin Finck         ZwClose(FileHandle);
648c2c66affSColin Finck         return(Status);
649c2c66affSColin Finck     }
650c2c66affSColin Finck 
651c2c66affSColin Finck     Status = ObReferenceObjectByHandle(FileHandle,
652c2c66affSColin Finck                                        FILE_ALL_ACCESS,
653c2c66affSColin Finck                                        IoFileObjectType,
654c2c66affSColin Finck                                        KernelMode,
655c2c66affSColin Finck                                        (PVOID*)&FileObject,
656c2c66affSColin Finck                                        NULL);
657c2c66affSColin Finck     if (!NT_SUCCESS(Status))
658c2c66affSColin Finck     {
659c2c66affSColin Finck         ZwClose(FileHandle);
660c2c66affSColin Finck         return(Status);
661c2c66affSColin Finck     }
662c2c66affSColin Finck 
663c2c66affSColin Finck     CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
664c2c66affSColin Finck 
665c2c66affSColin Finck     if (CurrentRetDescList == NULL)
666c2c66affSColin Finck     {
667c2c66affSColin Finck         ObDereferenceObject(FileObject);
668c2c66affSColin Finck         ZwClose(FileHandle);
669c2c66affSColin Finck         return(STATUS_NO_MEMORY);
670c2c66affSColin Finck     }
671c2c66affSColin Finck 
672c2c66affSColin Finck #if defined(__GNUC__)
673c2c66affSColin Finck     Vcn.QuadPart = 0LL;
674c2c66affSColin Finck #else
675c2c66affSColin Finck 
676c2c66affSColin Finck     Vcn.QuadPart = 0;
677c2c66affSColin Finck #endif
678c2c66affSColin Finck 
679c2c66affSColin Finck     ExtentCount = 0;
680c2c66affSColin Finck     MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit;
681c2c66affSColin Finck     while(1)
682c2c66affSColin Finck     {
683c2c66affSColin Finck         Status = ZwFsControlFile(FileHandle,
684c2c66affSColin Finck                                  0,
685c2c66affSColin Finck                                  NULL,
686c2c66affSColin Finck                                  NULL,
687c2c66affSColin Finck                                  &IoStatus,
688c2c66affSColin Finck                                  FSCTL_GET_RETRIEVAL_POINTERS,
689c2c66affSColin Finck                                  &Vcn,
690c2c66affSColin Finck                                  sizeof(LARGE_INTEGER),
691c2c66affSColin Finck                                  &CurrentRetDescList->RetrievalPointers,
692c2c66affSColin Finck                                  sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER));
693c2c66affSColin Finck         if (!NT_SUCCESS(Status))
694c2c66affSColin Finck         {
695c2c66affSColin Finck             while (RetDescList)
696c2c66affSColin Finck             {
697c2c66affSColin Finck                 CurrentRetDescList = RetDescList;
698c2c66affSColin Finck                 RetDescList = RetDescList->Next;
699c2c66affSColin Finck                 ExFreePool(CurrentRetDescList);
700c2c66affSColin Finck             }
701c2c66affSColin Finck             ObDereferenceObject(FileObject);
702c2c66affSColin Finck             ZwClose(FileHandle);
703c2c66affSColin Finck             return(Status);
704c2c66affSColin Finck         }
705c2c66affSColin Finck         ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount;
706c2c66affSColin Finck         if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart)
707c2c66affSColin Finck         {
708c2c66affSColin Finck             CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
709c2c66affSColin Finck             if (CurrentRetDescList->Next == NULL)
710c2c66affSColin Finck             {
711c2c66affSColin Finck                 while (RetDescList)
712c2c66affSColin Finck                 {
713c2c66affSColin Finck                     CurrentRetDescList = RetDescList;
714c2c66affSColin Finck                     RetDescList = RetDescList->Next;
715c2c66affSColin Finck                     ExFreePool(CurrentRetDescList);
716c2c66affSColin Finck                 }
717c2c66affSColin Finck                 ObDereferenceObject(FileObject);
718c2c66affSColin Finck                 ZwClose(FileHandle);
719c2c66affSColin Finck                 return(STATUS_NO_MEMORY);
720c2c66affSColin Finck             }
721c2c66affSColin Finck             Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn;
722c2c66affSColin Finck             CurrentRetDescList = CurrentRetDescList->Next;
723c2c66affSColin Finck         }
724c2c66affSColin Finck         else
725c2c66affSColin Finck         {
726c2c66affSColin Finck             break;
727c2c66affSColin Finck         }
728c2c66affSColin Finck     }
729c2c66affSColin Finck 
730c2c66affSColin Finck     PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
731c2c66affSColin Finck     if (PagingFile == NULL)
732c2c66affSColin Finck     {
733c2c66affSColin Finck         while (RetDescList)
734c2c66affSColin Finck         {
735c2c66affSColin Finck             CurrentRetDescList = RetDescList;
736c2c66affSColin Finck             RetDescList = RetDescList->Next;
737c2c66affSColin Finck             ExFreePool(CurrentRetDescList);
738c2c66affSColin Finck         }
739c2c66affSColin Finck         ObDereferenceObject(FileObject);
740c2c66affSColin Finck         ZwClose(FileHandle);
741c2c66affSColin Finck         return(STATUS_NO_MEMORY);
742c2c66affSColin Finck     }
743c2c66affSColin Finck 
744c2c66affSColin Finck     RtlZeroMemory(PagingFile, sizeof(*PagingFile));
745c2c66affSColin Finck 
746*2969c28aSPierre Schweitzer     PagingFile->FileHandle = FileHandle;
747c2c66affSColin Finck     PagingFile->FileObject = FileObject;
748c2c66affSColin Finck     PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart;
749c2c66affSColin Finck     PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
750c2c66affSColin Finck     PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
751c2c66affSColin Finck     PagingFile->UsedPages = 0;
752c2c66affSColin Finck     KeInitializeSpinLock(&PagingFile->AllocMapLock);
753c2c66affSColin Finck 
754c2c66affSColin Finck     AllocMapSize = (PagingFile->FreePages / 32) + 1;
755c2c66affSColin Finck     PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
756c2c66affSColin Finck                                           AllocMapSize * sizeof(ULONG));
757c2c66affSColin Finck     PagingFile->AllocMapSize = AllocMapSize;
758c2c66affSColin Finck 
759c2c66affSColin Finck     if (PagingFile->AllocMap == NULL)
760c2c66affSColin Finck     {
761c2c66affSColin Finck         while (RetDescList)
762c2c66affSColin Finck         {
763c2c66affSColin Finck             CurrentRetDescList = RetDescList;
764c2c66affSColin Finck             RetDescList = RetDescList->Next;
765c2c66affSColin Finck             ExFreePool(CurrentRetDescList);
766c2c66affSColin Finck         }
767c2c66affSColin Finck         ExFreePool(PagingFile);
768c2c66affSColin Finck         ObDereferenceObject(FileObject);
769c2c66affSColin Finck         ZwClose(FileHandle);
770c2c66affSColin Finck         return(STATUS_NO_MEMORY);
771c2c66affSColin Finck     }
772c2c66affSColin Finck     DPRINT("ExtentCount: %lu\n", ExtentCount);
773c2c66affSColin Finck     Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER);
774c2c66affSColin Finck     PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size);
775c2c66affSColin Finck     if (PagingFile->RetrievalPointers == NULL)
776c2c66affSColin Finck     {
777c2c66affSColin Finck         while (RetDescList)
778c2c66affSColin Finck         {
779c2c66affSColin Finck             CurrentRetDescList = RetDescList;
780c2c66affSColin Finck             RetDescList = RetDescList->Next;
781c2c66affSColin Finck             ExFreePool(CurrentRetDescList);
782c2c66affSColin Finck         }
783c2c66affSColin Finck         ExFreePool(PagingFile->AllocMap);
784c2c66affSColin Finck         ExFreePool(PagingFile);
785c2c66affSColin Finck         ObDereferenceObject(FileObject);
786c2c66affSColin Finck         ZwClose(FileHandle);
787c2c66affSColin Finck         return(STATUS_NO_MEMORY);
788c2c66affSColin Finck     }
789c2c66affSColin Finck 
790c2c66affSColin Finck     RtlZeroMemory(PagingFile->AllocMap, AllocMapSize * sizeof(ULONG));
791c2c66affSColin Finck     RtlZeroMemory(PagingFile->RetrievalPointers, Size);
792c2c66affSColin Finck 
793c2c66affSColin Finck     Count = 0;
794c2c66affSColin Finck     PagingFile->RetrievalPointers->ExtentCount = ExtentCount;
795c2c66affSColin Finck     PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn;
796c2c66affSColin Finck     CurrentRetDescList = RetDescList;
797c2c66affSColin Finck     while (CurrentRetDescList)
798c2c66affSColin Finck     {
799c2c66affSColin Finck         memcpy(&PagingFile->RetrievalPointers->Extents[Count],
800c2c66affSColin Finck                CurrentRetDescList->RetrievalPointers.Extents,
801c2c66affSColin Finck                CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER));
802c2c66affSColin Finck         Count += CurrentRetDescList->RetrievalPointers.ExtentCount;
803c2c66affSColin Finck         RetDescList = CurrentRetDescList;
804c2c66affSColin Finck         CurrentRetDescList = CurrentRetDescList->Next;
805c2c66affSColin Finck         ExFreePool(RetDescList);
806c2c66affSColin Finck     }
807c2c66affSColin Finck 
808c2c66affSColin Finck     if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount ||
809c2c66affSColin Finck             PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart)
810c2c66affSColin Finck     {
811c2c66affSColin Finck         ExFreePool(PagingFile->RetrievalPointers);
812c2c66affSColin Finck         ExFreePool(PagingFile->AllocMap);
813c2c66affSColin Finck         ExFreePool(PagingFile);
814c2c66affSColin Finck         ObDereferenceObject(FileObject);
815c2c66affSColin Finck         ZwClose(FileHandle);
816c2c66affSColin Finck         return(STATUS_UNSUCCESSFUL);
817c2c66affSColin Finck     }
818c2c66affSColin Finck 
819c2c66affSColin Finck     /*
820c2c66affSColin Finck      * Change the entries from lcn's to volume offset's.
821c2c66affSColin Finck      */
822c2c66affSColin Finck     PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit;
823c2c66affSColin Finck     for (i = 0; i < ExtentCount; i++)
824c2c66affSColin Finck     {
825c2c66affSColin Finck         PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit;
826c2c66affSColin Finck         PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit;
827c2c66affSColin Finck     }
828c2c66affSColin Finck 
829c2c66affSColin Finck     KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
830c2c66affSColin Finck     for (i = 0; i < MAX_PAGING_FILES; i++)
831c2c66affSColin Finck     {
832c2c66affSColin Finck         if (PagingFileList[i] == NULL)
833c2c66affSColin Finck         {
834c2c66affSColin Finck             PagingFileList[i] = PagingFile;
835c2c66affSColin Finck             break;
836c2c66affSColin Finck         }
837c2c66affSColin Finck     }
838c2c66affSColin Finck     MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
839c2c66affSColin Finck     MmNumberOfPagingFiles++;
840c2c66affSColin Finck     KeReleaseSpinLock(&PagingFileListLock, oldIrql);
841c2c66affSColin Finck 
842c2c66affSColin Finck     MmSwapSpaceMessage = FALSE;
843c2c66affSColin Finck 
844c2c66affSColin Finck     return(STATUS_SUCCESS);
845c2c66affSColin Finck }
846c2c66affSColin Finck 
847c2c66affSColin Finck /* EOF */
848