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)
29 /* INCLUDES *****************************************************************/
35 #if defined (ALLOC_PRAGMA)
36 #pragma alloc_text(INIT, MmInitPagingFile)
39 /* GLOBALS *******************************************************************/
41 #define PAIRS_PER_RUN (1024)
43 /* List of paging files, both used and free */
44 PMMPAGING_FILE MmPagingFile
[MAX_PAGING_FILES
];
46 /* Lock for examining the list of paging files */
47 KGUARDED_MUTEX MmPageFileCreationLock
;
49 /* Number of paging files */
50 ULONG MmNumberOfPagingFiles
;
52 /* Number of pages that are available for swapping */
53 PFN_COUNT MiFreeSwapPages
;
55 /* Number of pages that have been allocated for swapping */
56 PFN_COUNT MiUsedSwapPages
;
58 BOOLEAN MmZeroPageFile
;
61 * Number of pages that have been reserved for swapping but not yet allocated
63 static PFN_COUNT MiReservedSwapPages
;
66 * Ratio between reserved and available swap pages, e.g. setting this to five
67 * forces one swap page to be available for every five swap pages that are
68 * reserved. Setting this to zero turns off commit checking altogether.
70 #define MM_PAGEFILE_COMMIT_RATIO (1)
73 * Number of pages that can be used for potentially swapable memory without
74 * pagefile space being reserved. The intention is that this allows smss
75 * to start up and create page files while ordinarily having a commit
78 #define MM_PAGEFILE_COMMIT_GRACE (256)
81 * Translate between a swap entry and a file and offset pair.
83 #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
84 #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
85 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
87 /* Make sure there can be only 16 paging files */
88 C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES
);
90 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
92 static BOOLEAN MmSystemPageFileLocated
= FALSE
;
94 /* FUNCTIONS *****************************************************************/
98 MmBuildMdlFromPages(PMDL Mdl
, PPFN_NUMBER Pages
)
100 memcpy(Mdl
+ 1, Pages
, sizeof(PFN_NUMBER
) * (PAGE_ROUND_UP(Mdl
->ByteOffset
+Mdl
->ByteCount
)/PAGE_SIZE
));
102 /* FIXME: this flag should be set by the caller perhaps? */
103 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
109 MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject
)
113 /* Loop through all the paging files */
114 for (i
= 0; i
< MmNumberOfPagingFiles
; i
++)
116 /* Check if this is one of them */
117 if (MmPagingFile
[i
]->FileObject
== FileObject
) return TRUE
;
126 MmShowOutOfSpaceMessagePagingFile(VOID
)
128 if (!MmSwapSpaceMessage
)
130 DPRINT1("MM: Out of swap space.\n");
131 MmSwapSpaceMessage
= TRUE
;
137 MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_NUMBER Page
)
141 LARGE_INTEGER file_offset
;
142 IO_STATUS_BLOCK Iosb
;
145 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
146 PMDL Mdl
= (PMDL
)MdlBase
;
148 DPRINT("MmWriteToSwapPage\n");
152 KeBugCheck(MEMORY_MANAGEMENT
);
153 return(STATUS_UNSUCCESSFUL
);
156 i
= FILE_FROM_ENTRY(SwapEntry
);
157 offset
= OFFSET_FROM_ENTRY(SwapEntry
) - 1;
159 if (MmPagingFile
[i
]->FileObject
== NULL
||
160 MmPagingFile
[i
]->FileObject
->DeviceObject
== NULL
)
162 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
163 KeBugCheck(MEMORY_MANAGEMENT
);
166 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
167 MmBuildMdlFromPages(Mdl
, &Page
);
168 Mdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
170 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
172 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
173 Status
= IoSynchronousPageWrite(MmPagingFile
[i
]->FileObject
,
178 if (Status
== STATUS_PENDING
)
180 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
181 Status
= Iosb
.Status
;
184 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
186 MmUnmapLockedPages (Mdl
->MappedSystemVa
, Mdl
);
194 MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_NUMBER Page
)
196 return MiReadPageFile(Page
, FILE_FROM_ENTRY(SwapEntry
), OFFSET_FROM_ENTRY(SwapEntry
) - 1);
202 _In_ PFN_NUMBER Page
,
203 _In_ ULONG PageFileIndex
,
204 _In_ ULONG_PTR PageFileOffset
)
206 LARGE_INTEGER file_offset
;
207 IO_STATUS_BLOCK Iosb
;
210 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
211 PMDL Mdl
= (PMDL
)MdlBase
;
212 PMMPAGING_FILE PagingFile
;
214 DPRINT("MiReadSwapFile\n");
216 if (PageFileOffset
== 0)
218 KeBugCheck(MEMORY_MANAGEMENT
);
219 return(STATUS_UNSUCCESSFUL
);
222 ASSERT(PageFileIndex
< MAX_PAGING_FILES
);
224 PagingFile
= MmPagingFile
[PageFileIndex
];
226 if (PagingFile
->FileObject
== NULL
|| PagingFile
->FileObject
->DeviceObject
== NULL
)
228 DPRINT1("Bad paging file %u\n", PageFileIndex
);
229 KeBugCheck(MEMORY_MANAGEMENT
);
232 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
233 MmBuildMdlFromPages(Mdl
, &Page
);
234 Mdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
236 file_offset
.QuadPart
= PageFileOffset
* PAGE_SIZE
;
238 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
239 Status
= IoPageRead(PagingFile
->FileObject
,
244 if (Status
== STATUS_PENDING
)
246 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
247 Status
= Iosb
.Status
;
249 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
251 MmUnmapLockedPages (Mdl
->MappedSystemVa
, Mdl
);
259 MmInitPagingFile(VOID
)
263 KeInitializeGuardedMutex(&MmPageFileCreationLock
);
267 MiReservedSwapPages
= 0;
269 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
271 MmPagingFile
[i
] = NULL
;
273 MmNumberOfPagingFiles
= 0;
278 MmFreeSwapPage(SWAPENTRY Entry
)
282 PMMPAGING_FILE PagingFile
;
284 i
= FILE_FROM_ENTRY(Entry
);
285 off
= OFFSET_FROM_ENTRY(Entry
) - 1;
287 KeAcquireGuardedMutex(&MmPageFileCreationLock
);
289 PagingFile
= MmPagingFile
[i
];
290 if (PagingFile
== NULL
)
292 KeBugCheck(MEMORY_MANAGEMENT
);
295 RtlClearBit(PagingFile
->Bitmap
, off
>> 5);
297 PagingFile
->FreeSpace
++;
298 PagingFile
->CurrentUsage
--;
303 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
308 MmAllocSwapPage(VOID
)
314 KeAcquireGuardedMutex(&MmPageFileCreationLock
);
316 if (MiFreeSwapPages
== 0)
318 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
322 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
324 if (MmPagingFile
[i
] != NULL
&&
325 MmPagingFile
[i
]->FreeSpace
>= 1)
327 off
= RtlFindClearBitsAndSet(MmPagingFile
[i
]->Bitmap
, 1, 0);
328 if (off
== 0xFFFFFFFF)
330 KeBugCheck(MEMORY_MANAGEMENT
);
331 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
332 return(STATUS_UNSUCCESSFUL
);
336 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
338 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
+ 1);
343 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
344 KeBugCheck(MEMORY_MANAGEMENT
);
349 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
350 IN PLARGE_INTEGER MinimumSize
,
351 IN PLARGE_INTEGER MaximumSize
,
355 OBJECT_ATTRIBUTES ObjectAttributes
;
357 IO_STATUS_BLOCK IoStatus
;
358 PFILE_OBJECT FileObject
;
359 PMMPAGING_FILE PagingFile
;
362 KPROCESSOR_MODE PreviousMode
;
363 UNICODE_STRING PageFileName
;
364 LARGE_INTEGER SafeMinimumSize
, SafeMaximumSize
, AllocationSize
;
365 FILE_FS_DEVICE_INFORMATION FsDeviceInfo
;
366 SECURITY_DESCRIPTOR SecurityDescriptor
;
369 DEVICE_TYPE DeviceType
;
371 DPRINT("NtCreatePagingFile(FileName %wZ, MinimumSize %I64d)\n",
372 FileName
, MinimumSize
->QuadPart
);
376 if (MmNumberOfPagingFiles
>= MAX_PAGING_FILES
)
378 return STATUS_TOO_MANY_PAGING_FILES
;
381 PreviousMode
= ExGetPreviousMode();
383 if (PreviousMode
!= KernelMode
)
385 if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege
, PreviousMode
) != TRUE
)
387 return STATUS_PRIVILEGE_NOT_HELD
;
392 SafeMinimumSize
= ProbeForReadLargeInteger(MinimumSize
);
393 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
395 PageFileName
.Length
= FileName
->Length
;
396 PageFileName
.MaximumLength
= FileName
->MaximumLength
;
397 PageFileName
.Buffer
= FileName
->Buffer
;
399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
401 /* Return the exception code */
402 _SEH2_YIELD(return _SEH2_GetExceptionCode());
408 SafeMinimumSize
= *MinimumSize
;
409 SafeMaximumSize
= *MaximumSize
;
411 PageFileName
.Length
= FileName
->Length
;
412 PageFileName
.MaximumLength
= FileName
->MaximumLength
;
413 PageFileName
.Buffer
= FileName
->Buffer
;
416 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
417 smaller than the maximum */
418 if (0 != SafeMinimumSize
.u
.HighPart
)
420 return STATUS_INVALID_PARAMETER_2
;
422 if (0 != SafeMaximumSize
.u
.HighPart
)
424 return STATUS_INVALID_PARAMETER_3
;
426 if (SafeMaximumSize
.u
.LowPart
< SafeMinimumSize
.u
.LowPart
)
428 return STATUS_INVALID_PARAMETER_MIX
;
431 /* Validate name length */
432 if (PageFileName
.Length
> 128 * sizeof(WCHAR
))
434 return STATUS_OBJECT_NAME_INVALID
;
437 /* We won't care about any potential UNICODE_NULL */
438 PageFileName
.MaximumLength
= PageFileName
.Length
;
439 /* Allocate a buffer to keep name copy */
440 Buffer
= ExAllocatePoolWithTag(PagedPool
, PageFileName
.Length
, TAG_MM
);
443 return STATUS_INSUFFICIENT_RESOURCES
;
447 if (PreviousMode
!= KernelMode
)
451 if (PageFileName
.Length
!= 0)
453 ProbeForRead(PageFileName
.Buffer
, PageFileName
.Length
, sizeof(WCHAR
));
456 RtlCopyMemory(Buffer
, PageFileName
.Buffer
, PageFileName
.Length
);
458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
460 ExFreePoolWithTag(Buffer
, TAG_MM
);
462 /* Return the exception code */
463 _SEH2_YIELD(return _SEH2_GetExceptionCode());
469 RtlCopyMemory(Buffer
, PageFileName
.Buffer
, PageFileName
.Length
);
472 /* Erase caller's buffer with ours */
473 PageFileName
.Buffer
= Buffer
;
475 /* Create the security descriptor for the page file */
476 Status
= RtlCreateSecurityDescriptor(&SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
477 if (!NT_SUCCESS(Status
))
479 ExFreePoolWithTag(Buffer
, TAG_MM
);
483 /* Create the DACL: we will only allow two SIDs */
484 Count
= sizeof(ACL
) + (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
485 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
));
486 Dacl
= ExAllocatePoolWithTag(PagedPool
, Count
, 'lcaD');
489 ExFreePoolWithTag(Buffer
, TAG_MM
);
490 return STATUS_INSUFFICIENT_RESOURCES
;
493 /* Initialize the DACL */
494 Status
= RtlCreateAcl(Dacl
, Count
, ACL_REVISION
);
495 if (!NT_SUCCESS(Status
))
497 ExFreePoolWithTag(Dacl
, 'lcaD');
498 ExFreePoolWithTag(Buffer
, TAG_MM
);
502 /* Grant full access to admins */
503 Status
= RtlAddAccessAllowedAce(Dacl
, ACL_REVISION
, FILE_ALL_ACCESS
, SeAliasAdminsSid
);
504 if (!NT_SUCCESS(Status
))
506 ExFreePoolWithTag(Dacl
, 'lcaD');
507 ExFreePoolWithTag(Buffer
, TAG_MM
);
511 /* Grant full access to SYSTEM */
512 Status
= RtlAddAccessAllowedAce(Dacl
, ACL_REVISION
, FILE_ALL_ACCESS
, SeLocalSystemSid
);
513 if (!NT_SUCCESS(Status
))
515 ExFreePoolWithTag(Dacl
, 'lcaD');
516 ExFreePoolWithTag(Buffer
, TAG_MM
);
520 /* Attach the DACL to the security descriptor */
521 Status
= RtlSetDaclSecurityDescriptor(&SecurityDescriptor
, TRUE
, Dacl
, FALSE
);
522 if (!NT_SUCCESS(Status
))
524 ExFreePoolWithTag(Dacl
, 'lcaD');
525 ExFreePoolWithTag(Buffer
, TAG_MM
);
529 InitializeObjectAttributes(&ObjectAttributes
,
533 &SecurityDescriptor
);
535 /* Make sure we can at least store a complete page:
536 * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
537 * a problem if the paging file is fragmented. Suppose the first cluster
538 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
539 * paging file but of another file. We can't write a complete page (4096
540 * bytes) to the physical location of cluster 3042 then. */
541 AllocationSize
.QuadPart
= SafeMinimumSize
.QuadPart
+ PAGE_SIZE
;
543 /* First, attempt to replace the page file, if existing */
544 Status
= IoCreateFile(&FileHandle
,
545 SYNCHRONIZE
| WRITE_DAC
| FILE_READ_DATA
| FILE_WRITE_DATA
,
549 FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
,
552 FILE_DELETE_ON_CLOSE
| FILE_NO_COMPRESSION
| FILE_NO_INTERMEDIATE_BUFFERING
,
557 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
558 /* If we failed, relax a bit constraints, someone may be already holding the
559 * the file, so share write, don't attempt to replace and don't delete on close
560 * (basically, don't do anything conflicting)
561 * This can happen if the caller attempts to extend a page file.
563 if (!NT_SUCCESS(Status
))
567 Status
= IoCreateFile(&FileHandle
,
568 SYNCHRONIZE
| FILE_WRITE_DATA
,
572 FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
,
573 FILE_SHARE_WRITE
| FILE_SHARE_READ
,
575 FILE_NO_COMPRESSION
| FILE_NO_INTERMEDIATE_BUFFERING
,
580 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
581 if (!NT_SUCCESS(Status
))
583 ExFreePoolWithTag(Dacl
, 'lcaD');
584 ExFreePoolWithTag(Buffer
, TAG_MM
);
588 /* We opened it! Check we are that "someone" ;-)
589 * First, get the opened file object.
591 Status
= ObReferenceObjectByHandle(FileHandle
,
592 FILE_READ_DATA
| FILE_WRITE_DATA
,
597 if (!NT_SUCCESS(Status
))
600 ExFreePoolWithTag(Dacl
, 'lcaD');
601 ExFreePoolWithTag(Buffer
, TAG_MM
);
605 /* Find if it matches a previous page file */
608 /* FIXME: should be calling unsafe instead,
609 * we should already be in a guarded region
611 KeAcquireGuardedMutex(&MmPageFileCreationLock
);
612 if (MmNumberOfPagingFiles
> 0)
616 while (MmPagingFile
[i
]->FileObject
->SectionObjectPointer
!= FileObject
->SectionObjectPointer
)
619 if (i
>= MmNumberOfPagingFiles
)
625 /* This is the matching page file */
626 PagingFile
= MmPagingFile
[i
];
629 /* If we didn't find the page file, fail */
630 if (PagingFile
== NULL
)
632 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
633 ObDereferenceObject(FileObject
);
635 ExFreePoolWithTag(Dacl
, 'lcaD');
636 ExFreePoolWithTag(Buffer
, TAG_MM
);
637 return STATUS_NOT_FOUND
;
640 /* Don't allow page file shrinking */
641 if (PagingFile
->MinimumSize
> (SafeMinimumSize
.QuadPart
>> PAGE_SHIFT
))
643 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
644 ObDereferenceObject(FileObject
);
646 ExFreePoolWithTag(Dacl
, 'lcaD');
647 ExFreePoolWithTag(Buffer
, TAG_MM
);
648 return STATUS_INVALID_PARAMETER_2
;
651 if ((SafeMaximumSize
.QuadPart
>> PAGE_SHIFT
) < PagingFile
->MaximumSize
)
653 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
654 ObDereferenceObject(FileObject
);
656 ExFreePoolWithTag(Dacl
, 'lcaD');
657 ExFreePoolWithTag(Buffer
, TAG_MM
);
658 return STATUS_INVALID_PARAMETER_3
;
661 /* FIXME: implement parameters checking and page file extension */
664 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
665 ObDereferenceObject(FileObject
);
667 ExFreePoolWithTag(Dacl
, 'lcaD');
668 ExFreePoolWithTag(Buffer
, TAG_MM
);
669 return STATUS_NOT_IMPLEMENTED
;
672 if (!NT_SUCCESS(Status
))
674 DPRINT1("Failed creating page file: %lx\n", Status
);
675 ExFreePoolWithTag(Dacl
, 'lcaD');
676 ExFreePoolWithTag(Buffer
, TAG_MM
);
680 /* Set the security descriptor */
681 if (NT_SUCCESS(IoStatus
.Status
))
683 Status
= ZwSetSecurityObject(FileHandle
, DACL_SECURITY_INFORMATION
, &SecurityDescriptor
);
684 if (!NT_SUCCESS(Status
))
686 ExFreePoolWithTag(Dacl
, 'lcaD');
688 ExFreePoolWithTag(Buffer
, TAG_MM
);
693 /* DACL is no longer needed, free it */
694 ExFreePoolWithTag(Dacl
, 'lcaD');
696 /* FIXME: To enable once page file managment is moved to ARM3 */
698 /* Check we won't overflow commit limit with the page file */
699 if (MmTotalCommitLimitMaximum
+ (SafeMaximumSize
.QuadPart
>> PAGE_SHIFT
) <= MmTotalCommitLimitMaximum
)
702 ExFreePoolWithTag(Buffer
, TAG_MM
);
703 return STATUS_INVALID_PARAMETER_3
;
707 /* Set its end of file to minimal size */
708 Status
= ZwSetInformationFile(FileHandle
,
711 sizeof(LARGE_INTEGER
),
712 FileEndOfFileInformation
);
713 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(IoStatus
.Status
))
716 ExFreePoolWithTag(Buffer
, TAG_MM
);
720 Status
= ObReferenceObjectByHandle(FileHandle
,
721 FILE_READ_DATA
| FILE_WRITE_DATA
,
726 if (!NT_SUCCESS(Status
))
729 ExFreePoolWithTag(Buffer
, TAG_MM
);
733 /* Only allow page file on a few device types */
734 DeviceType
= IoGetRelatedDeviceObject(FileObject
)->DeviceType
;
735 if (DeviceType
!= FILE_DEVICE_DISK_FILE_SYSTEM
&& DeviceType
!= FILE_DEVICE_NETWORK_FILE_SYSTEM
&&
736 DeviceType
!= FILE_DEVICE_DFS_VOLUME
&& DeviceType
!= FILE_DEVICE_DFS_FILE_SYSTEM
)
738 ObDereferenceObject(FileObject
);
740 ExFreePoolWithTag(Buffer
, TAG_MM
);
744 /* Deny page file creation on a floppy disk */
745 FsDeviceInfo
.Characteristics
= 0;
746 IoQueryVolumeInformation(FileObject
, FileFsDeviceInformation
, sizeof(FsDeviceInfo
), &FsDeviceInfo
, &Count
);
747 if (BooleanFlagOn(FsDeviceInfo
.Characteristics
, FILE_FLOPPY_DISKETTE
))
749 ObDereferenceObject(FileObject
);
751 ExFreePoolWithTag(Buffer
, TAG_MM
);
752 return STATUS_FLOPPY_VOLUME
;
755 PagingFile
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*PagingFile
), TAG_MM
);
756 if (PagingFile
== NULL
)
758 ObDereferenceObject(FileObject
);
760 ExFreePoolWithTag(Buffer
, TAG_MM
);
761 return STATUS_INSUFFICIENT_RESOURCES
;
764 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
766 PagingFile
->FileHandle
= FileHandle
;
767 PagingFile
->FileObject
= FileObject
;
768 PagingFile
->MaximumSize
= (SafeMaximumSize
.QuadPart
>> PAGE_SHIFT
);
769 PagingFile
->Size
= (SafeMinimumSize
.QuadPart
>> PAGE_SHIFT
);
770 PagingFile
->MinimumSize
= (SafeMinimumSize
.QuadPart
>> PAGE_SHIFT
);
771 /* First page is never used: it's the header
774 PagingFile
->FreeSpace
= (ULONG
)(SafeMinimumSize
.QuadPart
/ PAGE_SIZE
) - 1;
775 PagingFile
->CurrentUsage
= 0;
776 PagingFile
->PageFileName
= PageFileName
;
777 ASSERT(PagingFile
->Size
== PagingFile
->FreeSpace
+ PagingFile
->CurrentUsage
+ 1);
779 AllocMapSize
= sizeof(RTL_BITMAP
) + (((PagingFile
->MaximumSize
+ 31) / 32) * sizeof(ULONG
));
780 PagingFile
->Bitmap
= ExAllocatePoolWithTag(NonPagedPool
,
783 if (PagingFile
->Bitmap
== NULL
)
785 ExFreePoolWithTag(PagingFile
, TAG_MM
);
786 ObDereferenceObject(FileObject
);
788 ExFreePoolWithTag(Buffer
, TAG_MM
);
789 return STATUS_INSUFFICIENT_RESOURCES
;
792 RtlInitializeBitMap(PagingFile
->Bitmap
,
793 (PULONG
)(PagingFile
->Bitmap
+ 1),
794 (ULONG
)(PagingFile
->MaximumSize
));
795 RtlClearAllBits(PagingFile
->Bitmap
);
797 /* FIXME: should be calling unsafe instead,
798 * we should already be in a guarded region
800 KeAcquireGuardedMutex(&MmPageFileCreationLock
);
801 ASSERT(MmPagingFile
[MmNumberOfPagingFiles
] == NULL
);
802 MmPagingFile
[MmNumberOfPagingFiles
] = PagingFile
;
803 MmNumberOfPagingFiles
++;
804 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreeSpace
;
805 KeReleaseGuardedMutex(&MmPageFileCreationLock
);
807 MmSwapSpaceMessage
= FALSE
;
809 if (!MmSystemPageFileLocated
&& BooleanFlagOn(FileObject
->DeviceObject
->Flags
, DO_SYSTEM_BOOT_PARTITION
))
811 MmSystemPageFileLocated
= IoInitializeCrashDump(FileHandle
);
814 return STATUS_SUCCESS
;