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 *****************************************************************/
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
;
49 LARGE_INTEGER MaximumSize
;
50 LARGE_INTEGER CurrentSize
;
54 KSPIN_LOCK AllocMapLock
;
56 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
58 PAGINGFILE
, *PPAGINGFILE
;
60 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
62 struct _RETRIEVEL_DESCRIPTOR_LIST
* Next
;
63 RETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
65 RETRIEVEL_DESCRIPTOR_LIST
, *PRETRIEVEL_DESCRIPTOR_LIST
;
67 /* GLOBALS *******************************************************************/
69 #define PAIRS_PER_RUN (1024)
71 #define MAX_PAGING_FILES (32)
73 /* List of paging files, both used and free */
74 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
76 /* Lock for examining the list of paging files */
77 static KSPIN_LOCK PagingFileListLock
;
79 /* Number of paging files */
80 static ULONG MiPagingFileCount
;
82 /* Number of pages that are available for swapping */
83 ULONG MiFreeSwapPages
;
85 /* Number of pages that have been allocated for swapping */
86 ULONG MiUsedSwapPages
;
89 * Number of pages that have been reserved for swapping but not yet allocated
91 static ULONG MiReservedSwapPages
;
94 * Ratio between reserved and available swap pages, e.g. setting this to five
95 * forces one swap page to be available for every five swap pages that are
96 * reserved. Setting this to zero turns off commit checking altogether.
98 #define MM_PAGEFILE_COMMIT_RATIO (1)
101 * Number of pages that can be used for potentially swapable memory without
102 * pagefile space being reserved. The intention is that this allows smss
103 * to start up and create page files while ordinarily having a commit
106 #define MM_PAGEFILE_COMMIT_GRACE (256)
109 * Translate between a swap entry and a file and offset pair.
111 #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
112 #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
113 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | (j) << 11 | 0x400)
115 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
117 /* FUNCTIONS *****************************************************************/
121 MmBuildMdlFromPages(PMDL Mdl
, PPFN_TYPE Pages
)
123 memcpy(Mdl
+ 1, Pages
, sizeof(PFN_TYPE
) * (PAGE_ROUND_UP(Mdl
->ByteOffset
+Mdl
->ByteCount
)/PAGE_SIZE
));
125 /* FIXME: this flag should be set by the caller perhaps? */
126 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
132 MmIsFileAPagingFile(PFILE_OBJECT FileObject
)
136 /* Loop through all the paging files */
137 for (i
= 0; i
< MiPagingFileCount
; i
++)
139 /* Check if this is one of them */
140 if (PagingFileList
[i
]->FileObject
== FileObject
) return TRUE
;
149 MmShowOutOfSpaceMessagePagingFile(VOID
)
151 if (!MmSwapSpaceMessage
)
153 DPRINT1("MM: Out of swap space.\n");
154 MmSwapSpaceMessage
= TRUE
;
159 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
, LARGE_INTEGER Offset
)
161 /* Simple binary search */
162 ULONG first
, last
, mid
;
164 last
= RetrievalPointers
->ExtentCount
- 1;
165 while (first
<= last
)
167 mid
= (last
- first
) / 2 + first
;
168 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
)
172 Offset
.QuadPart
+= RetrievalPointers
->Extents
[0].Lcn
.QuadPart
- RetrievalPointers
->StartingVcn
.QuadPart
;
177 if (Offset
.QuadPart
>= RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
)
179 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
;
187 if (mid
== RetrievalPointers
->ExtentCount
- 1)
191 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
+1].NextVcn
.QuadPart
)
193 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
+1].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
;
199 KeBugCheck(MEMORY_MANAGEMENT
);
200 #if defined(__GNUC__)
202 return (LARGE_INTEGER
)0LL;
206 const LARGE_INTEGER dummy
=
217 MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
220 LARGE_INTEGER file_offset
;
221 IO_STATUS_BLOCK Iosb
;
224 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
225 PMDL Mdl
= (PMDL
)MdlBase
;
227 DPRINT("MmWriteToSwapPage\n");
231 KeBugCheck(MEMORY_MANAGEMENT
);
232 return(STATUS_UNSUCCESSFUL
);
235 i
= FILE_FROM_ENTRY(SwapEntry
);
236 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
238 if (i
>= MAX_PAGING_FILES
)
240 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
241 KeBugCheck(MEMORY_MANAGEMENT
);
243 if (PagingFileList
[i
]->FileObject
== NULL
||
244 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
246 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
247 KeBugCheck(MEMORY_MANAGEMENT
);
250 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
251 MmBuildMdlFromPages(Mdl
, &Page
);
252 Mdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
254 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
255 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
257 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
258 Status
= IoSynchronousPageWrite(PagingFileList
[i
]->FileObject
,
263 if (Status
== STATUS_PENDING
)
265 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
266 Status
= Iosb
.Status
;
269 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
271 MmUnmapLockedPages (Mdl
->MappedSystemVa
, Mdl
);
278 MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
281 LARGE_INTEGER file_offset
;
282 IO_STATUS_BLOCK Iosb
;
285 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
286 PMDL Mdl
= (PMDL
)MdlBase
;
288 DPRINT("MmReadFromSwapPage\n");
292 KeBugCheck(MEMORY_MANAGEMENT
);
293 return(STATUS_UNSUCCESSFUL
);
296 i
= FILE_FROM_ENTRY(SwapEntry
);
297 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
299 if (i
>= MAX_PAGING_FILES
)
301 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
302 KeBugCheck(MEMORY_MANAGEMENT
);
304 if (PagingFileList
[i
]->FileObject
== NULL
||
305 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
307 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
308 KeBugCheck(MEMORY_MANAGEMENT
);
311 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
312 MmBuildMdlFromPages(Mdl
, &Page
);
313 Mdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
315 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
316 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
318 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
319 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
324 if (Status
== STATUS_PENDING
)
326 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
327 Status
= Iosb
.Status
;
329 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
331 MmUnmapLockedPages (Mdl
->MappedSystemVa
, Mdl
);
339 MmInitPagingFile(VOID
)
343 KeInitializeSpinLock(&PagingFileListLock
);
347 MiReservedSwapPages
= 0;
349 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
351 PagingFileList
[i
] = NULL
;
353 MiPagingFileCount
= 0;
358 MmReserveSwapPages(ULONG Nr
)
361 ULONG MiAvailSwapPages
;
363 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
365 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
366 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
367 if ((MM_PAGEFILE_COMMIT_RATIO
!= 0) && (MiAvailSwapPages
< MiReservedSwapPages
))
369 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
372 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
378 MmDereserveSwapPages(ULONG Nr
)
382 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
383 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
384 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
388 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
393 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
395 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
397 for (j
= 0; j
< 32; j
++)
399 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
401 PagingFile
->AllocMap
[i
] |= (1 << j
);
402 PagingFile
->UsedPages
++;
403 PagingFile
->FreePages
--;
404 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
405 return((i
* 32) + j
);
410 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
416 MmFreeSwapPage(SWAPENTRY Entry
)
422 i
= FILE_FROM_ENTRY(Entry
);
423 off
= OFFSET_FROM_ENTRY(Entry
);
425 if (i
>= MAX_PAGING_FILES
)
427 DPRINT1("Bad swap entry 0x%.8X\n", Entry
);
428 KeBugCheck(MEMORY_MANAGEMENT
);
431 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
432 if (PagingFileList
[i
] == NULL
)
434 KeBugCheck(MEMORY_MANAGEMENT
);
436 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
438 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
440 PagingFileList
[i
]->FreePages
++;
441 PagingFileList
[i
]->UsedPages
--;
446 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
447 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
452 MmIsAvailableSwapPage(VOID
)
454 return(MiFreeSwapPages
> 0);
459 MmAllocSwapPage(VOID
)
466 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
468 if (MiFreeSwapPages
== 0)
470 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
474 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
476 if (PagingFileList
[i
] != NULL
&&
477 PagingFileList
[i
]->FreePages
>= 1)
479 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
480 if (off
== 0xFFFFFFFF)
482 KeBugCheck(MEMORY_MANAGEMENT
);
483 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
484 return(STATUS_UNSUCCESSFUL
);
488 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
490 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
495 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
496 KeBugCheck(MEMORY_MANAGEMENT
);
500 static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
501 MmAllocRetrievelDescriptorList(ULONG Pairs
)
504 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
506 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* 2 * sizeof(LARGE_INTEGER
);
507 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
510 RtlZeroMemory(RetDescList
, Size
);
517 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
518 IN PLARGE_INTEGER InitialSize
,
519 IN PLARGE_INTEGER MaximumSize
,
522 NTSTATUS Status
= STATUS_SUCCESS
;
523 OBJECT_ATTRIBUTES ObjectAttributes
;
525 IO_STATUS_BLOCK IoStatus
;
526 PFILE_OBJECT FileObject
;
527 PPAGINGFILE PagingFile
;
530 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
531 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
532 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
534 ULONG BytesPerAllocationUnit
;
537 LARGE_INTEGER MaxVcn
;
540 KPROCESSOR_MODE PreviousMode
;
541 UNICODE_STRING CapturedFileName
;
542 LARGE_INTEGER SafeInitialSize
, SafeMaximumSize
;
544 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
545 FileName
, InitialSize
->QuadPart
);
547 if (MiPagingFileCount
>= MAX_PAGING_FILES
)
549 return(STATUS_TOO_MANY_PAGING_FILES
);
552 PreviousMode
= ExGetPreviousMode();
554 if (PreviousMode
!= KernelMode
)
558 SafeInitialSize
= ProbeForReadLargeInteger(InitialSize
);
559 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
561 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
563 Status
= _SEH2_GetExceptionCode();
567 if (!NT_SUCCESS(Status
))
574 SafeInitialSize
= *InitialSize
;
575 SafeMaximumSize
= *MaximumSize
;
578 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
579 smaller than the maximum */
580 if (0 != SafeInitialSize
.u
.HighPart
)
582 return STATUS_INVALID_PARAMETER_2
;
584 if (0 != SafeMaximumSize
.u
.HighPart
)
586 return STATUS_INVALID_PARAMETER_3
;
588 if (SafeMaximumSize
.u
.LowPart
< SafeInitialSize
.u
.LowPart
)
590 return STATUS_INVALID_PARAMETER_MIX
;
593 Status
= ProbeAndCaptureUnicodeString(&CapturedFileName
,
596 if (!NT_SUCCESS(Status
))
601 InitializeObjectAttributes(&ObjectAttributes
,
607 Status
= IoCreateFile(&FileHandle
,
615 FILE_SYNCHRONOUS_IO_NONALERT
,
620 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
622 ReleaseCapturedUnicodeString(&CapturedFileName
,
624 if (!NT_SUCCESS(Status
))
629 Status
= ZwQueryVolumeInformationFile(FileHandle
,
632 sizeof(FILE_FS_SIZE_INFORMATION
),
633 FileFsSizeInformation
);
634 if (!NT_SUCCESS(Status
))
640 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
*
641 FsSizeInformation
.BytesPerSector
;
642 /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
643 * a problem if the paging file is fragmented. Suppose the first cluster
644 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
645 * paging file but of another file. We can't write a complete page (4096
646 * bytes) to the physical location of cluster 3042 then. */
647 if (BytesPerAllocationUnit
% PAGE_SIZE
)
649 DPRINT1("BytesPerAllocationUnit %d is not a multiple of PAGE_SIZE %d\n",
650 BytesPerAllocationUnit
, PAGE_SIZE
);
652 return STATUS_UNSUCCESSFUL
;
655 Status
= ZwSetInformationFile(FileHandle
,
658 sizeof(LARGE_INTEGER
),
659 FileAllocationInformation
);
660 if (!NT_SUCCESS(Status
))
666 Status
= ObReferenceObjectByHandle(FileHandle
,
672 if (!NT_SUCCESS(Status
))
678 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
680 if (CurrentRetDescList
== NULL
)
682 ObDereferenceObject(FileObject
);
684 return(STATUS_NO_MEMORY
);
687 #if defined(__GNUC__)
695 MaxVcn
.QuadPart
= (SafeInitialSize
.QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
;
698 Status
= ZwFsControlFile(FileHandle
,
703 FSCTL_GET_RETRIEVAL_POINTERS
,
705 sizeof(LARGE_INTEGER
),
706 &CurrentRetDescList
->RetrievalPointers
,
707 sizeof(RETRIEVAL_POINTERS_BUFFER
) + PAIRS_PER_RUN
* 2 * sizeof(LARGE_INTEGER
));
708 if (!NT_SUCCESS(Status
))
712 CurrentRetDescList
= RetDescList
;
713 RetDescList
= RetDescList
->Next
;
714 ExFreePool(CurrentRetDescList
);
716 ObDereferenceObject(FileObject
);
720 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
721 if (CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
.QuadPart
< MaxVcn
.QuadPart
)
723 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
724 if (CurrentRetDescList
->Next
== NULL
)
728 CurrentRetDescList
= RetDescList
;
729 RetDescList
= RetDescList
->Next
;
730 ExFreePool(CurrentRetDescList
);
732 ObDereferenceObject(FileObject
);
734 return(STATUS_NO_MEMORY
);
736 Vcn
= CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
;
737 CurrentRetDescList
= CurrentRetDescList
->Next
;
745 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
746 if (PagingFile
== NULL
)
750 CurrentRetDescList
= RetDescList
;
751 RetDescList
= RetDescList
->Next
;
752 ExFreePool(CurrentRetDescList
);
754 ObDereferenceObject(FileObject
);
756 return(STATUS_NO_MEMORY
);
759 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
761 PagingFile
->FileObject
= FileObject
;
762 PagingFile
->MaximumSize
.QuadPart
= SafeMaximumSize
.QuadPart
;
763 PagingFile
->CurrentSize
.QuadPart
= SafeInitialSize
.QuadPart
;
764 PagingFile
->FreePages
= (ULONG
)(SafeInitialSize
.QuadPart
/ PAGE_SIZE
);
765 PagingFile
->UsedPages
= 0;
766 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
768 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
769 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
770 AllocMapSize
* sizeof(ULONG
));
771 PagingFile
->AllocMapSize
= AllocMapSize
;
773 if (PagingFile
->AllocMap
== NULL
)
777 CurrentRetDescList
= RetDescList
;
778 RetDescList
= RetDescList
->Next
;
779 ExFreePool(CurrentRetDescList
);
781 ExFreePool(PagingFile
);
782 ObDereferenceObject(FileObject
);
784 return(STATUS_NO_MEMORY
);
786 DPRINT("ExtentCount: %d\n", ExtentCount
);
787 Size
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + ExtentCount
* 2 * sizeof(LARGE_INTEGER
);
788 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
789 if (PagingFile
->RetrievalPointers
== NULL
)
793 CurrentRetDescList
= RetDescList
;
794 RetDescList
= RetDescList
->Next
;
795 ExFreePool(CurrentRetDescList
);
797 ExFreePool(PagingFile
->AllocMap
);
798 ExFreePool(PagingFile
);
799 ObDereferenceObject(FileObject
);
801 return(STATUS_NO_MEMORY
);
804 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
805 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
808 PagingFile
->RetrievalPointers
->ExtentCount
= ExtentCount
;
809 PagingFile
->RetrievalPointers
->StartingVcn
= RetDescList
->RetrievalPointers
.StartingVcn
;
810 CurrentRetDescList
= RetDescList
;
811 while (CurrentRetDescList
)
813 memcpy(&PagingFile
->RetrievalPointers
->Extents
[Count
],
814 CurrentRetDescList
->RetrievalPointers
.Extents
,
815 CurrentRetDescList
->RetrievalPointers
.ExtentCount
* 2 * sizeof(LARGE_INTEGER
));
816 Count
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
817 RetDescList
= CurrentRetDescList
;
818 CurrentRetDescList
= CurrentRetDescList
->Next
;
819 ExFreePool(RetDescList
);
822 if (PagingFile
->RetrievalPointers
->ExtentCount
!= ExtentCount
||
823 PagingFile
->RetrievalPointers
->Extents
[ExtentCount
- 1].NextVcn
.QuadPart
!= MaxVcn
.QuadPart
)
825 ExFreePool(PagingFile
->RetrievalPointers
);
826 ExFreePool(PagingFile
->AllocMap
);
827 ExFreePool(PagingFile
);
828 ObDereferenceObject(FileObject
);
830 return(STATUS_UNSUCCESSFUL
);
834 * Change the entries from lcn's to volume offset's.
836 PagingFile
->RetrievalPointers
->StartingVcn
.QuadPart
*= BytesPerAllocationUnit
;
837 for (i
= 0; i
< ExtentCount
; i
++)
839 PagingFile
->RetrievalPointers
->Extents
[i
].Lcn
.QuadPart
*= BytesPerAllocationUnit
;
840 PagingFile
->RetrievalPointers
->Extents
[i
].NextVcn
.QuadPart
*= BytesPerAllocationUnit
;
843 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
844 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
846 if (PagingFileList
[i
] == NULL
)
848 PagingFileList
[i
] = PagingFile
;
852 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
854 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
858 MmSwapSpaceMessage
= FALSE
;
860 return(STATUS_SUCCESS
);