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.49 2004/08/01 07:24:58 hbirr 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>
35 #include <internal/ps.h>
36 #include <internal/ldr.h>
37 #include <rosrtl/string.h>
40 #include <internal/debug.h>
42 /* TYPES *********************************************************************/
44 typedef struct _PAGINGFILE
46 LIST_ENTRY PagingFileListEntry
;
47 PFILE_OBJECT FileObject
;
48 LARGE_INTEGER MaximumSize
;
49 LARGE_INTEGER CurrentSize
;
53 KSPIN_LOCK AllocMapLock
;
55 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers
;
57 PAGINGFILE
, *PPAGINGFILE
;
59 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
61 struct _RETRIEVEL_DESCRIPTOR_LIST
* Next
;
62 GET_RETRIEVAL_DESCRIPTOR RetrievalPointers
;
64 RETRIEVEL_DESCRIPTOR_LIST
, *PRETRIEVEL_DESCRIPTOR_LIST
;
66 /* GLOBALS *******************************************************************/
68 #define PAIRS_PER_RUN (1024)
70 #define MAX_PAGING_FILES (32)
72 /* List of paging files, both used and free */
73 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
75 /* Lock for examining the list of paging files */
76 static KSPIN_LOCK PagingFileListLock
;
78 /* Number of paging files */
79 static ULONG MiPagingFileCount
;
81 /* Number of pages that are available for swapping */
82 ULONG MiFreeSwapPages
;
84 /* Number of pages that have been allocated for swapping */
85 ULONG MiUsedSwapPages
;
88 * Number of pages that have been reserved for swapping but not yet allocated
90 static ULONG MiReservedSwapPages
;
93 * Ratio between reserved and available swap pages, e.g. setting this to five
94 * forces one swap page to be available for every five swap pages that are
95 * reserved. Setting this to zero turns off commit checking altogether.
97 #define MM_PAGEFILE_COMMIT_RATIO (1)
100 * Number of pages that can be used for potentially swapable memory without
101 * pagefile space being reserved. The intention is that this allows smss
102 * to start up and create page files while ordinarily having a commit
105 #define MM_PAGEFILE_COMMIT_GRACE (256)
107 static PVOID MmCoreDumpPageFrame
= NULL
;
108 static ULONG MmCoreDumpSize
;
109 static DUMP_POINTERS MmCoreDumpPointers
;
110 static PMM_CORE_DUMP_FUNCTIONS MmCoreDumpFunctions
;
111 static ULONG MmCoreDumpPageFile
= 0xFFFFFFFF;
112 static ROS_QUERY_LCN_MAPPING MmCoreDumpLcnMapping
;
114 ULONG MmCoreDumpType
= MM_CORE_DUMP_TYPE_NONE
;
117 * Translate between a swap entry and a file and offset pair.
119 #define FILE_FROM_ENTRY(i) ((i) >> 24)
120 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
121 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
123 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
125 /* FUNCTIONS *****************************************************************/
128 MmShowOutOfSpaceMessagePagingFile(VOID
)
130 if (!MmSwapSpaceMessage
)
132 DPRINT1("MM: Out of swap space.\n");
133 MmSwapSpaceMessage
= TRUE
;
138 MmGetOffsetPageFile(PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers
, LARGE_INTEGER Offset
)
140 /* Simple binary search */
141 ULONG first
, last
, mid
;
143 last
= RetrievalPointers
->NumberOfPairs
- 1;
144 while (first
<= last
)
146 mid
= (last
- first
) / 2 + first
;
147 if ((ULONGLONG
) Offset
.QuadPart
< RetrievalPointers
->Pair
[mid
].Vcn
)
151 Offset
.QuadPart
+= RetrievalPointers
->Pair
[0].Lcn
- RetrievalPointers
->StartVcn
;
156 if ((ULONGLONG
) Offset
.QuadPart
>= RetrievalPointers
->Pair
[mid
-1].Vcn
)
158 Offset
.QuadPart
+= RetrievalPointers
->Pair
[mid
].Lcn
- RetrievalPointers
->Pair
[mid
-1].Vcn
;
166 if (mid
== RetrievalPointers
->NumberOfPairs
- 1)
170 if ((ULONGLONG
) Offset
.QuadPart
< RetrievalPointers
->Pair
[mid
+1].Vcn
)
172 Offset
.QuadPart
+= RetrievalPointers
->Pair
[mid
+1].Lcn
- RetrievalPointers
->Pair
[mid
].Vcn
;
179 #if defined(__GNUC__)
181 return (LARGE_INTEGER
)0LL;
185 const LARGE_INTEGER dummy
=
194 NTSTATUS
MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
197 LARGE_INTEGER file_offset
;
198 IO_STATUS_BLOCK Iosb
;
201 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
202 PMDL Mdl
= (PMDL
)MdlBase
;
204 DPRINT("MmWriteToSwapPage\n");
209 return(STATUS_UNSUCCESSFUL
);
212 i
= FILE_FROM_ENTRY(SwapEntry
);
213 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
215 if (i
>= MAX_PAGING_FILES
)
217 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
220 if (PagingFileList
[i
]->FileObject
== NULL
||
221 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
223 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
227 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
228 MmBuildMdlFromPages(Mdl
, &Page
);
230 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
231 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
233 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
234 Status
= IoPageWrite(PagingFileList
[i
]->FileObject
,
239 if (Status
== STATUS_PENDING
)
241 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
242 Status
= Iosb
.Status
;
244 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
248 NTSTATUS
MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
251 LARGE_INTEGER file_offset
;
252 IO_STATUS_BLOCK Iosb
;
255 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
256 PMDL Mdl
= (PMDL
)MdlBase
;
258 DPRINT("MmReadFromSwapPage\n");
263 return(STATUS_UNSUCCESSFUL
);
266 i
= FILE_FROM_ENTRY(SwapEntry
);
267 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
269 if (i
>= MAX_PAGING_FILES
)
271 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
274 if (PagingFileList
[i
]->FileObject
== NULL
||
275 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
277 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
281 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
282 MmBuildMdlFromPages(Mdl
, &Page
);
284 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
285 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
287 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
288 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
293 if (Status
== STATUS_PENDING
)
295 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
296 Status
= Iosb
.Status
;
298 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
303 MmInitPagingFile(VOID
)
307 KeInitializeSpinLock(&PagingFileListLock
);
311 MiReservedSwapPages
= 0;
313 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
315 PagingFileList
[i
] = NULL
;
317 MiPagingFileCount
= 0;
320 * Initialize the crash dump support.
322 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
)
324 MmCoreDumpPageFrame
= MmAllocateSection(PAGE_SIZE
);
325 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
327 MmCoreDumpSize
= MmStats
.NrTotalPages
* 4096 + 1024 * 1024;
331 MmCoreDumpSize
= 1024 * 1024;
337 MmReserveSwapPages(ULONG Nr
)
340 ULONG MiAvailSwapPages
;
342 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
344 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
345 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
346 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
348 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
351 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
356 MmDereserveSwapPages(ULONG Nr
)
360 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
361 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
362 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
366 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
371 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
373 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
375 for (j
= 0; j
< 32; j
++)
377 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
379 PagingFile
->AllocMap
[i
] |= (1 << j
);
380 PagingFile
->UsedPages
++;
381 PagingFile
->FreePages
--;
382 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
383 return((i
* 32) + j
);
388 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
393 MmFreeSwapPage(SWAPENTRY Entry
)
399 i
= FILE_FROM_ENTRY(Entry
);
400 off
= OFFSET_FROM_ENTRY(Entry
);
402 if (i
>= MAX_PAGING_FILES
)
404 DPRINT1("Bad swap entry 0x%.8X\n", Entry
);
408 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
409 if (PagingFileList
[i
] == NULL
)
413 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
415 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
417 PagingFileList
[i
]->FreePages
++;
418 PagingFileList
[i
]->UsedPages
--;
423 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
424 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
428 MmIsAvailableSwapPage(VOID
)
430 return(MiFreeSwapPages
> 0);
434 MmAllocSwapPage(VOID
)
441 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
443 if (MiFreeSwapPages
== 0)
445 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
449 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
451 if (PagingFileList
[i
] != NULL
&&
452 PagingFileList
[i
]->FreePages
>= 1)
454 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
455 if (off
== 0xFFFFFFFF)
458 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
459 return(STATUS_UNSUCCESSFUL
);
463 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
465 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
470 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
475 STATIC PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
476 MmAllocRetrievelDescriptorList(ULONG Pairs
)
479 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
481 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* sizeof(MAPPING_PAIR
);
482 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
485 RtlZeroMemory(RetDescList
, Size
);
492 MmDumpToPagingFile(ULONG BugCode
,
493 ULONG BugCodeParameter1
,
494 ULONG BugCodeParameter2
,
495 ULONG BugCodeParameter3
,
496 ULONG BugCodeParameter4
,
497 PKTRAP_FRAME TrapFrame
)
499 PMM_CORE_DUMP_HEADER Headers
;
501 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
502 PMDL Mdl
= (PMDL
)MdlBase
;
503 PETHREAD Thread
= PsGetCurrentThread();
506 LONGLONG NextOffset
= 0;
508 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers
;
509 LARGE_INTEGER DiskOffset
;
511 if (MmCoreDumpPageFile
== 0xFFFFFFFF)
513 return(STATUS_UNSUCCESSFUL
);
516 DbgPrint("\nMM: Dumping core: ");
518 /* Prepare the dump headers. */
519 Headers
= (PMM_CORE_DUMP_HEADER
)MmCoreDumpPageFrame
;
520 Headers
->Magic
= MM_CORE_DUMP_HEADER_MAGIC
;
521 Headers
->Version
= MM_CORE_DUMP_HEADER_VERSION
;
522 Headers
->Type
= MmCoreDumpType
;
523 if (TrapFrame
!= NULL
)
525 if (!(TrapFrame
->Eflags
& (1 << 17)))
527 memcpy(&Headers
->TrapFrame
, TrapFrame
,
528 sizeof(KTRAP_FRAME
) - (4 * sizeof(DWORD
)));
532 memcpy(&Headers
->TrapFrame
, TrapFrame
, sizeof(KTRAP_FRAME
));
535 Headers
->BugCheckCode
= BugCode
;
536 Headers
->BugCheckParameters
[0] = BugCodeParameter1
;
537 Headers
->BugCheckParameters
[1] = BugCodeParameter2
;
538 Headers
->BugCheckParameters
[2] = BugCodeParameter3
;
539 Headers
->BugCheckParameters
[3] = BugCodeParameter4
;
540 Headers
->FaultingStackBase
= (PVOID
)Thread
->Tcb
.StackLimit
;
541 Headers
->FaultingStackSize
= StackSize
=
542 (ULONG
)((char*)Thread
->Tcb
.StackBase
- Thread
->Tcb
.StackLimit
);
543 Headers
->PhysicalMemorySize
= MmStats
.NrTotalPages
* PAGE_SIZE
;
545 /* Initialize the dump device. */
546 Status
= MmCoreDumpFunctions
->DumpInit();
547 if (!NT_SUCCESS(Status
))
549 DPRINT1("MM: Failed to initialize core dump device.\n");
553 /* Initialize the MDL. */
554 MmInitializeMdl(Mdl
, MmCoreDumpPageFrame
, PAGE_SIZE
);
555 Mdl
->MdlFlags
= MDL_PAGES_LOCKED
|MDL_IO_PAGE_READ
|MDL_SOURCE_IS_NONPAGED_POOL
;
556 MdlMap
= (PULONG
)(Mdl
+ 1);
559 /* Initialize the retrieval offsets. */
560 RetrievalPointers
= PagingFileList
[MmCoreDumpPageFile
]->RetrievalPointers
;
562 /* Dump the header. */
563 MdlMap
[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame
).QuadPart
>> PAGE_SHIFT
;
564 #if defined(__GNUC__)
566 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, (LARGE_INTEGER
)0LL);
570 const LARGE_INTEGER dummy
=
574 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
577 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
578 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
579 if (!NT_SUCCESS(Status
))
581 DPRINT1("MM: Failed to write core dump header\n.");
584 NextOffset
+= PAGE_SIZE
;
589 /* Write out the contents of physical memory. */
590 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
592 for (i
= 0; i
< MmStats
.NrTotalPages
; i
++)
595 MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame
,
599 #if defined(__GNUC__)
601 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
,
602 (LARGE_INTEGER
)NextOffset
);
607 dummy
.QuadPart
= NextOffset
;
608 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
611 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
612 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
613 MmRawDeleteVirtualMapping(MmCoreDumpPageFrame
);
614 if (!NT_SUCCESS(Status
))
616 DPRINT1("MM: Failed to write page to core dump.\n");
619 if ((i
% ((1024*1024) / PAGE_SIZE
)) == 0)
621 DbgPrint("\b\b%.2d", i
/ ((1024*1024)/PAGE_SIZE
));
623 NextOffset
+= PAGE_SIZE
;
628 MmCoreDumpFunctions
->DumpFinish();
629 return(STATUS_SUCCESS
);
633 MmInitializeCrashDump(HANDLE PageFileHandle
, ULONG PageFileNum
)
635 PFILE_OBJECT PageFile
;
636 PDEVICE_OBJECT PageFileDevice
;
640 IO_STATUS_BLOCK Iosb
;
641 UNICODE_STRING DiskDumpName
;
642 ANSI_STRING ProcName
;
643 PIO_STACK_LOCATION StackPtr
;
644 PMODULE_OBJECT ModuleObject
;
646 Status
= ZwFsControlFile(PageFileHandle
,
651 FSCTL_ROS_QUERY_LCN_MAPPING
,
654 &MmCoreDumpLcnMapping
,
655 sizeof(ROS_QUERY_LCN_MAPPING
));
656 if (!NT_SUCCESS(Status
) ||
657 Iosb
.Information
!= sizeof(ROS_QUERY_LCN_MAPPING
))
662 /* Get the underlying storage device. */
664 ObReferenceObjectByHandle(PageFileHandle
,
670 if (!NT_SUCCESS(Status
))
675 PageFileDevice
= PageFile
->Vpb
->RealDevice
;
677 /* Get the dump pointers. */
678 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
679 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS
,
684 sizeof(MmCoreDumpPointers
),
690 ObDereferenceObject(PageFile
);
691 return(STATUS_NO_MEMORY
);// tMk - is this correct return code ???
694 StackPtr
= IoGetNextIrpStackLocation(Irp
);
695 StackPtr
->FileObject
= PageFile
;
696 StackPtr
->DeviceObject
= PageFileDevice
;
697 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
698 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(MmCoreDumpPointers
);
700 Status
= IoCallDriver(PageFileDevice
,Irp
);
701 if (Status
== STATUS_PENDING
)
703 Status
= KeWaitForSingleObject(&Event
,
709 if (Status
!= STATUS_SUCCESS
||
710 Iosb
.Information
!= sizeof(MmCoreDumpPointers
))
712 ObDereferenceObject(PageFile
);
716 /* Load the diskdump driver. */
717 RtlRosInitUnicodeStringFromLiteral(&DiskDumpName
, L
"DiskDump");
718 ModuleObject
= LdrGetModuleObject(&DiskDumpName
);
719 if (ModuleObject
== NULL
)
721 return(STATUS_OBJECT_NAME_NOT_FOUND
);
723 RtlInitAnsiString(&ProcName
, "DiskDumpFunctions");
724 Status
= LdrGetProcedureAddress(ModuleObject
->Base
,
727 (PVOID
*)&MmCoreDumpFunctions
);
728 if (!NT_SUCCESS(Status
))
730 ObDereferenceObject(PageFile
);
734 /* Prepare for disk dumping. */
735 Status
= MmCoreDumpFunctions
->DumpPrepare(PageFileDevice
,
736 &MmCoreDumpPointers
);
737 if (!NT_SUCCESS(Status
))
739 ObDereferenceObject(PageFile
);
743 MmCoreDumpPageFile
= PageFileNum
;
744 ObDereferenceObject(PageFile
);
745 return(STATUS_SUCCESS
);
749 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
750 IN PLARGE_INTEGER InitialSize
,
751 IN PLARGE_INTEGER MaximumSize
,
755 OBJECT_ATTRIBUTES ObjectAttributes
;
757 IO_STATUS_BLOCK IoStatus
;
758 PFILE_OBJECT FileObject
;
759 PPAGINGFILE PagingFile
;
762 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
763 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
764 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
766 ULONG BytesPerAllocationUnit
;
773 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
774 FileName
, InitialSize
->QuadPart
);
776 if (MiPagingFileCount
>= MAX_PAGING_FILES
)
778 return(STATUS_TOO_MANY_PAGING_FILES
);
781 InitializeObjectAttributes(&ObjectAttributes
,
787 Status
= IoCreateFile(&FileHandle
,
795 FILE_SYNCHRONOUS_IO_NONALERT
,
800 SL_OPEN_PAGING_FILE
);
801 if (!NT_SUCCESS(Status
))
806 Status
= NtQueryVolumeInformationFile(FileHandle
,
809 sizeof(FILE_FS_SIZE_INFORMATION
),
810 FileFsSizeInformation
);
811 if (!NT_SUCCESS(Status
))
817 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
* FsSizeInformation
.BytesPerSector
;
818 if (BytesPerAllocationUnit
% PAGE_SIZE
)
821 return STATUS_UNSUCCESSFUL
;
824 Status
= NtSetInformationFile(FileHandle
,
827 sizeof(LARGE_INTEGER
),
828 FileAllocationInformation
);
829 if (!NT_SUCCESS(Status
))
835 Status
= ObReferenceObjectByHandle(FileHandle
,
841 if (!NT_SUCCESS(Status
))
847 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
849 if (CurrentRetDescList
== NULL
)
851 ObDereferenceObject(FileObject
);
853 return(STATUS_NO_MEMORY
);
856 #if defined(__GNUC__)
864 MaxVcn
= (ULONG
)((InitialSize
->QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
);
867 Status
= NtFsControlFile(FileHandle
,
872 FSCTL_GET_RETRIEVAL_POINTERS
,
874 sizeof(LARGE_INTEGER
),
875 &CurrentRetDescList
->RetrievalPointers
,
876 sizeof(GET_RETRIEVAL_DESCRIPTOR
) + PAIRS_PER_RUN
* sizeof(MAPPING_PAIR
));
877 if (!NT_SUCCESS(Status
))
881 CurrentRetDescList
= RetDescList
;
882 RetDescList
= RetDescList
->Next
;
883 ExFreePool(CurrentRetDescList
);
885 ObDereferenceObject(FileObject
);
889 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
;
890 if ((ULONG
)CurrentRetDescList
->RetrievalPointers
.Pair
[CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
-1].Vcn
< MaxVcn
)
892 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
893 if (CurrentRetDescList
->Next
== NULL
)
897 CurrentRetDescList
= RetDescList
;
898 RetDescList
= RetDescList
->Next
;
899 ExFreePool(CurrentRetDescList
);
901 ObDereferenceObject(FileObject
);
903 return(STATUS_NO_MEMORY
);
905 Vcn
.QuadPart
= CurrentRetDescList
->RetrievalPointers
.Pair
[CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
-1].Vcn
;
906 CurrentRetDescList
= CurrentRetDescList
->Next
;
914 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
915 if (PagingFile
== NULL
)
919 CurrentRetDescList
= RetDescList
;
920 RetDescList
= RetDescList
->Next
;
921 ExFreePool(CurrentRetDescList
);
923 ObDereferenceObject(FileObject
);
925 return(STATUS_NO_MEMORY
);
928 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
930 PagingFile
->FileObject
= FileObject
;
931 PagingFile
->MaximumSize
.QuadPart
= MaximumSize
->QuadPart
;
932 PagingFile
->CurrentSize
.QuadPart
= InitialSize
->QuadPart
;
933 PagingFile
->FreePages
= (ULONG
)(InitialSize
->QuadPart
/ PAGE_SIZE
);
934 PagingFile
->UsedPages
= 0;
935 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
937 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
938 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
939 AllocMapSize
* sizeof(ULONG
));
940 PagingFile
->AllocMapSize
= AllocMapSize
;
942 if (PagingFile
->AllocMap
== NULL
)
946 CurrentRetDescList
= RetDescList
;
947 RetDescList
= RetDescList
->Next
;
948 ExFreePool(CurrentRetDescList
);
950 ExFreePool(PagingFile
);
951 ObDereferenceObject(FileObject
);
953 return(STATUS_NO_MEMORY
);
955 DPRINT("ExtentCount: %d\n", ExtentCount
);
956 Size
= sizeof(GET_RETRIEVAL_DESCRIPTOR
) + ExtentCount
* sizeof(MAPPING_PAIR
);
957 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
958 if (PagingFile
->RetrievalPointers
== NULL
)
962 CurrentRetDescList
= RetDescList
;
963 RetDescList
= RetDescList
->Next
;
964 ExFreePool(CurrentRetDescList
);
966 ExFreePool(PagingFile
->AllocMap
);
967 ExFreePool(PagingFile
);
968 ObDereferenceObject(FileObject
);
970 return(STATUS_NO_MEMORY
);
973 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
974 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
977 PagingFile
->RetrievalPointers
->NumberOfPairs
= ExtentCount
;
978 PagingFile
->RetrievalPointers
->StartVcn
= RetDescList
->RetrievalPointers
.StartVcn
;
979 CurrentRetDescList
= RetDescList
;
980 while (CurrentRetDescList
)
982 memcpy(&PagingFile
->RetrievalPointers
->Pair
[Count
],
983 CurrentRetDescList
->RetrievalPointers
.Pair
,
984 CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
* sizeof(MAPPING_PAIR
));
985 Count
+= CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
;
986 RetDescList
= CurrentRetDescList
;
987 CurrentRetDescList
= CurrentRetDescList
->Next
;
988 ExFreePool(RetDescList
);
991 if (PagingFile
->RetrievalPointers
->NumberOfPairs
!= ExtentCount
||
992 (ULONG
)PagingFile
->RetrievalPointers
->Pair
[ExtentCount
- 1].Vcn
!= MaxVcn
)
994 ExFreePool(PagingFile
->RetrievalPointers
);
995 ExFreePool(PagingFile
->AllocMap
);
996 ExFreePool(PagingFile
);
997 ObDereferenceObject(FileObject
);
999 return(STATUS_UNSUCCESSFUL
);
1003 * Change the entries from lcn's to volume offset's.
1005 PagingFile
->RetrievalPointers
->StartVcn
*= BytesPerAllocationUnit
;
1006 for (i
= 0; i
< ExtentCount
; i
++)
1008 PagingFile
->RetrievalPointers
->Pair
[i
].Lcn
*= BytesPerAllocationUnit
;
1009 PagingFile
->RetrievalPointers
->Pair
[i
].Vcn
*= BytesPerAllocationUnit
;
1012 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
1013 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
1015 if (PagingFileList
[i
] == NULL
)
1017 PagingFileList
[i
] = PagingFile
;
1021 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
1022 MiPagingFileCount
++;
1023 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
1025 /* Check whether this pagefile can be a crash dump target. */
1026 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
&&
1027 PagingFile
->CurrentSize
.QuadPart
>= MmCoreDumpSize
&&
1028 MmCoreDumpPageFile
== 0xFFFFFFFF)
1030 MmInitializeCrashDump(FileHandle
, i
);
1032 NtClose(FileHandle
);
1034 MmSwapSpaceMessage
= FALSE
;
1036 return(STATUS_SUCCESS
);