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.18 2002/03/18 16:15:08 ekohl 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
;
45 LARGE_INTEGER MaximumSize
;
46 LARGE_INTEGER CurrentSize
;
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 paging files */
65 static ULONG MiPagingFileCount
;
67 /* Number of pages that are available for swapping */
68 static ULONG MiFreeSwapPages
;
70 /* Number of pages that have been allocated for swapping */
71 static ULONG MiUsedSwapPages
;
74 * Number of pages that have been reserved for swapping but not yet allocated
76 static ULONG MiReservedSwapPages
;
79 * Ratio between reserved and available swap pages, e.g. setting this to five
80 * forces one swap page to be available for every five swap pages that are
81 * reserved. Setting this to zero turns off commit checking altogether.
83 #define MM_PAGEFILE_COMMIT_RATIO (1)
86 * Number of pages that can be used for potentially swapable memory without
87 * pagefile space being reserved. The intention is that this allows smss
88 * to start up and create page files while ordinarily having a commit
91 #define MM_PAGEFILE_COMMIT_GRACE (256)
94 static PVOID MmCoreDumpPageFrame
;
95 static BYTE MmCoreDumpHeader
[PAGESIZE
];
99 * Translate between a swap entry and a file and offset pair.
101 #define FILE_FROM_ENTRY(i) ((i) >> 24)
102 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
103 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
105 /* FUNCTIONS *****************************************************************/
107 NTSTATUS
MmWriteToSwapPage(SWAPENTRY SwapEntry
, PMDL Mdl
)
110 LARGE_INTEGER file_offset
;
111 IO_STATUS_BLOCK Iosb
;
117 return(STATUS_UNSUCCESSFUL
);
120 i
= FILE_FROM_ENTRY(SwapEntry
);
121 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
123 if (i
> MAX_PAGING_FILES
)
125 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
128 if (PagingFileList
[i
]->FileObject
== NULL
||
129 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
131 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
135 file_offset
.QuadPart
= offset
* 4096;
137 Status
= IoPageWrite(PagingFileList
[i
]->FileObject
,
145 NTSTATUS
MmReadFromSwapPage(SWAPENTRY SwapEntry
, PMDL Mdl
)
148 LARGE_INTEGER file_offset
;
149 IO_STATUS_BLOCK Iosb
;
155 return(STATUS_UNSUCCESSFUL
);
158 i
= FILE_FROM_ENTRY(SwapEntry
);
159 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
161 if (i
> MAX_PAGING_FILES
)
163 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
166 if (PagingFileList
[i
]->FileObject
== NULL
||
167 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
169 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
173 file_offset
.QuadPart
= offset
* 4096;
175 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
184 MmInitPagingFile(VOID
)
188 KeInitializeSpinLock(&PagingFileListLock
);
192 MiReservedSwapPages
= 0;
194 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
196 PagingFileList
[i
] = NULL
;
198 MiPagingFileCount
= 0;
202 MmReserveSwapPages(ULONG Nr
)
205 ULONG MiAvailSwapPages
;
207 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
209 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
210 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
212 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
215 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
216 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
222 MmDereserveSwapPages(ULONG Nr
)
226 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
227 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
228 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
232 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
237 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
239 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
241 for (j
= 0; j
< 32; j
++)
243 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
252 PagingFile
->AllocMap
[i
] |= (1 << j
);
253 PagingFile
->UsedPages
++;
254 PagingFile
->FreePages
--;
255 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
256 return((i
* 32) + j
);
259 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
264 MmFreeSwapPage(SWAPENTRY Entry
)
270 i
= FILE_FROM_ENTRY(Entry
);
271 off
= OFFSET_FROM_ENTRY(Entry
);
273 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
274 if (PagingFileList
[i
] == NULL
)
278 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
280 PagingFileList
[i
]->AllocMap
[off
/ 32] &= (~(1 << (off
% 32)));
282 PagingFileList
[i
]->FreePages
++;
283 PagingFileList
[i
]->UsedPages
--;
288 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
289 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
293 MmAllocSwapPage(VOID
)
299 static BOOLEAN SwapSpaceMessage
= FALSE
;
301 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
303 if (MiFreeSwapPages
== 0)
305 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
306 if (!SwapSpaceMessage
)
308 DPRINT1("MM: Out of swap space.\n");
309 SwapSpaceMessage
= TRUE
;
314 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
316 if (PagingFileList
[i
] != NULL
&&
317 PagingFileList
[i
]->FreePages
>= 1)
319 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
320 if (off
== 0xFFFFFFFF)
323 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
324 return(STATUS_UNSUCCESSFUL
);
328 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
330 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
335 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
336 if (!SwapSpaceMessage
)
338 DPRINT1("MM: Out of swap space.\n");
339 SwapSpaceMessage
= TRUE
;
345 NTSTATUS STDCALL
MmDumpToPagingFile(PCONTEXT Context
,
350 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Magic
=
351 MM_CORE_DUMP_HEADER_MAGIC
;
352 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Version
=
353 MM_CORE_DUMP_HEADER_VERSION
;
354 memcpy(&((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Context
,
357 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->DumpLength
= 0;
358 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->BugCode
= BugCode
;
359 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->ExceptionCode
=
361 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Cr2
= Cr2
;
362 ((PMM_CORE_DUMP_HEADER
)MmCoreDumpHeader
)->Cr3
= 0;
367 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
368 IN PLARGE_INTEGER InitialSize
,
369 IN PLARGE_INTEGER MaximumSize
,
373 OBJECT_ATTRIBUTES ObjectAttributes
;
375 IO_STATUS_BLOCK IoStatus
;
376 PFILE_OBJECT FileObject
;
377 PPAGINGFILE PagingFile
;
383 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
384 FileName
, InitialSize
->QuadPart
);
386 if (MiPagingFileCount
>= MAX_PAGING_FILES
)
388 return(STATUS_TOO_MANY_PAGING_FILES
);
391 InitializeObjectAttributes(&ObjectAttributes
,
397 Status
= IoCreateFile(&FileHandle
,
405 FILE_SYNCHRONOUS_IO_NONALERT
,
410 SL_OPEN_PAGING_FILE
);
411 if (!NT_SUCCESS(Status
))
416 Buffer
= ExAllocatePool(NonPagedPool
, 4096);
417 memset(Buffer
, 0, 4096);
418 Status
= NtWriteFile(FileHandle
,
427 if (!NT_SUCCESS(Status
))
434 Status
= ObReferenceObjectByHandle(FileHandle
,
440 if (!NT_SUCCESS(Status
))
448 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
449 if (PagingFile
== NULL
)
451 ObDereferenceObject(FileObject
);
452 return(STATUS_NO_MEMORY
);
455 PagingFile
->FileObject
= FileObject
;
456 PagingFile
->MaximumSize
.QuadPart
= MaximumSize
->QuadPart
;
457 PagingFile
->CurrentSize
.QuadPart
= InitialSize
->QuadPart
;
458 PagingFile
->FreePages
= InitialSize
->QuadPart
/ PAGESIZE
;
459 PagingFile
->UsedPages
= 0;
460 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
462 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
463 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
464 AllocMapSize
* sizeof(ULONG
));
465 PagingFile
->AllocMapSize
= AllocMapSize
;
467 if (PagingFile
->AllocMap
== NULL
)
469 ExFreePool(PagingFile
);
470 ObDereferenceObject(FileObject
);
471 return(STATUS_NO_MEMORY
);
474 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
475 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
477 if (PagingFileList
[i
] == NULL
)
479 PagingFileList
[i
] = PagingFile
;
483 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
485 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
487 return(STATUS_SUCCESS
);