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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 *****************************************************************/
34 #if defined (ALLOC_PRAGMA)
35 #pragma alloc_text(INIT, MmInitPagingFile)
40 MiFindExportedRoutineByName(IN PVOID DllBase
,
41 IN PANSI_STRING ExportName
);
43 /* TYPES *********************************************************************/
45 typedef struct _PAGINGFILE
47 LIST_ENTRY PagingFileListEntry
;
48 PFILE_OBJECT FileObject
;
50 LARGE_INTEGER MaximumSize
;
51 LARGE_INTEGER CurrentSize
;
55 KSPIN_LOCK AllocMapLock
;
57 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
59 PAGINGFILE
, *PPAGINGFILE
;
61 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
63 struct _RETRIEVEL_DESCRIPTOR_LIST
* Next
;
64 RETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
66 RETRIEVEL_DESCRIPTOR_LIST
, *PRETRIEVEL_DESCRIPTOR_LIST
;
68 /* GLOBALS *******************************************************************/
70 #define PAIRS_PER_RUN (1024)
72 #define MAX_PAGING_FILES (16)
74 /* List of paging files, both used and free */
75 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
77 /* Lock for examining the list of paging files */
78 static KSPIN_LOCK PagingFileListLock
;
80 /* Number of paging files */
81 ULONG MmNumberOfPagingFiles
;
83 /* Number of pages that are available for swapping */
84 PFN_COUNT MiFreeSwapPages
;
86 /* Number of pages that have been allocated for swapping */
87 PFN_COUNT MiUsedSwapPages
;
89 BOOLEAN MmZeroPageFile
;
92 * Number of pages that have been reserved for swapping but not yet allocated
94 static PFN_COUNT MiReservedSwapPages
;
97 * Ratio between reserved and available swap pages, e.g. setting this to five
98 * forces one swap page to be available for every five swap pages that are
99 * reserved. Setting this to zero turns off commit checking altogether.
101 #define MM_PAGEFILE_COMMIT_RATIO (1)
104 * Number of pages that can be used for potentially swapable memory without
105 * pagefile space being reserved. The intention is that this allows smss
106 * to start up and create page files while ordinarily having a commit
109 #define MM_PAGEFILE_COMMIT_GRACE (256)
112 * Translate between a swap entry and a file and offset pair.
114 #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
115 #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
116 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
118 /* Make sure there can be only 16 paging files */
119 C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES
);
121 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
123 /* FUNCTIONS *****************************************************************/
127 MmBuildMdlFromPages(PMDL Mdl
, PPFN_NUMBER Pages
)
129 memcpy(Mdl
+ 1, Pages
, sizeof(PFN_NUMBER
) * (PAGE_ROUND_UP(Mdl
->ByteOffset
+Mdl
->ByteCount
)/PAGE_SIZE
));
131 /* FIXME: this flag should be set by the caller perhaps? */
132 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
138 MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject
)
142 /* Loop through all the paging files */
143 for (i
= 0; i
< MmNumberOfPagingFiles
; i
++)
145 /* Check if this is one of them */
146 if (PagingFileList
[i
]->FileObject
== FileObject
) return TRUE
;
155 MmShowOutOfSpaceMessagePagingFile(VOID
)
157 if (!MmSwapSpaceMessage
)
159 DPRINT1("MM: Out of swap space.\n");
160 MmSwapSpaceMessage
= TRUE
;
165 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
, LARGE_INTEGER Offset
)
167 /* Simple binary search */
168 ULONG first
, last
, mid
;
170 last
= RetrievalPointers
->ExtentCount
- 1;
171 while (first
<= last
)
173 mid
= (last
- first
) / 2 + first
;
174 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
)
178 Offset
.QuadPart
+= RetrievalPointers
->Extents
[0].Lcn
.QuadPart
- RetrievalPointers
->StartingVcn
.QuadPart
;
183 if (Offset
.QuadPart
>= RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
)
185 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
;
193 if (mid
== RetrievalPointers
->ExtentCount
- 1)
197 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
+1].NextVcn
.QuadPart
)
199 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
+1].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
;
205 KeBugCheck(MEMORY_MANAGEMENT
);
206 #if defined(__GNUC__)
208 return (LARGE_INTEGER
)0LL;
212 const LARGE_INTEGER dummy
=
223 MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_NUMBER Page
)
227 LARGE_INTEGER file_offset
;
228 IO_STATUS_BLOCK Iosb
;
231 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
232 PMDL Mdl
= (PMDL
)MdlBase
;
234 DPRINT("MmWriteToSwapPage\n");
238 KeBugCheck(MEMORY_MANAGEMENT
);
239 return(STATUS_UNSUCCESSFUL
);
242 i
= FILE_FROM_ENTRY(SwapEntry
);
243 offset
= OFFSET_FROM_ENTRY(SwapEntry
) - 1;
245 if (PagingFileList
[i
]->FileObject
== NULL
||
246 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
248 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
249 KeBugCheck(MEMORY_MANAGEMENT
);
252 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
253 MmBuildMdlFromPages(Mdl
, &Page
);
254 Mdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
256 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
257 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
259 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
260 Status
= IoSynchronousPageWrite(PagingFileList
[i
]->FileObject
,
265 if (Status
== STATUS_PENDING
)
267 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
268 Status
= Iosb
.Status
;
271 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
273 MmUnmapLockedPages (Mdl
->MappedSystemVa
, Mdl
);
281 MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_NUMBER Page
)
283 return MiReadPageFile(Page
, FILE_FROM_ENTRY(SwapEntry
), OFFSET_FROM_ENTRY(SwapEntry
) - 1);
289 _In_ PFN_NUMBER Page
,
290 _In_ ULONG PageFileIndex
,
291 _In_ ULONG_PTR PageFileOffset
)
293 LARGE_INTEGER file_offset
;
294 IO_STATUS_BLOCK Iosb
;
297 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
298 PMDL Mdl
= (PMDL
)MdlBase
;
299 PPAGINGFILE PagingFile
;
301 DPRINT("MiReadSwapFile\n");
303 if (PageFileOffset
== 0)
305 KeBugCheck(MEMORY_MANAGEMENT
);
306 return(STATUS_UNSUCCESSFUL
);
309 ASSERT(PageFileIndex
< MAX_PAGING_FILES
);
311 PagingFile
= PagingFileList
[PageFileIndex
];
313 if (PagingFile
->FileObject
== NULL
|| PagingFile
->FileObject
->DeviceObject
== NULL
)
315 DPRINT1("Bad paging file %u\n", PageFileIndex
);
316 KeBugCheck(MEMORY_MANAGEMENT
);
319 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
320 MmBuildMdlFromPages(Mdl
, &Page
);
321 Mdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
323 file_offset
.QuadPart
= PageFileOffset
* PAGE_SIZE
;
324 file_offset
= MmGetOffsetPageFile(PagingFile
->RetrievalPointers
, file_offset
);
326 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
327 Status
= IoPageRead(PagingFile
->FileObject
,
332 if (Status
== STATUS_PENDING
)
334 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
335 Status
= Iosb
.Status
;
337 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
339 MmUnmapLockedPages (Mdl
->MappedSystemVa
, Mdl
);
347 MmInitPagingFile(VOID
)
351 KeInitializeSpinLock(&PagingFileListLock
);
355 MiReservedSwapPages
= 0;
357 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
359 PagingFileList
[i
] = NULL
;
361 MmNumberOfPagingFiles
= 0;
365 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
370 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
372 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
374 for (j
= 0; j
< 32; j
++)
376 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
378 PagingFile
->AllocMap
[i
] |= (1 << j
);
379 PagingFile
->UsedPages
++;
380 PagingFile
->FreePages
--;
381 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
382 return((i
* 32) + j
);
387 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
393 MmFreeSwapPage(SWAPENTRY Entry
)
399 i
= FILE_FROM_ENTRY(Entry
);
400 off
= OFFSET_FROM_ENTRY(Entry
) - 1;
402 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
403 if (PagingFileList
[i
] == NULL
)
405 KeBugCheck(MEMORY_MANAGEMENT
);
407 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
409 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
411 PagingFileList
[i
]->FreePages
++;
412 PagingFileList
[i
]->UsedPages
--;
417 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
418 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
423 MmAllocSwapPage(VOID
)
430 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
432 if (MiFreeSwapPages
== 0)
434 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
438 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
440 if (PagingFileList
[i
] != NULL
&&
441 PagingFileList
[i
]->FreePages
>= 1)
443 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
444 if (off
== 0xFFFFFFFF)
446 KeBugCheck(MEMORY_MANAGEMENT
);
447 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
448 return(STATUS_UNSUCCESSFUL
);
452 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
454 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
+ 1);
459 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
460 KeBugCheck(MEMORY_MANAGEMENT
);
464 static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
465 MmAllocRetrievelDescriptorList(ULONG Pairs
)
468 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
470 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* 2 * sizeof(LARGE_INTEGER
);
471 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
474 RtlZeroMemory(RetDescList
, Size
);
481 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
482 IN PLARGE_INTEGER InitialSize
,
483 IN PLARGE_INTEGER MaximumSize
,
487 OBJECT_ATTRIBUTES ObjectAttributes
;
489 IO_STATUS_BLOCK IoStatus
;
490 PFILE_OBJECT FileObject
;
491 PPAGINGFILE PagingFile
;
494 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
495 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
496 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
498 ULONG BytesPerAllocationUnit
;
501 LARGE_INTEGER MaxVcn
;
504 KPROCESSOR_MODE PreviousMode
;
505 UNICODE_STRING CapturedFileName
;
506 LARGE_INTEGER SafeInitialSize
, SafeMaximumSize
, AllocationSize
;
508 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
509 FileName
, InitialSize
->QuadPart
);
511 if (MmNumberOfPagingFiles
>= MAX_PAGING_FILES
)
513 return STATUS_TOO_MANY_PAGING_FILES
;
516 PreviousMode
= ExGetPreviousMode();
518 if (PreviousMode
!= KernelMode
)
520 if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege
, PreviousMode
) != TRUE
)
522 return STATUS_PRIVILEGE_NOT_HELD
;
527 SafeInitialSize
= ProbeForReadLargeInteger(InitialSize
);
528 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
530 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
532 /* Return the exception code */
533 _SEH2_YIELD(return _SEH2_GetExceptionCode());
539 SafeInitialSize
= *InitialSize
;
540 SafeMaximumSize
= *MaximumSize
;
543 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
544 smaller than the maximum */
545 if (0 != SafeInitialSize
.u
.HighPart
)
547 return STATUS_INVALID_PARAMETER_2
;
549 if (0 != SafeMaximumSize
.u
.HighPart
)
551 return STATUS_INVALID_PARAMETER_3
;
553 if (SafeMaximumSize
.u
.LowPart
< SafeInitialSize
.u
.LowPart
)
555 return STATUS_INVALID_PARAMETER_MIX
;
558 Status
= ProbeAndCaptureUnicodeString(&CapturedFileName
,
561 if (!NT_SUCCESS(Status
))
566 InitializeObjectAttributes(&ObjectAttributes
,
572 /* Make sure we can at least store a complete page:
573 * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
574 * a problem if the paging file is fragmented. Suppose the first cluster
575 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
576 * paging file but of another file. We can't write a complete page (4096
577 * bytes) to the physical location of cluster 3042 then. */
578 AllocationSize
.QuadPart
= SafeInitialSize
.QuadPart
+ PAGE_SIZE
;
580 /* First, attempt to replace the page file, if existing */
581 Status
= IoCreateFile(&FileHandle
,
582 SYNCHRONIZE
| WRITE_DAC
| FILE_READ_DATA
| FILE_WRITE_DATA
,
586 FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
,
589 FILE_DELETE_ON_CLOSE
| FILE_NO_COMPRESSION
| FILE_NO_INTERMEDIATE_BUFFERING
,
594 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
595 /* If we failed, relax a bit constraints, someone may be already holding the
596 * the file, so share write, don't attempt to replace and don't delete on close
597 * (basically, don't do anything conflicting)
599 if (!NT_SUCCESS(Status
))
601 Status
= IoCreateFile(&FileHandle
,
602 SYNCHRONIZE
| FILE_WRITE_DATA
,
606 FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
,
607 FILE_SHARE_WRITE
| FILE_SHARE_READ
,
609 FILE_NO_COMPRESSION
| FILE_NO_INTERMEDIATE_BUFFERING
,
614 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
617 ReleaseCapturedUnicodeString(&CapturedFileName
,
619 if (!NT_SUCCESS(Status
))
621 DPRINT1("Failed creating page file: %lx\n", Status
);
625 Status
= ZwQueryVolumeInformationFile(FileHandle
,
628 sizeof(FILE_FS_SIZE_INFORMATION
),
629 FileFsSizeInformation
);
630 if (!NT_SUCCESS(Status
))
636 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
*
637 FsSizeInformation
.BytesPerSector
;
639 /* Set its end of file to initial size */
640 Status
= ZwSetInformationFile(FileHandle
,
643 sizeof(LARGE_INTEGER
),
644 FileEndOfFileInformation
);
645 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(IoStatus
.Status
))
651 Status
= ObReferenceObjectByHandle(FileHandle
,
657 if (!NT_SUCCESS(Status
))
663 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
665 if (CurrentRetDescList
== NULL
)
667 ObDereferenceObject(FileObject
);
669 return(STATUS_NO_MEMORY
);
672 #if defined(__GNUC__)
680 MaxVcn
.QuadPart
= (SafeInitialSize
.QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
;
683 Status
= ZwFsControlFile(FileHandle
,
688 FSCTL_GET_RETRIEVAL_POINTERS
,
690 sizeof(LARGE_INTEGER
),
691 &CurrentRetDescList
->RetrievalPointers
,
692 sizeof(RETRIEVAL_POINTERS_BUFFER
) + PAIRS_PER_RUN
* 2 * sizeof(LARGE_INTEGER
));
693 if (!NT_SUCCESS(Status
))
697 CurrentRetDescList
= RetDescList
;
698 RetDescList
= RetDescList
->Next
;
699 ExFreePool(CurrentRetDescList
);
701 ObDereferenceObject(FileObject
);
705 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
706 if (CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
.QuadPart
< MaxVcn
.QuadPart
)
708 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
709 if (CurrentRetDescList
->Next
== NULL
)
713 CurrentRetDescList
= RetDescList
;
714 RetDescList
= RetDescList
->Next
;
715 ExFreePool(CurrentRetDescList
);
717 ObDereferenceObject(FileObject
);
719 return(STATUS_NO_MEMORY
);
721 Vcn
= CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
;
722 CurrentRetDescList
= CurrentRetDescList
->Next
;
730 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
731 if (PagingFile
== NULL
)
735 CurrentRetDescList
= RetDescList
;
736 RetDescList
= RetDescList
->Next
;
737 ExFreePool(CurrentRetDescList
);
739 ObDereferenceObject(FileObject
);
741 return(STATUS_NO_MEMORY
);
744 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
746 PagingFile
->FileHandle
= FileHandle
;
747 PagingFile
->FileObject
= FileObject
;
748 PagingFile
->MaximumSize
.QuadPart
= SafeMaximumSize
.QuadPart
;
749 PagingFile
->CurrentSize
.QuadPart
= SafeInitialSize
.QuadPart
;
750 PagingFile
->FreePages
= (ULONG
)(SafeInitialSize
.QuadPart
/ PAGE_SIZE
);
751 PagingFile
->UsedPages
= 0;
752 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
754 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
755 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
756 AllocMapSize
* sizeof(ULONG
));
757 PagingFile
->AllocMapSize
= AllocMapSize
;
759 if (PagingFile
->AllocMap
== NULL
)
763 CurrentRetDescList
= RetDescList
;
764 RetDescList
= RetDescList
->Next
;
765 ExFreePool(CurrentRetDescList
);
767 ExFreePool(PagingFile
);
768 ObDereferenceObject(FileObject
);
770 return(STATUS_NO_MEMORY
);
772 DPRINT("ExtentCount: %lu\n", ExtentCount
);
773 Size
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + ExtentCount
* 2 * sizeof(LARGE_INTEGER
);
774 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
775 if (PagingFile
->RetrievalPointers
== NULL
)
779 CurrentRetDescList
= RetDescList
;
780 RetDescList
= RetDescList
->Next
;
781 ExFreePool(CurrentRetDescList
);
783 ExFreePool(PagingFile
->AllocMap
);
784 ExFreePool(PagingFile
);
785 ObDereferenceObject(FileObject
);
787 return(STATUS_NO_MEMORY
);
790 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
791 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
794 PagingFile
->RetrievalPointers
->ExtentCount
= ExtentCount
;
795 PagingFile
->RetrievalPointers
->StartingVcn
= RetDescList
->RetrievalPointers
.StartingVcn
;
796 CurrentRetDescList
= RetDescList
;
797 while (CurrentRetDescList
)
799 memcpy(&PagingFile
->RetrievalPointers
->Extents
[Count
],
800 CurrentRetDescList
->RetrievalPointers
.Extents
,
801 CurrentRetDescList
->RetrievalPointers
.ExtentCount
* 2 * sizeof(LARGE_INTEGER
));
802 Count
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
803 RetDescList
= CurrentRetDescList
;
804 CurrentRetDescList
= CurrentRetDescList
->Next
;
805 ExFreePool(RetDescList
);
808 if (PagingFile
->RetrievalPointers
->ExtentCount
!= ExtentCount
||
809 PagingFile
->RetrievalPointers
->Extents
[ExtentCount
- 1].NextVcn
.QuadPart
!= MaxVcn
.QuadPart
)
811 ExFreePool(PagingFile
->RetrievalPointers
);
812 ExFreePool(PagingFile
->AllocMap
);
813 ExFreePool(PagingFile
);
814 ObDereferenceObject(FileObject
);
816 return(STATUS_UNSUCCESSFUL
);
820 * Change the entries from lcn's to volume offset's.
822 PagingFile
->RetrievalPointers
->StartingVcn
.QuadPart
*= BytesPerAllocationUnit
;
823 for (i
= 0; i
< ExtentCount
; i
++)
825 PagingFile
->RetrievalPointers
->Extents
[i
].Lcn
.QuadPart
*= BytesPerAllocationUnit
;
826 PagingFile
->RetrievalPointers
->Extents
[i
].NextVcn
.QuadPart
*= BytesPerAllocationUnit
;
829 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
830 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
832 if (PagingFileList
[i
] == NULL
)
834 PagingFileList
[i
] = PagingFile
;
838 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
839 MmNumberOfPagingFiles
++;
840 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
842 MmSwapSpaceMessage
= FALSE
;
844 return(STATUS_SUCCESS
);