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 299 KeReleaseGuardedMutex(&MmPageFileCreationLock); 300 } 301 302 SWAPENTRY 303 NTAPI 304 MmAllocSwapPage(VOID) 305 { 306 ULONG i; 307 ULONG off; 308 SWAPENTRY entry; 309 310 KeAcquireGuardedMutex(&MmPageFileCreationLock); 311 312 if (MiFreeSwapPages == 0) 313 { 314 KeReleaseGuardedMutex(&MmPageFileCreationLock); 315 return(0); 316 } 317 318 for (i = 0; i < MAX_PAGING_FILES; i++) 319 { 320 if (MmPagingFile[i] != NULL && 321 MmPagingFile[i]->FreeSpace >= 1) 322 { 323 off = RtlFindClearBitsAndSet(MmPagingFile[i]->Bitmap, 1, 0); 324 if (off == 0xFFFFFFFF) 325 { 326 KeBugCheck(MEMORY_MANAGEMENT); 327 KeReleaseGuardedMutex(&MmPageFileCreationLock); 328 return(STATUS_UNSUCCESSFUL); 329 } 330 MiUsedSwapPages++; 331 MiFreeSwapPages--; 332 KeReleaseGuardedMutex(&MmPageFileCreationLock); 333 334 entry = ENTRY_FROM_FILE_OFFSET(i, off + 1); 335 return(entry); 336 } 337 } 338 339 KeReleaseGuardedMutex(&MmPageFileCreationLock); 340 KeBugCheck(MEMORY_MANAGEMENT); 341 return(0); 342 } 343 344 NTSTATUS NTAPI 345 NtCreatePagingFile(IN PUNICODE_STRING FileName, 346 IN PLARGE_INTEGER MinimumSize, 347 IN PLARGE_INTEGER MaximumSize, 348 IN ULONG Reserved) 349 { 350 NTSTATUS Status; 351 OBJECT_ATTRIBUTES ObjectAttributes; 352 HANDLE FileHandle; 353 IO_STATUS_BLOCK IoStatus; 354 PFILE_OBJECT FileObject; 355 PMMPAGING_FILE PagingFile; 356 SIZE_T AllocMapSize; 357 ULONG Count; 358 KPROCESSOR_MODE PreviousMode; 359 UNICODE_STRING PageFileName; 360 LARGE_INTEGER SafeMinimumSize, SafeMaximumSize, AllocationSize; 361 FILE_FS_DEVICE_INFORMATION FsDeviceInfo; 362 SECURITY_DESCRIPTOR SecurityDescriptor; 363 PACL Dacl; 364 PWSTR Buffer; 365 DEVICE_TYPE DeviceType; 366 367 PAGED_CODE(); 368 369 DPRINT("NtCreatePagingFile(FileName: '%wZ', MinimumSize: %I64d, MaximumSize: %I64d)\n", 370 FileName, MinimumSize->QuadPart, MaximumSize->QuadPart); 371 372 if (MmNumberOfPagingFiles >= MAX_PAGING_FILES) 373 { 374 return STATUS_TOO_MANY_PAGING_FILES; 375 } 376 377 PreviousMode = ExGetPreviousMode(); 378 379 if (PreviousMode != KernelMode) 380 { 381 if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege, PreviousMode) != TRUE) 382 { 383 return STATUS_PRIVILEGE_NOT_HELD; 384 } 385 386 _SEH2_TRY 387 { 388 SafeMinimumSize = ProbeForReadLargeInteger(MinimumSize); 389 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); 390 PageFileName = ProbeForReadUnicodeString(FileName); 391 } 392 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 393 { 394 /* Return the exception code */ 395 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 396 } 397 _SEH2_END; 398 } 399 else 400 { 401 SafeMinimumSize = *MinimumSize; 402 SafeMaximumSize = *MaximumSize; 403 PageFileName = *FileName; 404 } 405 406 /* 407 * Pagefiles can't be larger than 4GB and of course 408 * the minimum should be smaller than the maximum. 409 */ 410 // TODO: Actually validate the lower bound of these sizes! 411 if (0 != SafeMinimumSize.u.HighPart) 412 { 413 return STATUS_INVALID_PARAMETER_2; 414 } 415 if (0 != SafeMaximumSize.u.HighPart) 416 { 417 return STATUS_INVALID_PARAMETER_3; 418 } 419 if (SafeMaximumSize.u.LowPart < SafeMinimumSize.u.LowPart) 420 { 421 return STATUS_INVALID_PARAMETER_MIX; 422 } 423 424 /* Validate the name length */ 425 if ((PageFileName.Length == 0) || 426 (PageFileName.Length > 128 * sizeof(WCHAR))) 427 { 428 return STATUS_OBJECT_NAME_INVALID; 429 } 430 431 /* We don't care about any potential UNICODE_NULL */ 432 PageFileName.MaximumLength = PageFileName.Length; 433 /* Allocate a buffer to keep the name copy */ 434 Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM); 435 if (Buffer == NULL) 436 { 437 return STATUS_INSUFFICIENT_RESOURCES; 438 } 439 440 /* Copy the name */ 441 if (PreviousMode != KernelMode) 442 { 443 _SEH2_TRY 444 { 445 ProbeForRead(PageFileName.Buffer, PageFileName.Length, sizeof(WCHAR)); 446 RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length); 447 } 448 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 449 { 450 ExFreePoolWithTag(Buffer, TAG_MM); 451 452 /* Return the exception code */ 453 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 454 } 455 _SEH2_END; 456 } 457 else 458 { 459 RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length); 460 } 461 462 /* Replace caller's buffer with ours */ 463 PageFileName.Buffer = Buffer; 464 465 /* Create the security descriptor for the page file */ 466 Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); 467 if (!NT_SUCCESS(Status)) 468 { 469 ExFreePoolWithTag(Buffer, TAG_MM); 470 return Status; 471 } 472 473 /* Create the DACL: we will only allow two SIDs */ 474 Count = sizeof(ACL) + (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 475 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); 476 Dacl = ExAllocatePoolWithTag(PagedPool, Count, 'lcaD'); 477 if (Dacl == NULL) 478 { 479 ExFreePoolWithTag(Buffer, TAG_MM); 480 return STATUS_INSUFFICIENT_RESOURCES; 481 } 482 483 /* Initialize the DACL */ 484 Status = RtlCreateAcl(Dacl, Count, ACL_REVISION); 485 if (!NT_SUCCESS(Status)) 486 { 487 ExFreePoolWithTag(Dacl, 'lcaD'); 488 ExFreePoolWithTag(Buffer, TAG_MM); 489 return Status; 490 } 491 492 /* Grant full access to admins */ 493 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid); 494 if (!NT_SUCCESS(Status)) 495 { 496 ExFreePoolWithTag(Dacl, 'lcaD'); 497 ExFreePoolWithTag(Buffer, TAG_MM); 498 return Status; 499 } 500 501 /* Grant full access to SYSTEM */ 502 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid); 503 if (!NT_SUCCESS(Status)) 504 { 505 ExFreePoolWithTag(Dacl, 'lcaD'); 506 ExFreePoolWithTag(Buffer, TAG_MM); 507 return Status; 508 } 509 510 /* Attach the DACL to the security descriptor */ 511 Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE); 512 if (!NT_SUCCESS(Status)) 513 { 514 ExFreePoolWithTag(Dacl, 'lcaD'); 515 ExFreePoolWithTag(Buffer, TAG_MM); 516 return Status; 517 } 518 519 InitializeObjectAttributes(&ObjectAttributes, 520 &PageFileName, 521 OBJ_KERNEL_HANDLE, 522 NULL, 523 &SecurityDescriptor); 524 525 /* Make sure we can at least store a complete page: 526 * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is 527 * a problem if the paging file is fragmented. Suppose the first cluster 528 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the 529 * paging file but of another file. We can't write a complete page (4096 530 * bytes) to the physical location of cluster 3042 then. */ 531 AllocationSize.QuadPart = SafeMinimumSize.QuadPart + PAGE_SIZE; 532 533 /* First, attempt to replace the page file, if existing */ 534 Status = IoCreateFile(&FileHandle, 535 SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA, 536 &ObjectAttributes, 537 &IoStatus, 538 &AllocationSize, 539 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 540 FILE_SHARE_WRITE, 541 FILE_SUPERSEDE, 542 FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING, 543 NULL, 544 0, 545 CreateFileTypeNone, 546 NULL, 547 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); 548 /* If we failed, relax a bit constraints, someone may be already holding the 549 * the file, so share write, don't attempt to replace and don't delete on close 550 * (basically, don't do anything conflicting) 551 * This can happen if the caller attempts to extend a page file. 552 */ 553 if (!NT_SUCCESS(Status)) 554 { 555 ULONG i; 556 557 Status = IoCreateFile(&FileHandle, 558 SYNCHRONIZE | FILE_WRITE_DATA, 559 &ObjectAttributes, 560 &IoStatus, 561 &AllocationSize, 562 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 563 FILE_SHARE_WRITE | FILE_SHARE_READ, 564 FILE_OPEN, 565 FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING, 566 NULL, 567 0, 568 CreateFileTypeNone, 569 NULL, 570 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); 571 if (!NT_SUCCESS(Status)) 572 { 573 ExFreePoolWithTag(Dacl, 'lcaD'); 574 ExFreePoolWithTag(Buffer, TAG_MM); 575 return Status; 576 } 577 578 /* We opened it! Check we are that "someone" ;-) 579 * First, get the opened file object. 580 */ 581 Status = ObReferenceObjectByHandle(FileHandle, 582 FILE_READ_DATA | FILE_WRITE_DATA, 583 IoFileObjectType, 584 KernelMode, 585 (PVOID*)&FileObject, 586 NULL); 587 if (!NT_SUCCESS(Status)) 588 { 589 ZwClose(FileHandle); 590 ExFreePoolWithTag(Dacl, 'lcaD'); 591 ExFreePoolWithTag(Buffer, TAG_MM); 592 return Status; 593 } 594 595 /* Find if it matches a previous page file */ 596 PagingFile = NULL; 597 598 /* FIXME: should be calling unsafe instead, 599 * we should already be in a guarded region 600 */ 601 KeAcquireGuardedMutex(&MmPageFileCreationLock); 602 if (MmNumberOfPagingFiles > 0) 603 { 604 i = 0; 605 606 while (MmPagingFile[i]->FileObject->SectionObjectPointer != FileObject->SectionObjectPointer) 607 { 608 ++i; 609 if (i >= MmNumberOfPagingFiles) 610 { 611 break; 612 } 613 } 614 615 /* This is the matching page file */ 616 PagingFile = MmPagingFile[i]; 617 } 618 619 /* If we didn't find the page file, fail */ 620 if (PagingFile == NULL) 621 { 622 KeReleaseGuardedMutex(&MmPageFileCreationLock); 623 ObDereferenceObject(FileObject); 624 ZwClose(FileHandle); 625 ExFreePoolWithTag(Dacl, 'lcaD'); 626 ExFreePoolWithTag(Buffer, TAG_MM); 627 return STATUS_NOT_FOUND; 628 } 629 630 /* Don't allow page file shrinking */ 631 if (PagingFile->MinimumSize > (SafeMinimumSize.QuadPart >> PAGE_SHIFT)) 632 { 633 KeReleaseGuardedMutex(&MmPageFileCreationLock); 634 ObDereferenceObject(FileObject); 635 ZwClose(FileHandle); 636 ExFreePoolWithTag(Dacl, 'lcaD'); 637 ExFreePoolWithTag(Buffer, TAG_MM); 638 return STATUS_INVALID_PARAMETER_2; 639 } 640 641 if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) < PagingFile->MaximumSize) 642 { 643 KeReleaseGuardedMutex(&MmPageFileCreationLock); 644 ObDereferenceObject(FileObject); 645 ZwClose(FileHandle); 646 ExFreePoolWithTag(Dacl, 'lcaD'); 647 ExFreePoolWithTag(Buffer, TAG_MM); 648 return STATUS_INVALID_PARAMETER_3; 649 } 650 651 /* FIXME: implement parameters checking and page file extension */ 652 UNIMPLEMENTED; 653 654 KeReleaseGuardedMutex(&MmPageFileCreationLock); 655 ObDereferenceObject(FileObject); 656 ZwClose(FileHandle); 657 ExFreePoolWithTag(Dacl, 'lcaD'); 658 ExFreePoolWithTag(Buffer, TAG_MM); 659 return STATUS_NOT_IMPLEMENTED; 660 } 661 662 if (!NT_SUCCESS(Status)) 663 { 664 DPRINT1("Failed creating page file: %lx\n", Status); 665 ExFreePoolWithTag(Dacl, 'lcaD'); 666 ExFreePoolWithTag(Buffer, TAG_MM); 667 return Status; 668 } 669 670 /* Set the security descriptor */ 671 if (NT_SUCCESS(IoStatus.Status)) 672 { 673 Status = ZwSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, &SecurityDescriptor); 674 if (!NT_SUCCESS(Status)) 675 { 676 ExFreePoolWithTag(Dacl, 'lcaD'); 677 ZwClose(FileHandle); 678 ExFreePoolWithTag(Buffer, TAG_MM); 679 return Status; 680 } 681 } 682 683 /* DACL is no longer needed, free it */ 684 ExFreePoolWithTag(Dacl, 'lcaD'); 685 686 /* FIXME: To enable once page file managment is moved to ARM3 */ 687 #if 0 688 /* Check we won't overflow commit limit with the page file */ 689 if (MmTotalCommitLimitMaximum + (SafeMaximumSize.QuadPart >> PAGE_SHIFT) <= MmTotalCommitLimitMaximum) 690 { 691 ZwClose(FileHandle); 692 ExFreePoolWithTag(Buffer, TAG_MM); 693 return STATUS_INVALID_PARAMETER_3; 694 } 695 #endif 696 697 /* Set its end of file to minimal size */ 698 Status = ZwSetInformationFile(FileHandle, 699 &IoStatus, 700 &SafeMinimumSize, 701 sizeof(LARGE_INTEGER), 702 FileEndOfFileInformation); 703 if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status)) 704 { 705 ZwClose(FileHandle); 706 ExFreePoolWithTag(Buffer, TAG_MM); 707 return Status; 708 } 709 710 Status = ObReferenceObjectByHandle(FileHandle, 711 FILE_READ_DATA | FILE_WRITE_DATA, 712 IoFileObjectType, 713 KernelMode, 714 (PVOID*)&FileObject, 715 NULL); 716 if (!NT_SUCCESS(Status)) 717 { 718 ZwClose(FileHandle); 719 ExFreePoolWithTag(Buffer, TAG_MM); 720 return Status; 721 } 722 723 /* Only allow page file on a few device types */ 724 DeviceType = IoGetRelatedDeviceObject(FileObject)->DeviceType; 725 if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM && DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM && 726 DeviceType != FILE_DEVICE_DFS_VOLUME && DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM) 727 { 728 ObDereferenceObject(FileObject); 729 ZwClose(FileHandle); 730 ExFreePoolWithTag(Buffer, TAG_MM); 731 return Status; 732 } 733 734 /* Deny page file creation on a floppy disk */ 735 FsDeviceInfo.Characteristics = 0; 736 IoQueryVolumeInformation(FileObject, FileFsDeviceInformation, sizeof(FsDeviceInfo), &FsDeviceInfo, &Count); 737 if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE)) 738 { 739 ObDereferenceObject(FileObject); 740 ZwClose(FileHandle); 741 ExFreePoolWithTag(Buffer, TAG_MM); 742 return STATUS_FLOPPY_VOLUME; 743 } 744 745 PagingFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(*PagingFile), TAG_MM); 746 if (PagingFile == NULL) 747 { 748 ObDereferenceObject(FileObject); 749 ZwClose(FileHandle); 750 ExFreePoolWithTag(Buffer, TAG_MM); 751 return STATUS_INSUFFICIENT_RESOURCES; 752 } 753 754 RtlZeroMemory(PagingFile, sizeof(*PagingFile)); 755 756 PagingFile->FileHandle = FileHandle; 757 PagingFile->FileObject = FileObject; 758 PagingFile->MaximumSize = (SafeMaximumSize.QuadPart >> PAGE_SHIFT); 759 PagingFile->Size = (SafeMinimumSize.QuadPart >> PAGE_SHIFT); 760 PagingFile->MinimumSize = (SafeMinimumSize.QuadPart >> PAGE_SHIFT); 761 /* First page is never used: it's the header 762 * TODO: write it 763 */ 764 PagingFile->FreeSpace = (ULONG)(SafeMinimumSize.QuadPart / PAGE_SIZE) - 1; 765 PagingFile->CurrentUsage = 0; 766 PagingFile->PageFileName = PageFileName; 767 ASSERT(PagingFile->Size == PagingFile->FreeSpace + PagingFile->CurrentUsage + 1); 768 769 AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->MaximumSize + 31) / 32) * sizeof(ULONG)); 770 PagingFile->Bitmap = ExAllocatePoolWithTag(NonPagedPool, 771 AllocMapSize, 772 TAG_MM); 773 if (PagingFile->Bitmap == NULL) 774 { 775 ExFreePoolWithTag(PagingFile, TAG_MM); 776 ObDereferenceObject(FileObject); 777 ZwClose(FileHandle); 778 ExFreePoolWithTag(Buffer, TAG_MM); 779 return STATUS_INSUFFICIENT_RESOURCES; 780 } 781 782 RtlInitializeBitMap(PagingFile->Bitmap, 783 (PULONG)(PagingFile->Bitmap + 1), 784 (ULONG)(PagingFile->MaximumSize)); 785 RtlClearAllBits(PagingFile->Bitmap); 786 787 /* FIXME: should be calling unsafe instead, 788 * we should already be in a guarded region 789 */ 790 KeAcquireGuardedMutex(&MmPageFileCreationLock); 791 ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL); 792 MmPagingFile[MmNumberOfPagingFiles] = PagingFile; 793 MmNumberOfPagingFiles++; 794 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreeSpace; 795 KeReleaseGuardedMutex(&MmPageFileCreationLock); 796 797 MmSwapSpaceMessage = FALSE; 798 799 if (!MmSystemPageFileLocated && BooleanFlagOn(FileObject->DeviceObject->Flags, DO_SYSTEM_BOOT_PARTITION)) 800 { 801 MmSystemPageFileLocated = IoInitializeCrashDump(FileHandle); 802 } 803 804 return STATUS_SUCCESS; 805 } 806 807 /* EOF */ 808