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.17 2002/02/08 02:57:07 chorns 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>
37 #include <internal/debug.h>
39 /* TYPES *********************************************************************/
41 typedef struct _PAGINGFILE
43 LIST_ENTRY PagingFileListEntry
;
44 PFILE_OBJECT FileObject
;
50 KSPIN_LOCK AllocMapLock
;
52 } PAGINGFILE
, *PPAGINGFILE
;
54 /* GLOBALS *******************************************************************/
56 #define MAX_PAGING_FILES (32)
58 /* List of paging files, both used and free */
59 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
61 /* Lock for examining the list of paging files */
62 static KSPIN_LOCK PagingFileListLock
;
64 /* Number of pages that are available for swapping */
65 static ULONG MiFreeSwapPages
;
67 /* Number of pages that have been allocated for swapping */
68 static ULONG MiUsedSwapPages
;
71 * Number of pages that have been reserved for swapping but not yet allocated
73 static ULONG MiReservedSwapPages
;
76 * Ratio between reserved and available swap pages, e.g. setting this to five
77 * forces one swap page to be available for every five swap pages that are
78 * reserved. Setting this to zero turns off commit checking altogether.
80 #define MM_PAGEFILE_COMMIT_RATIO (1)
83 * Number of pages that can be used for potentially swapable memory without
84 * pagefile space being reserved. The intention is that this allows smss
85 * to start up and create page files while ordinarily having a commit
88 #define MM_PAGEFILE_COMMIT_GRACE (256)
91 static PVOID MmCoreDumpPageFrame
;
92 static BYTE MmCoreDumpHeader
[PAGESIZE
];
96 * Translate between a swap entry and a file and offset pair.
98 #define FILE_FROM_ENTRY(i) ((i) >> 24)
99 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
100 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
102 /* FUNCTIONS *****************************************************************/
104 NTSTATUS
MmWriteToSwapPage(SWAPENTRY SwapEntry
, PMDL Mdl
)
107 LARGE_INTEGER file_offset
;
108 IO_STATUS_BLOCK Iosb
;
114 return(STATUS_UNSUCCESSFUL
);
117 i
= FILE_FROM_ENTRY(SwapEntry
);
118 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
120 if (i
> MAX_PAGING_FILES
)
122 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
125 if (PagingFileList
[i
]->FileObject
== NULL
||
126 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
128 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
132 file_offset
.QuadPart
= offset
* 4096;
134 Status
= IoPageWrite(PagingFileList
[i
]->FileObject
,
142 NTSTATUS
MmReadFromSwapPage(SWAPENTRY SwapEntry
, PMDL Mdl
)
145 LARGE_INTEGER file_offset
;
146 IO_STATUS_BLOCK Iosb
;
152 return(STATUS_UNSUCCESSFUL
);
155 i
= FILE_FROM_ENTRY(SwapEntry
);
156 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
158 if (i
> MAX_PAGING_FILES
)
160 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
163 if (PagingFileList
[i
]->FileObject
== NULL
||
164 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
166 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
170 file_offset
.QuadPart
= offset
* 4096;
172 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
181 MmInitPagingFile(VOID
)
185 KeInitializeSpinLock(&PagingFileListLock
);
189 MiReservedSwapPages
= 0;
191 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
193 PagingFileList
[i
] = NULL
;
198 MmReserveSwapPages(ULONG Nr
)
201 ULONG MiAvailSwapPages
;
203 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
205 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
206 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
208 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
211 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
212 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
218 MmDereserveSwapPages(ULONG Nr
)
222 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
223 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
224 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
228 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
233 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
235 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
237 for (j
= 0; j
< 32; j
++)
239 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
248 PagingFile
->AllocMap
[i
] |= (1 << j
);
249 PagingFile
->UsedPages
++;
250 PagingFile
->FreePages
--;
251 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
252 return((i
* 32) + j
);
255 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
260 MmFreeSwapPage(SWAPENTRY Entry
)
266 i
= FILE_FROM_ENTRY(Entry
);
267 off
= OFFSET_FROM_ENTRY(Entry
);
269 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
270 if (PagingFileList
[i
] == NULL
)
274 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
276 PagingFileList
[i
]->AllocMap
[off
/ 32] &= (~(1 << (off
% 32)));
278 PagingFileList
[i
]->FreePages
++;
279 PagingFileList
[i
]->UsedPages
--;
284 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
285 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
289 MmAllocSwapPage(VOID
)
295 static BOOLEAN SwapSpaceMessage
= FALSE
;
297 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
299 if (MiFreeSwapPages
== 0)
301 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
302 if (!SwapSpaceMessage
)
304 DPRINT1("MM: Out of swap space.\n");
305 SwapSpaceMessage
= TRUE
;
310 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
312 if (PagingFileList
[i
] != NULL
&&
313 PagingFileList
[i
]->FreePages
>= 1)
315 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
316 if (off
== 0xFFFFFFFF)
319 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
320 return(STATUS_UNSUCCESSFUL
);
324 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
326 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
331 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
332 if (!SwapSpaceMessage
)
334 DPRINT1("MM: Out of swap space.\n");
335 SwapSpaceMessage
= TRUE
;
341 NTSTATUS STDCALL
MmDumpToPagingFile(PCONTEXT Context
,
346 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Magic
=
347 MM_CORE_DUMP_HEADER_MAGIC
;
348 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Version
=
349 MM_CORE_DUMP_HEADER_VERSION
;
350 memcpy(&((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Context
,
353 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->DumpLength
= 0;
354 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->BugCode
= BugCode
;
355 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->ExceptionCode
=
357 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Cr2
= Cr2
;
358 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Cr3
= 0;
363 NtCreatePagingFile(IN PUNICODE_STRING PageFileName
,
364 IN ULONG MinimumSize
,
365 IN ULONG MaximumSize
,
366 OUT PULONG ActualSize
)
369 OBJECT_ATTRIBUTES ObjectAttributes
;
371 IO_STATUS_BLOCK IoStatus
;
372 PFILE_OBJECT FileObject
;
373 PPAGINGFILE PagingFile
;
378 LARGE_INTEGER ByteOffset
;
380 DPRINT("NtCreatePagingFile(PageFileName %wZ, MinimumSize %d)\n",
381 PageFileName
, MinimumSize
);
383 InitializeObjectAttributes(&ObjectAttributes
,
389 Status
= IoCreateFile(&FileHandle
,
397 FILE_SYNCHRONOUS_IO_NONALERT
,
402 SL_OPEN_PAGING_FILE
);
403 if (!NT_SUCCESS(Status
))
408 Buffer
= ExAllocatePool(NonPagedPool
, 4096);
409 memset(Buffer
, 0, 4096);
410 ByteOffset
.QuadPart
= MinimumSize
* 4096;
411 Status
= NtWriteFile(FileHandle
,
420 if (!NT_SUCCESS(Status
))
427 Status
= ObReferenceObjectByHandle(FileHandle
,
433 if (!NT_SUCCESS(Status
))
441 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
442 if (PagingFile
== NULL
)
444 ObDereferenceObject(FileObject
);
445 return(STATUS_NO_MEMORY
);
448 PagingFile
->FileObject
= FileObject
;
449 PagingFile
->MaximumSize
= PagingFile
->CurrentSize
= MinimumSize
;
450 PagingFile
->FreePages
= MinimumSize
;
451 PagingFile
->UsedPages
= 0;
452 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
454 AllocMapSize
= (MinimumSize
/ 32) + 1;
455 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
456 AllocMapSize
* sizeof(ULONG
));
457 PagingFile
->AllocMapSize
= AllocMapSize
;
459 if (PagingFile
->AllocMap
== NULL
)
461 ExFreePool(PagingFile
);
462 ObDereferenceObject(FileObject
);
463 return(STATUS_NO_MEMORY
);
466 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
467 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
469 if (PagingFileList
[i
] == NULL
)
471 PagingFileList
[i
] = PagingFile
;
475 MiFreeSwapPages
= MiFreeSwapPages
+ MinimumSize
;
476 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
478 return(STATUS_SUCCESS
);