[NEWCC]
[reactos.git] / reactos / ntoskrnl / cache / section / data.c
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/mm/section.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 /* INCLUDES *****************************************************************/
46
47 #include <ntoskrnl.h>
48 #include "newmm.h"
49 #include "../newcc.h"
50 #define NDEBUG
51 #include <debug.h>
52 #include "../mm/ARM3/miarm.h"
53
54 #define DPRINTC DPRINT
55
56 LIST_ENTRY MiSegmentList;
57
58 extern KEVENT MpwThreadEvent;
59 extern KSPIN_LOCK MiSectionPageTableLock;
60 extern PMMWSL MmWorkingSetList;
61
62 /* GLOBALS *******************************************************************/
63
64 ULONG_PTR MmSubsectionBase;
65
66 static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
67 {
68 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
69 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
70 };
71
72 /* FUNCTIONS *****************************************************************/
73
74 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
75
76 VOID
77 NTAPI
78 _MmLockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line)
79 {
80 //DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line);
81 ExAcquireFastMutex(&Segment->Lock);
82 Segment->Locked = TRUE;
83 }
84
85 VOID
86 NTAPI
87 _MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line)
88 {
89 ASSERT(Segment->Locked);
90 Segment->Locked = FALSE;
91 ExReleaseFastMutex(&Segment->Lock);
92 //DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line);
93 }
94
95 NTSTATUS
96 NTAPI
97 MiZeroFillSection
98 (PVOID Address,
99 PLARGE_INTEGER FileOffsetPtr,
100 ULONG Length)
101 {
102 PFN_NUMBER Page;
103 PMMSUPPORT AddressSpace;
104 PMEMORY_AREA MemoryArea;
105 PMM_SECTION_SEGMENT Segment;
106 LARGE_INTEGER FileOffset = *FileOffsetPtr, End, FirstMapped;
107 KIRQL OldIrql;
108
109 DPRINT("MiZeroFillSection(Address %x,Offset %x,Length %x)\n", Address, FileOffset.LowPart, Length);
110
111 AddressSpace = MmGetKernelAddressSpace();
112
113 MmLockAddressSpace(AddressSpace);
114 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
115 MmUnlockAddressSpace(AddressSpace);
116 if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW || MemoryArea->DeleteInProgress)
117 {
118 return STATUS_NOT_MAPPED_DATA;
119 }
120
121 Segment = MemoryArea->Data.SectionData.Segment;
122 End.QuadPart = FileOffset.QuadPart + Length;
123 End.LowPart = PAGE_ROUND_DOWN(End.LowPart);
124 FileOffset.LowPart = PAGE_ROUND_UP(FileOffset.LowPart);
125 FirstMapped.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart;
126 DPRINT
127 ("Pulling zero pages for %08x%08x-%08x%08x\n",
128 FileOffset.u.HighPart, FileOffset.u.LowPart,
129 End.u.HighPart, End.u.LowPart);
130 while (FileOffset.QuadPart < End.QuadPart)
131 {
132 PVOID Address;
133 ULONG Entry;
134
135 if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page)))
136 break;
137
138 MmLockAddressSpace(AddressSpace);
139 MmLockSectionSegment(Segment);
140
141 Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset);
142 if (Entry == 0)
143 {
144 MmSetPageEntrySectionSegment(Segment, &FileOffset, MAKE_PFN_SSE(Page));
145 Address = ((PCHAR)MemoryArea->StartingAddress) + FileOffset.QuadPart - FirstMapped.QuadPart;
146
147 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
148 MmReferencePage(Page);
149 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
150
151 MmCreateVirtualMapping(NULL, Address, PAGE_READWRITE, &Page, 1);
152 MmInsertRmap(Page, NULL, Address);
153 }
154 else
155 MmReleasePageMemoryConsumer(MC_CACHE, Page);
156
157 MmUnlockSectionSegment(Segment);
158 MmUnlockAddressSpace(AddressSpace);
159
160 FileOffset.QuadPart += PAGE_SIZE;
161 }
162 return STATUS_SUCCESS;
163 }
164
165 NTSTATUS
166 NTAPI
167 _MiFlushMappedSection
168 (PVOID BaseAddress,
169 PLARGE_INTEGER BaseOffset,
170 PLARGE_INTEGER FileSize,
171 BOOLEAN WriteData,
172 const char *File,
173 int Line)
174 {
175 NTSTATUS Status = STATUS_SUCCESS;
176 ULONG_PTR PageAddress;
177 PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
178 PMEMORY_AREA MemoryArea;
179 PMM_SECTION_SEGMENT Segment;
180 ULONG_PTR BeginningAddress, EndingAddress;
181 LARGE_INTEGER ViewOffset;
182 LARGE_INTEGER FileOffset;
183 PFN_NUMBER Page;
184 PPFN_NUMBER Pages;
185 KIRQL OldIrql;
186
187 DPRINT("MiFlushMappedSection(%x,%08x,%x,%d,%s:%d)\n", BaseAddress, BaseOffset->LowPart, FileSize, WriteData, File, Line);
188
189 MmLockAddressSpace(AddressSpace);
190 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
191 if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_CACHE || MemoryArea->DeleteInProgress)
192 {
193 MmUnlockAddressSpace(AddressSpace);
194 DPRINT("STATUS_NOT_MAPPED_DATA\n");
195 return STATUS_NOT_MAPPED_DATA;
196 }
197 BeginningAddress = PAGE_ROUND_DOWN((ULONG_PTR)MemoryArea->StartingAddress);
198 EndingAddress = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress);
199 Segment = MemoryArea->Data.SectionData.Segment;
200 ViewOffset.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart;
201
202 ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart);
203
204 MmLockSectionSegment(Segment);
205
206 Pages = ExAllocatePool
207 (NonPagedPool,
208 sizeof(PFN_NUMBER) *
209 ((EndingAddress - BeginningAddress) >> PAGE_SHIFT));
210
211 if (!Pages)
212 {
213 ASSERT(FALSE);
214 }
215
216 //DPRINT("Getting pages in range %08x-%08x\n", BeginningAddress, EndingAddress);
217
218 for (PageAddress = BeginningAddress;
219 PageAddress < EndingAddress;
220 PageAddress += PAGE_SIZE)
221 {
222 ULONG Entry;
223 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
224 Entry =
225 MmGetPageEntrySectionSegment
226 (MemoryArea->Data.SectionData.Segment,
227 &FileOffset);
228 Page = PFN_FROM_SSE(Entry);
229 if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) &&
230 (MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) &&
231 FileOffset.QuadPart < FileSize->QuadPart)
232 {
233 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
234 MmReferencePage(Page);
235 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
236 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Entry;
237 }
238 else
239 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0;
240 }
241
242 MmUnlockSectionSegment(Segment);
243 MmUnlockAddressSpace(AddressSpace);
244
245 for (PageAddress = BeginningAddress;
246 PageAddress < EndingAddress;
247 PageAddress += PAGE_SIZE)
248 {
249 ULONG Entry;
250 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
251 Entry = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT];
252 Page = PFN_FROM_SSE(Entry);
253 if (Page)
254 {
255 if (WriteData) {
256 //DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart);
257 Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page);
258 } else
259 Status = STATUS_SUCCESS;
260
261 if (NT_SUCCESS(Status)) {
262 MmLockAddressSpace(AddressSpace);
263 MmSetCleanAllRmaps(Page);
264 MmSetPageProtect(MmGetAddressSpaceOwner(AddressSpace), (PVOID)PageAddress, PAGE_READONLY);
265 MmLockSectionSegment(Segment);
266 Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset);
267 if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page)
268 MmSetPageEntrySectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry));
269 MmUnlockSectionSegment(Segment);
270 MmUnlockAddressSpace(AddressSpace);
271 } else {
272 DPRINT
273 ("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n",
274 FileOffset.u.HighPart, FileOffset.u.LowPart,
275 (ULONG)(FileSize->QuadPart - FileOffset.QuadPart),
276 PageAddress,
277 Page,
278 FileSize->u.HighPart,
279 FileSize->u.LowPart,
280 &Segment->FileObject->FileName,
281 Status);
282 }
283 MmReleasePageMemoryConsumer(MC_CACHE, Page);
284 }
285 }
286
287 ExFreePool(Pages);
288
289 return Status;
290 }
291
292 VOID
293 NTAPI
294 MmFinalizeSegment(PMM_SECTION_SEGMENT Segment)
295 {
296 KIRQL OldIrql = 0;
297
298 DPRINT("Finalize segment %p\n", Segment);
299
300 MmLockSectionSegment(Segment);
301 RemoveEntryList(&Segment->ListOfSegments);
302 if (Segment->Flags & MM_DATAFILE_SEGMENT) {
303 KeAcquireSpinLock(&Segment->FileObject->IrpListLock, &OldIrql);
304 if (Segment->Flags & MM_SEGMENT_FINALIZE) {
305 KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
306 MmUnlockSectionSegment(Segment);
307 return;
308 }
309 Segment->Flags |= MM_SEGMENT_FINALIZE;
310 DPRINTC("Finalizing data file segment %p\n", Segment);
311
312 Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL;
313 KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
314 MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
315 MmUnlockSectionSegment(Segment);
316 DPRINT("Dereference file object %wZ\n", &Segment->FileObject->FileName);
317 ObDereferenceObject(Segment->FileObject);
318 DPRINT("Done with %wZ\n", &Segment->FileObject->FileName);
319 Segment->FileObject = NULL;
320 } else {
321 DPRINTC("Finalizing segment %p\n", Segment);
322 MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
323 MmUnlockSectionSegment(Segment);
324 }
325 DPRINTC("Segment %p destroy\n", Segment);
326 ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT);
327 }
328
329 NTSTATUS
330 NTAPI
331 MmCreateCacheSection(PROS_SECTION_OBJECT *SectionObject,
332 ACCESS_MASK DesiredAccess,
333 POBJECT_ATTRIBUTES ObjectAttributes,
334 PLARGE_INTEGER UMaximumSize,
335 ULONG SectionPageProtection,
336 ULONG AllocationAttributes,
337 PFILE_OBJECT FileObject)
338 /*
339 * Create a section backed by a data file
340 */
341 {
342 PROS_SECTION_OBJECT Section;
343 NTSTATUS Status;
344 ULARGE_INTEGER MaximumSize;
345 PMM_SECTION_SEGMENT Segment;
346 IO_STATUS_BLOCK Iosb;
347 CC_FILE_SIZES FileSizes;
348 FILE_STANDARD_INFORMATION FileInfo;
349 KIRQL OldIrql;
350
351 DPRINT("MmCreateDataFileSection\n");
352
353 /*
354 * Create the section
355 */
356 Status = ObCreateObject(ExGetPreviousMode(),
357 MmSectionObjectType,
358 ObjectAttributes,
359 ExGetPreviousMode(),
360 NULL,
361 sizeof(ROS_SECTION_OBJECT),
362 0,
363 0,
364 (PVOID*)(PVOID)&Section);
365 if (!NT_SUCCESS(Status))
366 {
367 DPRINT("Failed: %x\n", Status);
368 return(Status);
369 }
370 /*
371 * Initialize it
372 */
373 RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
374 Section->Type = 'SC';
375 Section->Size = 'TN';
376 Section->SectionPageProtection = SectionPageProtection;
377 Section->AllocationAttributes = AllocationAttributes;
378 Section->Segment = NULL;
379
380 Section->FileObject = FileObject;
381
382 DPRINT("Getting original file size\n");
383 /* A hack: If we're cached, we can overcome deadlocking with the upper
384 * layer filesystem call by retriving the object sizes from the cache
385 * which is made to keep track. If I had to guess, they were figuring
386 * out a similar problem.
387 */
388 if (!CcGetFileSizes(FileObject, &FileSizes))
389 {
390 /*
391 * FIXME: This is propably not entirely correct. We can't look into
392 * the standard FCB header because it might not be initialized yet
393 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
394 * standard file information is filled on first request).
395 */
396 DPRINT("Querying info\n");
397 Status = IoQueryFileInformation
398 (FileObject,
399 FileStandardInformation,
400 sizeof(FILE_STANDARD_INFORMATION),
401 &FileInfo,
402 &Iosb.Information);
403 DPRINT("Query => %x\n", Status);
404
405 if (!NT_SUCCESS(Status))
406 {
407 DPRINT("Status %x\n", Status);
408 ObDereferenceObject(Section);
409 return Status;
410 }
411 ASSERT(Status != STATUS_PENDING);
412
413 FileSizes.ValidDataLength = FileInfo.EndOfFile;
414 FileSizes.FileSize = FileInfo.EndOfFile;
415 }
416 DPRINT("Got %08x\n", FileSizes.ValidDataLength.u.LowPart);
417
418 /*
419 * FIXME: Revise this once a locking order for file size changes is
420 * decided
421 *
422 * We're handed down a maximum size in every case. Should we still check at all?
423 */
424 if (UMaximumSize != NULL && UMaximumSize->QuadPart)
425 {
426 DPRINT("Taking maximum %x\n", UMaximumSize->LowPart);
427 MaximumSize.QuadPart = UMaximumSize->QuadPart;
428 }
429 else
430 {
431 DPRINT("Got file size %08x%08x\n", FileSizes.FileSize.u.HighPart, FileSizes.FileSize.u.LowPart);
432 MaximumSize.QuadPart = FileSizes.FileSize.QuadPart;
433 }
434
435 /* Mapping zero-sized files isn't allowed. */
436 if (MaximumSize.QuadPart == 0)
437 {
438 DPRINT("Zero size file\n");
439 ObDereferenceObject(Section);
440 return STATUS_FILE_INVALID;
441 }
442
443 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
444 TAG_MM_SECTION_SEGMENT);
445 if (Segment == NULL)
446 {
447 DPRINT("Failed: STATUS_NO_MEMORY\n");
448 ObDereferenceObject(Section);
449 return(STATUS_NO_MEMORY);
450 }
451
452 DPRINT("Zeroing %x\n", Segment);
453 RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT));
454 ExInitializeFastMutex(&Segment->Lock);
455
456 Segment->ReferenceCount = 1;
457 Segment->Locked = TRUE;
458 RtlZeroMemory(&Segment->Image, sizeof(Segment->Image));
459 Section->Segment = Segment;
460
461 KeAcquireSpinLock(&FileObject->IrpListLock, &OldIrql);
462 /*
463 * If this file hasn't been mapped as a data file before then allocate a
464 * section segment to describe the data file mapping
465 */
466 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
467 {
468 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
469 KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql);
470
471 /*
472 * Set the lock before assigning the segment to the file object
473 */
474 ExAcquireFastMutex(&Segment->Lock);
475
476 DPRINT("Filling out Segment info (No previous data section)\n");
477 ObReferenceObject(FileObject);
478 Segment->FileObject = FileObject;
479 Segment->Protection = SectionPageProtection;
480 Segment->Flags = MM_DATAFILE_SEGMENT;
481 memset(&Segment->Image, 0, sizeof(Segment->Image));
482 Segment->WriteCopy = FALSE;
483
484 if (AllocationAttributes & SEC_RESERVE)
485 {
486 Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
487 }
488 else
489 {
490 Segment->RawLength.QuadPart = MaximumSize.QuadPart;
491 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
492 }
493 MiInitializeSectionPageTable(Segment);
494 InsertHeadList(&MiSegmentList, &Segment->ListOfSegments);
495 }
496 else
497 {
498 KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql);
499 DPRINTC("Free Segment %x\n", Segment);
500 ExFreePool(Segment);
501
502 DPRINT("Filling out Segment info (previous data section)\n");
503
504 /*
505 * If the file is already mapped as a data file then we may need
506 * to extend it
507 */
508 Segment =
509 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
510 DataSectionObject;
511 Section->Segment = Segment;
512 (void)InterlockedIncrementUL(&Segment->ReferenceCount);
513
514 MmLockSectionSegment(Segment);
515
516 if (MaximumSize.QuadPart > Segment->RawLength.QuadPart &&
517 !(AllocationAttributes & SEC_RESERVE))
518 {
519 Segment->RawLength.QuadPart = MaximumSize.QuadPart;
520 Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
521 }
522 }
523
524 MmUnlockSectionSegment(Segment);
525
526 Section->MaximumSize.QuadPart = MaximumSize.QuadPart;
527
528 /* Extend file if section is longer */
529 DPRINT("MaximumSize %08x%08x ValidDataLength %08x%08x\n",
530 MaximumSize.u.HighPart, MaximumSize.u.LowPart,
531 FileSizes.ValidDataLength.u.HighPart, FileSizes.ValidDataLength.u.LowPart);
532 if (MaximumSize.QuadPart > FileSizes.ValidDataLength.QuadPart)
533 {
534 DPRINT("Changing file size to %08x%08x, segment %x\n", MaximumSize.u.HighPart, MaximumSize.u.LowPart, Segment);
535 Status = IoSetInformation(FileObject, FileEndOfFileInformation, sizeof(LARGE_INTEGER), &MaximumSize);
536 DPRINT("Change: Status %x\n", Status);
537 if (!NT_SUCCESS(Status))
538 {
539 DPRINT("Could not expand section\n");
540 ObDereferenceObject(Section);
541 return Status;
542 }
543 }
544
545 DPRINTC("Segment %x created (%x)\n", Segment, Segment->Flags);
546
547 *SectionObject = Section;
548 return(STATUS_SUCCESS);
549 }
550
551 NTSTATUS
552 NTAPI
553 _MiMapViewOfSegment
554 (PMMSUPPORT AddressSpace,
555 PMM_SECTION_SEGMENT Segment,
556 PVOID* BaseAddress,
557 SIZE_T ViewSize,
558 ULONG Protect,
559 PLARGE_INTEGER ViewOffset,
560 ULONG AllocationType,
561 const char *file,
562 int line)
563 {
564 PMEMORY_AREA MArea;
565 NTSTATUS Status;
566 PHYSICAL_ADDRESS BoundaryAddressMultiple;
567
568 BoundaryAddressMultiple.QuadPart = 0;
569
570 Status = MmCreateMemoryArea
571 (AddressSpace,
572 MEMORY_AREA_CACHE,
573 BaseAddress,
574 ViewSize,
575 Protect,
576 &MArea,
577 FALSE,
578 AllocationType,
579 BoundaryAddressMultiple);
580
581 if (!NT_SUCCESS(Status))
582 {
583 DPRINT("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
584 (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
585 return(Status);
586 }
587
588 DPRINTC("MiMapViewOfSegment %x %x %x %x %x %wZ %s:%d\n", MmGetAddressSpaceOwner(AddressSpace), *BaseAddress, Segment, ViewOffset ? ViewOffset->LowPart : 0, ViewSize, Segment->FileObject ? &Segment->FileObject->FileName : NULL, file, line);
589
590 MArea->Data.SectionData.Segment = Segment;
591 if (ViewOffset)
592 MArea->Data.SectionData.ViewOffset = *ViewOffset;
593 else
594 MArea->Data.SectionData.ViewOffset.QuadPart = 0;
595
596 #if 0
597 MArea->NotPresent = MmNotPresentFaultPageFile;
598 MArea->AccessFault = MiCowSectionPage;
599 MArea->PageOut = MmPageOutPageFileView;
600 #endif
601
602 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
603 ViewSize, 0, Protect);
604
605 DPRINTC
606 ("MiMapViewOfSegment(P %x, A %x, T %x)\n",
607 MmGetAddressSpaceOwner(AddressSpace), *BaseAddress, MArea->Type);
608
609 return(STATUS_SUCCESS);
610 }
611
612 VOID
613 NTAPI
614 MiFreeSegmentPage
615 (PMM_SECTION_SEGMENT Segment,
616 PLARGE_INTEGER FileOffset)
617 {
618 ULONG Entry;
619 PFILE_OBJECT FileObject = Segment->FileObject;
620
621 Entry = MmGetPageEntrySectionSegment(Segment, FileOffset);
622 DPRINTC("MiFreeSegmentPage(%x:%08x%08x -> Entry %x\n",
623 Segment, FileOffset->HighPart, FileOffset->LowPart, Entry);
624
625 if (Entry && !IS_SWAP_FROM_SSE(Entry))
626 {
627 // The segment is carrying a dirty page.
628 PFN_NUMBER OldPage = PFN_FROM_SSE(Entry);
629 if (IS_DIRTY_SSE(Entry) && FileObject)
630 {
631 DPRINT("MiWriteBackPage(%x,%wZ,%08x%08x)\n", Segment, &FileObject->FileName, FileOffset->u.HighPart, FileOffset->u.LowPart);
632 MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage);
633 }
634 DPRINTC("Free page %x (off %x from %x) (ref ct %d, ent %x, dirty? %s)\n", OldPage, FileOffset->LowPart, Segment, MmGetReferenceCountPage(OldPage), Entry, IS_DIRTY_SSE(Entry) ? "true" : "false");
635
636 MmSetPageEntrySectionSegment(Segment, FileOffset, 0);
637 MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
638 }
639 else if (IS_SWAP_FROM_SSE(Entry))
640 {
641 DPRINT("Free swap\n");
642 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
643 }
644
645 DPRINT("Done\n");
646 }
647
648 VOID
649 MmFreeCacheSectionPage
650 (PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
651 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
652 {
653 ULONG Entry;
654 PVOID *ContextData = Context;
655 PMMSUPPORT AddressSpace;
656 PEPROCESS Process;
657 PMM_SECTION_SEGMENT Segment;
658 LARGE_INTEGER Offset;
659
660 DPRINT("MmFreeSectionPage(%x,%x,%x,%x,%d)\n", MmGetAddressSpaceOwner(ContextData[0]), Address, Page, SwapEntry, Dirty);
661
662 AddressSpace = ContextData[0];
663 Process = MmGetAddressSpaceOwner(AddressSpace);
664 Address = (PVOID)PAGE_ROUND_DOWN(Address);
665 Segment = ContextData[1];
666 Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress +
667 MemoryArea->Data.SectionData.ViewOffset.QuadPart;
668
669 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
670
671 if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty)
672 {
673 DPRINT("Freeing section page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
674 MmSetPageEntrySectionSegment(Segment, &Offset, DIRTY_SSE(Entry));
675 }
676 if (Page)
677 {
678 DPRINT("Removing page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
679 MmSetSavedSwapEntryPage(Page, 0);
680 MmDeleteRmap(Page, Process, Address);
681 MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
682 MmReleasePageMemoryConsumer(MC_CACHE, Page);
683 }
684 if (SwapEntry != 0)
685 {
686 MmFreeSwapPage(SwapEntry);
687 }
688 }
689
690 NTSTATUS
691 NTAPI
692 MmUnmapViewOfCacheSegment
693 (PMMSUPPORT AddressSpace,
694 PVOID BaseAddress)
695 {
696 PVOID Context[2];
697 PMEMORY_AREA MemoryArea;
698 PMM_SECTION_SEGMENT Segment;
699
700 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
701 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
702 {
703 ASSERT(MemoryArea);
704 return(STATUS_UNSUCCESSFUL);
705 }
706
707 MemoryArea->DeleteInProgress = TRUE;
708 Segment = MemoryArea->Data.SectionData.Segment;
709 MemoryArea->Data.SectionData.Segment = NULL;
710
711 MmLockSectionSegment(Segment);
712
713 Context[0] = AddressSpace;
714 Context[1] = Segment;
715 DPRINT("MmFreeMemoryArea(%x,%x)\n", MmGetAddressSpaceOwner(AddressSpace), MemoryArea->StartingAddress);
716 MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context);
717
718 MmUnlockSectionSegment(Segment);
719
720 DPRINTC("MiUnmapViewOfSegment %x %x %x\n", MmGetAddressSpaceOwner(AddressSpace), BaseAddress, Segment);
721
722 return(STATUS_SUCCESS);
723 }
724
725 NTSTATUS
726 NTAPI
727 MmExtendCacheSection
728 (PROS_SECTION_OBJECT Section,
729 PLARGE_INTEGER NewSize,
730 BOOLEAN ExtendFile)
731 {
732 LARGE_INTEGER OldSize;
733 PMM_SECTION_SEGMENT Segment = Section->Segment;
734 DPRINT("Extend Segment %x\n", Segment);
735
736 MmLockSectionSegment(Segment);
737 OldSize.QuadPart = Segment->RawLength.QuadPart;
738 MmUnlockSectionSegment(Segment);
739
740 DPRINT("OldSize %08x%08x NewSize %08x%08x\n",
741 OldSize.u.HighPart, OldSize.u.LowPart,
742 NewSize->u.HighPart, NewSize->u.LowPart);
743
744 if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart)
745 {
746 NTSTATUS Status;
747 Status = IoSetInformation(Segment->FileObject, FileEndOfFileInformation, sizeof(LARGE_INTEGER), NewSize);
748 if (!NT_SUCCESS(Status)) return Status;
749 }
750
751 MmLockSectionSegment(Segment);
752 Segment->RawLength.QuadPart = NewSize->QuadPart;
753 Segment->Length.QuadPart = MAX(Segment->Length.QuadPart, PAGE_ROUND_UP(Segment->RawLength.LowPart));
754 MmUnlockSectionSegment(Segment);
755 return STATUS_SUCCESS;
756 }
757
758 NTSTATUS
759 NTAPI
760 MmMapCacheViewInSystemSpaceAtOffset
761 (IN PMM_SECTION_SEGMENT Segment,
762 OUT PVOID *MappedBase,
763 PLARGE_INTEGER FileOffset,
764 IN OUT PULONG ViewSize)
765 {
766 PMMSUPPORT AddressSpace;
767 NTSTATUS Status;
768
769 DPRINT("MmMapViewInSystemSpaceAtOffset() called offset %08x%08x\n", FileOffset->HighPart, FileOffset->LowPart);
770
771 AddressSpace = MmGetKernelAddressSpace();
772
773 MmLockAddressSpace(AddressSpace);
774 MmLockSectionSegment(Segment);
775
776 Status = MiMapViewOfSegment
777 (AddressSpace,
778 Segment,
779 MappedBase,
780 *ViewSize,
781 PAGE_READWRITE,
782 FileOffset,
783 0);
784
785 MmUnlockSectionSegment(Segment);
786 MmUnlockAddressSpace(AddressSpace);
787
788 return Status;
789 }
790
791 /*
792 * @implemented
793 */
794 NTSTATUS NTAPI
795 MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase)
796 {
797 PMMSUPPORT AddressSpace;
798 NTSTATUS Status;
799
800 DPRINT("MmUnmapViewInSystemSpace() called\n");
801
802 AddressSpace = MmGetKernelAddressSpace();
803
804 Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase);
805
806 return Status;
807 }
808
809 /* EOF */