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 #ifdef NEWCC 116 /* 117 118 MiFlushMappedSection 119 120 Called from cache code to cause dirty pages of a section 121 to be written back. This doesn't affect the mapping. 122 123 BaseOffset is the base at which to start writing in file space. 124 FileSize is the length of the file as understood by the cache. 125 126 */ 127 NTSTATUS 128 NTAPI 129 _MiFlushMappedSection(PVOID BaseAddress, 130 PLARGE_INTEGER BaseOffset, 131 PLARGE_INTEGER FileSize, 132 BOOLEAN WriteData, 133 const char *File, 134 int Line) 135 { 136 NTSTATUS Status = STATUS_SUCCESS; 137 ULONG_PTR PageAddress; 138 PMMSUPPORT AddressSpace = MmGetKernelAddressSpace(); 139 PMEMORY_AREA MemoryArea; 140 PMM_SECTION_SEGMENT Segment; 141 ULONG_PTR BeginningAddress, EndingAddress; 142 LARGE_INTEGER ViewOffset; 143 LARGE_INTEGER FileOffset; 144 PFN_NUMBER Page; 145 PPFN_NUMBER Pages; 146 KIRQL OldIrql; 147 148 DPRINT("MiFlushMappedSection(%p,%I64x,%I64x,%u,%s:%d)\n", 149 BaseAddress, 150 BaseOffset->QuadPart, 151 FileSize ? FileSize->QuadPart : 0, 152 WriteData, 153 File, 154 Line); 155 156 MmLockAddressSpace(AddressSpace); 157 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress); 158 if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_CACHE || MemoryArea->DeleteInProgress) 159 { 160 MmUnlockAddressSpace(AddressSpace); 161 DPRINT("STATUS_NOT_MAPPED_DATA\n"); 162 return STATUS_NOT_MAPPED_DATA; 163 } 164 BeginningAddress = PAGE_ROUND_DOWN(MA_GetStartingAddress(MemoryArea)); 165 EndingAddress = PAGE_ROUND_UP(MA_GetEndingAddress(MemoryArea)); 166 Segment = MemoryArea->Data.SectionData.Segment; 167 ViewOffset.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart; 168 169 ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart); 170 171 MmLockSectionSegment(Segment); 172 173 Pages = ExAllocatePool(NonPagedPool, 174 sizeof(PFN_NUMBER) * ((EndingAddress - BeginningAddress) >> PAGE_SHIFT)); 175 176 if (!Pages) 177 { 178 ASSERT(FALSE); 179 } 180 181 //DPRINT("Getting pages in range %08x-%08x\n", BeginningAddress, EndingAddress); 182 183 for (PageAddress = BeginningAddress; 184 PageAddress < EndingAddress; 185 PageAddress += PAGE_SIZE) 186 { 187 ULONG_PTR Entry; 188 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress; 189 Entry = MmGetPageEntrySectionSegment(MemoryArea->Data.SectionData.Segment, 190 &FileOffset); 191 Page = PFN_FROM_SSE(Entry); 192 if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) && 193 (MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) && 194 FileOffset.QuadPart < FileSize->QuadPart) 195 { 196 OldIrql = MiAcquirePfnLock(); 197 MmReferencePage(Page); 198 MiReleasePfnLock(OldIrql); 199 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Entry; 200 } 201 else 202 { 203 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0; 204 } 205 } 206 207 MmUnlockSectionSegment(Segment); 208 MmUnlockAddressSpace(AddressSpace); 209 210 for (PageAddress = BeginningAddress; 211 PageAddress < EndingAddress; 212 PageAddress += PAGE_SIZE) 213 { 214 ULONG_PTR Entry; 215 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress; 216 Entry = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT]; 217 Page = PFN_FROM_SSE(Entry); 218 if (Page) 219 { 220 if (WriteData) { 221 //DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart); 222 Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page); 223 } else 224 Status = STATUS_SUCCESS; 225 226 if (NT_SUCCESS(Status)) { 227 MmLockAddressSpace(AddressSpace); 228 MmSetCleanAllRmaps(Page); 229 230 MmSetPageProtect(MmGetAddressSpaceOwner(AddressSpace), 231 (PVOID)PageAddress, 232 PAGE_READONLY); 233 234 MmLockSectionSegment(Segment); 235 Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset); 236 237 if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page) 238 MmSetPageEntrySectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry)); 239 240 MmUnlockSectionSegment(Segment); 241 MmUnlockAddressSpace(AddressSpace); 242 } else { 243 DPRINT("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n", 244 FileOffset.u.HighPart, 245 FileOffset.u.LowPart, 246 (ULONG)(FileSize->QuadPart - FileOffset.QuadPart), 247 PageAddress, 248 Page, 249 FileSize->u.HighPart, 250 FileSize->u.LowPart, 251 &Segment->FileObject->FileName, 252 Status); 253 } 254 MmReleasePageMemoryConsumer(MC_CACHE, Page); 255 } 256 } 257 258 ExFreePool(Pages); 259 260 return Status; 261 } 262 263 /* 264 265 This deletes a segment entirely including its page map. 266 It must have been unmapped in every address space. 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 ObDereferenceObject(FileObject); 344 return Status; 345 } 346 347 /* Initialize it */ 348 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT)); 349 Section->Type = 'SC'; 350 Section->Size = 'TN'; 351 Section->SectionPageProtection = SectionPageProtection; 352 Section->AllocationAttributes = AllocationAttributes; 353 Section->Segment = NULL; 354 355 Section->FileObject = FileObject; 356 357 DPRINT("Getting original file size\n"); 358 /* A hack: If we're cached, we can overcome deadlocking with the upper 359 * layer filesystem call by retriving the object sizes from the cache 360 * which is made to keep track. If I had to guess, they were figuring 361 * out a similar problem. 362 */ 363 if (!CcGetFileSizes(FileObject, &FileSizes)) 364 { 365 ULONG Information; 366 /* 367 * FIXME: This is propably not entirely correct. We can't look into 368 * the standard FCB header because it might not be initialized yet 369 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the 370 * standard file information is filled on first request). 371 */ 372 DPRINT("Querying info\n"); 373 Status = IoQueryFileInformation(FileObject, 374 FileStandardInformation, 375 sizeof(FILE_STANDARD_INFORMATION), 376 &FileInfo, 377 &Information); 378 Iosb.Information = Information; 379 DPRINT("Query => %x\n", Status); 380 DBG_UNREFERENCED_LOCAL_VARIABLE(Iosb); 381 382 if (!NT_SUCCESS(Status)) 383 { 384 DPRINT("Status %x\n", Status); 385 ObDereferenceObject(Section); 386 ObDereferenceObject(FileObject); 387 return Status; 388 } 389 ASSERT(Status != STATUS_PENDING); 390 391 FileSizes.ValidDataLength = FileInfo.EndOfFile; 392 FileSizes.FileSize = FileInfo.EndOfFile; 393 } 394 DPRINT("Got %I64x\n", FileSizes.ValidDataLength.QuadPart); 395 396 /* 397 * FIXME: Revise this once a locking order for file size changes is 398 * decided 399 * 400 * We're handed down a maximum size in every case. Should we still check at all? 401 */ 402 if (UMaximumSize != NULL && UMaximumSize->QuadPart) 403 { 404 DPRINT("Taking maximum %I64x\n", UMaximumSize->QuadPart); 405 MaximumSize.QuadPart = UMaximumSize->QuadPart; 406 } 407 else 408 { 409 DPRINT("Got file size %I64x\n", FileSizes.FileSize.QuadPart); 410 MaximumSize.QuadPart = FileSizes.FileSize.QuadPart; 411 } 412 413 /* Mapping zero-sized files isn't allowed. */ 414 if (MaximumSize.QuadPart == 0) 415 { 416 DPRINT("Zero size file\n"); 417 ObDereferenceObject(Section); 418 ObDereferenceObject(FileObject); 419 return STATUS_FILE_INVALID; 420 } 421 422 Segment = ExAllocatePoolWithTag(NonPagedPool, 423 sizeof(MM_SECTION_SEGMENT), 424 TAG_MM_SECTION_SEGMENT); 425 if (Segment == NULL) 426 { 427 DPRINT("Failed: STATUS_NO_MEMORY\n"); 428 ObDereferenceObject(Section); 429 ObDereferenceObject(FileObject); 430 return STATUS_NO_MEMORY; 431 } 432 433 DPRINT("Zeroing %p\n", Segment); 434 RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT)); 435 ExInitializeFastMutex(&Segment->Lock); 436 437 Segment->ReferenceCount = 1; 438 Segment->Locked = TRUE; 439 RtlZeroMemory(&Segment->Image, sizeof(Segment->Image)); 440 Section->Segment = Segment; 441 442 KeAcquireSpinLock(&FileObject->IrpListLock, &OldIrql); 443 /* 444 * If this file hasn't been mapped as a data file before then allocate a 445 * section segment to describe the data file mapping 446 */ 447 if (FileObject->SectionObjectPointer->DataSectionObject == NULL) 448 { 449 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment; 450 KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql); 451 452 /* 453 * Set the lock before assigning the segment to the file object 454 */ 455 ExAcquireFastMutex(&Segment->Lock); 456 457 DPRINT("Filling out Segment info (No previous data section)\n"); 458 ObReferenceObject(FileObject); 459 Segment->FileObject = FileObject; 460 Segment->Protection = SectionPageProtection; 461 Segment->Flags = MM_DATAFILE_SEGMENT; 462 memset(&Segment->Image, 0, sizeof(Segment->Image)); 463 Segment->WriteCopy = FALSE; 464 465 if (AllocationAttributes & SEC_RESERVE) 466 { 467 Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0; 468 } 469 else 470 { 471 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 472 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 473 } 474 MiInitializeSectionPageTable(Segment); 475 InsertHeadList(&MiSegmentList, &Segment->ListOfSegments); 476 } 477 else 478 { 479 KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql); 480 DPRINTC("Free Segment %p\n", Segment); 481 ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT); 482 483 DPRINT("Filling out Segment info (previous data section)\n"); 484 485 /* 486 * If the file is already mapped as a data file then we may need 487 * to extend it 488 */ 489 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->DataSectionObject; 490 Section->Segment = Segment; 491 (void)InterlockedIncrementUL(&Segment->ReferenceCount); 492 493 MmLockSectionSegment(Segment); 494 495 if (MaximumSize.QuadPart > Segment->RawLength.QuadPart && 496 !(AllocationAttributes & SEC_RESERVE)) 497 { 498 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 499 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 500 } 501 } 502 503 MmUnlockSectionSegment(Segment); 504 505 Section->MaximumSize.QuadPart = MaximumSize.QuadPart; 506 507 /* Extend file if section is longer */ 508 DPRINT("MaximumSize %I64x ValidDataLength %I64x\n", 509 MaximumSize.QuadPart, 510 FileSizes.ValidDataLength.QuadPart); 511 if (MaximumSize.QuadPart > FileSizes.ValidDataLength.QuadPart) 512 { 513 DPRINT("Changing file size to %I64x, segment %p\n", 514 MaximumSize.QuadPart, 515 Segment); 516 517 Status = IoSetInformation(FileObject, 518 FileEndOfFileInformation, 519 sizeof(LARGE_INTEGER), 520 &MaximumSize); 521 522 DPRINT("Change: Status %x\n", Status); 523 if (!NT_SUCCESS(Status)) 524 { 525 DPRINT("Could not expand section\n"); 526 ObDereferenceObject(Section); 527 return Status; 528 } 529 } 530 531 DPRINTC("Segment %p created (%x)\n", Segment, Segment->Flags); 532 533 *SectionObject = Section; 534 return STATUS_SUCCESS; 535 } 536 537 NTSTATUS 538 NTAPI 539 _MiMapViewOfSegment(PMMSUPPORT AddressSpace, 540 PMM_SECTION_SEGMENT Segment, 541 PVOID* BaseAddress, 542 SIZE_T ViewSize, 543 ULONG Protect, 544 PLARGE_INTEGER ViewOffset, 545 ULONG AllocationType, 546 const char *file, 547 int line) 548 { 549 PMEMORY_AREA MArea; 550 NTSTATUS Status; 551 552 Status = MmCreateMemoryArea(AddressSpace, 553 MEMORY_AREA_CACHE, 554 BaseAddress, 555 ViewSize, 556 Protect, 557 &MArea, 558 AllocationType, 559 *BaseAddress ? 560 PAGE_SIZE : MM_ALLOCATION_GRANULARITY); 561 562 if (!NT_SUCCESS(Status)) 563 { 564 DPRINT("Mapping between 0x%p and 0x%p failed (%X).\n", 565 (*BaseAddress), 566 (char*)(*BaseAddress) + ViewSize, 567 Status); 568 569 return Status; 570 } 571 572 DPRINTC("MiMapViewOfSegment %p %p %p %I64x %Ix %wZ %s:%d\n", 573 MmGetAddressSpaceOwner(AddressSpace), 574 *BaseAddress, 575 Segment, 576 ViewOffset ? ViewOffset->QuadPart : 0, 577 ViewSize, 578 Segment->FileObject ? &Segment->FileObject->FileName : NULL, 579 file, 580 line); 581 582 MArea->Data.SectionData.Segment = Segment; 583 if (ViewOffset) 584 MArea->Data.SectionData.ViewOffset = *ViewOffset; 585 else 586 MArea->Data.SectionData.ViewOffset.QuadPart = 0; 587 588 #if 0 589 MArea->NotPresent = MmNotPresentFaultPageFile; 590 MArea->AccessFault = MiCowSectionPage; 591 MArea->PageOut = MmPageOutPageFileView; 592 #endif 593 594 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead, 595 ViewSize, 596 0, 597 Protect); 598 599 DPRINTC("MiMapViewOfSegment(P %p, A %p, T %x)\n", 600 MmGetAddressSpaceOwner(AddressSpace), 601 *BaseAddress, 602 MArea->Type); 603 604 return STATUS_SUCCESS; 605 } 606 #endif 607 608 /* 609 610 Completely remove the page at FileOffset in Segment. The page must not 611 be mapped. 612 613 */ 614 615 VOID 616 NTAPI 617 MiFreeSegmentPage(PMM_SECTION_SEGMENT Segment, 618 PLARGE_INTEGER FileOffset) 619 { 620 ULONG_PTR Entry; 621 PFILE_OBJECT FileObject = Segment->FileObject; 622 623 Entry = MmGetPageEntrySectionSegment(Segment, FileOffset); 624 DPRINTC("MiFreeSegmentPage(%p:%I64x -> Entry %Ix\n", 625 Segment, 626 FileOffset->QuadPart, 627 Entry); 628 629 if (Entry && !IS_SWAP_FROM_SSE(Entry)) 630 { 631 // The segment is carrying a dirty page. 632 PFN_NUMBER OldPage = PFN_FROM_SSE(Entry); 633 if (IS_DIRTY_SSE(Entry) && FileObject) 634 { 635 DPRINT("MiWriteBackPage(%p,%wZ,%I64x)\n", 636 Segment, 637 &FileObject->FileName, 638 FileOffset->QuadPart); 639 640 MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage); 641 } 642 DPRINTC("Free page %Ix (off %I64x from %p) (ref ct %lu, ent %Ix, dirty? %s)\n", 643 OldPage, 644 FileOffset->QuadPart, 645 Segment, 646 MmGetReferenceCountPage(OldPage), 647 Entry, 648 IS_DIRTY_SSE(Entry) ? "true" : "false"); 649 650 MmSetPageEntrySectionSegment(Segment, FileOffset, 0); 651 MmReleasePageMemoryConsumer(MC_CACHE, OldPage); 652 } 653 else if (IS_SWAP_FROM_SSE(Entry)) 654 { 655 DPRINT("Free swap\n"); 656 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry)); 657 } 658 659 DPRINT("Done\n"); 660 } 661 662 VOID 663 MmFreeCacheSectionPage(PVOID Context, 664 MEMORY_AREA* MemoryArea, 665 PVOID Address, 666 PFN_NUMBER Page, 667 SWAPENTRY SwapEntry, 668 BOOLEAN Dirty) 669 { 670 ULONG_PTR Entry; 671 PVOID *ContextData = Context; 672 PMMSUPPORT AddressSpace; 673 PEPROCESS Process; 674 PMM_SECTION_SEGMENT Segment; 675 LARGE_INTEGER Offset; 676 677 DPRINT("MmFreeSectionPage(%p,%p,%Ix,%Ix,%u)\n", 678 MmGetAddressSpaceOwner(ContextData[0]), 679 Address, 680 Page, 681 SwapEntry, 682 Dirty); 683 684 AddressSpace = ContextData[0]; 685 Process = MmGetAddressSpaceOwner(AddressSpace); 686 Address = (PVOID)PAGE_ROUND_DOWN(Address); 687 Segment = ContextData[1]; 688 Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea) + 689 MemoryArea->Data.SectionData.ViewOffset.QuadPart; 690 691 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 692 693 if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty) 694 { 695 DPRINT("Freeing section page %p:%I64x -> %Ix\n", Segment, Offset.QuadPart, Entry); 696 MmSetPageEntrySectionSegment(Segment, &Offset, DIRTY_SSE(Entry)); 697 } 698 if (Page) 699 { 700 DPRINT("Removing page %p:%I64x -> %x\n", Segment, Offset.QuadPart, Entry); 701 MmSetSavedSwapEntryPage(Page, 0); 702 MmDeleteRmap(Page, Process, Address); 703 MmDeleteVirtualMapping(Process, Address, NULL, NULL); 704 MmReleasePageMemoryConsumer(MC_CACHE, Page); 705 } 706 if (SwapEntry != 0) 707 { 708 MmFreeSwapPage(SwapEntry); 709 } 710 } 711 712 #ifdef NEWCC 713 NTSTATUS 714 NTAPI 715 MmUnmapViewOfCacheSegment(PMMSUPPORT AddressSpace, 716 PVOID BaseAddress) 717 { 718 PVOID Context[2]; 719 PMEMORY_AREA MemoryArea; 720 PMM_SECTION_SEGMENT Segment; 721 722 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress); 723 if (MemoryArea == NULL || MemoryArea->DeleteInProgress) 724 { 725 ASSERT(MemoryArea); 726 return STATUS_UNSUCCESSFUL; 727 } 728 729 MemoryArea->DeleteInProgress = TRUE; 730 Segment = MemoryArea->Data.SectionData.Segment; 731 MemoryArea->Data.SectionData.Segment = NULL; 732 733 MmLockSectionSegment(Segment); 734 735 Context[0] = AddressSpace; 736 Context[1] = Segment; 737 738 DPRINT("MmFreeMemoryArea(%p,%p)\n", 739 MmGetAddressSpaceOwner(AddressSpace), 740 MA_GetStartingAddress(MemoryArea)); 741 742 MmLockAddressSpace(AddressSpace); 743 744 MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context); 745 746 MmUnlockAddressSpace(AddressSpace); 747 748 MmUnlockSectionSegment(Segment); 749 750 DPRINTC("MiUnmapViewOfSegment %p %p %p\n", 751 MmGetAddressSpaceOwner(AddressSpace), 752 BaseAddress, 753 Segment); 754 755 return STATUS_SUCCESS; 756 } 757 758 NTSTATUS 759 NTAPI 760 MmExtendCacheSection(PROS_SECTION_OBJECT Section, 761 PLARGE_INTEGER NewSize, 762 BOOLEAN ExtendFile) 763 { 764 LARGE_INTEGER OldSize; 765 PMM_SECTION_SEGMENT Segment = Section->Segment; 766 DPRINT("Extend Segment %p\n", Segment); 767 768 MmLockSectionSegment(Segment); 769 OldSize.QuadPart = Segment->RawLength.QuadPart; 770 MmUnlockSectionSegment(Segment); 771 772 DPRINT("OldSize 0x%I64x NewSize 0x%I64x\n", 773 OldSize.QuadPart, 774 NewSize->QuadPart); 775 776 if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart) 777 { 778 NTSTATUS Status; 779 780 Status = IoSetInformation(Segment->FileObject, 781 FileEndOfFileInformation, 782 sizeof(LARGE_INTEGER), 783 NewSize); 784 785 if (!NT_SUCCESS(Status)) return Status; 786 } 787 788 MmLockSectionSegment(Segment); 789 Segment->RawLength.QuadPart = NewSize->QuadPart; 790 Segment->Length.QuadPart = MAX(Segment->Length.QuadPart, 791 (LONG64)PAGE_ROUND_UP(Segment->RawLength.QuadPart)); 792 MmUnlockSectionSegment(Segment); 793 return STATUS_SUCCESS; 794 } 795 796 NTSTATUS 797 NTAPI 798 MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment, 799 OUT PVOID *MappedBase, 800 PLARGE_INTEGER FileOffset, 801 IN OUT PULONG ViewSize) 802 { 803 PMMSUPPORT AddressSpace; 804 NTSTATUS Status; 805 806 DPRINT("MmMapViewInSystemSpaceAtOffset() called offset 0x%I64x\n", 807 FileOffset->QuadPart); 808 809 AddressSpace = MmGetKernelAddressSpace(); 810 811 MmLockAddressSpace(AddressSpace); 812 MmLockSectionSegment(Segment); 813 814 Status = MiMapViewOfSegment(AddressSpace, 815 Segment, 816 MappedBase, 817 *ViewSize, 818 PAGE_READWRITE, 819 FileOffset, 820 0); 821 822 MmUnlockSectionSegment(Segment); 823 MmUnlockAddressSpace(AddressSpace); 824 825 return Status; 826 } 827 828 /* 829 * @implemented 830 */ 831 NTSTATUS NTAPI 832 MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase) 833 { 834 PMMSUPPORT AddressSpace; 835 NTSTATUS Status; 836 837 DPRINT("MmUnmapViewInSystemSpace() called\n"); 838 839 AddressSpace = MmGetKernelAddressSpace(); 840 841 Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase); 842 843 return Status; 844 } 845 #endif /* NEWCC */ 846 847 /* EOF */ 848