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