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
;
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 (16)
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 ULONG MmNumberOfPagingFiles
;
82 /* Number of pages that are available for swapping */
83 PFN_COUNT MiFreeSwapPages
;
85 /* Number of pages that have been allocated for swapping */
86 PFN_COUNT MiUsedSwapPages
;
88 BOOLEAN MmZeroPageFile
;
91 * Number of pages that have been reserved for swapping but not yet allocated
93 static PFN_COUNT MiReservedSwapPages
;
96 * Ratio between reserved and available swap pages, e.g. setting this to five
97 * forces one swap page to be available for every five swap pages that are
98 * reserved. Setting this to zero turns off commit checking altogether.
100 #define MM_PAGEFILE_COMMIT_RATIO (1)
103 * Number of pages that can be used for potentially swapable memory without
104 * pagefile space being reserved. The intention is that this allows smss
105 * to start up and create page files while ordinarily having a commit
108 #define MM_PAGEFILE_COMMIT_GRACE (256)
111 * Translate between a swap entry and a file and offset pair.
113 #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
114 #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
115 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
117 /* Make sure there can be only 16 paging files */
118 C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES
);
120 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
122 /* FUNCTIONS *****************************************************************/
126 MmBuildMdlFromPages(PMDL Mdl
, PPFN_NUMBER Pages
)
128 memcpy(Mdl
+ 1, Pages
, sizeof(PFN_NUMBER
) * (PAGE_ROUND_UP(Mdl
->ByteOffset
+Mdl
->ByteCount
)/PAGE_SIZE
));
130 /* FIXME: this flag should be set by the caller perhaps? */
131 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
137 MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject
)
141 /* Loop through all the paging files */
142 for (i
= 0; i
< MmNumberOfPagingFiles
; i
++)
144 /* Check if this is one of them */
145 if (PagingFileList
[i
]->FileObject
== FileObject
) return TRUE
;
154 MmShowOutOfSpaceMessagePagingFile(VOID
)
156 if (!MmSwapSpaceMessage
)
158 DPRINT1("MM: Out of swap space.\n");
159 MmSwapSpaceMessage
= TRUE
;
164 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
, LARGE_INTEGER Offset
)
166 /* Simple binary search */
167 ULONG first
, last
, mid
;
169 last
= RetrievalPointers
->ExtentCount
- 1;
170 while (first
<= last
)
172 mid
= (last
- first
) / 2 + first
;
173 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
)
177 Offset
.QuadPart
+= RetrievalPointers
->Extents
[0].Lcn
.QuadPart
- RetrievalPointers
->StartingVcn
.QuadPart
;
182 if (Offset
.QuadPart
>= RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
)
184 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
;
192 if (mid
== RetrievalPointers
->ExtentCount
- 1)
196 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
+1].NextVcn
.QuadPart
)
198 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
+1].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
;
204 KeBugCheck(MEMORY_MANAGEMENT
);
205 #if defined(__GNUC__)
207 return (LARGE_INTEGER
)0LL;
211 const LARGE_INTEGER dummy
=
222 MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_NUMBER Page
)
226 LARGE_INTEGER file_offset
;
227 IO_STATUS_BLOCK Iosb
;
230 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
231 PMDL Mdl
= (PMDL
)MdlBase
;
233 DPRINT("MmWriteToSwapPage\n");
237 KeBugCheck(MEMORY_MANAGEMENT
);
238 return(STATUS_UNSUCCESSFUL
);
241 i
= FILE_FROM_ENTRY(SwapEntry
);
242 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
244 if (PagingFileList
[i
]->FileObject
== NULL
||
245 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
247 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
248 KeBugCheck(MEMORY_MANAGEMENT
);
251 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
252 MmBuildMdlFromPages(Mdl
, &Page
);
253 Mdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
255 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
256 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
258 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
259 Status
= IoSynchronousPageWrite(PagingFileList
[i
]->FileObject
,
264 if (Status
== STATUS_PENDING
)
266 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
267 Status
= Iosb
.Status
;
270 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
272 MmUnmapLockedPages (Mdl
->MappedSystemVa
, Mdl
);
280 MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_NUMBER Page
)
282 return MiReadPageFile(Page
, FILE_FROM_ENTRY(SwapEntry
), OFFSET_FROM_ENTRY(SwapEntry
));
288 _In_ PFN_NUMBER Page
,
289 _In_ ULONG PageFileIndex
,
290 _In_ ULONG_PTR PageFileOffset
)
292 LARGE_INTEGER file_offset
;
293 IO_STATUS_BLOCK Iosb
;
296 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
297 PMDL Mdl
= (PMDL
)MdlBase
;
298 PPAGINGFILE PagingFile
;
300 DPRINT("MiReadSwapFile\n");
302 if (PageFileOffset
== 0)
304 KeBugCheck(MEMORY_MANAGEMENT
);
305 return(STATUS_UNSUCCESSFUL
);
308 ASSERT(PageFileIndex
< MAX_PAGING_FILES
);
310 PagingFile
= PagingFileList
[PageFileIndex
];
312 if (PagingFile
->FileObject
== NULL
|| PagingFile
->FileObject
->DeviceObject
== NULL
)
314 DPRINT1("Bad paging file %u\n", PageFileIndex
);
315 KeBugCheck(MEMORY_MANAGEMENT
);
318 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
319 MmBuildMdlFromPages(Mdl
, &Page
);
320 Mdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
322 file_offset
.QuadPart
= PageFileOffset
* PAGE_SIZE
;
323 file_offset
= MmGetOffsetPageFile(PagingFile
->RetrievalPointers
, file_offset
);
325 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
326 Status
= IoPageRead(PagingFile
->FileObject
,
331 if (Status
== STATUS_PENDING
)
333 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
334 Status
= Iosb
.Status
;
336 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
338 MmUnmapLockedPages (Mdl
->MappedSystemVa
, Mdl
);
346 MmInitPagingFile(VOID
)
350 KeInitializeSpinLock(&PagingFileListLock
);
354 MiReservedSwapPages
= 0;
356 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
358 PagingFileList
[i
] = NULL
;
360 MmNumberOfPagingFiles
= 0;
364 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
369 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
371 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
373 for (j
= 0; j
< 32; j
++)
375 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
377 PagingFile
->AllocMap
[i
] |= (1 << j
);
378 PagingFile
->UsedPages
++;
379 PagingFile
->FreePages
--;
380 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
381 return((i
* 32) + j
);
386 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
392 MmFreeSwapPage(SWAPENTRY Entry
)
398 i
= FILE_FROM_ENTRY(Entry
);
399 off
= OFFSET_FROM_ENTRY(Entry
);
401 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
402 if (PagingFileList
[i
] == NULL
)
404 KeBugCheck(MEMORY_MANAGEMENT
);
406 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
408 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
410 PagingFileList
[i
]->FreePages
++;
411 PagingFileList
[i
]->UsedPages
--;
416 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
417 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
422 MmAllocSwapPage(VOID
)
429 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
431 if (MiFreeSwapPages
== 0)
433 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
437 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
439 if (PagingFileList
[i
] != NULL
&&
440 PagingFileList
[i
]->FreePages
>= 1)
442 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
443 if (off
== 0xFFFFFFFF)
445 KeBugCheck(MEMORY_MANAGEMENT
);
446 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
447 return(STATUS_UNSUCCESSFUL
);
451 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
453 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
458 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
459 KeBugCheck(MEMORY_MANAGEMENT
);
463 static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
464 MmAllocRetrievelDescriptorList(ULONG Pairs
)
467 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
469 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* 2 * sizeof(LARGE_INTEGER
);
470 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
473 RtlZeroMemory(RetDescList
, Size
);
480 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
481 IN PLARGE_INTEGER InitialSize
,
482 IN PLARGE_INTEGER MaximumSize
,
486 OBJECT_ATTRIBUTES ObjectAttributes
;
488 IO_STATUS_BLOCK IoStatus
;
489 PFILE_OBJECT FileObject
;
490 PPAGINGFILE PagingFile
;
493 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
494 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
495 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
497 ULONG BytesPerAllocationUnit
;
500 LARGE_INTEGER MaxVcn
;
503 KPROCESSOR_MODE PreviousMode
;
504 UNICODE_STRING CapturedFileName
;
505 LARGE_INTEGER SafeInitialSize
, SafeMaximumSize
;
507 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
508 FileName
, InitialSize
->QuadPart
);
510 if (MmNumberOfPagingFiles
>= MAX_PAGING_FILES
)
512 return(STATUS_TOO_MANY_PAGING_FILES
);
515 PreviousMode
= ExGetPreviousMode();
517 if (PreviousMode
!= KernelMode
)
521 SafeInitialSize
= ProbeForReadLargeInteger(InitialSize
);
522 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
524 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
526 /* Return the exception code */
527 _SEH2_YIELD(return _SEH2_GetExceptionCode());
533 SafeInitialSize
= *InitialSize
;
534 SafeMaximumSize
= *MaximumSize
;
537 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
538 smaller than the maximum */
539 if (0 != SafeInitialSize
.u
.HighPart
)
541 return STATUS_INVALID_PARAMETER_2
;
543 if (0 != SafeMaximumSize
.u
.HighPart
)
545 return STATUS_INVALID_PARAMETER_3
;
547 if (SafeMaximumSize
.u
.LowPart
< SafeInitialSize
.u
.LowPart
)
549 return STATUS_INVALID_PARAMETER_MIX
;
552 Status
= ProbeAndCaptureUnicodeString(&CapturedFileName
,
555 if (!NT_SUCCESS(Status
))
560 InitializeObjectAttributes(&ObjectAttributes
,
566 Status
= IoCreateFile(&FileHandle
,
574 FILE_SYNCHRONOUS_IO_NONALERT
,
579 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
581 ReleaseCapturedUnicodeString(&CapturedFileName
,
583 if (!NT_SUCCESS(Status
))
588 Status
= ZwQueryVolumeInformationFile(FileHandle
,
591 sizeof(FILE_FS_SIZE_INFORMATION
),
592 FileFsSizeInformation
);
593 if (!NT_SUCCESS(Status
))
599 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
*
600 FsSizeInformation
.BytesPerSector
;
601 /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
602 * a problem if the paging file is fragmented. Suppose the first cluster
603 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
604 * paging file but of another file. We can't write a complete page (4096
605 * bytes) to the physical location of cluster 3042 then. */
606 if (BytesPerAllocationUnit
% PAGE_SIZE
)
608 DPRINT1("BytesPerAllocationUnit %lu is not a multiple of PAGE_SIZE %d\n",
609 BytesPerAllocationUnit
, PAGE_SIZE
);
611 return STATUS_UNSUCCESSFUL
;
614 Status
= ZwSetInformationFile(FileHandle
,
617 sizeof(LARGE_INTEGER
),
618 FileAllocationInformation
);
619 if (!NT_SUCCESS(Status
))
625 Status
= ObReferenceObjectByHandle(FileHandle
,
631 if (!NT_SUCCESS(Status
))
637 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
639 if (CurrentRetDescList
== NULL
)
641 ObDereferenceObject(FileObject
);
643 return(STATUS_NO_MEMORY
);
646 #if defined(__GNUC__)
654 MaxVcn
.QuadPart
= (SafeInitialSize
.QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
;
657 Status
= ZwFsControlFile(FileHandle
,
662 FSCTL_GET_RETRIEVAL_POINTERS
,
664 sizeof(LARGE_INTEGER
),
665 &CurrentRetDescList
->RetrievalPointers
,
666 sizeof(RETRIEVAL_POINTERS_BUFFER
) + PAIRS_PER_RUN
* 2 * sizeof(LARGE_INTEGER
));
667 if (!NT_SUCCESS(Status
))
671 CurrentRetDescList
= RetDescList
;
672 RetDescList
= RetDescList
->Next
;
673 ExFreePool(CurrentRetDescList
);
675 ObDereferenceObject(FileObject
);
679 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
680 if (CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
.QuadPart
< MaxVcn
.QuadPart
)
682 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
683 if (CurrentRetDescList
->Next
== NULL
)
687 CurrentRetDescList
= RetDescList
;
688 RetDescList
= RetDescList
->Next
;
689 ExFreePool(CurrentRetDescList
);
691 ObDereferenceObject(FileObject
);
693 return(STATUS_NO_MEMORY
);
695 Vcn
= CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
;
696 CurrentRetDescList
= CurrentRetDescList
->Next
;
704 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
705 if (PagingFile
== NULL
)
709 CurrentRetDescList
= RetDescList
;
710 RetDescList
= RetDescList
->Next
;
711 ExFreePool(CurrentRetDescList
);
713 ObDereferenceObject(FileObject
);
715 return(STATUS_NO_MEMORY
);
718 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
720 PagingFile
->FileObject
= FileObject
;
721 PagingFile
->MaximumSize
.QuadPart
= SafeMaximumSize
.QuadPart
;
722 PagingFile
->CurrentSize
.QuadPart
= SafeInitialSize
.QuadPart
;
723 PagingFile
->FreePages
= (ULONG
)(SafeInitialSize
.QuadPart
/ PAGE_SIZE
);
724 PagingFile
->UsedPages
= 0;
725 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
727 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
728 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
729 AllocMapSize
* sizeof(ULONG
));
730 PagingFile
->AllocMapSize
= AllocMapSize
;
732 if (PagingFile
->AllocMap
== NULL
)
736 CurrentRetDescList
= RetDescList
;
737 RetDescList
= RetDescList
->Next
;
738 ExFreePool(CurrentRetDescList
);
740 ExFreePool(PagingFile
);
741 ObDereferenceObject(FileObject
);
743 return(STATUS_NO_MEMORY
);
745 DPRINT("ExtentCount: %lu\n", ExtentCount
);
746 Size
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + ExtentCount
* 2 * sizeof(LARGE_INTEGER
);
747 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
748 if (PagingFile
->RetrievalPointers
== NULL
)
752 CurrentRetDescList
= RetDescList
;
753 RetDescList
= RetDescList
->Next
;
754 ExFreePool(CurrentRetDescList
);
756 ExFreePool(PagingFile
->AllocMap
);
757 ExFreePool(PagingFile
);
758 ObDereferenceObject(FileObject
);
760 return(STATUS_NO_MEMORY
);
763 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
764 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
767 PagingFile
->RetrievalPointers
->ExtentCount
= ExtentCount
;
768 PagingFile
->RetrievalPointers
->StartingVcn
= RetDescList
->RetrievalPointers
.StartingVcn
;
769 CurrentRetDescList
= RetDescList
;
770 while (CurrentRetDescList
)
772 memcpy(&PagingFile
->RetrievalPointers
->Extents
[Count
],
773 CurrentRetDescList
->RetrievalPointers
.Extents
,
774 CurrentRetDescList
->RetrievalPointers
.ExtentCount
* 2 * sizeof(LARGE_INTEGER
));
775 Count
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
776 RetDescList
= CurrentRetDescList
;
777 CurrentRetDescList
= CurrentRetDescList
->Next
;
778 ExFreePool(RetDescList
);
781 if (PagingFile
->RetrievalPointers
->ExtentCount
!= ExtentCount
||
782 PagingFile
->RetrievalPointers
->Extents
[ExtentCount
- 1].NextVcn
.QuadPart
!= MaxVcn
.QuadPart
)
784 ExFreePool(PagingFile
->RetrievalPointers
);
785 ExFreePool(PagingFile
->AllocMap
);
786 ExFreePool(PagingFile
);
787 ObDereferenceObject(FileObject
);
789 return(STATUS_UNSUCCESSFUL
);
793 * Change the entries from lcn's to volume offset's.
795 PagingFile
->RetrievalPointers
->StartingVcn
.QuadPart
*= BytesPerAllocationUnit
;
796 for (i
= 0; i
< ExtentCount
; i
++)
798 PagingFile
->RetrievalPointers
->Extents
[i
].Lcn
.QuadPart
*= BytesPerAllocationUnit
;
799 PagingFile
->RetrievalPointers
->Extents
[i
].NextVcn
.QuadPart
*= BytesPerAllocationUnit
;
802 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
803 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
805 if (PagingFileList
[i
] == NULL
)
807 PagingFileList
[i
] = PagingFile
;
811 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
812 MmNumberOfPagingFiles
++;
813 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
817 MmSwapSpaceMessage
= FALSE
;
819 return(STATUS_SUCCESS
);