Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendata.c
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section) 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * 00019 * PROJECT: ReactOS kernel 00020 * FILE: ntoskrnl/mm/section.c 00021 * PURPOSE: Implements section objects 00022 * 00023 * PROGRAMMERS: Rex Jolliff 00024 * David Welch 00025 * Eric Kohl 00026 * Emanuele Aliberti 00027 * Eugene Ingerman 00028 * Casper Hornstrup 00029 * KJK::Hyperion 00030 * Guido de Jong 00031 * Ge van Geldorp 00032 * Royce Mitchell III 00033 * Filip Navara 00034 * Aleksey Bragin 00035 * Jason Filby 00036 * Thomas Weidenmueller 00037 * Gunnar Andre' Dalsnes 00038 * Mike Nordell 00039 * Alex Ionescu 00040 * Gregor Anich 00041 * Steven Edwards 00042 * Herve Poussineau 00043 */ 00044 00045 /* 00046 00047 A note on this code: 00048 00049 Unlike the previous section code, this code does not rely on an active map 00050 for a page to exist in a data segment. Each mapping contains a large integer 00051 offset to map at, and the segment always represents the entire section space 00052 from zero to the maximum long long. This allows us to associate one single 00053 page map with each file object, and to let each mapping view an offset into 00054 the overall mapped file. Temporarily unmapping the file has no effect on the 00055 section membership. 00056 00057 This necessitates a change in the section page table implementation, which is 00058 now an RtlGenericTable. This will be elaborated more in sptab.c. One upshot 00059 of this change is that a mapping of a small files takes a bit more than 1/4 00060 of the size in nonpaged kernel space as it did previously. 00061 00062 When we need other threads that may be competing for the same page fault to 00063 wait, we have a mechanism seperate from PageOps for dealing with that, which 00064 was suggested by Travis Geiselbrecht after a conversation I had with Alex 00065 Ionescu. That mechanism is the MM_WAIT_ENTRY, which is the all-ones SWAPENTRY. 00066 00067 When we wish for other threads to know that we're waiting and will finish 00068 handling a page fault, we place the swap entry MM_WAIT_ENTRY in the page table 00069 at the fault address (this works on either the section page table or a process 00070 address space), perform any blocking operations required, then replace the 00071 entry. 00072 00073 */ 00074 00075 /* INCLUDES *****************************************************************/ 00076 00077 #include <ntoskrnl.h> 00078 #include "newmm.h" 00079 #include "../newcc.h" 00080 #define NDEBUG 00081 #include <debug.h> 00082 #include "../mm/ARM3/miarm.h" 00083 00084 #define DPRINTC DPRINT 00085 00086 LIST_ENTRY MiSegmentList; 00087 00088 extern KEVENT MpwThreadEvent; 00089 extern KSPIN_LOCK MiSectionPageTableLock; 00090 extern PMMWSL MmWorkingSetList; 00091 00092 /* GLOBALS *******************************************************************/ 00093 00094 ULONG_PTR MmSubsectionBase; 00095 00096 static const INFORMATION_CLASS_INFO ExSectionInfoClass[] = 00097 { 00098 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */ 00099 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */ 00100 }; 00101 00102 /* FUNCTIONS *****************************************************************/ 00103 00104 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */ 00105 00106 VOID 00107 NTAPI 00108 _MmLockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line) 00109 { 00110 //DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line); 00111 ExAcquireFastMutex(&Segment->Lock); 00112 Segment->Locked = TRUE; 00113 } 00114 00115 VOID 00116 NTAPI 00117 _MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line) 00118 { 00119 ASSERT(Segment->Locked); 00120 Segment->Locked = FALSE; 00121 ExReleaseFastMutex(&Segment->Lock); 00122 //DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line); 00123 } 00124 00125 NTSTATUS 00126 NTAPI 00127 MiZeroFillSection(PVOID Address, PLARGE_INTEGER FileOffsetPtr, ULONG Length) 00128 { 00129 PFN_NUMBER Page; 00130 PMMSUPPORT AddressSpace; 00131 PMEMORY_AREA MemoryArea; 00132 PMM_SECTION_SEGMENT Segment; 00133 LARGE_INTEGER FileOffset = *FileOffsetPtr, End, FirstMapped; 00134 KIRQL OldIrql; 00135 00136 DPRINT("MiZeroFillSection(Address %x,Offset %x,Length %x)\n", 00137 Address, 00138 FileOffset.LowPart, 00139 Length); 00140 00141 AddressSpace = MmGetKernelAddressSpace(); 00142 00143 MmLockAddressSpace(AddressSpace); 00144 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address); 00145 MmUnlockAddressSpace(AddressSpace); 00146 if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW || MemoryArea->DeleteInProgress) 00147 { 00148 return STATUS_NOT_MAPPED_DATA; 00149 } 00150 00151 Segment = MemoryArea->Data.SectionData.Segment; 00152 End.QuadPart = FileOffset.QuadPart + Length; 00153 End.LowPart = PAGE_ROUND_DOWN(End.LowPart); 00154 FileOffset.LowPart = PAGE_ROUND_UP(FileOffset.LowPart); 00155 FirstMapped.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart; 00156 DPRINT("Pulling zero pages for %08x%08x-%08x%08x\n", 00157 FileOffset.u.HighPart, FileOffset.u.LowPart, 00158 End.u.HighPart, End.u.LowPart); 00159 while (FileOffset.QuadPart < End.QuadPart) 00160 { 00161 PVOID Address; 00162 ULONG_PTR Entry; 00163 00164 if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page))) 00165 break; 00166 00167 MmLockAddressSpace(AddressSpace); 00168 MmLockSectionSegment(Segment); 00169 00170 Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset); 00171 if (Entry == 0) 00172 { 00173 MmSetPageEntrySectionSegment(Segment, &FileOffset, MAKE_PFN_SSE(Page)); 00174 Address = ((PCHAR)MemoryArea->StartingAddress) + FileOffset.QuadPart - FirstMapped.QuadPart; 00175 00176 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00177 MmReferencePage(Page); 00178 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00179 00180 MmCreateVirtualMapping(NULL, Address, PAGE_READWRITE, &Page, 1); 00181 MmInsertRmap(Page, NULL, Address); 00182 } 00183 else 00184 { 00185 MmReleasePageMemoryConsumer(MC_CACHE, Page); 00186 } 00187 00188 MmUnlockSectionSegment(Segment); 00189 MmUnlockAddressSpace(AddressSpace); 00190 00191 FileOffset.QuadPart += PAGE_SIZE; 00192 } 00193 return STATUS_SUCCESS; 00194 } 00195 00196 /* 00197 00198 MiFlushMappedSection 00199 00200 Called from cache code to cause dirty pages of a section 00201 to be written back. This doesn't affect the mapping. 00202 00203 BaseOffset is the base at which to start writing in file space. 00204 FileSize is the length of the file as understood by the cache. 00205 00206 */ 00207 NTSTATUS 00208 NTAPI 00209 _MiFlushMappedSection(PVOID BaseAddress, 00210 PLARGE_INTEGER BaseOffset, 00211 PLARGE_INTEGER FileSize, 00212 BOOLEAN WriteData, 00213 const char *File, 00214 int Line) 00215 { 00216 NTSTATUS Status = STATUS_SUCCESS; 00217 ULONG_PTR PageAddress; 00218 PMMSUPPORT AddressSpace = MmGetKernelAddressSpace(); 00219 PMEMORY_AREA MemoryArea; 00220 PMM_SECTION_SEGMENT Segment; 00221 ULONG_PTR BeginningAddress, EndingAddress; 00222 LARGE_INTEGER ViewOffset; 00223 LARGE_INTEGER FileOffset; 00224 PFN_NUMBER Page; 00225 PPFN_NUMBER Pages; 00226 KIRQL OldIrql; 00227 00228 DPRINT("MiFlushMappedSection(%x,%08x,%x,%d,%s:%d)\n", 00229 BaseAddress, 00230 BaseOffset->LowPart, 00231 FileSize, 00232 WriteData, 00233 File, 00234 Line); 00235 00236 MmLockAddressSpace(AddressSpace); 00237 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress); 00238 if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_CACHE || MemoryArea->DeleteInProgress) 00239 { 00240 MmUnlockAddressSpace(AddressSpace); 00241 DPRINT("STATUS_NOT_MAPPED_DATA\n"); 00242 return STATUS_NOT_MAPPED_DATA; 00243 } 00244 BeginningAddress = PAGE_ROUND_DOWN((ULONG_PTR)MemoryArea->StartingAddress); 00245 EndingAddress = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress); 00246 Segment = MemoryArea->Data.SectionData.Segment; 00247 ViewOffset.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart; 00248 00249 ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart); 00250 00251 MmLockSectionSegment(Segment); 00252 00253 Pages = ExAllocatePool(NonPagedPool, 00254 sizeof(PFN_NUMBER) * ((EndingAddress - BeginningAddress) >> PAGE_SHIFT)); 00255 00256 if (!Pages) 00257 { 00258 ASSERT(FALSE); 00259 } 00260 00261 //DPRINT("Getting pages in range %08x-%08x\n", BeginningAddress, EndingAddress); 00262 00263 for (PageAddress = BeginningAddress; 00264 PageAddress < EndingAddress; 00265 PageAddress += PAGE_SIZE) 00266 { 00267 ULONG_PTR Entry; 00268 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress; 00269 Entry = MmGetPageEntrySectionSegment(MemoryArea->Data.SectionData.Segment, 00270 &FileOffset); 00271 Page = PFN_FROM_SSE(Entry); 00272 if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) && 00273 (MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) && 00274 FileOffset.QuadPart < FileSize->QuadPart) 00275 { 00276 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00277 MmReferencePage(Page); 00278 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00279 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Entry; 00280 } 00281 else 00282 { 00283 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0; 00284 } 00285 } 00286 00287 MmUnlockSectionSegment(Segment); 00288 MmUnlockAddressSpace(AddressSpace); 00289 00290 for (PageAddress = BeginningAddress; 00291 PageAddress < EndingAddress; 00292 PageAddress += PAGE_SIZE) 00293 { 00294 ULONG_PTR Entry; 00295 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress; 00296 Entry = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT]; 00297 Page = PFN_FROM_SSE(Entry); 00298 if (Page) 00299 { 00300 if (WriteData) { 00301 //DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart); 00302 Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page); 00303 } else 00304 Status = STATUS_SUCCESS; 00305 00306 if (NT_SUCCESS(Status)) { 00307 MmLockAddressSpace(AddressSpace); 00308 MmSetCleanAllRmaps(Page); 00309 00310 MmSetPageProtect(MmGetAddressSpaceOwner(AddressSpace), 00311 (PVOID)PageAddress, 00312 PAGE_READONLY); 00313 00314 MmLockSectionSegment(Segment); 00315 Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset); 00316 00317 if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page) 00318 MmSetPageEntrySectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry)); 00319 00320 MmUnlockSectionSegment(Segment); 00321 MmUnlockAddressSpace(AddressSpace); 00322 } else { 00323 DPRINT("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n", 00324 FileOffset.u.HighPart, 00325 FileOffset.u.LowPart, 00326 (ULONG)(FileSize->QuadPart - FileOffset.QuadPart), 00327 PageAddress, 00328 Page, 00329 FileSize->u.HighPart, 00330 FileSize->u.LowPart, 00331 &Segment->FileObject->FileName, 00332 Status); 00333 } 00334 MmReleasePageMemoryConsumer(MC_CACHE, Page); 00335 } 00336 } 00337 00338 ExFreePool(Pages); 00339 00340 return Status; 00341 } 00342 00343 /* 00344 00345 This deletes a segment entirely including its page map. 00346 It must have been unmapped in every address space. 00347 00348 */ 00349 00350 VOID 00351 NTAPI 00352 MmFinalizeSegment(PMM_SECTION_SEGMENT Segment) 00353 { 00354 KIRQL OldIrql = 0; 00355 00356 DPRINT("Finalize segment %p\n", Segment); 00357 00358 MmLockSectionSegment(Segment); 00359 RemoveEntryList(&Segment->ListOfSegments); 00360 if (Segment->Flags & MM_DATAFILE_SEGMENT) { 00361 KeAcquireSpinLock(&Segment->FileObject->IrpListLock, &OldIrql); 00362 if (Segment->Flags & MM_SEGMENT_FINALIZE) { 00363 KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql); 00364 MmUnlockSectionSegment(Segment); 00365 return; 00366 } 00367 Segment->Flags |= MM_SEGMENT_FINALIZE; 00368 DPRINTC("Finalizing data file segment %p\n", Segment); 00369 00370 Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL; 00371 KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql); 00372 MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage); 00373 MmUnlockSectionSegment(Segment); 00374 DPRINT("Dereference file object %wZ\n", &Segment->FileObject->FileName); 00375 ObDereferenceObject(Segment->FileObject); 00376 DPRINT("Done with %wZ\n", &Segment->FileObject->FileName); 00377 Segment->FileObject = NULL; 00378 } else { 00379 DPRINTC("Finalizing segment %p\n", Segment); 00380 MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage); 00381 MmUnlockSectionSegment(Segment); 00382 } 00383 DPRINTC("Segment %p destroy\n", Segment); 00384 ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT); 00385 } 00386 00387 NTSTATUS 00388 NTAPI 00389 MmCreateCacheSection(PROS_SECTION_OBJECT *SectionObject, 00390 ACCESS_MASK DesiredAccess, 00391 POBJECT_ATTRIBUTES ObjectAttributes, 00392 PLARGE_INTEGER UMaximumSize, 00393 ULONG SectionPageProtection, 00394 ULONG AllocationAttributes, 00395 PFILE_OBJECT FileObject) 00396 /* 00397 * Create a section backed by a data file. 00398 */ 00399 { 00400 PROS_SECTION_OBJECT Section; 00401 NTSTATUS Status; 00402 LARGE_INTEGER MaximumSize; 00403 PMM_SECTION_SEGMENT Segment; 00404 IO_STATUS_BLOCK Iosb; 00405 CC_FILE_SIZES FileSizes; 00406 FILE_STANDARD_INFORMATION FileInfo; 00407 KIRQL OldIrql; 00408 00409 DPRINT("MmCreateDataFileSection\n"); 00410 00411 /* Create the section */ 00412 Status = ObCreateObject(ExGetPreviousMode(), 00413 MmSectionObjectType, 00414 ObjectAttributes, 00415 ExGetPreviousMode(), 00416 NULL, 00417 sizeof(ROS_SECTION_OBJECT), 00418 0, 00419 0, 00420 (PVOID*)(PVOID)&Section); 00421 if (!NT_SUCCESS(Status)) 00422 { 00423 DPRINT("Failed: %x\n", Status); 00424 return Status; 00425 } 00426 00427 /* Initialize it */ 00428 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT)); 00429 Section->Type = 'SC'; 00430 Section->Size = 'TN'; 00431 Section->SectionPageProtection = SectionPageProtection; 00432 Section->AllocationAttributes = AllocationAttributes; 00433 Section->Segment = NULL; 00434 00435 Section->FileObject = FileObject; 00436 00437 DPRINT("Getting original file size\n"); 00438 /* A hack: If we're cached, we can overcome deadlocking with the upper 00439 * layer filesystem call by retriving the object sizes from the cache 00440 * which is made to keep track. If I had to guess, they were figuring 00441 * out a similar problem. 00442 */ 00443 if (!CcGetFileSizes(FileObject, &FileSizes)) 00444 { 00445 ULONG Information; 00446 /* 00447 * FIXME: This is propably not entirely correct. We can't look into 00448 * the standard FCB header because it might not be initialized yet 00449 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the 00450 * standard file information is filled on first request). 00451 */ 00452 DPRINT("Querying info\n"); 00453 Status = IoQueryFileInformation(FileObject, 00454 FileStandardInformation, 00455 sizeof(FILE_STANDARD_INFORMATION), 00456 &FileInfo, 00457 &Information); 00458 Iosb.Information = Information; 00459 DPRINT("Query => %x\n", Status); 00460 00461 if (!NT_SUCCESS(Status)) 00462 { 00463 DPRINT("Status %x\n", Status); 00464 ObDereferenceObject(Section); 00465 return Status; 00466 } 00467 ASSERT(Status != STATUS_PENDING); 00468 00469 FileSizes.ValidDataLength = FileInfo.EndOfFile; 00470 FileSizes.FileSize = FileInfo.EndOfFile; 00471 } 00472 DPRINT("Got %08x\n", FileSizes.ValidDataLength.u.LowPart); 00473 00474 /* 00475 * FIXME: Revise this once a locking order for file size changes is 00476 * decided 00477 * 00478 * We're handed down a maximum size in every case. Should we still check at all? 00479 */ 00480 if (UMaximumSize != NULL && UMaximumSize->QuadPart) 00481 { 00482 DPRINT("Taking maximum %x\n", UMaximumSize->LowPart); 00483 MaximumSize.QuadPart = UMaximumSize->QuadPart; 00484 } 00485 else 00486 { 00487 DPRINT("Got file size %08x%08x\n", 00488 FileSizes.FileSize.u.HighPart, 00489 FileSizes.FileSize.u.LowPart); 00490 00491 MaximumSize.QuadPart = FileSizes.FileSize.QuadPart; 00492 } 00493 00494 /* Mapping zero-sized files isn't allowed. */ 00495 if (MaximumSize.QuadPart == 0) 00496 { 00497 DPRINT("Zero size file\n"); 00498 ObDereferenceObject(Section); 00499 return STATUS_FILE_INVALID; 00500 } 00501 00502 Segment = ExAllocatePoolWithTag(NonPagedPool, 00503 sizeof(MM_SECTION_SEGMENT), 00504 TAG_MM_SECTION_SEGMENT); 00505 if (Segment == NULL) 00506 { 00507 DPRINT("Failed: STATUS_NO_MEMORY\n"); 00508 ObDereferenceObject(Section); 00509 return STATUS_NO_MEMORY; 00510 } 00511 00512 DPRINT("Zeroing %x\n", Segment); 00513 RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT)); 00514 ExInitializeFastMutex(&Segment->Lock); 00515 00516 Segment->ReferenceCount = 1; 00517 Segment->Locked = TRUE; 00518 RtlZeroMemory(&Segment->Image, sizeof(Segment->Image)); 00519 Section->Segment = Segment; 00520 00521 KeAcquireSpinLock(&FileObject->IrpListLock, &OldIrql); 00522 /* 00523 * If this file hasn't been mapped as a data file before then allocate a 00524 * section segment to describe the data file mapping 00525 */ 00526 if (FileObject->SectionObjectPointer->DataSectionObject == NULL) 00527 { 00528 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment; 00529 KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql); 00530 00531 /* 00532 * Set the lock before assigning the segment to the file object 00533 */ 00534 ExAcquireFastMutex(&Segment->Lock); 00535 00536 DPRINT("Filling out Segment info (No previous data section)\n"); 00537 ObReferenceObject(FileObject); 00538 Segment->FileObject = FileObject; 00539 Segment->Protection = SectionPageProtection; 00540 Segment->Flags = MM_DATAFILE_SEGMENT; 00541 memset(&Segment->Image, 0, sizeof(Segment->Image)); 00542 Segment->WriteCopy = FALSE; 00543 00544 if (AllocationAttributes & SEC_RESERVE) 00545 { 00546 Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0; 00547 } 00548 else 00549 { 00550 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 00551 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 00552 } 00553 MiInitializeSectionPageTable(Segment); 00554 InsertHeadList(&MiSegmentList, &Segment->ListOfSegments); 00555 } 00556 else 00557 { 00558 KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql); 00559 DPRINTC("Free Segment %x\n", Segment); 00560 ExFreePool(Segment); 00561 00562 DPRINT("Filling out Segment info (previous data section)\n"); 00563 00564 /* 00565 * If the file is already mapped as a data file then we may need 00566 * to extend it 00567 */ 00568 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->DataSectionObject; 00569 Section->Segment = Segment; 00570 (void)InterlockedIncrementUL(&Segment->ReferenceCount); 00571 00572 MmLockSectionSegment(Segment); 00573 00574 if (MaximumSize.QuadPart > Segment->RawLength.QuadPart && 00575 !(AllocationAttributes & SEC_RESERVE)) 00576 { 00577 Segment->RawLength.QuadPart = MaximumSize.QuadPart; 00578 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); 00579 } 00580 } 00581 00582 MmUnlockSectionSegment(Segment); 00583 00584 Section->MaximumSize.QuadPart = MaximumSize.QuadPart; 00585 00586 /* Extend file if section is longer */ 00587 DPRINT("MaximumSize %08x%08x ValidDataLength %08x%08x\n", 00588 MaximumSize.u.HighPart, 00589 MaximumSize.u.LowPart, 00590 FileSizes.ValidDataLength.u.HighPart, 00591 FileSizes.ValidDataLength.u.LowPart); 00592 if (MaximumSize.QuadPart > FileSizes.ValidDataLength.QuadPart) 00593 { 00594 DPRINT("Changing file size to %08x%08x, segment %x\n", 00595 MaximumSize.u.HighPart, 00596 MaximumSize.u.LowPart, 00597 Segment); 00598 00599 Status = IoSetInformation(FileObject, 00600 FileEndOfFileInformation, 00601 sizeof(LARGE_INTEGER), 00602 &MaximumSize); 00603 00604 DPRINT("Change: Status %x\n", Status); 00605 if (!NT_SUCCESS(Status)) 00606 { 00607 DPRINT("Could not expand section\n"); 00608 ObDereferenceObject(Section); 00609 return Status; 00610 } 00611 } 00612 00613 DPRINTC("Segment %x created (%x)\n", Segment, Segment->Flags); 00614 00615 *SectionObject = Section; 00616 return STATUS_SUCCESS; 00617 } 00618 00619 NTSTATUS 00620 NTAPI 00621 _MiMapViewOfSegment(PMMSUPPORT AddressSpace, 00622 PMM_SECTION_SEGMENT Segment, 00623 PVOID* BaseAddress, 00624 SIZE_T ViewSize, 00625 ULONG Protect, 00626 PLARGE_INTEGER ViewOffset, 00627 ULONG AllocationType, 00628 const char *file, 00629 int line) 00630 { 00631 PMEMORY_AREA MArea; 00632 NTSTATUS Status; 00633 PHYSICAL_ADDRESS BoundaryAddressMultiple; 00634 00635 BoundaryAddressMultiple.QuadPart = 0; 00636 00637 Status = MmCreateMemoryArea(AddressSpace, 00638 MEMORY_AREA_CACHE, 00639 BaseAddress, 00640 ViewSize, 00641 Protect, 00642 &MArea, 00643 FALSE, 00644 AllocationType, 00645 BoundaryAddressMultiple); 00646 00647 if (!NT_SUCCESS(Status)) 00648 { 00649 DPRINT("Mapping between 0x%.8X and 0x%.8X failed (%X).\n", 00650 (*BaseAddress), 00651 (char*)(*BaseAddress) + ViewSize, 00652 Status); 00653 00654 return Status; 00655 } 00656 00657 DPRINTC("MiMapViewOfSegment %x %x %x %x %x %wZ %s:%d\n", 00658 MmGetAddressSpaceOwner(AddressSpace), 00659 *BaseAddress, 00660 Segment, 00661 ViewOffset ? ViewOffset->LowPart : 0, 00662 ViewSize, 00663 Segment->FileObject ? &Segment->FileObject->FileName : NULL, 00664 file, 00665 line); 00666 00667 MArea->Data.SectionData.Segment = Segment; 00668 if (ViewOffset) 00669 MArea->Data.SectionData.ViewOffset = *ViewOffset; 00670 else 00671 MArea->Data.SectionData.ViewOffset.QuadPart = 0; 00672 00673 #if 0 00674 MArea->NotPresent = MmNotPresentFaultPageFile; 00675 MArea->AccessFault = MiCowSectionPage; 00676 MArea->PageOut = MmPageOutPageFileView; 00677 #endif 00678 00679 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead, 00680 ViewSize, 00681 0, 00682 Protect); 00683 00684 DPRINTC("MiMapViewOfSegment(P %x, A %x, T %x)\n", 00685 MmGetAddressSpaceOwner(AddressSpace), 00686 *BaseAddress, 00687 MArea->Type); 00688 00689 return STATUS_SUCCESS; 00690 } 00691 00692 /* 00693 00694 Completely remove the page at FileOffset in Segment. The page must not 00695 be mapped. 00696 00697 */ 00698 00699 VOID 00700 NTAPI 00701 MiFreeSegmentPage(PMM_SECTION_SEGMENT Segment, 00702 PLARGE_INTEGER FileOffset) 00703 { 00704 ULONG_PTR Entry; 00705 PFILE_OBJECT FileObject = Segment->FileObject; 00706 00707 Entry = MmGetPageEntrySectionSegment(Segment, FileOffset); 00708 DPRINTC("MiFreeSegmentPage(%x:%08x%08x -> Entry %x\n", 00709 Segment, 00710 FileOffset->HighPart, 00711 FileOffset->LowPart, 00712 Entry); 00713 00714 if (Entry && !IS_SWAP_FROM_SSE(Entry)) 00715 { 00716 // The segment is carrying a dirty page. 00717 PFN_NUMBER OldPage = PFN_FROM_SSE(Entry); 00718 if (IS_DIRTY_SSE(Entry) && FileObject) 00719 { 00720 DPRINT("MiWriteBackPage(%x,%wZ,%08x%08x)\n", 00721 Segment, 00722 &FileObject->FileName, 00723 FileOffset->u.HighPart, 00724 FileOffset->u.LowPart); 00725 00726 MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage); 00727 } 00728 DPRINTC("Free page %x (off %x from %x) (ref ct %d, ent %x, dirty? %s)\n", 00729 OldPage, 00730 FileOffset->LowPart, 00731 Segment, 00732 MmGetReferenceCountPage(OldPage), 00733 Entry, 00734 IS_DIRTY_SSE(Entry) ? "true" : "false"); 00735 00736 MmSetPageEntrySectionSegment(Segment, FileOffset, 0); 00737 MmReleasePageMemoryConsumer(MC_CACHE, OldPage); 00738 } 00739 else if (IS_SWAP_FROM_SSE(Entry)) 00740 { 00741 DPRINT("Free swap\n"); 00742 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry)); 00743 } 00744 00745 DPRINT("Done\n"); 00746 } 00747 00748 VOID 00749 MmFreeCacheSectionPage(PVOID Context, 00750 MEMORY_AREA* MemoryArea, 00751 PVOID Address, 00752 PFN_NUMBER Page, 00753 SWAPENTRY SwapEntry, 00754 BOOLEAN Dirty) 00755 { 00756 ULONG_PTR Entry; 00757 PVOID *ContextData = Context; 00758 PMMSUPPORT AddressSpace; 00759 PEPROCESS Process; 00760 PMM_SECTION_SEGMENT Segment; 00761 LARGE_INTEGER Offset; 00762 00763 DPRINT("MmFreeSectionPage(%x,%x,%x,%x,%d)\n", 00764 MmGetAddressSpaceOwner(ContextData[0]), 00765 Address, 00766 Page, 00767 SwapEntry, 00768 Dirty); 00769 00770 AddressSpace = ContextData[0]; 00771 Process = MmGetAddressSpaceOwner(AddressSpace); 00772 Address = (PVOID)PAGE_ROUND_DOWN(Address); 00773 Segment = ContextData[1]; 00774 Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress + 00775 MemoryArea->Data.SectionData.ViewOffset.QuadPart; 00776 00777 Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 00778 00779 if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty) 00780 { 00781 DPRINT("Freeing section page %x:%x -> %x\n", Segment, Offset.LowPart, Entry); 00782 MmSetPageEntrySectionSegment(Segment, &Offset, DIRTY_SSE(Entry)); 00783 } 00784 if (Page) 00785 { 00786 DPRINT("Removing page %x:%x -> %x\n", Segment, Offset.LowPart, Entry); 00787 MmSetSavedSwapEntryPage(Page, 0); 00788 MmDeleteRmap(Page, Process, Address); 00789 MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL); 00790 MmReleasePageMemoryConsumer(MC_CACHE, Page); 00791 } 00792 if (SwapEntry != 0) 00793 { 00794 MmFreeSwapPage(SwapEntry); 00795 } 00796 } 00797 00798 NTSTATUS 00799 NTAPI 00800 MmUnmapViewOfCacheSegment(PMMSUPPORT AddressSpace, 00801 PVOID BaseAddress) 00802 { 00803 PVOID Context[2]; 00804 PMEMORY_AREA MemoryArea; 00805 PMM_SECTION_SEGMENT Segment; 00806 00807 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress); 00808 if (MemoryArea == NULL || MemoryArea->DeleteInProgress) 00809 { 00810 ASSERT(MemoryArea); 00811 return STATUS_UNSUCCESSFUL; 00812 } 00813 00814 MemoryArea->DeleteInProgress = TRUE; 00815 Segment = MemoryArea->Data.SectionData.Segment; 00816 MemoryArea->Data.SectionData.Segment = NULL; 00817 00818 MmLockSectionSegment(Segment); 00819 00820 Context[0] = AddressSpace; 00821 Context[1] = Segment; 00822 00823 DPRINT("MmFreeMemoryArea(%x,%x)\n", 00824 MmGetAddressSpaceOwner(AddressSpace), 00825 MemoryArea->StartingAddress); 00826 00827 MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context); 00828 00829 MmUnlockSectionSegment(Segment); 00830 00831 DPRINTC("MiUnmapViewOfSegment %x %x %x\n", 00832 MmGetAddressSpaceOwner(AddressSpace), 00833 BaseAddress, 00834 Segment); 00835 00836 return STATUS_SUCCESS; 00837 } 00838 00839 NTSTATUS 00840 NTAPI 00841 MmExtendCacheSection(PROS_SECTION_OBJECT Section, 00842 PLARGE_INTEGER NewSize, 00843 BOOLEAN ExtendFile) 00844 { 00845 LARGE_INTEGER OldSize; 00846 PMM_SECTION_SEGMENT Segment = Section->Segment; 00847 DPRINT("Extend Segment %x\n", Segment); 00848 00849 MmLockSectionSegment(Segment); 00850 OldSize.QuadPart = Segment->RawLength.QuadPart; 00851 MmUnlockSectionSegment(Segment); 00852 00853 DPRINT("OldSize %08x%08x NewSize %08x%08x\n", 00854 OldSize.u.HighPart, OldSize.u.LowPart, 00855 NewSize->u.HighPart, NewSize->u.LowPart); 00856 00857 if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart) 00858 { 00859 NTSTATUS Status; 00860 00861 Status = IoSetInformation(Segment->FileObject, 00862 FileEndOfFileInformation, 00863 sizeof(LARGE_INTEGER), 00864 NewSize); 00865 00866 if (!NT_SUCCESS(Status)) return Status; 00867 } 00868 00869 MmLockSectionSegment(Segment); 00870 Segment->RawLength.QuadPart = NewSize->QuadPart; 00871 Segment->Length.QuadPart = MAX(Segment->Length.QuadPart, 00872 (LONG64)PAGE_ROUND_UP(Segment->RawLength.QuadPart)); 00873 MmUnlockSectionSegment(Segment); 00874 return STATUS_SUCCESS; 00875 } 00876 00877 NTSTATUS 00878 NTAPI 00879 MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment, 00880 OUT PVOID *MappedBase, 00881 PLARGE_INTEGER FileOffset, 00882 IN OUT PULONG ViewSize) 00883 { 00884 PMMSUPPORT AddressSpace; 00885 NTSTATUS Status; 00886 00887 DPRINT("MmMapViewInSystemSpaceAtOffset() called offset %08x%08x\n", 00888 FileOffset->HighPart, 00889 FileOffset->LowPart); 00890 00891 AddressSpace = MmGetKernelAddressSpace(); 00892 00893 MmLockAddressSpace(AddressSpace); 00894 MmLockSectionSegment(Segment); 00895 00896 Status = MiMapViewOfSegment(AddressSpace, 00897 Segment, 00898 MappedBase, 00899 *ViewSize, 00900 PAGE_READWRITE, 00901 FileOffset, 00902 0); 00903 00904 MmUnlockSectionSegment(Segment); 00905 MmUnlockAddressSpace(AddressSpace); 00906 00907 return Status; 00908 } 00909 00910 /* 00911 * @implemented 00912 */ 00913 NTSTATUS NTAPI 00914 MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase) 00915 { 00916 PMMSUPPORT AddressSpace; 00917 NTSTATUS Status; 00918 00919 DPRINT("MmUnmapViewInSystemSpace() called\n"); 00920 00921 AddressSpace = MmGetKernelAddressSpace(); 00922 00923 Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase); 00924 00925 return Status; 00926 } 00927 00928 /* EOF */ Generated on Sun May 27 2012 04:28:09 for ReactOS by
1.7.6.1
|