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.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/pagefile.c
22 * PURPOSE: Paging file functions
23 * PROGRAMMER: David Welch (welch@mcmail.com)
28 /* INCLUDES *****************************************************************/
32 #include <internal/debug.h>
34 #if defined (ALLOC_PRAGMA)
35 #pragma alloc_text(INIT, MmInitPagingFile)
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 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
54 PAGINGFILE
, *PPAGINGFILE
;
56 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
58 struct _RETRIEVEL_DESCRIPTOR_LIST
* Next
;
59 RETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
61 RETRIEVEL_DESCRIPTOR_LIST
, *PRETRIEVEL_DESCRIPTOR_LIST
;
63 /* GLOBALS *******************************************************************/
65 #define PAIRS_PER_RUN (1024)
67 #define MAX_PAGING_FILES (32)
69 /* List of paging files, both used and free */
70 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
72 /* Lock for examining the list of paging files */
73 static KSPIN_LOCK PagingFileListLock
;
75 /* Number of paging files */
76 static ULONG MiPagingFileCount
;
78 /* Number of pages that are available for swapping */
79 ULONG MiFreeSwapPages
;
81 /* Number of pages that have been allocated for swapping */
82 ULONG MiUsedSwapPages
;
85 * Number of pages that have been reserved for swapping but not yet allocated
87 static ULONG MiReservedSwapPages
;
90 * Ratio between reserved and available swap pages, e.g. setting this to five
91 * forces one swap page to be available for every five swap pages that are
92 * reserved. Setting this to zero turns off commit checking altogether.
94 #define MM_PAGEFILE_COMMIT_RATIO (1)
97 * Number of pages that can be used for potentially swapable memory without
98 * pagefile space being reserved. The intention is that this allows smss
99 * to start up and create page files while ordinarily having a commit
102 #define MM_PAGEFILE_COMMIT_GRACE (256)
104 static PVOID MmCoreDumpPageFrame
= NULL
;
105 static ULONG MmCoreDumpSize
;
106 static DUMP_POINTERS MmCoreDumpPointers
;
107 static PMM_CORE_DUMP_FUNCTIONS MmCoreDumpFunctions
;
108 static ULONG MmCoreDumpPageFile
= 0xFFFFFFFF;
109 static ROS_QUERY_LCN_MAPPING MmCoreDumpLcnMapping
;
111 ULONG MmCoreDumpType
= MM_CORE_DUMP_TYPE_NONE
;
114 * Translate between a swap entry and a file and offset pair.
116 #define FILE_FROM_ENTRY(i) ((i) >> 24)
117 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
118 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
120 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
122 /* FUNCTIONS *****************************************************************/
126 MmIsFileAPagingFile(PFILE_OBJECT FileObject
)
130 /* Loop through all the paging files */
131 for (i
= 0; i
< MiPagingFileCount
; i
++)
133 /* Check if this is one of them */
134 if (PagingFileList
[i
]->FileObject
== FileObject
) return TRUE
;
143 MmShowOutOfSpaceMessagePagingFile(VOID
)
145 if (!MmSwapSpaceMessage
)
147 DPRINT1("MM: Out of swap space.\n");
148 MmSwapSpaceMessage
= TRUE
;
153 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
, LARGE_INTEGER Offset
)
155 /* Simple binary search */
156 ULONG first
, last
, mid
;
158 last
= RetrievalPointers
->ExtentCount
- 1;
159 while (first
<= last
)
161 mid
= (last
- first
) / 2 + first
;
162 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
)
166 Offset
.QuadPart
+= RetrievalPointers
->Extents
[0].Lcn
.QuadPart
- RetrievalPointers
->StartingVcn
.QuadPart
;
171 if (Offset
.QuadPart
>= RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
)
173 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
;
181 if (mid
== RetrievalPointers
->ExtentCount
- 1)
185 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
+1].NextVcn
.QuadPart
)
187 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
+1].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
;
194 #if defined(__GNUC__)
196 return (LARGE_INTEGER
)0LL;
200 const LARGE_INTEGER dummy
=
211 MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
214 LARGE_INTEGER file_offset
;
215 IO_STATUS_BLOCK Iosb
;
218 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
219 PMDL Mdl
= (PMDL
)MdlBase
;
221 DPRINT("MmWriteToSwapPage\n");
226 return(STATUS_UNSUCCESSFUL
);
229 i
= FILE_FROM_ENTRY(SwapEntry
);
230 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
232 if (i
>= MAX_PAGING_FILES
)
234 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
237 if (PagingFileList
[i
]->FileObject
== NULL
||
238 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
240 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
244 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
245 MmBuildMdlFromPages(Mdl
, &Page
);
247 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
248 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
250 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
251 Status
= IoSynchronousPageWrite(PagingFileList
[i
]->FileObject
,
256 if (Status
== STATUS_PENDING
)
258 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
259 Status
= Iosb
.Status
;
261 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
267 MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
270 LARGE_INTEGER file_offset
;
271 IO_STATUS_BLOCK Iosb
;
274 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
275 PMDL Mdl
= (PMDL
)MdlBase
;
277 DPRINT("MmReadFromSwapPage\n");
282 return(STATUS_UNSUCCESSFUL
);
285 i
= FILE_FROM_ENTRY(SwapEntry
);
286 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
288 if (i
>= MAX_PAGING_FILES
)
290 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
293 if (PagingFileList
[i
]->FileObject
== NULL
||
294 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
296 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
300 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
301 MmBuildMdlFromPages(Mdl
, &Page
);
303 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
304 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
306 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
307 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
312 if (Status
== STATUS_PENDING
)
314 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
315 Status
= Iosb
.Status
;
317 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
324 MmInitPagingFile(VOID
)
328 KeInitializeSpinLock(&PagingFileListLock
);
332 MiReservedSwapPages
= 0;
334 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
336 PagingFileList
[i
] = NULL
;
338 MiPagingFileCount
= 0;
341 * Initialize the crash dump support.
343 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
)
345 MmCoreDumpPageFrame
= MmAllocateSection(PAGE_SIZE
, NULL
);
346 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
348 MmCoreDumpSize
= MmStats
.NrTotalPages
* 4096 + 1024 * 1024;
352 MmCoreDumpSize
= 1024 * 1024;
359 MmReserveSwapPages(ULONG Nr
)
362 ULONG MiAvailSwapPages
;
364 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
366 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
367 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
368 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
370 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
373 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
379 MmDereserveSwapPages(ULONG Nr
)
383 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
384 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
385 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
389 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
394 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
396 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
398 for (j
= 0; j
< 32; j
++)
400 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
402 PagingFile
->AllocMap
[i
] |= (1 << j
);
403 PagingFile
->UsedPages
++;
404 PagingFile
->FreePages
--;
405 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
406 return((i
* 32) + j
);
411 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
417 MmFreeSwapPage(SWAPENTRY Entry
)
423 i
= FILE_FROM_ENTRY(Entry
);
424 off
= OFFSET_FROM_ENTRY(Entry
);
426 if (i
>= MAX_PAGING_FILES
)
428 DPRINT1("Bad swap entry 0x%.8X\n", Entry
);
432 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
433 if (PagingFileList
[i
] == NULL
)
437 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
439 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
441 PagingFileList
[i
]->FreePages
++;
442 PagingFileList
[i
]->UsedPages
--;
447 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
448 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
453 MmIsAvailableSwapPage(VOID
)
455 return(MiFreeSwapPages
> 0);
460 MmAllocSwapPage(VOID
)
467 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
469 if (MiFreeSwapPages
== 0)
471 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
475 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
477 if (PagingFileList
[i
] != NULL
&&
478 PagingFileList
[i
]->FreePages
>= 1)
480 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
481 if (off
== 0xFFFFFFFF)
484 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
485 return(STATUS_UNSUCCESSFUL
);
489 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
491 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
496 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
501 STATIC PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
502 MmAllocRetrievelDescriptorList(ULONG Pairs
)
505 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
507 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* 2 * sizeof(LARGE_INTEGER
);
508 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
511 RtlZeroMemory(RetDescList
, Size
);
518 MmDumpToPagingFile(ULONG BugCode
,
519 ULONG BugCodeParameter1
,
520 ULONG BugCodeParameter2
,
521 ULONG BugCodeParameter3
,
522 ULONG BugCodeParameter4
,
523 PKTRAP_FRAME TrapFrame
)
525 PMM_CORE_DUMP_HEADER Headers
;
527 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
528 PMDL Mdl
= (PMDL
)MdlBase
;
529 PETHREAD Thread
= PsGetCurrentThread();
532 LONGLONG NextOffset
= 0;
534 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
535 LARGE_INTEGER DiskOffset
;
537 if (MmCoreDumpPageFile
== 0xFFFFFFFF)
539 return(STATUS_UNSUCCESSFUL
);
542 DbgPrint("\nMM: Dumping core: ");
544 /* Prepare the dump headers. */
545 Headers
= (PMM_CORE_DUMP_HEADER
)MmCoreDumpPageFrame
;
546 Headers
->Magic
= MM_CORE_DUMP_HEADER_MAGIC
;
547 Headers
->Version
= MM_CORE_DUMP_HEADER_VERSION
;
548 Headers
->Type
= MmCoreDumpType
;
549 if (TrapFrame
!= NULL
)
551 if (!(TrapFrame
->EFlags
& (1 << 17)))
553 memcpy(&Headers
->TrapFrame
, TrapFrame
,
554 sizeof(KTRAP_FRAME
) - (4 * sizeof(DWORD
)));
558 memcpy(&Headers
->TrapFrame
, TrapFrame
, sizeof(KTRAP_FRAME
));
561 Headers
->BugCheckCode
= BugCode
;
562 Headers
->BugCheckParameters
[0] = BugCodeParameter1
;
563 Headers
->BugCheckParameters
[1] = BugCodeParameter2
;
564 Headers
->BugCheckParameters
[2] = BugCodeParameter3
;
565 Headers
->BugCheckParameters
[3] = BugCodeParameter4
;
566 Headers
->FaultingStackBase
= (PVOID
)Thread
->Tcb
.StackLimit
;
567 Headers
->FaultingStackSize
=
568 StackSize
= (ULONG_PTR
)Thread
->Tcb
.StackBase
- (ULONG_PTR
)Thread
->Tcb
.StackLimit
;
569 Headers
->PhysicalMemorySize
= MmStats
.NrTotalPages
* PAGE_SIZE
;
571 /* Initialize the dump device. */
572 Status
= MmCoreDumpFunctions
->DumpInit();
573 if (!NT_SUCCESS(Status
))
575 DPRINT1("MM: Failed to initialize core dump device.\n");
579 /* Initialize the MDL. */
580 MmInitializeMdl(Mdl
, MmCoreDumpPageFrame
, PAGE_SIZE
);
581 Mdl
->MdlFlags
= MDL_PAGES_LOCKED
|MDL_IO_PAGE_READ
|MDL_SOURCE_IS_NONPAGED_POOL
;
582 MdlMap
= (PULONG
)(Mdl
+ 1);
585 /* Initialize the retrieval offsets. */
586 RetrievalPointers
= PagingFileList
[MmCoreDumpPageFile
]->RetrievalPointers
;
588 /* Dump the header. */
589 MdlMap
[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame
).QuadPart
>> PAGE_SHIFT
;
590 #if defined(__GNUC__)
592 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, (LARGE_INTEGER
)0LL);
596 const LARGE_INTEGER dummy
=
600 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
603 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
604 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
605 if (!NT_SUCCESS(Status
))
607 DPRINT1("MM: Failed to write core dump header\n.");
610 NextOffset
+= PAGE_SIZE
;
615 /* Write out the contents of physical memory. */
616 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
618 for (i
= 0; i
< MmStats
.NrTotalPages
; i
++)
621 MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame
,
625 #if defined(__GNUC__)
627 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
,
628 (LARGE_INTEGER
)NextOffset
);
633 dummy
.QuadPart
= NextOffset
;
634 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
637 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
638 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
639 MmRawDeleteVirtualMapping(MmCoreDumpPageFrame
);
640 if (!NT_SUCCESS(Status
))
642 DPRINT1("MM: Failed to write page to core dump.\n");
645 if ((i
% ((1024*1024) / PAGE_SIZE
)) == 0)
647 DbgPrint("\b\b%.2d", i
/ ((1024*1024)/PAGE_SIZE
));
649 NextOffset
+= PAGE_SIZE
;
654 MmCoreDumpFunctions
->DumpFinish();
655 return(STATUS_SUCCESS
);
659 MmInitializeCrashDump(HANDLE PageFileHandle
, ULONG PageFileNum
)
661 PFILE_OBJECT PageFile
;
662 PDEVICE_OBJECT PageFileDevice
;
666 IO_STATUS_BLOCK Iosb
;
667 UNICODE_STRING DiskDumpName
= RTL_CONSTANT_STRING(L
"DiskDump");
668 ANSI_STRING ProcName
;
669 PIO_STACK_LOCATION StackPtr
;
670 PLDR_DATA_TABLE_ENTRY ModuleObject
;
672 Status
= ZwFsControlFile(PageFileHandle
,
677 FSCTL_ROS_QUERY_LCN_MAPPING
,
680 &MmCoreDumpLcnMapping
,
681 sizeof(ROS_QUERY_LCN_MAPPING
));
682 if (!NT_SUCCESS(Status
) ||
683 Iosb
.Information
!= sizeof(ROS_QUERY_LCN_MAPPING
))
688 /* Get the underlying storage device. */
690 ObReferenceObjectByHandle(PageFileHandle
,
696 if (!NT_SUCCESS(Status
))
701 PageFileDevice
= PageFile
->Vpb
->RealDevice
;
703 /* Get the dump pointers. */
704 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
705 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS
,
710 sizeof(MmCoreDumpPointers
),
716 ObDereferenceObject(PageFile
);
717 return(STATUS_NO_MEMORY
);// tMk - is this correct return code ???
720 StackPtr
= IoGetNextIrpStackLocation(Irp
);
721 StackPtr
->FileObject
= PageFile
;
722 StackPtr
->DeviceObject
= PageFileDevice
;
723 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
724 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(MmCoreDumpPointers
);
726 Status
= IoCallDriver(PageFileDevice
,Irp
);
727 if (Status
== STATUS_PENDING
)
729 Status
= KeWaitForSingleObject(&Event
,
735 if (Status
!= STATUS_SUCCESS
||
736 Iosb
.Information
!= sizeof(MmCoreDumpPointers
))
738 ObDereferenceObject(PageFile
);
742 /* Load the diskdump driver. */
743 ModuleObject
= LdrGetModuleObject(&DiskDumpName
);
744 if (ModuleObject
== NULL
)
746 return(STATUS_OBJECT_NAME_NOT_FOUND
);
748 RtlInitAnsiString(&ProcName
, "DiskDumpFunctions");
749 Status
= LdrGetProcedureAddress(ModuleObject
->DllBase
,
752 (PVOID
*)&MmCoreDumpFunctions
);
753 if (!NT_SUCCESS(Status
))
755 ObDereferenceObject(PageFile
);
759 /* Prepare for disk dumping. */
760 Status
= MmCoreDumpFunctions
->DumpPrepare(PageFileDevice
,
761 &MmCoreDumpPointers
);
762 if (!NT_SUCCESS(Status
))
764 ObDereferenceObject(PageFile
);
768 MmCoreDumpPageFile
= PageFileNum
;
769 ObDereferenceObject(PageFile
);
770 return(STATUS_SUCCESS
);
774 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
775 IN PLARGE_INTEGER InitialSize
,
776 IN PLARGE_INTEGER MaximumSize
,
780 OBJECT_ATTRIBUTES ObjectAttributes
;
782 IO_STATUS_BLOCK IoStatus
;
783 PFILE_OBJECT FileObject
;
784 PPAGINGFILE PagingFile
;
787 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
788 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
789 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
791 ULONG BytesPerAllocationUnit
;
794 LARGE_INTEGER MaxVcn
;
797 KPROCESSOR_MODE PreviousMode
;
798 UNICODE_STRING CapturedFileName
;
799 LARGE_INTEGER SafeInitialSize
, SafeMaximumSize
;
801 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
802 FileName
, InitialSize
->QuadPart
);
804 if (MiPagingFileCount
>= MAX_PAGING_FILES
)
806 return(STATUS_TOO_MANY_PAGING_FILES
);
809 PreviousMode
= ExGetPreviousMode();
811 if (PreviousMode
!= KernelMode
)
815 SafeInitialSize
= ProbeForReadLargeInteger(InitialSize
);
816 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
820 Status
= _SEH_GetExceptionCode();
824 if (!NT_SUCCESS(Status
))
831 SafeInitialSize
= *InitialSize
;
832 SafeMaximumSize
= *MaximumSize
;
835 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
836 smaller than the maximum */
837 if (0 != SafeInitialSize
.u
.HighPart
)
839 return STATUS_INVALID_PARAMETER_2
;
841 if (0 != SafeMaximumSize
.u
.HighPart
)
843 return STATUS_INVALID_PARAMETER_3
;
845 if (SafeMaximumSize
.u
.LowPart
< SafeInitialSize
.u
.LowPart
)
847 return STATUS_INVALID_PARAMETER_MIX
;
850 Status
= ProbeAndCaptureUnicodeString(&CapturedFileName
,
853 if (!NT_SUCCESS(Status
))
858 InitializeObjectAttributes(&ObjectAttributes
,
864 Status
= IoCreateFile(&FileHandle
,
872 FILE_SYNCHRONOUS_IO_NONALERT
,
877 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
879 ReleaseCapturedUnicodeString(&CapturedFileName
,
881 if (!NT_SUCCESS(Status
))
886 Status
= ZwQueryVolumeInformationFile(FileHandle
,
889 sizeof(FILE_FS_SIZE_INFORMATION
),
890 FileFsSizeInformation
);
891 if (!NT_SUCCESS(Status
))
897 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
*
898 FsSizeInformation
.BytesPerSector
;
899 /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
900 * a problem if the paging file is fragmented. Suppose the first cluster
901 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
902 * paging file but of another file. We can't write a complete page (4096
903 * bytes) to the physical location of cluster 3042 then. */
904 if (BytesPerAllocationUnit
% PAGE_SIZE
)
906 DPRINT1("BytesPerAllocationUnit %d is not a multiple of PAGE_SIZE %d\n",
907 BytesPerAllocationUnit
, PAGE_SIZE
);
909 return STATUS_UNSUCCESSFUL
;
912 Status
= ZwSetInformationFile(FileHandle
,
915 sizeof(LARGE_INTEGER
),
916 FileAllocationInformation
);
917 if (!NT_SUCCESS(Status
))
923 Status
= ObReferenceObjectByHandle(FileHandle
,
929 if (!NT_SUCCESS(Status
))
935 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
937 if (CurrentRetDescList
== NULL
)
939 ObDereferenceObject(FileObject
);
941 return(STATUS_NO_MEMORY
);
944 #if defined(__GNUC__)
952 MaxVcn
.QuadPart
= (SafeInitialSize
.QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
;
955 Status
= ZwFsControlFile(FileHandle
,
960 FSCTL_GET_RETRIEVAL_POINTERS
,
962 sizeof(LARGE_INTEGER
),
963 &CurrentRetDescList
->RetrievalPointers
,
964 sizeof(RETRIEVAL_POINTERS_BUFFER
) + PAIRS_PER_RUN
* 2 * sizeof(LARGE_INTEGER
));
965 if (!NT_SUCCESS(Status
))
969 CurrentRetDescList
= RetDescList
;
970 RetDescList
= RetDescList
->Next
;
971 ExFreePool(CurrentRetDescList
);
973 ObDereferenceObject(FileObject
);
977 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
978 if (CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
.QuadPart
< MaxVcn
.QuadPart
)
980 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
981 if (CurrentRetDescList
->Next
== NULL
)
985 CurrentRetDescList
= RetDescList
;
986 RetDescList
= RetDescList
->Next
;
987 ExFreePool(CurrentRetDescList
);
989 ObDereferenceObject(FileObject
);
991 return(STATUS_NO_MEMORY
);
993 Vcn
= CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
;
994 CurrentRetDescList
= CurrentRetDescList
->Next
;
1002 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
1003 if (PagingFile
== NULL
)
1007 CurrentRetDescList
= RetDescList
;
1008 RetDescList
= RetDescList
->Next
;
1009 ExFreePool(CurrentRetDescList
);
1011 ObDereferenceObject(FileObject
);
1012 ZwClose(FileHandle
);
1013 return(STATUS_NO_MEMORY
);
1016 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
1018 PagingFile
->FileObject
= FileObject
;
1019 PagingFile
->MaximumSize
.QuadPart
= SafeMaximumSize
.QuadPart
;
1020 PagingFile
->CurrentSize
.QuadPart
= SafeInitialSize
.QuadPart
;
1021 PagingFile
->FreePages
= (ULONG
)(SafeInitialSize
.QuadPart
/ PAGE_SIZE
);
1022 PagingFile
->UsedPages
= 0;
1023 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
1025 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
1026 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
1027 AllocMapSize
* sizeof(ULONG
));
1028 PagingFile
->AllocMapSize
= AllocMapSize
;
1030 if (PagingFile
->AllocMap
== NULL
)
1034 CurrentRetDescList
= RetDescList
;
1035 RetDescList
= RetDescList
->Next
;
1036 ExFreePool(CurrentRetDescList
);
1038 ExFreePool(PagingFile
);
1039 ObDereferenceObject(FileObject
);
1040 ZwClose(FileHandle
);
1041 return(STATUS_NO_MEMORY
);
1043 DPRINT("ExtentCount: %d\n", ExtentCount
);
1044 Size
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + ExtentCount
* 2 * sizeof(LARGE_INTEGER
);
1045 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
1046 if (PagingFile
->RetrievalPointers
== NULL
)
1050 CurrentRetDescList
= RetDescList
;
1051 RetDescList
= RetDescList
->Next
;
1052 ExFreePool(CurrentRetDescList
);
1054 ExFreePool(PagingFile
->AllocMap
);
1055 ExFreePool(PagingFile
);
1056 ObDereferenceObject(FileObject
);
1057 ZwClose(FileHandle
);
1058 return(STATUS_NO_MEMORY
);
1061 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
1062 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
1065 PagingFile
->RetrievalPointers
->ExtentCount
= ExtentCount
;
1066 PagingFile
->RetrievalPointers
->StartingVcn
= RetDescList
->RetrievalPointers
.StartingVcn
;
1067 CurrentRetDescList
= RetDescList
;
1068 while (CurrentRetDescList
)
1070 memcpy(&PagingFile
->RetrievalPointers
->Extents
[Count
],
1071 CurrentRetDescList
->RetrievalPointers
.Extents
,
1072 CurrentRetDescList
->RetrievalPointers
.ExtentCount
* 2 * sizeof(LARGE_INTEGER
));
1073 Count
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
1074 RetDescList
= CurrentRetDescList
;
1075 CurrentRetDescList
= CurrentRetDescList
->Next
;
1076 ExFreePool(RetDescList
);
1079 if (PagingFile
->RetrievalPointers
->ExtentCount
!= ExtentCount
||
1080 PagingFile
->RetrievalPointers
->Extents
[ExtentCount
- 1].NextVcn
.QuadPart
!= MaxVcn
.QuadPart
)
1082 ExFreePool(PagingFile
->RetrievalPointers
);
1083 ExFreePool(PagingFile
->AllocMap
);
1084 ExFreePool(PagingFile
);
1085 ObDereferenceObject(FileObject
);
1086 ZwClose(FileHandle
);
1087 return(STATUS_UNSUCCESSFUL
);
1091 * Change the entries from lcn's to volume offset's.
1093 PagingFile
->RetrievalPointers
->StartingVcn
.QuadPart
*= BytesPerAllocationUnit
;
1094 for (i
= 0; i
< ExtentCount
; i
++)
1096 PagingFile
->RetrievalPointers
->Extents
[i
].Lcn
.QuadPart
*= BytesPerAllocationUnit
;
1097 PagingFile
->RetrievalPointers
->Extents
[i
].NextVcn
.QuadPart
*= BytesPerAllocationUnit
;
1100 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
1101 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
1103 if (PagingFileList
[i
] == NULL
)
1105 PagingFileList
[i
] = PagingFile
;
1109 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
1110 MiPagingFileCount
++;
1111 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
1113 /* Check whether this pagefile can be a crash dump target. */
1114 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
&&
1115 PagingFile
->CurrentSize
.QuadPart
>= MmCoreDumpSize
&&
1116 MmCoreDumpPageFile
== 0xFFFFFFFF)
1118 MmInitializeCrashDump(FileHandle
, i
);
1120 ZwClose(FileHandle
);
1122 MmSwapSpaceMessage
= FALSE
;
1124 return(STATUS_SUCCESS
);