3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: pagefile.c,v 1.15 2002/01/08 00:49:00 dwelch Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/pagefile.c
23 * PURPOSE: Paging file functions
24 * PROGRAMMER: David Welch (welch@mcmail.com)
29 /* INCLUDES *****************************************************************/
31 #include <ddk/ntddk.h>
32 #include <internal/io.h>
33 #include <internal/mm.h>
34 #include <napi/core.h>
36 #include <internal/debug.h>
38 /* TYPES *********************************************************************/
40 typedef struct _PAGINGFILE
42 LIST_ENTRY PagingFileListEntry
;
43 PFILE_OBJECT FileObject
;
49 KSPIN_LOCK AllocMapLock
;
51 } PAGINGFILE
, *PPAGINGFILE
;
53 /* GLOBALS *******************************************************************/
55 #define MAX_PAGING_FILES (32)
57 /* List of paging files, both used and free */
58 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
60 /* Lock for examining the list of paging files */
61 static KSPIN_LOCK PagingFileListLock
;
63 /* Number of pages that are available for swapping */
64 static ULONG MiFreeSwapPages
;
66 /* Number of pages that have been allocated for swapping */
67 static ULONG MiUsedSwapPages
;
70 * Number of pages that have been reserved for swapping but not yet allocated
72 static ULONG MiReservedSwapPages
;
75 * Ratio between reserved and available swap pages, e.g. setting this to five
76 * forces one swap page to be available for every five swap pages that are
77 * reserved. Setting this to zero turns off commit checking altogether.
79 #define MM_PAGEFILE_COMMIT_RATIO (1)
82 * Number of pages that can be used for potentially swapable memory without
83 * pagefile space being reserved. The intention is that this allows smss
84 * to start up and create page files while ordinarily having a commit
87 #define MM_PAGEFILE_COMMIT_GRACE (256)
90 static PVOID MmCoreDumpPageFrame
;
91 static BYTE MmCoreDumpHeader
[PAGESIZE
];
95 * Translate between a swap entry and a file and offset pair.
97 #define FILE_FROM_ENTRY(i) ((i) >> 24)
98 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
99 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
101 /* FUNCTIONS *****************************************************************/
103 NTSTATUS
MmWriteToSwapPage(SWAPENTRY SwapEntry
, PMDL Mdl
)
106 LARGE_INTEGER file_offset
;
107 IO_STATUS_BLOCK Iosb
;
113 return(STATUS_UNSUCCESSFUL
);
116 i
= FILE_FROM_ENTRY(SwapEntry
);
117 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
119 if (i
> MAX_PAGING_FILES
)
121 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
124 if (PagingFileList
[i
]->FileObject
== NULL
||
125 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
127 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
131 file_offset
.QuadPart
= offset
* 4096;
133 Status
= IoPageWrite(PagingFileList
[i
]->FileObject
,
141 NTSTATUS
MmReadFromSwapPage(SWAPENTRY SwapEntry
, PMDL Mdl
)
144 LARGE_INTEGER file_offset
;
145 IO_STATUS_BLOCK Iosb
;
151 return(STATUS_UNSUCCESSFUL
);
154 i
= FILE_FROM_ENTRY(SwapEntry
);
155 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
157 if (i
> MAX_PAGING_FILES
)
159 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
162 if (PagingFileList
[i
]->FileObject
== NULL
||
163 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
165 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
169 file_offset
.QuadPart
= offset
* 4096;
171 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
180 MmInitPagingFile(VOID
)
184 KeInitializeSpinLock(&PagingFileListLock
);
188 MiReservedSwapPages
= 0;
190 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
192 PagingFileList
[i
] = NULL
;
197 MmReserveSwapPages(ULONG Nr
)
200 ULONG MiAvailSwapPages
;
202 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
204 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
205 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
207 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
210 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
211 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
217 MmDereserveSwapPages(ULONG Nr
)
221 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
222 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
223 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
227 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
232 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
234 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
236 for (j
= 0; j
< 32; j
++)
238 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
247 PagingFile
->AllocMap
[i
] |= (1 << j
);
248 PagingFile
->UsedPages
++;
249 PagingFile
->FreePages
--;
250 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
251 return((i
* 32) + j
);
254 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
259 MmFreeSwapPage(SWAPENTRY Entry
)
265 i
= FILE_FROM_ENTRY(Entry
);
266 off
= OFFSET_FROM_ENTRY(Entry
);
268 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
269 if (PagingFileList
[i
] == NULL
)
273 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
275 PagingFileList
[i
]->AllocMap
[off
/ 32] &= (~(1 << (off
% 32)));
277 PagingFileList
[i
]->FreePages
++;
278 PagingFileList
[i
]->UsedPages
--;
283 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
284 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
288 MmAllocSwapPage(VOID
)
294 static BOOLEAN SwapSpaceMessage
= FALSE
;
296 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
298 if (MiFreeSwapPages
== 0)
300 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
301 if (!SwapSpaceMessage
)
303 DPRINT1("MM: Out of swap space.\n");
304 SwapSpaceMessage
= TRUE
;
309 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
311 if (PagingFileList
[i
] != NULL
&&
312 PagingFileList
[i
]->FreePages
>= 1)
314 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
315 if (off
== 0xFFFFFFFF)
318 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
319 return(STATUS_UNSUCCESSFUL
);
323 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
325 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
330 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
331 if (!SwapSpaceMessage
)
333 DPRINT1("MM: Out of swap space.\n");
334 SwapSpaceMessage
= TRUE
;
340 NTSTATUS STDCALL
MmDumpToPagingFile(PCONTEXT Context
,
345 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Magic
=
346 MM_CORE_DUMP_HEADER_MAGIC
;
347 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Version
=
348 MM_CORE_DUMP_HEADER_VERSION
;
349 memcpy(&((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Context
,
352 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->DumpLength
= 0;
353 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->BugCode
= BugCode
;
354 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->ExceptionCode
=
356 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Cr2
= Cr2
;
357 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Cr3
= 0;
362 NtCreatePagingFile(IN PUNICODE_STRING PageFileName
,
363 IN ULONG MinimumSize
,
364 IN ULONG MaximumSize
,
365 OUT PULONG ActualSize
)
368 OBJECT_ATTRIBUTES ObjectAttributes
;
370 IO_STATUS_BLOCK IoStatus
;
371 PFILE_OBJECT FileObject
;
372 PPAGINGFILE PagingFile
;
377 LARGE_INTEGER ByteOffset
;
379 DPRINT1("NtCreatePagingFile(PageFileName %wZ, MinimumSize %d)\n",
380 PageFileName
, MinimumSize
);
382 InitializeObjectAttributes(&ObjectAttributes
,
388 Status
= IoCreateFile(&FileHandle
,
396 FILE_SYNCHRONOUS_IO_NONALERT
,
401 SL_OPEN_PAGING_FILE
);
402 if (!NT_SUCCESS(Status
))
407 Buffer
= ExAllocatePool(NonPagedPool
, 4096);
408 memset(Buffer
, 0, 4096);
409 ByteOffset
.QuadPart
= MinimumSize
* 4096;
410 Status
= NtWriteFile(FileHandle
,
419 if (!NT_SUCCESS(Status
))
425 Status
= ObReferenceObjectByHandle(FileHandle
,
431 if (!NT_SUCCESS(Status
))
439 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
440 if (PagingFile
== NULL
)
442 ObDereferenceObject(FileObject
);
443 return(STATUS_NO_MEMORY
);
446 PagingFile
->FileObject
= FileObject
;
447 PagingFile
->MaximumSize
= PagingFile
->CurrentSize
= MinimumSize
;
448 PagingFile
->FreePages
= MinimumSize
;
449 PagingFile
->UsedPages
= 0;
450 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
452 AllocMapSize
= (MinimumSize
/ 32) + 1;
453 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
454 AllocMapSize
* sizeof(ULONG
));
455 PagingFile
->AllocMapSize
= AllocMapSize
;
457 if (PagingFile
->AllocMap
== NULL
)
459 ExFreePool(PagingFile
);
460 ObDereferenceObject(FileObject
);
461 return(STATUS_NO_MEMORY
);
464 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
465 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
467 if (PagingFileList
[i
] == NULL
)
469 PagingFileList
[i
] = PagingFile
;
473 MiFreeSwapPages
= MiFreeSwapPages
+ MinimumSize
;
474 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
476 return(STATUS_SUCCESS
);