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 VOID 257 INIT_FUNCTION 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 ULONG 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 DPRINT("NtCreatePagingFile(FileName %wZ, MinimumSize %I64d)\n", 372 FileName, MinimumSize->QuadPart); 373 374 PAGED_CODE(); 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 395 PageFileName.Length = FileName->Length; 396 PageFileName.MaximumLength = FileName->MaximumLength; 397 PageFileName.Buffer = FileName->Buffer; 398 } 399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 400 { 401 /* Return the exception code */ 402 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 403 } 404 _SEH2_END; 405 } 406 else 407 { 408 SafeMinimumSize = *MinimumSize; 409 SafeMaximumSize = *MaximumSize; 410 411 PageFileName.Length = FileName->Length; 412 PageFileName.MaximumLength = FileName->MaximumLength; 413 PageFileName.Buffer = FileName->Buffer; 414 } 415 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) 419 { 420 return STATUS_INVALID_PARAMETER_2; 421 } 422 if (0 != SafeMaximumSize.u.HighPart) 423 { 424 return STATUS_INVALID_PARAMETER_3; 425 } 426 if (SafeMaximumSize.u.LowPart < SafeMinimumSize.u.LowPart) 427 { 428 return STATUS_INVALID_PARAMETER_MIX; 429 } 430 431 /* Validate name length */ 432 if (PageFileName.Length > 128 * sizeof(WCHAR)) 433 { 434 return STATUS_OBJECT_NAME_INVALID; 435 } 436 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); 441 if (Buffer == NULL) 442 { 443 return STATUS_INSUFFICIENT_RESOURCES; 444 } 445 446 /* Copy name */ 447 if (PreviousMode != KernelMode) 448 { 449 _SEH2_TRY 450 { 451 if (PageFileName.Length != 0) 452 { 453 ProbeForRead(PageFileName.Buffer, PageFileName.Length, sizeof(WCHAR)); 454 } 455 456 RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length); 457 } 458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 459 { 460 ExFreePoolWithTag(Buffer, TAG_MM); 461 462 /* Return the exception code */ 463 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 464 } 465 _SEH2_END; 466 } 467 else 468 { 469 RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length); 470 } 471 472 /* Erase caller's buffer with ours */ 473 PageFileName.Buffer = Buffer; 474 475 /* Create the security descriptor for the page file */ 476 Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); 477 if (!NT_SUCCESS(Status)) 478 { 479 ExFreePoolWithTag(Buffer, TAG_MM); 480 return Status; 481 } 482 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'); 487 if (Dacl == NULL) 488 { 489 ExFreePoolWithTag(Buffer, TAG_MM); 490 return STATUS_INSUFFICIENT_RESOURCES; 491 } 492 493 /* Initialize the DACL */ 494 Status = RtlCreateAcl(Dacl, Count, ACL_REVISION); 495 if (!NT_SUCCESS(Status)) 496 { 497 ExFreePoolWithTag(Dacl, 'lcaD'); 498 ExFreePoolWithTag(Buffer, TAG_MM); 499 return Status; 500 } 501 502 /* Grant full access to admins */ 503 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid); 504 if (!NT_SUCCESS(Status)) 505 { 506 ExFreePoolWithTag(Dacl, 'lcaD'); 507 ExFreePoolWithTag(Buffer, TAG_MM); 508 return Status; 509 } 510 511 /* Grant full access to SYSTEM */ 512 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid); 513 if (!NT_SUCCESS(Status)) 514 { 515 ExFreePoolWithTag(Dacl, 'lcaD'); 516 ExFreePoolWithTag(Buffer, TAG_MM); 517 return Status; 518 } 519 520 /* Attach the DACL to the security descriptor */ 521 Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE); 522 if (!NT_SUCCESS(Status)) 523 { 524 ExFreePoolWithTag(Dacl, 'lcaD'); 525 ExFreePoolWithTag(Buffer, TAG_MM); 526 return Status; 527 } 528 529 InitializeObjectAttributes(&ObjectAttributes, 530 &PageFileName, 531 OBJ_KERNEL_HANDLE, 532 NULL, 533 &SecurityDescriptor); 534 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; 542 543 /* First, attempt to replace the page file, if existing */ 544 Status = IoCreateFile(&FileHandle, 545 SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA, 546 &ObjectAttributes, 547 &IoStatus, 548 &AllocationSize, 549 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 550 FILE_SHARE_WRITE, 551 FILE_SUPERSEDE, 552 FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING, 553 NULL, 554 0, 555 CreateFileTypeNone, 556 NULL, 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. 562 */ 563 if (!NT_SUCCESS(Status)) 564 { 565 ULONG i; 566 567 Status = IoCreateFile(&FileHandle, 568 SYNCHRONIZE | FILE_WRITE_DATA, 569 &ObjectAttributes, 570 &IoStatus, 571 &AllocationSize, 572 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 573 FILE_SHARE_WRITE | FILE_SHARE_READ, 574 FILE_OPEN, 575 FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING, 576 NULL, 577 0, 578 CreateFileTypeNone, 579 NULL, 580 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); 581 if (!NT_SUCCESS(Status)) 582 { 583 ExFreePoolWithTag(Dacl, 'lcaD'); 584 ExFreePoolWithTag(Buffer, TAG_MM); 585 return Status; 586 } 587 588 /* We opened it! Check we are that "someone" ;-) 589 * First, get the opened file object. 590 */ 591 Status = ObReferenceObjectByHandle(FileHandle, 592 FILE_READ_DATA | FILE_WRITE_DATA, 593 IoFileObjectType, 594 KernelMode, 595 (PVOID*)&FileObject, 596 NULL); 597 if (!NT_SUCCESS(Status)) 598 { 599 ZwClose(FileHandle); 600 ExFreePoolWithTag(Dacl, 'lcaD'); 601 ExFreePoolWithTag(Buffer, TAG_MM); 602 return Status; 603 } 604 605 /* Find if it matches a previous page file */ 606 PagingFile = NULL; 607 608 /* FIXME: should be calling unsafe instead, 609 * we should already be in a guarded region 610 */ 611 KeAcquireGuardedMutex(&MmPageFileCreationLock); 612 if (MmNumberOfPagingFiles > 0) 613 { 614 i = 0; 615 616 while (MmPagingFile[i]->FileObject->SectionObjectPointer != FileObject->SectionObjectPointer) 617 { 618 ++i; 619 if (i >= MmNumberOfPagingFiles) 620 { 621 break; 622 } 623 } 624 625 /* This is the matching page file */ 626 PagingFile = MmPagingFile[i]; 627 } 628 629 /* If we didn't find the page file, fail */ 630 if (PagingFile == NULL) 631 { 632 KeReleaseGuardedMutex(&MmPageFileCreationLock); 633 ObDereferenceObject(FileObject); 634 ZwClose(FileHandle); 635 ExFreePoolWithTag(Dacl, 'lcaD'); 636 ExFreePoolWithTag(Buffer, TAG_MM); 637 return STATUS_NOT_FOUND; 638 } 639 640 /* Don't allow page file shrinking */ 641 if (PagingFile->MinimumSize > (SafeMinimumSize.QuadPart >> PAGE_SHIFT)) 642 { 643 KeReleaseGuardedMutex(&MmPageFileCreationLock); 644 ObDereferenceObject(FileObject); 645 ZwClose(FileHandle); 646 ExFreePoolWithTag(Dacl, 'lcaD'); 647 ExFreePoolWithTag(Buffer, TAG_MM); 648 return STATUS_INVALID_PARAMETER_2; 649 } 650 651 if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) < PagingFile->MaximumSize) 652 { 653 KeReleaseGuardedMutex(&MmPageFileCreationLock); 654 ObDereferenceObject(FileObject); 655 ZwClose(FileHandle); 656 ExFreePoolWithTag(Dacl, 'lcaD'); 657 ExFreePoolWithTag(Buffer, TAG_MM); 658 return STATUS_INVALID_PARAMETER_3; 659 } 660 661 /* FIXME: implement parameters checking and page file extension */ 662 UNIMPLEMENTED; 663 664 KeReleaseGuardedMutex(&MmPageFileCreationLock); 665 ObDereferenceObject(FileObject); 666 ZwClose(FileHandle); 667 ExFreePoolWithTag(Dacl, 'lcaD'); 668 ExFreePoolWithTag(Buffer, TAG_MM); 669 return STATUS_NOT_IMPLEMENTED; 670 } 671 672 if (!NT_SUCCESS(Status)) 673 { 674 DPRINT1("Failed creating page file: %lx\n", Status); 675 ExFreePoolWithTag(Dacl, 'lcaD'); 676 ExFreePoolWithTag(Buffer, TAG_MM); 677 return Status; 678 } 679 680 /* Set the security descriptor */ 681 if (NT_SUCCESS(IoStatus.Status)) 682 { 683 Status = ZwSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, &SecurityDescriptor); 684 if (!NT_SUCCESS(Status)) 685 { 686 ExFreePoolWithTag(Dacl, 'lcaD'); 687 ZwClose(FileHandle); 688 ExFreePoolWithTag(Buffer, TAG_MM); 689 return Status; 690 } 691 } 692 693 /* DACL is no longer needed, free it */ 694 ExFreePoolWithTag(Dacl, 'lcaD'); 695 696 /* FIXME: To enable once page file managment is moved to ARM3 */ 697 #if 0 698 /* Check we won't overflow commit limit with the page file */ 699 if (MmTotalCommitLimitMaximum + (SafeMaximumSize.QuadPart >> PAGE_SHIFT) <= MmTotalCommitLimitMaximum) 700 { 701 ZwClose(FileHandle); 702 ExFreePoolWithTag(Buffer, TAG_MM); 703 return STATUS_INVALID_PARAMETER_3; 704 } 705 #endif 706 707 /* Set its end of file to minimal size */ 708 Status = ZwSetInformationFile(FileHandle, 709 &IoStatus, 710 &SafeMinimumSize, 711 sizeof(LARGE_INTEGER), 712 FileEndOfFileInformation); 713 if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status)) 714 { 715 ZwClose(FileHandle); 716 ExFreePoolWithTag(Buffer, TAG_MM); 717 return Status; 718 } 719 720 Status = ObReferenceObjectByHandle(FileHandle, 721 FILE_READ_DATA | FILE_WRITE_DATA, 722 IoFileObjectType, 723 KernelMode, 724 (PVOID*)&FileObject, 725 NULL); 726 if (!NT_SUCCESS(Status)) 727 { 728 ZwClose(FileHandle); 729 ExFreePoolWithTag(Buffer, TAG_MM); 730 return Status; 731 } 732 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) 737 { 738 ObDereferenceObject(FileObject); 739 ZwClose(FileHandle); 740 ExFreePoolWithTag(Buffer, TAG_MM); 741 return Status; 742 } 743 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)) 748 { 749 ObDereferenceObject(FileObject); 750 ZwClose(FileHandle); 751 ExFreePoolWithTag(Buffer, TAG_MM); 752 return STATUS_FLOPPY_VOLUME; 753 } 754 755 PagingFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(*PagingFile), TAG_MM); 756 if (PagingFile == NULL) 757 { 758 ObDereferenceObject(FileObject); 759 ZwClose(FileHandle); 760 ExFreePoolWithTag(Buffer, TAG_MM); 761 return STATUS_INSUFFICIENT_RESOURCES; 762 } 763 764 RtlZeroMemory(PagingFile, sizeof(*PagingFile)); 765 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 772 * TODO: write it 773 */ 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); 778 779 AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->MaximumSize + 31) / 32) * sizeof(ULONG)); 780 PagingFile->Bitmap = ExAllocatePoolWithTag(NonPagedPool, 781 AllocMapSize, 782 TAG_MM); 783 if (PagingFile->Bitmap == NULL) 784 { 785 ExFreePoolWithTag(PagingFile, TAG_MM); 786 ObDereferenceObject(FileObject); 787 ZwClose(FileHandle); 788 ExFreePoolWithTag(Buffer, TAG_MM); 789 return STATUS_INSUFFICIENT_RESOURCES; 790 } 791 792 RtlInitializeBitMap(PagingFile->Bitmap, 793 (PULONG)(PagingFile->Bitmap + 1), 794 (ULONG)(PagingFile->MaximumSize)); 795 RtlClearAllBits(PagingFile->Bitmap); 796 797 /* FIXME: should be calling unsafe instead, 798 * we should already be in a guarded region 799 */ 800 KeAcquireGuardedMutex(&MmPageFileCreationLock); 801 ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL); 802 MmPagingFile[MmNumberOfPagingFiles] = PagingFile; 803 MmNumberOfPagingFiles++; 804 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreeSpace; 805 KeReleaseGuardedMutex(&MmPageFileCreationLock); 806 807 MmSwapSpaceMessage = FALSE; 808 809 if (!MmSystemPageFileLocated && BooleanFlagOn(FileObject->DeviceObject->Flags, DO_SYSTEM_BOOT_PARTITION)) 810 { 811 MmSystemPageFileLocated = IoInitializeCrashDump(FileHandle); 812 } 813 814 return STATUS_SUCCESS; 815 } 816 817 /* EOF */ 818