1 /* 2 * ReactOS kernel 3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team 4 * 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. 9 * 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. 14 * 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. 18 */ 19 /* 20 * PROJECT: ReactOS kernel 21 * FILE: ntoskrnl/mm/pagefile.c 22 * PURPOSE: Paging file functions 23 * PROGRAMMER: David Welch (welch@mcmail.com) 24 * Pierre Schweitzer 25 * UPDATE HISTORY: 26 * Created 22/05/98 27 */ 28 29 /* INCLUDES *****************************************************************/ 30 31 #include <ntoskrnl.h> 32 #define NDEBUG 33 #include <debug.h> 34 35 /* GLOBALS *******************************************************************/ 36 37 #define PAIRS_PER_RUN (1024) 38 39 /* List of paging files, both used and free */ 40 PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES]; 41 42 /* Lock for examining the list of paging files */ 43 KGUARDED_MUTEX MmPageFileCreationLock; 44 45 /* Number of paging files */ 46 ULONG MmNumberOfPagingFiles; 47 48 /* Number of pages that are available for swapping */ 49 PFN_COUNT MiFreeSwapPages; 50 51 /* Number of pages that have been allocated for swapping */ 52 PFN_COUNT MiUsedSwapPages; 53 54 BOOLEAN MmZeroPageFile; 55 56 /* 57 * Number of pages that have been reserved for swapping but not yet allocated 58 */ 59 static PFN_COUNT MiReservedSwapPages; 60 61 /* 62 * Ratio between reserved and available swap pages, e.g. setting this to five 63 * forces one swap page to be available for every five swap pages that are 64 * reserved. Setting this to zero turns off commit checking altogether. 65 */ 66 #define MM_PAGEFILE_COMMIT_RATIO (1) 67 68 /* 69 * Number of pages that can be used for potentially swapable memory without 70 * pagefile space being reserved. The intention is that this allows smss 71 * to start up and create page files while ordinarily having a commit 72 * ratio of one. 73 */ 74 #define MM_PAGEFILE_COMMIT_GRACE (256) 75 76 /* 77 * Translate between a swap entry and a file and offset pair. 78 */ 79 #define FILE_FROM_ENTRY(i) ((i) & 0x0f) 80 #define OFFSET_FROM_ENTRY(i) ((i) >> 11) 81 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400) 82 83 /* Make sure there can be only 16 paging files */ 84 C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES); 85 86 static BOOLEAN MmSwapSpaceMessage = FALSE; 87 88 static BOOLEAN MmSystemPageFileLocated = FALSE; 89 90 /* FUNCTIONS *****************************************************************/ 91 92 VOID 93 NTAPI 94 MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages) 95 { 96 memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE)); 97 } 98 99 100 BOOLEAN 101 NTAPI 102 MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject) 103 { 104 ULONG i; 105 106 /* Loop through all the paging files */ 107 for (i = 0; i < MmNumberOfPagingFiles; i++) 108 { 109 /* Check if this is one of them */ 110 if (MmPagingFile[i]->FileObject == FileObject) return TRUE; 111 } 112 113 /* Nothing found */ 114 return FALSE; 115 } 116 117 VOID 118 NTAPI 119 MmShowOutOfSpaceMessagePagingFile(VOID) 120 { 121 if (!MmSwapSpaceMessage) 122 { 123 DPRINT1("MM: Out of swap space.\n"); 124 MmSwapSpaceMessage = TRUE; 125 } 126 } 127 128 NTSTATUS 129 NTAPI 130 MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) 131 { 132 ULONG i; 133 ULONG_PTR offset; 134 LARGE_INTEGER file_offset; 135 IO_STATUS_BLOCK Iosb; 136 NTSTATUS Status; 137 KEVENT Event; 138 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; 139 PMDL Mdl = (PMDL)MdlBase; 140 141 DPRINT("MmWriteToSwapPage\n"); 142 143 if (SwapEntry == 0) 144 { 145 KeBugCheck(MEMORY_MANAGEMENT); 146 return(STATUS_UNSUCCESSFUL); 147 } 148 149 i = FILE_FROM_ENTRY(SwapEntry); 150 offset = OFFSET_FROM_ENTRY(SwapEntry) - 1; 151 152 if (MmPagingFile[i]->FileObject == NULL || 153 MmPagingFile[i]->FileObject->DeviceObject == NULL) 154 { 155 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry); 156 KeBugCheck(MEMORY_MANAGEMENT); 157 } 158 159 MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 160 MmBuildMdlFromPages(Mdl, &Page); 161 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 162 163 file_offset.QuadPart = offset * PAGE_SIZE; 164 165 KeInitializeEvent(&Event, NotificationEvent, FALSE); 166 Status = IoSynchronousPageWrite(MmPagingFile[i]->FileObject, 167 Mdl, 168 &file_offset, 169 &Event, 170 &Iosb); 171 if (Status == STATUS_PENDING) 172 { 173 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 174 Status = Iosb.Status; 175 } 176 177 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 178 { 179 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 180 } 181 return(Status); 182 } 183 184 185 NTSTATUS 186 NTAPI 187 MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) 188 { 189 return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry)); 190 } 191 192 NTSTATUS 193 NTAPI 194 MiReadPageFile( 195 _In_ PFN_NUMBER Page, 196 _In_ ULONG PageFileIndex, 197 _In_ ULONG_PTR PageFileOffset) 198 { 199 LARGE_INTEGER file_offset; 200 IO_STATUS_BLOCK Iosb; 201 NTSTATUS Status; 202 KEVENT Event; 203 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; 204 PMDL Mdl = (PMDL)MdlBase; 205 PMMPAGING_FILE PagingFile; 206 207 DPRINT("MiReadSwapFile\n"); 208 209 if (PageFileOffset == 0) 210 { 211 KeBugCheck(MEMORY_MANAGEMENT); 212 return(STATUS_UNSUCCESSFUL); 213 } 214 215 /* Normalize offset. */ 216 PageFileOffset--; 217 218 ASSERT(PageFileIndex < MAX_PAGING_FILES); 219 220 PagingFile = MmPagingFile[PageFileIndex]; 221 222 if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL) 223 { 224 DPRINT1("Bad paging file %u\n", PageFileIndex); 225 KeBugCheck(MEMORY_MANAGEMENT); 226 } 227 228 MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 229 MmBuildMdlFromPages(Mdl, &Page); 230 Mdl->MdlFlags |= MDL_PAGES_LOCKED | MDL_IO_PAGE_READ; 231 232 file_offset.QuadPart = PageFileOffset * PAGE_SIZE; 233 234 KeInitializeEvent(&Event, NotificationEvent, FALSE); 235 Status = IoPageRead(PagingFile->FileObject, 236 Mdl, 237 &file_offset, 238 &Event, 239 &Iosb); 240 if (Status == STATUS_PENDING) 241 { 242 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 243 Status = Iosb.Status; 244 } 245 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 246 { 247 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 248 } 249 return(Status); 250 } 251 252 CODE_SEG("INIT") 253 VOID 254 NTAPI 255 MmInitPagingFile(VOID) 256 { 257 ULONG i; 258 259 KeInitializeGuardedMutex(&MmPageFileCreationLock); 260 261 MiFreeSwapPages = 0; 262 MiUsedSwapPages = 0; 263 MiReservedSwapPages = 0; 264 265 for (i = 0; i < MAX_PAGING_FILES; i++) 266 { 267 MmPagingFile[i] = NULL; 268 } 269 MmNumberOfPagingFiles = 0; 270 } 271 272 VOID 273 NTAPI 274 MmFreeSwapPage(SWAPENTRY Entry) 275 { 276 ULONG i; 277 ULONG_PTR off; 278 PMMPAGING_FILE PagingFile; 279 280 i = FILE_FROM_ENTRY(Entry); 281 off = OFFSET_FROM_ENTRY(Entry) - 1; 282 283 KeAcquireGuardedMutex(&MmPageFileCreationLock); 284 285 PagingFile = MmPagingFile[i]; 286 if (PagingFile == NULL) 287 { 288 KeBugCheck(MEMORY_MANAGEMENT); 289 } 290 291 RtlClearBit(PagingFile->Bitmap, off >> 5); 292 293 PagingFile->FreeSpace++; 294 PagingFile->CurrentUsage--; 295 296 MiFreeSwapPages++; 297 MiUsedSwapPages--; 298 UpdateTotalCommittedPages(-1); 299 300 KeReleaseGuardedMutex(&MmPageFileCreationLock); 301 } 302 303 SWAPENTRY 304 NTAPI 305 MmAllocSwapPage(VOID) 306 { 307 ULONG i; 308 ULONG off; 309 SWAPENTRY entry; 310 311 KeAcquireGuardedMutex(&MmPageFileCreationLock); 312 313 if (MiFreeSwapPages == 0) 314 { 315 KeReleaseGuardedMutex(&MmPageFileCreationLock); 316 return(0); 317 } 318 319 for (i = 0; i < MAX_PAGING_FILES; i++) 320 { 321 if (MmPagingFile[i] != NULL && 322 MmPagingFile[i]->FreeSpace >= 1) 323 { 324 off = RtlFindClearBitsAndSet(MmPagingFile[i]->Bitmap, 1, 0); 325 if (off == 0xFFFFFFFF) 326 { 327 KeBugCheck(MEMORY_MANAGEMENT); 328 KeReleaseGuardedMutex(&MmPageFileCreationLock); 329 return(STATUS_UNSUCCESSFUL); 330 } 331 MiUsedSwapPages++; 332 MiFreeSwapPages--; 333 UpdateTotalCommittedPages(1); 334 335 KeReleaseGuardedMutex(&MmPageFileCreationLock); 336 337 entry = ENTRY_FROM_FILE_OFFSET(i, off + 1); 338 return(entry); 339 } 340 } 341 342 KeReleaseGuardedMutex(&MmPageFileCreationLock); 343 KeBugCheck(MEMORY_MANAGEMENT); 344 return(0); 345 } 346 347 NTSTATUS NTAPI 348 NtCreatePagingFile(IN PUNICODE_STRING FileName, 349 IN PLARGE_INTEGER MinimumSize, 350 IN PLARGE_INTEGER MaximumSize, 351 IN ULONG Reserved) 352 { 353 NTSTATUS Status; 354 OBJECT_ATTRIBUTES ObjectAttributes; 355 HANDLE FileHandle; 356 IO_STATUS_BLOCK IoStatus; 357 PFILE_OBJECT FileObject; 358 PMMPAGING_FILE PagingFile; 359 SIZE_T AllocMapSize; 360 ULONG Count; 361 KPROCESSOR_MODE PreviousMode; 362 UNICODE_STRING PageFileName; 363 LARGE_INTEGER SafeMinimumSize, SafeMaximumSize, AllocationSize; 364 FILE_FS_DEVICE_INFORMATION FsDeviceInfo; 365 SECURITY_DESCRIPTOR SecurityDescriptor; 366 PACL Dacl; 367 PWSTR Buffer; 368 DEVICE_TYPE DeviceType; 369 370 PAGED_CODE(); 371 372 DPRINT("NtCreatePagingFile(FileName: '%wZ', MinimumSize: %I64d, MaximumSize: %I64d)\n", 373 FileName, MinimumSize->QuadPart, MaximumSize->QuadPart); 374 375 if (MmNumberOfPagingFiles >= MAX_PAGING_FILES) 376 { 377 return STATUS_TOO_MANY_PAGING_FILES; 378 } 379 380 PreviousMode = ExGetPreviousMode(); 381 382 if (PreviousMode != KernelMode) 383 { 384 if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege, PreviousMode) != TRUE) 385 { 386 return STATUS_PRIVILEGE_NOT_HELD; 387 } 388 389 _SEH2_TRY 390 { 391 SafeMinimumSize = ProbeForReadLargeInteger(MinimumSize); 392 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); 393 PageFileName = ProbeForReadUnicodeString(FileName); 394 } 395 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 396 { 397 /* Return the exception code */ 398 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 399 } 400 _SEH2_END; 401 } 402 else 403 { 404 SafeMinimumSize = *MinimumSize; 405 SafeMaximumSize = *MaximumSize; 406 PageFileName = *FileName; 407 } 408 409 /* 410 * Pagefiles can't be larger than 4GB and of course 411 * the minimum should be smaller than the maximum. 412 */ 413 // TODO: Actually validate the lower bound of these sizes! 414 if (0 != SafeMinimumSize.u.HighPart) 415 { 416 return STATUS_INVALID_PARAMETER_2; 417 } 418 if (0 != SafeMaximumSize.u.HighPart) 419 { 420 return STATUS_INVALID_PARAMETER_3; 421 } 422 if (SafeMaximumSize.u.LowPart < SafeMinimumSize.u.LowPart) 423 { 424 return STATUS_INVALID_PARAMETER_MIX; 425 } 426 427 /* Validate the name length */ 428 if ((PageFileName.Length == 0) || 429 (PageFileName.Length > 128 * sizeof(WCHAR))) 430 { 431 return STATUS_OBJECT_NAME_INVALID; 432 } 433 434 /* We don't care about any potential UNICODE_NULL */ 435 PageFileName.MaximumLength = PageFileName.Length; 436 /* Allocate a buffer to keep the name copy */ 437 Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM); 438 if (Buffer == NULL) 439 { 440 return STATUS_INSUFFICIENT_RESOURCES; 441 } 442 443 /* Copy the name */ 444 if (PreviousMode != KernelMode) 445 { 446 _SEH2_TRY 447 { 448 ProbeForRead(PageFileName.Buffer, PageFileName.Length, sizeof(WCHAR)); 449 RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length); 450 } 451 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 452 { 453 ExFreePoolWithTag(Buffer, TAG_MM); 454 455 /* Return the exception code */ 456 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 457 } 458 _SEH2_END; 459 } 460 else 461 { 462 RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length); 463 } 464 465 /* Replace caller's buffer with ours */ 466 PageFileName.Buffer = Buffer; 467 468 /* Create the security descriptor for the page file */ 469 Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); 470 if (!NT_SUCCESS(Status)) 471 { 472 ExFreePoolWithTag(Buffer, TAG_MM); 473 return Status; 474 } 475 476 /* Create the DACL: we will only allow two SIDs */ 477 Count = sizeof(ACL) + (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 478 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); 479 Dacl = ExAllocatePoolWithTag(PagedPool, Count, 'lcaD'); 480 if (Dacl == NULL) 481 { 482 ExFreePoolWithTag(Buffer, TAG_MM); 483 return STATUS_INSUFFICIENT_RESOURCES; 484 } 485 486 /* Initialize the DACL */ 487 Status = RtlCreateAcl(Dacl, Count, ACL_REVISION); 488 if (!NT_SUCCESS(Status)) 489 { 490 ExFreePoolWithTag(Dacl, 'lcaD'); 491 ExFreePoolWithTag(Buffer, TAG_MM); 492 return Status; 493 } 494 495 /* Grant full access to admins */ 496 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid); 497 if (!NT_SUCCESS(Status)) 498 { 499 ExFreePoolWithTag(Dacl, 'lcaD'); 500 ExFreePoolWithTag(Buffer, TAG_MM); 501 return Status; 502 } 503 504 /* Grant full access to SYSTEM */ 505 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid); 506 if (!NT_SUCCESS(Status)) 507 { 508 ExFreePoolWithTag(Dacl, 'lcaD'); 509 ExFreePoolWithTag(Buffer, TAG_MM); 510 return Status; 511 } 512 513 /* Attach the DACL to the security descriptor */ 514 Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE); 515 if (!NT_SUCCESS(Status)) 516 { 517 ExFreePoolWithTag(Dacl, 'lcaD'); 518 ExFreePoolWithTag(Buffer, TAG_MM); 519 return Status; 520 } 521 522 InitializeObjectAttributes(&ObjectAttributes, 523 &PageFileName, 524 OBJ_KERNEL_HANDLE, 525 NULL, 526 &SecurityDescriptor); 527 528 /* Make sure we can at least store a complete page: 529 * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is 530 * a problem if the paging file is fragmented. Suppose the first cluster 531 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the 532 * paging file but of another file. We can't write a complete page (4096 533 * bytes) to the physical location of cluster 3042 then. */ 534 AllocationSize.QuadPart = SafeMinimumSize.QuadPart + PAGE_SIZE; 535 536 /* First, attempt to replace the page file, if existing */ 537 Status = IoCreateFile(&FileHandle, 538 SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA, 539 &ObjectAttributes, 540 &IoStatus, 541 &AllocationSize, 542 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 543 FILE_SHARE_WRITE, 544 FILE_SUPERSEDE, 545 FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING, 546 NULL, 547 0, 548 CreateFileTypeNone, 549 NULL, 550 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); 551 /* If we failed, relax a bit constraints, someone may be already holding the 552 * the file, so share write, don't attempt to replace and don't delete on close 553 * (basically, don't do anything conflicting) 554 * This can happen if the caller attempts to extend a page file. 555 */ 556 if (!NT_SUCCESS(Status)) 557 { 558 ULONG i; 559 560 Status = IoCreateFile(&FileHandle, 561 SYNCHRONIZE | FILE_WRITE_DATA, 562 &ObjectAttributes, 563 &IoStatus, 564 &AllocationSize, 565 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 566 FILE_SHARE_WRITE | FILE_SHARE_READ, 567 FILE_OPEN, 568 FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING, 569 NULL, 570 0, 571 CreateFileTypeNone, 572 NULL, 573 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); 574 if (!NT_SUCCESS(Status)) 575 { 576 ExFreePoolWithTag(Dacl, 'lcaD'); 577 ExFreePoolWithTag(Buffer, TAG_MM); 578 return Status; 579 } 580 581 /* We opened it! Check we are that "someone" ;-) 582 * First, get the opened file object. 583 */ 584 Status = ObReferenceObjectByHandle(FileHandle, 585 FILE_READ_DATA | FILE_WRITE_DATA, 586 IoFileObjectType, 587 KernelMode, 588 (PVOID*)&FileObject, 589 NULL); 590 if (!NT_SUCCESS(Status)) 591 { 592 ZwClose(FileHandle); 593 ExFreePoolWithTag(Dacl, 'lcaD'); 594 ExFreePoolWithTag(Buffer, TAG_MM); 595 return Status; 596 } 597 598 /* Find if it matches a previous page file */ 599 PagingFile = NULL; 600 601 /* FIXME: should be calling unsafe instead, 602 * we should already be in a guarded region 603 */ 604 KeAcquireGuardedMutex(&MmPageFileCreationLock); 605 if (MmNumberOfPagingFiles > 0) 606 { 607 i = 0; 608 609 while (MmPagingFile[i]->FileObject->SectionObjectPointer != FileObject->SectionObjectPointer) 610 { 611 ++i; 612 if (i >= MmNumberOfPagingFiles) 613 { 614 break; 615 } 616 } 617 618 /* This is the matching page file */ 619 PagingFile = MmPagingFile[i]; 620 } 621 622 /* If we didn't find the page file, fail */ 623 if (PagingFile == NULL) 624 { 625 KeReleaseGuardedMutex(&MmPageFileCreationLock); 626 ObDereferenceObject(FileObject); 627 ZwClose(FileHandle); 628 ExFreePoolWithTag(Dacl, 'lcaD'); 629 ExFreePoolWithTag(Buffer, TAG_MM); 630 return STATUS_NOT_FOUND; 631 } 632 633 /* Don't allow page file shrinking */ 634 if (PagingFile->MinimumSize > (SafeMinimumSize.QuadPart >> PAGE_SHIFT)) 635 { 636 KeReleaseGuardedMutex(&MmPageFileCreationLock); 637 ObDereferenceObject(FileObject); 638 ZwClose(FileHandle); 639 ExFreePoolWithTag(Dacl, 'lcaD'); 640 ExFreePoolWithTag(Buffer, TAG_MM); 641 return STATUS_INVALID_PARAMETER_2; 642 } 643 644 if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) < PagingFile->MaximumSize) 645 { 646 KeReleaseGuardedMutex(&MmPageFileCreationLock); 647 ObDereferenceObject(FileObject); 648 ZwClose(FileHandle); 649 ExFreePoolWithTag(Dacl, 'lcaD'); 650 ExFreePoolWithTag(Buffer, TAG_MM); 651 return STATUS_INVALID_PARAMETER_3; 652 } 653 654 /* FIXME: implement parameters checking and page file extension */ 655 UNIMPLEMENTED; 656 657 KeReleaseGuardedMutex(&MmPageFileCreationLock); 658 ObDereferenceObject(FileObject); 659 ZwClose(FileHandle); 660 ExFreePoolWithTag(Dacl, 'lcaD'); 661 ExFreePoolWithTag(Buffer, TAG_MM); 662 return STATUS_NOT_IMPLEMENTED; 663 } 664 665 if (!NT_SUCCESS(Status)) 666 { 667 DPRINT1("Failed creating page file: %lx\n", Status); 668 ExFreePoolWithTag(Dacl, 'lcaD'); 669 ExFreePoolWithTag(Buffer, TAG_MM); 670 return Status; 671 } 672 673 /* Set the security descriptor */ 674 if (NT_SUCCESS(IoStatus.Status)) 675 { 676 Status = ZwSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, &SecurityDescriptor); 677 if (!NT_SUCCESS(Status)) 678 { 679 ExFreePoolWithTag(Dacl, 'lcaD'); 680 ZwClose(FileHandle); 681 ExFreePoolWithTag(Buffer, TAG_MM); 682 return Status; 683 } 684 } 685 686 /* DACL is no longer needed, free it */ 687 ExFreePoolWithTag(Dacl, 'lcaD'); 688 689 /* FIXME: To enable once page file managment is moved to ARM3 */ 690 #if 0 691 /* Check we won't overflow commit limit with the page file */ 692 if (MmTotalCommitLimitMaximum + (SafeMaximumSize.QuadPart >> PAGE_SHIFT) <= MmTotalCommitLimitMaximum) 693 { 694 ZwClose(FileHandle); 695 ExFreePoolWithTag(Buffer, TAG_MM); 696 return STATUS_INVALID_PARAMETER_3; 697 } 698 #endif 699 700 /* Set its end of file to minimal size */ 701 Status = ZwSetInformationFile(FileHandle, 702 &IoStatus, 703 &SafeMinimumSize, 704 sizeof(LARGE_INTEGER), 705 FileEndOfFileInformation); 706 if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status)) 707 { 708 ZwClose(FileHandle); 709 ExFreePoolWithTag(Buffer, TAG_MM); 710 return Status; 711 } 712 713 Status = ObReferenceObjectByHandle(FileHandle, 714 FILE_READ_DATA | FILE_WRITE_DATA, 715 IoFileObjectType, 716 KernelMode, 717 (PVOID*)&FileObject, 718 NULL); 719 if (!NT_SUCCESS(Status)) 720 { 721 ZwClose(FileHandle); 722 ExFreePoolWithTag(Buffer, TAG_MM); 723 return Status; 724 } 725 726 /* Only allow page file on a few device types */ 727 DeviceType = IoGetRelatedDeviceObject(FileObject)->DeviceType; 728 if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM && DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM && 729 DeviceType != FILE_DEVICE_DFS_VOLUME && DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM) 730 { 731 ObDereferenceObject(FileObject); 732 ZwClose(FileHandle); 733 ExFreePoolWithTag(Buffer, TAG_MM); 734 return Status; 735 } 736 737 /* Deny page file creation on a floppy disk */ 738 FsDeviceInfo.Characteristics = 0; 739 IoQueryVolumeInformation(FileObject, FileFsDeviceInformation, sizeof(FsDeviceInfo), &FsDeviceInfo, &Count); 740 if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE)) 741 { 742 ObDereferenceObject(FileObject); 743 ZwClose(FileHandle); 744 ExFreePoolWithTag(Buffer, TAG_MM); 745 return STATUS_FLOPPY_VOLUME; 746 } 747 748 PagingFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(*PagingFile), TAG_MM); 749 if (PagingFile == NULL) 750 { 751 ObDereferenceObject(FileObject); 752 ZwClose(FileHandle); 753 ExFreePoolWithTag(Buffer, TAG_MM); 754 return STATUS_INSUFFICIENT_RESOURCES; 755 } 756 757 RtlZeroMemory(PagingFile, sizeof(*PagingFile)); 758 759 PagingFile->FileHandle = FileHandle; 760 PagingFile->FileObject = FileObject; 761 PagingFile->MaximumSize = (SafeMaximumSize.QuadPart >> PAGE_SHIFT); 762 PagingFile->Size = (SafeMinimumSize.QuadPart >> PAGE_SHIFT); 763 PagingFile->MinimumSize = (SafeMinimumSize.QuadPart >> PAGE_SHIFT); 764 /* First page is never used: it's the header 765 * TODO: write it 766 */ 767 PagingFile->FreeSpace = (ULONG)(SafeMinimumSize.QuadPart / PAGE_SIZE) - 1; 768 PagingFile->CurrentUsage = 0; 769 PagingFile->PageFileName = PageFileName; 770 ASSERT(PagingFile->Size == PagingFile->FreeSpace + PagingFile->CurrentUsage + 1); 771 772 AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->MaximumSize + 31) / 32) * sizeof(ULONG)); 773 PagingFile->Bitmap = ExAllocatePoolWithTag(NonPagedPool, 774 AllocMapSize, 775 TAG_MM); 776 if (PagingFile->Bitmap == NULL) 777 { 778 ExFreePoolWithTag(PagingFile, TAG_MM); 779 ObDereferenceObject(FileObject); 780 ZwClose(FileHandle); 781 ExFreePoolWithTag(Buffer, TAG_MM); 782 return STATUS_INSUFFICIENT_RESOURCES; 783 } 784 785 RtlInitializeBitMap(PagingFile->Bitmap, 786 (PULONG)(PagingFile->Bitmap + 1), 787 (ULONG)(PagingFile->MaximumSize)); 788 RtlClearAllBits(PagingFile->Bitmap); 789 790 /* FIXME: should be calling unsafe instead, 791 * we should already be in a guarded region 792 */ 793 KeAcquireGuardedMutex(&MmPageFileCreationLock); 794 ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL); 795 MmPagingFile[MmNumberOfPagingFiles] = PagingFile; 796 MmNumberOfPagingFiles++; 797 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreeSpace; 798 KeReleaseGuardedMutex(&MmPageFileCreationLock); 799 800 MmSwapSpaceMessage = FALSE; 801 802 if (!MmSystemPageFileLocated && BooleanFlagOn(FileObject->DeviceObject->Flags, DO_SYSTEM_BOOT_PARTITION)) 803 { 804 MmSystemPageFileLocated = IoInitializeCrashDump(FileHandle); 805 } 806 807 return STATUS_SUCCESS; 808 } 809 810 /* EOF */ 811