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