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 * UPDATE HISTORY: 25 * Created 22/05/98 26 */ 27 28 /* INCLUDES *****************************************************************/ 29 30 #include <ntoskrnl.h> 31 #define NDEBUG 32 #include <debug.h> 33 34 #if defined (ALLOC_PRAGMA) 35 #pragma alloc_text(INIT, MmInitPagingFile) 36 #endif 37 38 PVOID 39 NTAPI 40 MiFindExportedRoutineByName(IN PVOID DllBase, 41 IN PANSI_STRING ExportName); 42 43 /* TYPES *********************************************************************/ 44 45 typedef struct _PAGINGFILE 46 { 47 LIST_ENTRY PagingFileListEntry; 48 PFILE_OBJECT FileObject; 49 LARGE_INTEGER MaximumSize; 50 LARGE_INTEGER CurrentSize; 51 PFN_NUMBER FreePages; 52 PFN_NUMBER UsedPages; 53 PULONG AllocMap; 54 KSPIN_LOCK AllocMapLock; 55 ULONG AllocMapSize; 56 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers; 57 } 58 PAGINGFILE, *PPAGINGFILE; 59 60 typedef struct _RETRIEVEL_DESCRIPTOR_LIST 61 { 62 struct _RETRIEVEL_DESCRIPTOR_LIST* Next; 63 RETRIEVAL_POINTERS_BUFFER RetrievalPointers; 64 } 65 RETRIEVEL_DESCRIPTOR_LIST, *PRETRIEVEL_DESCRIPTOR_LIST; 66 67 /* GLOBALS *******************************************************************/ 68 69 #define PAIRS_PER_RUN (1024) 70 71 #define MAX_PAGING_FILES (16) 72 73 /* List of paging files, both used and free */ 74 static PPAGINGFILE PagingFileList[MAX_PAGING_FILES]; 75 76 /* Lock for examining the list of paging files */ 77 static KSPIN_LOCK PagingFileListLock; 78 79 /* Number of paging files */ 80 ULONG MmNumberOfPagingFiles; 81 82 /* Number of pages that are available for swapping */ 83 PFN_COUNT MiFreeSwapPages; 84 85 /* Number of pages that have been allocated for swapping */ 86 PFN_COUNT MiUsedSwapPages; 87 88 BOOLEAN MmZeroPageFile; 89 90 /* 91 * Number of pages that have been reserved for swapping but not yet allocated 92 */ 93 static PFN_COUNT MiReservedSwapPages; 94 95 /* 96 * Ratio between reserved and available swap pages, e.g. setting this to five 97 * forces one swap page to be available for every five swap pages that are 98 * reserved. Setting this to zero turns off commit checking altogether. 99 */ 100 #define MM_PAGEFILE_COMMIT_RATIO (1) 101 102 /* 103 * Number of pages that can be used for potentially swapable memory without 104 * pagefile space being reserved. The intention is that this allows smss 105 * to start up and create page files while ordinarily having a commit 106 * ratio of one. 107 */ 108 #define MM_PAGEFILE_COMMIT_GRACE (256) 109 110 /* 111 * Translate between a swap entry and a file and offset pair. 112 */ 113 #define FILE_FROM_ENTRY(i) ((i) & 0x0f) 114 #define OFFSET_FROM_ENTRY(i) ((i) >> 11) 115 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400) 116 117 /* Make sure there can be only 16 paging files */ 118 C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES); 119 120 static BOOLEAN MmSwapSpaceMessage = FALSE; 121 122 /* FUNCTIONS *****************************************************************/ 123 124 VOID 125 NTAPI 126 MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages) 127 { 128 memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE)); 129 130 /* FIXME: this flag should be set by the caller perhaps? */ 131 Mdl->MdlFlags |= MDL_IO_PAGE_READ; 132 } 133 134 135 BOOLEAN 136 NTAPI 137 MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject) 138 { 139 ULONG i; 140 141 /* Loop through all the paging files */ 142 for (i = 0; i < MmNumberOfPagingFiles; i++) 143 { 144 /* Check if this is one of them */ 145 if (PagingFileList[i]->FileObject == FileObject) return TRUE; 146 } 147 148 /* Nothing found */ 149 return FALSE; 150 } 151 152 VOID 153 NTAPI 154 MmShowOutOfSpaceMessagePagingFile(VOID) 155 { 156 if (!MmSwapSpaceMessage) 157 { 158 DPRINT1("MM: Out of swap space.\n"); 159 MmSwapSpaceMessage = TRUE; 160 } 161 } 162 163 static LARGE_INTEGER 164 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers, LARGE_INTEGER Offset) 165 { 166 /* Simple binary search */ 167 ULONG first, last, mid; 168 first = 0; 169 last = RetrievalPointers->ExtentCount - 1; 170 while (first <= last) 171 { 172 mid = (last - first) / 2 + first; 173 if (Offset.QuadPart < RetrievalPointers->Extents[mid].NextVcn.QuadPart) 174 { 175 if (mid == 0) 176 { 177 Offset.QuadPart += RetrievalPointers->Extents[0].Lcn.QuadPart - RetrievalPointers->StartingVcn.QuadPart; 178 return Offset; 179 } 180 else 181 { 182 if (Offset.QuadPart >= RetrievalPointers->Extents[mid-1].NextVcn.QuadPart) 183 { 184 Offset.QuadPart += RetrievalPointers->Extents[mid].Lcn.QuadPart - RetrievalPointers->Extents[mid-1].NextVcn.QuadPart; 185 return Offset; 186 } 187 last = mid - 1; 188 } 189 } 190 else 191 { 192 if (mid == RetrievalPointers->ExtentCount - 1) 193 { 194 break; 195 } 196 if (Offset.QuadPart < RetrievalPointers->Extents[mid+1].NextVcn.QuadPart) 197 { 198 Offset.QuadPart += RetrievalPointers->Extents[mid+1].Lcn.QuadPart - RetrievalPointers->Extents[mid].NextVcn.QuadPart; 199 return Offset; 200 } 201 first = mid + 1; 202 } 203 } 204 KeBugCheck(MEMORY_MANAGEMENT); 205 #if defined(__GNUC__) 206 207 return (LARGE_INTEGER)0LL; 208 #else 209 210 { 211 const LARGE_INTEGER dummy = 212 { 213 {0} 214 }; 215 return dummy; 216 } 217 #endif 218 } 219 220 NTSTATUS 221 NTAPI 222 MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) 223 { 224 ULONG i; 225 ULONG_PTR offset; 226 LARGE_INTEGER file_offset; 227 IO_STATUS_BLOCK Iosb; 228 NTSTATUS Status; 229 KEVENT Event; 230 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; 231 PMDL Mdl = (PMDL)MdlBase; 232 233 DPRINT("MmWriteToSwapPage\n"); 234 235 if (SwapEntry == 0) 236 { 237 KeBugCheck(MEMORY_MANAGEMENT); 238 return(STATUS_UNSUCCESSFUL); 239 } 240 241 i = FILE_FROM_ENTRY(SwapEntry); 242 offset = OFFSET_FROM_ENTRY(SwapEntry) - 1; 243 244 if (PagingFileList[i]->FileObject == NULL || 245 PagingFileList[i]->FileObject->DeviceObject == NULL) 246 { 247 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry); 248 KeBugCheck(MEMORY_MANAGEMENT); 249 } 250 251 MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 252 MmBuildMdlFromPages(Mdl, &Page); 253 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 254 255 file_offset.QuadPart = offset * PAGE_SIZE; 256 file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset); 257 258 KeInitializeEvent(&Event, NotificationEvent, FALSE); 259 Status = IoSynchronousPageWrite(PagingFileList[i]->FileObject, 260 Mdl, 261 &file_offset, 262 &Event, 263 &Iosb); 264 if (Status == STATUS_PENDING) 265 { 266 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 267 Status = Iosb.Status; 268 } 269 270 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 271 { 272 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 273 } 274 return(Status); 275 } 276 277 278 NTSTATUS 279 NTAPI 280 MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) 281 { 282 return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry) - 1); 283 } 284 285 NTSTATUS 286 NTAPI 287 MiReadPageFile( 288 _In_ PFN_NUMBER Page, 289 _In_ ULONG PageFileIndex, 290 _In_ ULONG_PTR PageFileOffset) 291 { 292 LARGE_INTEGER file_offset; 293 IO_STATUS_BLOCK Iosb; 294 NTSTATUS Status; 295 KEVENT Event; 296 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; 297 PMDL Mdl = (PMDL)MdlBase; 298 PPAGINGFILE PagingFile; 299 300 DPRINT("MiReadSwapFile\n"); 301 302 if (PageFileOffset == 0) 303 { 304 KeBugCheck(MEMORY_MANAGEMENT); 305 return(STATUS_UNSUCCESSFUL); 306 } 307 308 ASSERT(PageFileIndex < MAX_PAGING_FILES); 309 310 PagingFile = PagingFileList[PageFileIndex]; 311 312 if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL) 313 { 314 DPRINT1("Bad paging file %u\n", PageFileIndex); 315 KeBugCheck(MEMORY_MANAGEMENT); 316 } 317 318 MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 319 MmBuildMdlFromPages(Mdl, &Page); 320 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 321 322 file_offset.QuadPart = PageFileOffset * PAGE_SIZE; 323 file_offset = MmGetOffsetPageFile(PagingFile->RetrievalPointers, file_offset); 324 325 KeInitializeEvent(&Event, NotificationEvent, FALSE); 326 Status = IoPageRead(PagingFile->FileObject, 327 Mdl, 328 &file_offset, 329 &Event, 330 &Iosb); 331 if (Status == STATUS_PENDING) 332 { 333 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 334 Status = Iosb.Status; 335 } 336 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 337 { 338 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 339 } 340 return(Status); 341 } 342 343 VOID 344 INIT_FUNCTION 345 NTAPI 346 MmInitPagingFile(VOID) 347 { 348 ULONG i; 349 350 KeInitializeSpinLock(&PagingFileListLock); 351 352 MiFreeSwapPages = 0; 353 MiUsedSwapPages = 0; 354 MiReservedSwapPages = 0; 355 356 for (i = 0; i < MAX_PAGING_FILES; i++) 357 { 358 PagingFileList[i] = NULL; 359 } 360 MmNumberOfPagingFiles = 0; 361 } 362 363 static ULONG 364 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile) 365 { 366 KIRQL oldIrql; 367 ULONG i, j; 368 369 KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql); 370 371 for (i = 0; i < PagingFile->AllocMapSize; i++) 372 { 373 for (j = 0; j < 32; j++) 374 { 375 if (!(PagingFile->AllocMap[i] & (1 << j))) 376 { 377 PagingFile->AllocMap[i] |= (1 << j); 378 PagingFile->UsedPages++; 379 PagingFile->FreePages--; 380 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql); 381 return((i * 32) + j); 382 } 383 } 384 } 385 386 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql); 387 return(0xFFFFFFFF); 388 } 389 390 VOID 391 NTAPI 392 MmFreeSwapPage(SWAPENTRY Entry) 393 { 394 ULONG i; 395 ULONG_PTR off; 396 KIRQL oldIrql; 397 398 i = FILE_FROM_ENTRY(Entry); 399 off = OFFSET_FROM_ENTRY(Entry) - 1; 400 401 KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 402 if (PagingFileList[i] == NULL) 403 { 404 KeBugCheck(MEMORY_MANAGEMENT); 405 } 406 KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock); 407 408 PagingFileList[i]->AllocMap[off >> 5] &= (~(1 << (off % 32))); 409 410 PagingFileList[i]->FreePages++; 411 PagingFileList[i]->UsedPages--; 412 413 MiFreeSwapPages++; 414 MiUsedSwapPages--; 415 416 KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock); 417 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 418 } 419 420 SWAPENTRY 421 NTAPI 422 MmAllocSwapPage(VOID) 423 { 424 KIRQL oldIrql; 425 ULONG i; 426 ULONG off; 427 SWAPENTRY entry; 428 429 KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 430 431 if (MiFreeSwapPages == 0) 432 { 433 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 434 return(0); 435 } 436 437 for (i = 0; i < MAX_PAGING_FILES; i++) 438 { 439 if (PagingFileList[i] != NULL && 440 PagingFileList[i]->FreePages >= 1) 441 { 442 off = MiAllocPageFromPagingFile(PagingFileList[i]); 443 if (off == 0xFFFFFFFF) 444 { 445 KeBugCheck(MEMORY_MANAGEMENT); 446 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 447 return(STATUS_UNSUCCESSFUL); 448 } 449 MiUsedSwapPages++; 450 MiFreeSwapPages--; 451 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 452 453 entry = ENTRY_FROM_FILE_OFFSET(i, off + 1); 454 return(entry); 455 } 456 } 457 458 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 459 KeBugCheck(MEMORY_MANAGEMENT); 460 return(0); 461 } 462 463 static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL 464 MmAllocRetrievelDescriptorList(ULONG Pairs) 465 { 466 ULONG Size; 467 PRETRIEVEL_DESCRIPTOR_LIST RetDescList; 468 469 Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER); 470 RetDescList = ExAllocatePool(NonPagedPool, Size); 471 if (RetDescList) 472 { 473 RtlZeroMemory(RetDescList, Size); 474 } 475 476 return RetDescList; 477 } 478 479 NTSTATUS NTAPI 480 NtCreatePagingFile(IN PUNICODE_STRING FileName, 481 IN PLARGE_INTEGER InitialSize, 482 IN PLARGE_INTEGER MaximumSize, 483 IN ULONG Reserved) 484 { 485 NTSTATUS Status; 486 OBJECT_ATTRIBUTES ObjectAttributes; 487 HANDLE FileHandle; 488 IO_STATUS_BLOCK IoStatus; 489 PFILE_OBJECT FileObject; 490 PPAGINGFILE PagingFile; 491 KIRQL oldIrql; 492 ULONG AllocMapSize; 493 FILE_FS_SIZE_INFORMATION FsSizeInformation; 494 PRETRIEVEL_DESCRIPTOR_LIST RetDescList; 495 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList; 496 ULONG i; 497 ULONG BytesPerAllocationUnit; 498 LARGE_INTEGER Vcn; 499 ULONG ExtentCount; 500 LARGE_INTEGER MaxVcn; 501 ULONG Count; 502 ULONG Size; 503 KPROCESSOR_MODE PreviousMode; 504 UNICODE_STRING CapturedFileName; 505 LARGE_INTEGER SafeInitialSize, SafeMaximumSize; 506 507 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n", 508 FileName, InitialSize->QuadPart); 509 510 if (MmNumberOfPagingFiles >= MAX_PAGING_FILES) 511 { 512 return(STATUS_TOO_MANY_PAGING_FILES); 513 } 514 515 PreviousMode = ExGetPreviousMode(); 516 517 if (PreviousMode != KernelMode) 518 { 519 _SEH2_TRY 520 { 521 SafeInitialSize = ProbeForReadLargeInteger(InitialSize); 522 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); 523 } 524 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 525 { 526 /* Return the exception code */ 527 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 528 } 529 _SEH2_END; 530 } 531 else 532 { 533 SafeInitialSize = *InitialSize; 534 SafeMaximumSize = *MaximumSize; 535 } 536 537 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be 538 smaller than the maximum */ 539 if (0 != SafeInitialSize.u.HighPart) 540 { 541 return STATUS_INVALID_PARAMETER_2; 542 } 543 if (0 != SafeMaximumSize.u.HighPart) 544 { 545 return STATUS_INVALID_PARAMETER_3; 546 } 547 if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart) 548 { 549 return STATUS_INVALID_PARAMETER_MIX; 550 } 551 552 Status = ProbeAndCaptureUnicodeString(&CapturedFileName, 553 PreviousMode, 554 FileName); 555 if (!NT_SUCCESS(Status)) 556 { 557 return(Status); 558 } 559 560 InitializeObjectAttributes(&ObjectAttributes, 561 &CapturedFileName, 562 OBJ_KERNEL_HANDLE, 563 NULL, 564 NULL); 565 566 Status = IoCreateFile(&FileHandle, 567 FILE_ALL_ACCESS, 568 &ObjectAttributes, 569 &IoStatus, 570 NULL, 571 0, 572 0, 573 FILE_OPEN_IF, 574 FILE_SYNCHRONOUS_IO_NONALERT, 575 NULL, 576 0, 577 CreateFileTypeNone, 578 NULL, 579 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); 580 581 ReleaseCapturedUnicodeString(&CapturedFileName, 582 PreviousMode); 583 if (!NT_SUCCESS(Status)) 584 { 585 return(Status); 586 } 587 588 Status = ZwQueryVolumeInformationFile(FileHandle, 589 &IoStatus, 590 &FsSizeInformation, 591 sizeof(FILE_FS_SIZE_INFORMATION), 592 FileFsSizeInformation); 593 if (!NT_SUCCESS(Status)) 594 { 595 ZwClose(FileHandle); 596 return Status; 597 } 598 599 BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit * 600 FsSizeInformation.BytesPerSector; 601 /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is 602 * a problem if the paging file is fragmented. Suppose the first cluster 603 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the 604 * paging file but of another file. We can't write a complete page (4096 605 * bytes) to the physical location of cluster 3042 then. */ 606 if (BytesPerAllocationUnit % PAGE_SIZE) 607 { 608 DPRINT1("BytesPerAllocationUnit %lu is not a multiple of PAGE_SIZE %d\n", 609 BytesPerAllocationUnit, PAGE_SIZE); 610 ZwClose(FileHandle); 611 return STATUS_UNSUCCESSFUL; 612 } 613 614 Status = ZwSetInformationFile(FileHandle, 615 &IoStatus, 616 &SafeInitialSize, 617 sizeof(LARGE_INTEGER), 618 FileAllocationInformation); 619 if (!NT_SUCCESS(Status)) 620 { 621 ZwClose(FileHandle); 622 return(Status); 623 } 624 625 Status = ObReferenceObjectByHandle(FileHandle, 626 FILE_ALL_ACCESS, 627 IoFileObjectType, 628 KernelMode, 629 (PVOID*)&FileObject, 630 NULL); 631 if (!NT_SUCCESS(Status)) 632 { 633 ZwClose(FileHandle); 634 return(Status); 635 } 636 637 CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN); 638 639 if (CurrentRetDescList == NULL) 640 { 641 ObDereferenceObject(FileObject); 642 ZwClose(FileHandle); 643 return(STATUS_NO_MEMORY); 644 } 645 646 #if defined(__GNUC__) 647 Vcn.QuadPart = 0LL; 648 #else 649 650 Vcn.QuadPart = 0; 651 #endif 652 653 ExtentCount = 0; 654 MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit; 655 while(1) 656 { 657 Status = ZwFsControlFile(FileHandle, 658 0, 659 NULL, 660 NULL, 661 &IoStatus, 662 FSCTL_GET_RETRIEVAL_POINTERS, 663 &Vcn, 664 sizeof(LARGE_INTEGER), 665 &CurrentRetDescList->RetrievalPointers, 666 sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER)); 667 if (!NT_SUCCESS(Status)) 668 { 669 while (RetDescList) 670 { 671 CurrentRetDescList = RetDescList; 672 RetDescList = RetDescList->Next; 673 ExFreePool(CurrentRetDescList); 674 } 675 ObDereferenceObject(FileObject); 676 ZwClose(FileHandle); 677 return(Status); 678 } 679 ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount; 680 if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart) 681 { 682 CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN); 683 if (CurrentRetDescList->Next == NULL) 684 { 685 while (RetDescList) 686 { 687 CurrentRetDescList = RetDescList; 688 RetDescList = RetDescList->Next; 689 ExFreePool(CurrentRetDescList); 690 } 691 ObDereferenceObject(FileObject); 692 ZwClose(FileHandle); 693 return(STATUS_NO_MEMORY); 694 } 695 Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn; 696 CurrentRetDescList = CurrentRetDescList->Next; 697 } 698 else 699 { 700 break; 701 } 702 } 703 704 PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile)); 705 if (PagingFile == NULL) 706 { 707 while (RetDescList) 708 { 709 CurrentRetDescList = RetDescList; 710 RetDescList = RetDescList->Next; 711 ExFreePool(CurrentRetDescList); 712 } 713 ObDereferenceObject(FileObject); 714 ZwClose(FileHandle); 715 return(STATUS_NO_MEMORY); 716 } 717 718 RtlZeroMemory(PagingFile, sizeof(*PagingFile)); 719 720 PagingFile->FileObject = FileObject; 721 PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart; 722 PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart; 723 PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE); 724 PagingFile->UsedPages = 0; 725 KeInitializeSpinLock(&PagingFile->AllocMapLock); 726 727 AllocMapSize = (PagingFile->FreePages / 32) + 1; 728 PagingFile->AllocMap = ExAllocatePool(NonPagedPool, 729 AllocMapSize * sizeof(ULONG)); 730 PagingFile->AllocMapSize = AllocMapSize; 731 732 if (PagingFile->AllocMap == NULL) 733 { 734 while (RetDescList) 735 { 736 CurrentRetDescList = RetDescList; 737 RetDescList = RetDescList->Next; 738 ExFreePool(CurrentRetDescList); 739 } 740 ExFreePool(PagingFile); 741 ObDereferenceObject(FileObject); 742 ZwClose(FileHandle); 743 return(STATUS_NO_MEMORY); 744 } 745 DPRINT("ExtentCount: %lu\n", ExtentCount); 746 Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER); 747 PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size); 748 if (PagingFile->RetrievalPointers == NULL) 749 { 750 while (RetDescList) 751 { 752 CurrentRetDescList = RetDescList; 753 RetDescList = RetDescList->Next; 754 ExFreePool(CurrentRetDescList); 755 } 756 ExFreePool(PagingFile->AllocMap); 757 ExFreePool(PagingFile); 758 ObDereferenceObject(FileObject); 759 ZwClose(FileHandle); 760 return(STATUS_NO_MEMORY); 761 } 762 763 RtlZeroMemory(PagingFile->AllocMap, AllocMapSize * sizeof(ULONG)); 764 RtlZeroMemory(PagingFile->RetrievalPointers, Size); 765 766 Count = 0; 767 PagingFile->RetrievalPointers->ExtentCount = ExtentCount; 768 PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn; 769 CurrentRetDescList = RetDescList; 770 while (CurrentRetDescList) 771 { 772 memcpy(&PagingFile->RetrievalPointers->Extents[Count], 773 CurrentRetDescList->RetrievalPointers.Extents, 774 CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER)); 775 Count += CurrentRetDescList->RetrievalPointers.ExtentCount; 776 RetDescList = CurrentRetDescList; 777 CurrentRetDescList = CurrentRetDescList->Next; 778 ExFreePool(RetDescList); 779 } 780 781 if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount || 782 PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart) 783 { 784 ExFreePool(PagingFile->RetrievalPointers); 785 ExFreePool(PagingFile->AllocMap); 786 ExFreePool(PagingFile); 787 ObDereferenceObject(FileObject); 788 ZwClose(FileHandle); 789 return(STATUS_UNSUCCESSFUL); 790 } 791 792 /* 793 * Change the entries from lcn's to volume offset's. 794 */ 795 PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit; 796 for (i = 0; i < ExtentCount; i++) 797 { 798 PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit; 799 PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit; 800 } 801 802 KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 803 for (i = 0; i < MAX_PAGING_FILES; i++) 804 { 805 if (PagingFileList[i] == NULL) 806 { 807 PagingFileList[i] = PagingFile; 808 break; 809 } 810 } 811 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages; 812 MmNumberOfPagingFiles++; 813 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 814 815 ZwClose(FileHandle); 816 817 MmSwapSpaceMessage = FALSE; 818 819 return(STATUS_SUCCESS); 820 } 821 822 /* EOF */ 823