1 /* 2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section) 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * 18 * 19 * PROJECT: ReactOS kernel 20 * FILE: ntoskrnl/cache/section/data.c 21 * PURPOSE: Implements section objects 22 * 23 * PROGRAMMERS: Rex Jolliff 24 * David Welch 25 * Eric Kohl 26 * Emanuele Aliberti 27 * Eugene Ingerman 28 * Casper Hornstrup 29 * KJK::Hyperion 30 * Guido de Jong 31 * Ge van Geldorp 32 * Royce Mitchell III 33 * Filip Navara 34 * Aleksey Bragin 35 * Jason Filby 36 * Thomas Weidenmueller 37 * Gunnar Andre' Dalsnes 38 * Mike Nordell 39 * Alex Ionescu 40 * Gregor Anich 41 * Steven Edwards 42 * Herve Poussineau 43 */ 44 45 /* 46 47 A note on this code: 48 49 Unlike the previous section code, this code does not rely on an active map 50 for a page to exist in a data segment. Each mapping contains a large integer 51 offset to map at, and the segment always represents the entire section space 52 from zero to the maximum long long. This allows us to associate one single 53 page map with each file object, and to let each mapping view an offset into 54 the overall mapped file. Temporarily unmapping the file has no effect on the 55 section membership. 56 57 This necessitates a change in the section page table implementation, which is 58 now an RtlGenericTable. This will be elaborated more in sptab.c. One upshot 59 of this change is that a mapping of a small files takes a bit more than 1/4 60 of the size in nonpaged kernel space as it did previously. 61 62 When we need other threads that may be competing for the same page fault to 63 wait, we have a mechanism seperate from PageOps for dealing with that, which 64 was suggested by Travis Geiselbrecht after a conversation I had with Alex 65 Ionescu. That mechanism is the MM_WAIT_ENTRY, which is the all-ones SWAPENTRY. 66 67 When we wish for other threads to know that we're waiting and will finish 68 handling a page fault, we place the swap entry MM_WAIT_ENTRY in the page table 69 at the fault address (this works on either the section page table or a process 70 address space), perform any blocking operations required, then replace the 71 entry. 72 73 */ 74 75 /* INCLUDES *****************************************************************/ 76 77 #include <ntoskrnl.h> 78 #include "newmm.h" 79 #include <cache/newcc.h> 80 #define NDEBUG 81 #include <debug.h> 82 #include <mm/ARM3/miarm.h> 83 84 #define DPRINTC DPRINT 85 86 LIST_ENTRY MiSegmentList; 87 88 extern KEVENT MpwThreadEvent; 89 extern KSPIN_LOCK MiSectionPageTableLock; 90 extern PMMWSL MmWorkingSetList; 91 92 /* FUNCTIONS *****************************************************************/ 93 94 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */ 95 96 VOID 97 NTAPI 98 _MmLockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line) 99 { 100 //DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line); 101 ExAcquireFastMutex(&Segment->Lock); 102 Segment->Locked = TRUE; 103 } 104 105 VOID 106 NTAPI 107 _MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line) 108 { 109 ASSERT(Segment->Locked); 110 Segment->Locked = FALSE; 111 ExReleaseFastMutex(&Segment->Lock); 112 //DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line); 113 } 114 115 /* 116 117 MiFlushMappedSection 118 119 Called from cache code to cause dirty pages of a section 120 to be written back. This doesn't affect the mapping. 121 122 BaseOffset is the base at which to start writing in file space. 123 FileSize is the length of the file as understood by the cache. 124 125 */ 126 NTSTATUS 127 NTAPI 128 _MiFlushMappedSection(PVOID BaseAddress, 129 PLARGE_INTEGER BaseOffset, 130 PLARGE_INTEGER FileSize, 131 BOOLEAN WriteData, 132 const char *File, 133 int Line) 134 { 135 NTSTATUS Status = STATUS_SUCCESS; 136 ULONG_PTR PageAddress; 137 PMMSUPPORT AddressSpace = MmGetKernelAddressSpace(); 138 PMEMORY_AREA MemoryArea; 139 PMM_SECTION_SEGMENT Segment; 140 ULONG_PTR BeginningAddress, EndingAddress; 141 LARGE_INTEGER ViewOffset; 142 LARGE_INTEGER FileOffset; 143 PFN_NUMBER Page; 144 PPFN_NUMBER Pages; 145 KIRQL OldIrql; 146 147 DPRINT("MiFlushMappedSection(%p,%I64x,%I64x,%u,%s:%d)\n", 148 BaseAddress, 149 BaseOffset->QuadPart, 150 FileSize ? FileSize->QuadPart : 0, 151 WriteData, 152 File, 153 Line); 154 155 MmLockAddressSpace(AddressSpace); 156 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress); 157 if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_CACHE || MemoryArea->DeleteInProgress) 158 { 159 MmUnlockAddressSpace(AddressSpace); 160 DPRINT("STATUS_NOT_MAPPED_DATA\n"); 161 return STATUS_NOT_MAPPED_DATA; 162 } 163 BeginningAddress = PAGE_ROUND_DOWN(MA_GetStartingAddress(MemoryArea)); 164 EndingAddress = PAGE_ROUND_UP(MA_GetEndingAddress(MemoryArea)); 165 Segment = MemoryArea->Data.SectionData.Segment; 166 ViewOffset.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart; 167 168 ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart); 169 170 MmLockSectionSegment(Segment); 171 172 Pages = ExAllocatePool(NonPagedPool, 173 sizeof(PFN_NUMBER) * ((EndingAddress - BeginningAddress) >> PAGE_SHIFT)); 174 175 if (!Pages) 176 { 177 ASSERT(FALSE); 178 } 179 180 //DPRINT("Getting pages in range %08x-%08x\n", BeginningAddress, EndingAddress); 181 182 for (PageAddress = BeginningAddress; 183 PageAddress < EndingAddress; 184 PageAddress += PAGE_SIZE) 185 { 186 ULONG_PTR Entry; 187 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress; 188 Entry = MmGetPageEntrySectionSegment(MemoryArea->Data.SectionData.Segment, 189 &FileOffset); 190 Page = PFN_FROM_SSE(Entry); 191 if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) && 192 (MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) && 193 FileOffset.QuadPart < FileSize->QuadPart) 194 { 195 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 196 MmReferencePage(Page); 197 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 198 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Entry; 199 } 200 else 201 { 202 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0; 203 } 204 } 205 206 MmUnlockSectionSegment(Segment); 207 MmUnlockAddressSpace(AddressSpace); 208 209 for (PageAddress = BeginningAddress; 210 PageAddress < EndingAddress; 211 PageAddress += PAGE_SIZE) 212 { 213 ULONG_PTR Entry; 214 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress; 215 Entry = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT]; 216 Page = PFN_FROM_SSE(Entry); 217 if (Page) 218 { 219 if (WriteData) { 220 //DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart); 221 Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page); 222 } else 223 Status = STATUS_SUCCESS; 224 225 if (NT_SUCCESS(Status)) { 226 MmLockAddressSpace(AddressSpace); 227 MmSetCleanAllRmaps(Page); 228 229 MmSetPageProtect(MmGetAddressSpaceOwner(AddressSpace), 230 (PVOID)PageAddress, 231 PAGE_READONLY); 232 233 MmLockSectionSegment(Segment); 234 Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset); 235 236 if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page) 237 MmSetPageEntrySectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry)); 238 239 MmUnlockSectionSegment(Segment); 240 MmUnlockAddressSpace(AddressSpace); 241 } else { 242 DPRINT("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n", 243 FileOffset.u.HighPart, 244 FileOffset.u.LowPart, 245 (ULONG)(FileSize->QuadPart - FileOffset.QuadPart), 246 PageAddress, 247 Page, 248 FileSize->u.HighPart, 249 FileSize->u.LowPart, 250 &Segment->FileObject->FileName, 251 Status); 252 } 253 MmReleasePageMemoryConsumer(MC_CACHE, Page); 254 } 255 } 256 257 ExFreePool(Pages); 258 259 return Status; 260 } 261 262 /* 263 264 This deletes a segment entirely including its page map. 265 It must have been unmapped in every address space. 266 267 */ 268 269 VOID 270 NTAPI 271 MmFinalizeSegment(PMM_SECTION_SEGMENT Segment) 272 { 273 KIRQL OldIrql = 0; 274 275 DPRINT("Finalize segment %p\n", Segment); 276 277 MmLockSectionSegment(Segment); 278 RemoveEntryList(&Segment->ListOfSegments); 279 if (Segment->Flags & MM_DATAFILE_SEGMENT) { 280 KeAcquireSpinLock(&Segment->FileObject->IrpListLock, &OldIrql); 281 if (Segment->Flags & MM_SEGMENT_FINALIZE) { 282 KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql); 283 MmUnlockSectionSegment(Segment); 284 return; 285 } 286 Segment->Flags |= MM_SEGMENT_FINALIZE; 287 DPRINTC("Finalizing data file segment %p\n", Segment); 288 289 Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL; 290 KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql); 291 MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage); 292 MmUnlockSectionSegment(Segment); 293 DPRINT("Dereference file object %wZ\n", &Segment->FileObject->FileName); 294 ObDereferenceObject(Segment->FileObject); 295 DPRINT("Done with %wZ\n", &Segment->FileObject->FileName); 296 Segment->FileObject = NULL; 297 } else { 298 DPRINTC("Finalizing segment %p\n", Segment); 299 MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage); 300 MmUnlockSectionSegment(Segment); 301 } 302 DPRINTC("Segment %p destroy\n", Segment); 303 ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT); 304 } 305 306 NTSTATUS 307 NTAPI 308 MmCreateCacheSection(PROS_SECTION_OBJECT *SectionObject, 309 ACCESS_MASK DesiredAccess, 310 POBJECT_ATTRIBUTES ObjectAttributes, 311 PLARGE_INTEGER UMaximumSize, 312 ULONG SectionPageProtection, 313 ULONG AllocationAttributes, 314 PFILE_OBJECT FileObject) 315 /* 316 * Create a section backed by a data file. 317 */ 318 { 319 PROS_SECTION_OBJECT Section; 320 NTSTATUS Status; 321 LARGE_INTEGER MaximumSize; 322 PMM_SECTION_SEGMENT Segment; 323 IO_STATUS_BLOCK Iosb; 324 CC_FILE_SIZES FileSizes; 325 FILE_STANDARD_INFORMATION FileInfo; 326 KIRQL OldIrql; 327 328 DPRINT("MmCreateDataFileSection\n"); 329 330 /* Create the section */ 331 Status = ObCreateObject(ExGetPreviousMode(), 332 MmSectionObjectType, 333 ObjectAttributes, 334 ExGetPreviousMode(), 335 NULL, 336 sizeof(ROS_SECTION_OBJECT), 337 0, 338 0, 339 (PVOID*)(PVOID)&Section); 340 if (!NT_SUCCESS(Status)) 341 { 342 DPRINT("Failed: %x\n", Status); 343 return Status; 344 } 345 346 /* Initialize it */ 347 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT)); 348 Section->Type = 'SC'; 349 Section->Size = 'TN'; 350 Section->SectionPageProtection = SectionPageProtection; 351 Section->AllocationAttributes = AllocationAttributes; 352 Section->Segment = NULL; 353 354 Section->FileObject = FileObject; 355 356 DPRINT("Getting original file size\n"); 357 /* A hack: If we're cached, we can overcome deadlocking with the upper 358 * layer filesystem call by retriving the object sizes from the cache 359 * which is made to keep track. If I had to guess, they were figuring 360 * out a similar problem. 361 */ 362 if (!CcGetFileSizes(FileObject, &FileSizes)) 363 { 364 ULONG Information; 365 /* 366 * FIXME: This is propably not entirely correct. We can't look into 367 * the standard FCB header because it might not be initialized yet 368 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the 369 * standard file information is filled on first request). 370 */ 371 DPRINT("Querying info\n"); 372 Status = IoQueryFileInformation(FileObject, 373 FileStandardInformation, 374 sizeof(FILE_STANDARD_INFORMATION), 375 &FileInfo, 376 &Information); 377 Iosb.Information = Information; 378 DPRINT("Query => %x\n", Status); 379 DBG_UNREFERENCED_LOCAL_VARIABLE(Iosb); 380 381 if (!NT_SUCCESS(Status)) 382 { 383 DPRINT("Status %x\n", Status); 384 ObDereferenceObject(Section); 385 return Status; 386 } 387 ASSERT(Status != STATUS_PENDING); 388 389 FileSizes.ValidDataLength = FileInfo.EndOfFile; 390 FileSizes.FileSize = FileInfo.EndOfFile; 391 } 392 DPRINT("Got %I64x\n", FileSizes.ValidDataLength.QuadPart); 393 394 /* 395 * FIXME: Revise this once a locking order for file size changes is 396 * decided 397 * 398 * We're handed down a maximum size in every case. Should we still check at all? 399 */ 400 if (UMaximumSize != NULL && UMaximumSize->QuadPart) 401 { 402 DPRINT("Taking maximum %I64x\n", UMaximumSize->QuadPart); 403 MaximumSize.QuadPart = UMaximumSize->QuadPart; 404 } 405 else 406 { 407 DPRINT("Got file size %I64x\n", FileSizes.FileSize.QuadPart); 408 MaximumSize.QuadPart = FileSizes.FileSize.QuadPart; 409 } 410 411 /* Mapping zero-sized files isn't allowed. */ 412 if (MaximumSize.QuadPart == 0) 413 { 414 DPRINT("Zero size file\n"); 415 ObDereferenceObject(Section); 416 return STATUS_FILE_INVALID; 417 } 418 419 Segment = ExAllocatePoolWithTag(NonPagedPool, 420 sizeof(MM_SECTION_SEGMENT), 421 TAG_MM_SECTION_SEGMENT); 422 if (Segment == NULL) 423 { 424 DPRINT("Failed: STATUS_NO_MEMORY\n"); 425 ObDereferenceObject(Section); 426 return STATUS_NO_MEMORY; 427 } 428 429 DPRINT("Zeroing %p\n", Segment); 430 RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT)); 431 ExInitializeFastMutex(&Segment->Lock); 432 433 Segment->ReferenceCount = 1; 434 Segment->Locked = TRUE; 435 RtlZeroMemory(&Segment->Image, sizeof(Segment->Image)); 436 Section->Segment = Segment; 437 438 KeAcquireSpinLock(&FileObject->IrpListLock, &OldIrql); 439 /* 440 * If this file hasn't been mapped as a data file before then allocate a 441 * section segment to describe the data file mapping 442 */ 443 if (FileObject->SectionObjectPointer->DataSectionObject == NULL) 444 { 445 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment; 446 KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql); 447 448 /* 449 * Set the lock before assigning the segment to the file object 450 */ 451 ExAcquireFastMutex(&Segment->Lock); 452 453 DPRINT("Filling out Segment info (No previous data section)\n"); 454 ObReferenceObject(FileObject); 455 Segment->FileObject = FileObject; 456 Segment->Protection = SectionPageProtection; 457 Segment->Flags = MM_DATAFILE_SEGMENT; 458 memset(&Segment->Image, 0, sizeof(Segment->Image)); 459 Segment->WriteCopy = FALSE; 460 461 if (AllocationAttributes & SEC_RESERVE) 462 { 463 Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0; 464 } 465 else 466 { 467 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 468 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 469 } 470 MiInitializeSectionPageTable(Segment); 471 InsertHeadList(&MiSegmentList, &Segment->ListOfSegments); 472 } 473 else 474 { 475 KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql); 476 DPRINTC("Free Segment %p\n", Segment); 477 ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT); 478 479 DPRINT("Filling out Segment info (previous data section)\n"); 480 481 /* 482 * If the file is already mapped as a data file then we may need 483 * to extend it 484 */ 485 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->DataSectionObject; 486 Section->Segment = Segment; 487 (void)InterlockedIncrementUL(&Segment->ReferenceCount); 488 489 MmLockSectionSegment(Segment); 490 491 if (MaximumSize.QuadPart > Segment->RawLength.QuadPart && 492 !(AllocationAttributes & SEC_RESERVE)) 493 { 494 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 495 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 496 } 497 } 498 499 MmUnlockSectionSegment(Segment); 500 501 Section->MaximumSize.QuadPart = MaximumSize.QuadPart; 502 503 /* Extend file if section is longer */ 504 DPRINT("MaximumSize %I64x ValidDataLength %I64x\n", 505 MaximumSize.QuadPart, 506 FileSizes.ValidDataLength.QuadPart); 507 if (MaximumSize.QuadPart > FileSizes.ValidDataLength.QuadPart) 508 { 509 DPRINT("Changing file size to %I64x, segment %p\n", 510 MaximumSize.QuadPart, 511 Segment); 512 513 Status = IoSetInformation(FileObject, 514 FileEndOfFileInformation, 515 sizeof(LARGE_INTEGER), 516 &MaximumSize); 517 518 DPRINT("Change: Status %x\n", Status); 519 if (!NT_SUCCESS(Status)) 520 { 521 DPRINT("Could not expand section\n"); 522 ObDereferenceObject(Section); 523 return Status; 524 } 525 } 526 527 DPRINTC("Segment %p created (%x)\n", Segment, Segment->Flags); 528 529 *SectionObject = Section; 530 return STATUS_SUCCESS; 531 } 532 533 NTSTATUS 534 NTAPI 535 _MiMapViewOfSegment(PMMSUPPORT AddressSpace, 536 PMM_SECTION_SEGMENT Segment, 537 PVOID* BaseAddress, 538 SIZE_T ViewSize, 539 ULONG Protect, 540 PLARGE_INTEGER ViewOffset, 541 ULONG AllocationType, 542 const char *file, 543 int line) 544 { 545 PMEMORY_AREA MArea; 546 NTSTATUS Status; 547 548 Status = MmCreateMemoryArea(AddressSpace, 549 MEMORY_AREA_CACHE, 550 BaseAddress, 551 ViewSize, 552 Protect, 553 &MArea, 554 AllocationType, 555 *BaseAddress ? 556 PAGE_SIZE : MM_ALLOCATION_GRANULARITY); 557 558 if (!NT_SUCCESS(Status)) 559 { 560 DPRINT("Mapping between 0x%p and 0x%p failed (%X).\n", 561 (*BaseAddress), 562 (char*)(*BaseAddress) + ViewSize, 563 Status); 564 565 return Status; 566 } 567 568 DPRINTC("MiMapViewOfSegment %p %p %p %I64x %Ix %wZ %s:%d\n", 569 MmGetAddressSpaceOwner(AddressSpace), 570 *BaseAddress, 571 Segment, 572 ViewOffset ? ViewOffset->QuadPart : 0, 573 ViewSize, 574 Segment->FileObject ? &Segment->FileObject->FileName : NULL, 575 file, 576 line); 577 578 MArea->Data.SectionData.Segment = Segment; 579 if (ViewOffset) 580 MArea->Data.SectionData.ViewOffset = *ViewOffset; 581 else 582 MArea->Data.SectionData.ViewOffset.QuadPart = 0; 583 584 #if 0 585 MArea->NotPresent = MmNotPresentFaultPageFile; 586 MArea->AccessFault = MiCowSectionPage; 587 MArea->PageOut = MmPageOutPageFileView; 588 #endif 589 590 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead, 591 ViewSize, 592 0, 593 Protect); 594 595 DPRINTC("MiMapViewOfSegment(P %p, A %p, T %x)\n", 596 MmGetAddressSpaceOwner(AddressSpace), 597 *BaseAddress, 598 MArea->Type); 599 600 return STATUS_SUCCESS; 601 } 602 603 /* 604 605 Completely remove the page at FileOffset in Segment. The page must not 606 be mapped. 607 608 */ 609 610 VOID 611 NTAPI 612 MiFreeSegmentPage(PMM_SECTION_SEGMENT Segment, 613 PLARGE_INTEGER FileOffset) 614 { 615 ULONG_PTR Entry; 616 PFILE_OBJECT FileObject = Segment->FileObject; 617 618 Entry = MmGetPageEntrySectionSegment(Segment, FileOffset); 619 DPRINTC("MiFreeSegmentPage(%p:%I64x -> Entry %Ix\n", 620 Segment, 621 FileOffset->QuadPart, 622 Entry); 623 624 if (Entry && !IS_SWAP_FROM_SSE(Entry)) 625 { 626 // The segment is carrying a dirty page. 627 PFN_NUMBER OldPage = PFN_FROM_SSE(Entry); 628 if (IS_DIRTY_SSE(Entry) && FileObject) 629 { 630 DPRINT("MiWriteBackPage(%p,%wZ,%I64x)\n", 631 Segment, 632 &FileObject->FileName, 633 FileOffset->QuadPart); 634 635 MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage); 636 } 637 DPRINTC("Free page %Ix (off %I64x from %p) (ref ct %lu, ent %Ix, dirty? %s)\n", 638 OldPage, 639 FileOffset->QuadPart, 640 Segment, 641 MmGetReferenceCountPage(OldPage), 642 Entry, 643 IS_DIRTY_SSE(Entry) ? "true" : "false"); 644 645 MmSetPageEntrySectionSegment(Segment, FileOffset, 0); 646 MmReleasePageMemoryConsumer(MC_CACHE, OldPage); 647 } 648 else if (IS_SWAP_FROM_SSE(Entry)) 649 { 650 DPRINT("Free swap\n"); 651 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry)); 652 } 653 654 DPRINT("Done\n"); 655 } 656 657 VOID 658 MmFreeCacheSectionPage(PVOID Context, 659 MEMORY_AREA* MemoryArea, 660 PVOID Address, 661 PFN_NUMBER Page, 662 SWAPENTRY SwapEntry, 663 BOOLEAN Dirty) 664 { 665 ULONG_PTR Entry; 666 PVOID *ContextData = Context; 667 PMMSUPPORT AddressSpace; 668 PEPROCESS Process; 669 PMM_SECTION_SEGMENT Segment; 670 LARGE_INTEGER Offset; 671 672 DPRINT("MmFreeSectionPage(%p,%p,%Ix,%Ix,%u)\n", 673 MmGetAddressSpaceOwner(ContextData[0]), 674 Address, 675 Page, 676 SwapEntry, 677 Dirty); 678 679 AddressSpace = ContextData[0]; 680 Process = MmGetAddressSpaceOwner(AddressSpace); 681 Address = (PVOID)PAGE_ROUND_DOWN(Address); 682 Segment = ContextData[1]; 683 Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea) + 684 MemoryArea->Data.SectionData.ViewOffset.QuadPart; 685 686 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 687 688 if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty) 689 { 690 DPRINT("Freeing section page %p:%I64x -> %Ix\n", Segment, Offset.QuadPart, Entry); 691 MmSetPageEntrySectionSegment(Segment, &Offset, DIRTY_SSE(Entry)); 692 } 693 if (Page) 694 { 695 DPRINT("Removing page %p:%I64x -> %x\n", Segment, Offset.QuadPart, Entry); 696 MmSetSavedSwapEntryPage(Page, 0); 697 MmDeleteRmap(Page, Process, Address); 698 MmDeleteVirtualMapping(Process, Address, NULL, NULL); 699 MmReleasePageMemoryConsumer(MC_CACHE, Page); 700 } 701 if (SwapEntry != 0) 702 { 703 MmFreeSwapPage(SwapEntry); 704 } 705 } 706 707 NTSTATUS 708 NTAPI 709 MmUnmapViewOfCacheSegment(PMMSUPPORT AddressSpace, 710 PVOID BaseAddress) 711 { 712 PVOID Context[2]; 713 PMEMORY_AREA MemoryArea; 714 PMM_SECTION_SEGMENT Segment; 715 716 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress); 717 if (MemoryArea == NULL || MemoryArea->DeleteInProgress) 718 { 719 ASSERT(MemoryArea); 720 return STATUS_UNSUCCESSFUL; 721 } 722 723 MemoryArea->DeleteInProgress = TRUE; 724 Segment = MemoryArea->Data.SectionData.Segment; 725 MemoryArea->Data.SectionData.Segment = NULL; 726 727 MmLockSectionSegment(Segment); 728 729 Context[0] = AddressSpace; 730 Context[1] = Segment; 731 732 DPRINT("MmFreeMemoryArea(%p,%p)\n", 733 MmGetAddressSpaceOwner(AddressSpace), 734 MA_GetStartingAddress(MemoryArea)); 735 736 MmLockAddressSpace(AddressSpace); 737 738 MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context); 739 740 MmUnlockAddressSpace(AddressSpace); 741 742 MmUnlockSectionSegment(Segment); 743 744 DPRINTC("MiUnmapViewOfSegment %p %p %p\n", 745 MmGetAddressSpaceOwner(AddressSpace), 746 BaseAddress, 747 Segment); 748 749 return STATUS_SUCCESS; 750 } 751 752 NTSTATUS 753 NTAPI 754 MmExtendCacheSection(PROS_SECTION_OBJECT Section, 755 PLARGE_INTEGER NewSize, 756 BOOLEAN ExtendFile) 757 { 758 LARGE_INTEGER OldSize; 759 PMM_SECTION_SEGMENT Segment = Section->Segment; 760 DPRINT("Extend Segment %p\n", Segment); 761 762 MmLockSectionSegment(Segment); 763 OldSize.QuadPart = Segment->RawLength.QuadPart; 764 MmUnlockSectionSegment(Segment); 765 766 DPRINT("OldSize 0x%I64x NewSize 0x%I64x\n", 767 OldSize.QuadPart, 768 NewSize->QuadPart); 769 770 if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart) 771 { 772 NTSTATUS Status; 773 774 Status = IoSetInformation(Segment->FileObject, 775 FileEndOfFileInformation, 776 sizeof(LARGE_INTEGER), 777 NewSize); 778 779 if (!NT_SUCCESS(Status)) return Status; 780 } 781 782 MmLockSectionSegment(Segment); 783 Segment->RawLength.QuadPart = NewSize->QuadPart; 784 Segment->Length.QuadPart = MAX(Segment->Length.QuadPart, 785 (LONG64)PAGE_ROUND_UP(Segment->RawLength.QuadPart)); 786 MmUnlockSectionSegment(Segment); 787 return STATUS_SUCCESS; 788 } 789 790 NTSTATUS 791 NTAPI 792 MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment, 793 OUT PVOID *MappedBase, 794 PLARGE_INTEGER FileOffset, 795 IN OUT PULONG ViewSize) 796 { 797 PMMSUPPORT AddressSpace; 798 NTSTATUS Status; 799 800 DPRINT("MmMapViewInSystemSpaceAtOffset() called offset 0x%I64x\n", 801 FileOffset->QuadPart); 802 803 AddressSpace = MmGetKernelAddressSpace(); 804 805 MmLockAddressSpace(AddressSpace); 806 MmLockSectionSegment(Segment); 807 808 Status = MiMapViewOfSegment(AddressSpace, 809 Segment, 810 MappedBase, 811 *ViewSize, 812 PAGE_READWRITE, 813 FileOffset, 814 0); 815 816 MmUnlockSectionSegment(Segment); 817 MmUnlockAddressSpace(AddressSpace); 818 819 return Status; 820 } 821 822 /* 823 * @implemented 824 */ 825 NTSTATUS NTAPI 826 MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase) 827 { 828 PMMSUPPORT AddressSpace; 829 NTSTATUS Status; 830 831 DPRINT("MmUnmapViewInSystemSpace() called\n"); 832 833 AddressSpace = MmGetKernelAddressSpace(); 834 835 Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase); 836 837 return Status; 838 } 839 840 /* EOF */ 841