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