Some memory manager cleanups
[reactos.git] / reactos / ntoskrnl / mm / pagefile.c
1 /* $Id: pagefile.c,v 1.8 2001/01/08 02:14:06 dwelch Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/pagefile.c
6 * PURPOSE: Paging file functions
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/bitops.h>
16 #include <internal/io.h>
17 #include <internal/mm.h>
18 #include <napi/core.h>
19
20 #include <internal/debug.h>
21
22 /* TYPES *********************************************************************/
23
24 typedef struct _PAGINGFILE
25 {
26 LIST_ENTRY PagingFileListEntry;
27 PFILE_OBJECT FileObject;
28 ULONG MaximumSize;
29 ULONG CurrentSize;
30 ULONG FreePages;
31 ULONG UsedPages;
32 PULONG AllocMap;
33 KSPIN_LOCK AllocMapLock;
34 ULONG AllocMapSize;
35 } PAGINGFILE, *PPAGINGFILE;
36
37 /* GLOBALS *******************************************************************/
38
39 #define MAX_PAGING_FILES (32)
40
41 static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
42 static KSPIN_LOCK PagingFileListLock;
43
44 static ULONG MiFreeSwapPages;
45 static ULONG MiUsedSwapPages;
46 static ULONG MiReservedSwapPages;
47
48 #define MM_PAGEFILE_COMMIT_RATIO (1)
49 #define MM_PAGEFILE_COMMIT_GRACE (256)
50
51 #if 0
52 static PVOID MmCoreDumpPageFrame;
53 static BYTE MmCoreDumpHeader[PAGESIZE];
54 #endif
55
56 #define FILE_FROM_ENTRY(i) ((i) >> 24)
57 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
58
59 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) || ((j) + 1))
60
61 /* FUNCTIONS *****************************************************************/
62
63 NTSTATUS MmWriteToSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
64 {
65 ULONG i, offset;
66 LARGE_INTEGER file_offset;
67 IO_STATUS_BLOCK Iosb;
68 NTSTATUS Status;
69
70 if (SwapEntry == 0)
71 {
72 KeBugCheck(0);
73 return(STATUS_UNSUCCESSFUL);
74 }
75
76 i = FILE_FROM_ENTRY(SwapEntry);
77 offset = OFFSET_FROM_ENTRY(SwapEntry);
78
79 file_offset.QuadPart = offset * 4096;
80
81 Status = IoPageWrite(PagingFileList[i]->FileObject,
82 Mdl,
83 &file_offset,
84 &Iosb);
85 return(Status);
86 }
87
88 NTSTATUS MmReadFromSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
89 {
90 ULONG i, offset;
91 LARGE_INTEGER file_offset;
92 IO_STATUS_BLOCK Iosb;
93 NTSTATUS Status;
94
95 if (SwapEntry == 0)
96 {
97 KeBugCheck(0);
98 return(STATUS_UNSUCCESSFUL);
99 }
100
101 i = FILE_FROM_ENTRY(SwapEntry);
102 offset = OFFSET_FROM_ENTRY(SwapEntry);
103
104 file_offset.QuadPart = offset * 4096;
105
106 Status = IoPageRead(PagingFileList[i]->FileObject,
107 Mdl,
108 &file_offset,
109 &Iosb);
110 return(Status);
111 }
112
113 VOID MmInitPagingFile(VOID)
114 {
115 ULONG i;
116
117 KeInitializeSpinLock(&PagingFileListLock);
118
119 MiFreeSwapPages = 0;
120 MiUsedSwapPages = 0;
121 MiReservedSwapPages = 0;
122
123 for (i = 0; i < MAX_PAGING_FILES; i++)
124 {
125 PagingFileList[i] = NULL;
126 }
127 }
128
129 VOID MmReserveSwapPages(ULONG Nr)
130 {
131 KIRQL oldIrql;
132
133 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
134 MiReservedSwapPages = MiReservedSwapPages + Nr;
135 // MiFreeSwapPages = MiFreeSwapPages - Nr;
136 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
137 }
138
139 VOID MmDereserveSwapPages(ULONG Nr)
140 {
141 KIRQL oldIrql;
142
143 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
144 MiReservedSwapPages = MiReservedSwapPages - Nr;
145 // MiFreeSwapPages = MiFreeSwapPages - Nr;
146 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
147 }
148
149 ULONG MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
150 {
151 KIRQL oldIrql;
152 ULONG i;
153 ULONG off;
154
155 KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
156
157 for (i = 0; i < PagingFile->AllocMapSize; i++)
158 {
159 off = find_first_zero_bit(PagingFile->AllocMap,
160 PagingFile->AllocMapSize * 32);
161 clear_bit(off % 32, &PagingFile->AllocMap[off / 32]);
162 PagingFile->UsedPages--;
163 PagingFile->FreePages++;
164 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
165 return(off);
166 }
167
168 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
169 return(0);
170 }
171
172 VOID MmFreeSwapPage(SWAPENTRY Entry)
173 {
174 ULONG i;
175 ULONG off;
176 KIRQL oldIrql;
177
178 i = FILE_FROM_ENTRY(Entry);
179 off = OFFSET_FROM_ENTRY(Entry);
180
181 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
182 KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock);
183
184 set_bit(off % 32, &PagingFileList[i]->AllocMap[off / 32]);
185
186 PagingFileList[i]->FreePages++;
187 PagingFileList[i]->UsedPages--;
188
189 MiFreeSwapPages++;
190 MiUsedSwapPages--;
191
192 KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock);
193 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
194 }
195
196 SWAPENTRY MmAllocSwapPage(VOID)
197 {
198 KIRQL oldIrql;
199 ULONG i;
200 ULONG off;
201 SWAPENTRY entry;
202
203 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
204
205 if (MiFreeSwapPages == 0)
206 {
207 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
208 return(0);
209 }
210
211 for (i = 0; i < MAX_PAGING_FILES; i++)
212 {
213 if (PagingFileList[i] != NULL &&
214 PagingFileList[i]->FreePages >= 1)
215 {
216 off = MiAllocPageFromPagingFile(PagingFileList[i]);
217 if (off != 0)
218 {
219 KeBugCheck(0);
220 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
221 return(STATUS_UNSUCCESSFUL);
222 }
223 MiUsedSwapPages++;
224 MiFreeSwapPages--;
225 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
226
227 entry = ENTRY_FROM_FILE_OFFSET(i, off);
228 return(entry);
229 }
230 }
231
232 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
233 return(0);
234 }
235
236 #if 0
237 NTSTATUS STDCALL MmDumpToPagingFile(PCONTEXT Context,
238 ULONG BugCode,
239 ULONG ExceptionCode,
240 ULONG Cr2)
241 {
242 ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Magic =
243 MM_CORE_DUMP_HEADER_MAGIC;
244 ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Version =
245 MM_CORE_DUMP_HEADER_VERSION;
246 memcpy(&((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Context,
247 Context,
248 sizeof(CONTEXT));
249 ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->DumpLength = 0;
250 ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->BugCode = BugCode;
251 ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->ExceptionCode =
252 ExceptionCode;
253 ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Cr2 = Cr2;
254 ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Cr3 = 0;
255 }
256 #endif
257
258 NTSTATUS STDCALL NtCreatePagingFile(IN PUNICODE_STRING PageFileName,
259 IN ULONG MinimumSize,
260 IN ULONG MaximumSize,
261 OUT PULONG ActualSize)
262 {
263 NTSTATUS Status;
264 OBJECT_ATTRIBUTES ObjectAttributes;
265 HANDLE FileHandle;
266 IO_STATUS_BLOCK IoStatus;
267 PFILE_OBJECT FileObject;
268 PPAGINGFILE PagingFile;
269 KIRQL oldIrql;
270 ULONG AllocMapSize;
271 ULONG i;
272
273 InitializeObjectAttributes(&ObjectAttributes,
274 PageFileName,
275 0,
276 NULL,
277 NULL);
278 Status = NtCreateFile(&FileHandle,
279 FILE_ALL_ACCESS,
280 &ObjectAttributes,
281 &IoStatus,
282 NULL,
283 0,
284 0,
285 FILE_OPEN,
286 FILE_SYNCHRONOUS_IO_NONALERT,
287 NULL,
288 0);
289 if (!NT_SUCCESS(Status))
290 {
291 return(Status);
292 }
293
294 Status = ObReferenceObjectByHandle(FileHandle,
295 FILE_ALL_ACCESS,
296 IoFileObjectType,
297 UserMode,
298 (PVOID*)&FileObject,
299 NULL);
300 if (!NT_SUCCESS(Status))
301 {
302 NtClose(FileHandle);
303 return(Status);
304 }
305
306 NtClose(FileHandle);
307
308 PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
309 if (PagingFile == NULL)
310 {
311 ObDereferenceObject(FileObject);
312 return(STATUS_NO_MEMORY);
313 }
314
315 PagingFile->FileObject = FileObject;
316 PagingFile->MaximumSize = PagingFile->CurrentSize = MinimumSize;
317 PagingFile->FreePages = MinimumSize;
318 PagingFile->UsedPages = 0;
319 KeInitializeSpinLock(&PagingFile->AllocMapLock);
320
321 AllocMapSize = (MinimumSize / 32) + 1;
322 PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
323 AllocMapSize * sizeof(ULONG));
324 PagingFile->AllocMapSize = AllocMapSize;
325
326 if (PagingFile->AllocMap == NULL)
327 {
328 ExFreePool(PagingFile);
329 ObDereferenceObject(FileObject);
330 return(STATUS_NO_MEMORY);
331 }
332
333 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
334 for (i = 0; i < MAX_PAGING_FILES; i++)
335 {
336 if (PagingFileList[i] == NULL)
337 {
338 PagingFileList[i] = PagingFile;
339 break;
340 }
341 }
342 MiFreeSwapPages = MiFreeSwapPages + MinimumSize;
343 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
344
345 return(STATUS_SUCCESS);
346 }
347
348
349 /* EOF */
350
351
352
353
354
355
356