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 = MiAcquirePfnLock(); 196 MmReferencePage(Page); 197 MiReleasePfnLock(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 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 607 /* 608 609 Completely remove the page at FileOffset in Segment. The page must not 610 be mapped. 611 612 */ 613 614 VOID 615 NTAPI 616 MiFreeSegmentPage(PMM_SECTION_SEGMENT Segment, 617 PLARGE_INTEGER FileOffset) 618 { 619 ULONG_PTR Entry; 620 PFILE_OBJECT FileObject = Segment->FileObject; 621 622 Entry = MmGetPageEntrySectionSegment(Segment, FileOffset); 623 DPRINTC("MiFreeSegmentPage(%p:%I64x -> Entry %Ix\n", 624 Segment, 625 FileOffset->QuadPart, 626 Entry); 627 628 if (Entry && !IS_SWAP_FROM_SSE(Entry)) 629 { 630 // The segment is carrying a dirty page. 631 PFN_NUMBER OldPage = PFN_FROM_SSE(Entry); 632 if (IS_DIRTY_SSE(Entry) && FileObject) 633 { 634 DPRINT("MiWriteBackPage(%p,%wZ,%I64x)\n", 635 Segment, 636 &FileObject->FileName, 637 FileOffset->QuadPart); 638 639 MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage); 640 } 641 DPRINTC("Free page %Ix (off %I64x from %p) (ref ct %lu, ent %Ix, dirty? %s)\n", 642 OldPage, 643 FileOffset->QuadPart, 644 Segment, 645 MmGetReferenceCountPage(OldPage), 646 Entry, 647 IS_DIRTY_SSE(Entry) ? "true" : "false"); 648 649 MmSetPageEntrySectionSegment(Segment, FileOffset, 0); 650 MmReleasePageMemoryConsumer(MC_CACHE, OldPage); 651 } 652 else if (IS_SWAP_FROM_SSE(Entry)) 653 { 654 DPRINT("Free swap\n"); 655 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry)); 656 } 657 658 DPRINT("Done\n"); 659 } 660 661 VOID 662 MmFreeCacheSectionPage(PVOID Context, 663 MEMORY_AREA* MemoryArea, 664 PVOID Address, 665 PFN_NUMBER Page, 666 SWAPENTRY SwapEntry, 667 BOOLEAN Dirty) 668 { 669 ULONG_PTR Entry; 670 PVOID *ContextData = Context; 671 PMMSUPPORT AddressSpace; 672 PEPROCESS Process; 673 PMM_SECTION_SEGMENT Segment; 674 LARGE_INTEGER Offset; 675 676 DPRINT("MmFreeSectionPage(%p,%p,%Ix,%Ix,%u)\n", 677 MmGetAddressSpaceOwner(ContextData[0]), 678 Address, 679 Page, 680 SwapEntry, 681 Dirty); 682 683 AddressSpace = ContextData[0]; 684 Process = MmGetAddressSpaceOwner(AddressSpace); 685 Address = (PVOID)PAGE_ROUND_DOWN(Address); 686 Segment = ContextData[1]; 687 Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea) + 688 MemoryArea->Data.SectionData.ViewOffset.QuadPart; 689 690 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 691 692 if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty) 693 { 694 DPRINT("Freeing section page %p:%I64x -> %Ix\n", Segment, Offset.QuadPart, Entry); 695 MmSetPageEntrySectionSegment(Segment, &Offset, DIRTY_SSE(Entry)); 696 } 697 if (Page) 698 { 699 DPRINT("Removing page %p:%I64x -> %x\n", Segment, Offset.QuadPart, Entry); 700 MmSetSavedSwapEntryPage(Page, 0); 701 MmDeleteRmap(Page, Process, Address); 702 MmDeleteVirtualMapping(Process, Address, NULL, NULL); 703 MmReleasePageMemoryConsumer(MC_CACHE, Page); 704 } 705 if (SwapEntry != 0) 706 { 707 MmFreeSwapPage(SwapEntry); 708 } 709 } 710 711 NTSTATUS 712 NTAPI 713 MmUnmapViewOfCacheSegment(PMMSUPPORT AddressSpace, 714 PVOID BaseAddress) 715 { 716 PVOID Context[2]; 717 PMEMORY_AREA MemoryArea; 718 PMM_SECTION_SEGMENT Segment; 719 720 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress); 721 if (MemoryArea == NULL || MemoryArea->DeleteInProgress) 722 { 723 ASSERT(MemoryArea); 724 return STATUS_UNSUCCESSFUL; 725 } 726 727 MemoryArea->DeleteInProgress = TRUE; 728 Segment = MemoryArea->Data.SectionData.Segment; 729 MemoryArea->Data.SectionData.Segment = NULL; 730 731 MmLockSectionSegment(Segment); 732 733 Context[0] = AddressSpace; 734 Context[1] = Segment; 735 736 DPRINT("MmFreeMemoryArea(%p,%p)\n", 737 MmGetAddressSpaceOwner(AddressSpace), 738 MA_GetStartingAddress(MemoryArea)); 739 740 MmLockAddressSpace(AddressSpace); 741 742 MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context); 743 744 MmUnlockAddressSpace(AddressSpace); 745 746 MmUnlockSectionSegment(Segment); 747 748 DPRINTC("MiUnmapViewOfSegment %p %p %p\n", 749 MmGetAddressSpaceOwner(AddressSpace), 750 BaseAddress, 751 Segment); 752 753 return STATUS_SUCCESS; 754 } 755 756 NTSTATUS 757 NTAPI 758 MmExtendCacheSection(PROS_SECTION_OBJECT Section, 759 PLARGE_INTEGER NewSize, 760 BOOLEAN ExtendFile) 761 { 762 LARGE_INTEGER OldSize; 763 PMM_SECTION_SEGMENT Segment = Section->Segment; 764 DPRINT("Extend Segment %p\n", Segment); 765 766 MmLockSectionSegment(Segment); 767 OldSize.QuadPart = Segment->RawLength.QuadPart; 768 MmUnlockSectionSegment(Segment); 769 770 DPRINT("OldSize 0x%I64x NewSize 0x%I64x\n", 771 OldSize.QuadPart, 772 NewSize->QuadPart); 773 774 if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart) 775 { 776 NTSTATUS Status; 777 778 Status = IoSetInformation(Segment->FileObject, 779 FileEndOfFileInformation, 780 sizeof(LARGE_INTEGER), 781 NewSize); 782 783 if (!NT_SUCCESS(Status)) return Status; 784 } 785 786 MmLockSectionSegment(Segment); 787 Segment->RawLength.QuadPart = NewSize->QuadPart; 788 Segment->Length.QuadPart = MAX(Segment->Length.QuadPart, 789 (LONG64)PAGE_ROUND_UP(Segment->RawLength.QuadPart)); 790 MmUnlockSectionSegment(Segment); 791 return STATUS_SUCCESS; 792 } 793 794 NTSTATUS 795 NTAPI 796 MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment, 797 OUT PVOID *MappedBase, 798 PLARGE_INTEGER FileOffset, 799 IN OUT PULONG ViewSize) 800 { 801 PMMSUPPORT AddressSpace; 802 NTSTATUS Status; 803 804 DPRINT("MmMapViewInSystemSpaceAtOffset() called offset 0x%I64x\n", 805 FileOffset->QuadPart); 806 807 AddressSpace = MmGetKernelAddressSpace(); 808 809 MmLockAddressSpace(AddressSpace); 810 MmLockSectionSegment(Segment); 811 812 Status = MiMapViewOfSegment(AddressSpace, 813 Segment, 814 MappedBase, 815 *ViewSize, 816 PAGE_READWRITE, 817 FileOffset, 818 0); 819 820 MmUnlockSectionSegment(Segment); 821 MmUnlockAddressSpace(AddressSpace); 822 823 return Status; 824 } 825 826 /* 827 * @implemented 828 */ 829 NTSTATUS NTAPI 830 MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase) 831 { 832 PMMSUPPORT AddressSpace; 833 NTSTATUS Status; 834 835 DPRINT("MmUnmapViewInSystemSpace() called\n"); 836 837 AddressSpace = MmGetKernelAddressSpace(); 838 839 Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase); 840 841 return Status; 842 } 843 844 /* EOF */ 845