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 separate 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
_MmLockSectionSegment(PMM_SECTION_SEGMENT Segment,const char * file,int line)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
_MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment,const char * file,int line)107 _MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line)
108 {
109 ASSERT(Segment->Locked);
110 Segment->Locked = FALSE;
111 ExReleaseFastMutex(&Segment->Lock);
112 //DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line);
113 }
114
115 #ifdef NEWCC
116 /*
117
118 MiFlushMappedSection
119
120 Called from cache code to cause dirty pages of a section
121 to be written back. This doesn't affect the mapping.
122
123 BaseOffset is the base at which to start writing in file space.
124 FileSize is the length of the file as understood by the cache.
125
126 */
127 NTSTATUS
128 NTAPI
_MiFlushMappedSection(PVOID BaseAddress,PLARGE_INTEGER BaseOffset,PLARGE_INTEGER FileSize,BOOLEAN WriteData,const char * File,int Line)129 _MiFlushMappedSection(PVOID BaseAddress,
130 PLARGE_INTEGER BaseOffset,
131 PLARGE_INTEGER FileSize,
132 BOOLEAN WriteData,
133 const char *File,
134 int Line)
135 {
136 NTSTATUS Status = STATUS_SUCCESS;
137 ULONG_PTR PageAddress;
138 PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
139 PMEMORY_AREA MemoryArea;
140 PMM_SECTION_SEGMENT Segment;
141 ULONG_PTR BeginningAddress, EndingAddress;
142 LARGE_INTEGER ViewOffset;
143 LARGE_INTEGER FileOffset;
144 PFN_NUMBER Page;
145 PPFN_NUMBER Pages;
146 KIRQL OldIrql;
147
148 DPRINT("MiFlushMappedSection(%p,%I64x,%I64x,%u,%s:%d)\n",
149 BaseAddress,
150 BaseOffset->QuadPart,
151 FileSize ? FileSize->QuadPart : 0,
152 WriteData,
153 File,
154 Line);
155
156 MmLockAddressSpace(AddressSpace);
157 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
158 if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_CACHE || MemoryArea->DeleteInProgress)
159 {
160 MmUnlockAddressSpace(AddressSpace);
161 DPRINT("STATUS_NOT_MAPPED_DATA\n");
162 return STATUS_NOT_MAPPED_DATA;
163 }
164 BeginningAddress = PAGE_ROUND_DOWN(MA_GetStartingAddress(MemoryArea));
165 EndingAddress = PAGE_ROUND_UP(MA_GetEndingAddress(MemoryArea));
166 Segment = MemoryArea->Data.SectionData.Segment;
167 ViewOffset.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart;
168
169 ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart);
170
171 MmLockSectionSegment(Segment);
172
173 Pages = ExAllocatePool(NonPagedPool,
174 sizeof(PFN_NUMBER) * ((EndingAddress - BeginningAddress) >> PAGE_SHIFT));
175
176 if (!Pages)
177 {
178 ASSERT(FALSE);
179 }
180
181 //DPRINT("Getting pages in range %08x-%08x\n", BeginningAddress, EndingAddress);
182
183 for (PageAddress = BeginningAddress;
184 PageAddress < EndingAddress;
185 PageAddress += PAGE_SIZE)
186 {
187 ULONG_PTR Entry;
188 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
189 Entry = MmGetPageEntrySectionSegment(MemoryArea->Data.SectionData.Segment,
190 &FileOffset);
191 Page = PFN_FROM_SSE(Entry);
192 if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) &&
193 (MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) &&
194 FileOffset.QuadPart < FileSize->QuadPart)
195 {
196 OldIrql = MiAcquirePfnLock();
197 MmReferencePage(Page);
198 MiReleasePfnLock(OldIrql);
199 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Entry;
200 }
201 else
202 {
203 Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0;
204 }
205 }
206
207 MmUnlockSectionSegment(Segment);
208 MmUnlockAddressSpace(AddressSpace);
209
210 for (PageAddress = BeginningAddress;
211 PageAddress < EndingAddress;
212 PageAddress += PAGE_SIZE)
213 {
214 ULONG_PTR Entry;
215 FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
216 Entry = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT];
217 Page = PFN_FROM_SSE(Entry);
218 if (Page)
219 {
220 if (WriteData) {
221 //DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart);
222 Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page);
223 } else
224 Status = STATUS_SUCCESS;
225
226 if (NT_SUCCESS(Status)) {
227 MmLockAddressSpace(AddressSpace);
228 MmSetCleanAllRmaps(Page);
229
230 MmSetPageProtect(MmGetAddressSpaceOwner(AddressSpace),
231 (PVOID)PageAddress,
232 PAGE_READONLY);
233
234 MmLockSectionSegment(Segment);
235 Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset);
236
237 if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page)
238 MmSetPageEntrySectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry));
239
240 MmUnlockSectionSegment(Segment);
241 MmUnlockAddressSpace(AddressSpace);
242 } else {
243 DPRINT("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n",
244 FileOffset.u.HighPart,
245 FileOffset.u.LowPart,
246 (ULONG)(FileSize->QuadPart - FileOffset.QuadPart),
247 PageAddress,
248 Page,
249 FileSize->u.HighPart,
250 FileSize->u.LowPart,
251 &Segment->FileObject->FileName,
252 Status);
253 }
254 MmReleasePageMemoryConsumer(MC_CACHE, Page);
255 }
256 }
257
258 ExFreePool(Pages);
259
260 return Status;
261 }
262
263 /*
264
265 This deletes a segment entirely including its page map.
266 It must have been unmapped in every address space.
267
268 */
269 VOID
270 NTAPI
MmFinalizeSegment(PMM_SECTION_SEGMENT Segment)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
MmCreateCacheSection(PROS_SECTION_OBJECT * SectionObject,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PLARGE_INTEGER UMaximumSize,ULONG SectionPageProtection,ULONG AllocationAttributes,PFILE_OBJECT FileObject)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
_MiMapViewOfSegment(PMMSUPPORT AddressSpace,PMM_SECTION_SEGMENT Segment,PVOID * BaseAddress,SIZE_T ViewSize,ULONG Protect,PLARGE_INTEGER ViewOffset,ULONG AllocationType,const char * file,int line)539 _MiMapViewOfSegment(PMMSUPPORT AddressSpace,
540 PMM_SECTION_SEGMENT Segment,
541 PVOID* BaseAddress,
542 SIZE_T ViewSize,
543 ULONG Protect,
544 PLARGE_INTEGER ViewOffset,
545 ULONG AllocationType,
546 const char *file,
547 int line)
548 {
549 PMEMORY_AREA MArea;
550 NTSTATUS Status;
551
552 Status = MmCreateMemoryArea(AddressSpace,
553 MEMORY_AREA_CACHE,
554 BaseAddress,
555 ViewSize,
556 Protect,
557 &MArea,
558 AllocationType,
559 *BaseAddress ?
560 PAGE_SIZE : MM_ALLOCATION_GRANULARITY);
561
562 if (!NT_SUCCESS(Status))
563 {
564 DPRINT("Mapping between 0x%p and 0x%p failed (%X).\n",
565 (*BaseAddress),
566 (char*)(*BaseAddress) + ViewSize,
567 Status);
568
569 return Status;
570 }
571
572 DPRINTC("MiMapViewOfSegment %p %p %p %I64x %Ix %wZ %s:%d\n",
573 MmGetAddressSpaceOwner(AddressSpace),
574 *BaseAddress,
575 Segment,
576 ViewOffset ? ViewOffset->QuadPart : 0,
577 ViewSize,
578 Segment->FileObject ? &Segment->FileObject->FileName : NULL,
579 file,
580 line);
581
582 MArea->Data.SectionData.Segment = Segment;
583 if (ViewOffset)
584 MArea->Data.SectionData.ViewOffset = *ViewOffset;
585 else
586 MArea->Data.SectionData.ViewOffset.QuadPart = 0;
587
588 #if 0
589 MArea->NotPresent = MmNotPresentFaultPageFile;
590 MArea->AccessFault = MiCowSectionPage;
591 MArea->PageOut = MmPageOutPageFileView;
592 #endif
593
594 MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
595 ViewSize,
596 0,
597 Protect);
598
599 DPRINTC("MiMapViewOfSegment(P %p, A %p, T %x)\n",
600 MmGetAddressSpaceOwner(AddressSpace),
601 *BaseAddress,
602 MArea->Type);
603
604 return STATUS_SUCCESS;
605 }
606 #endif
607
608 /*
609
610 Completely remove the page at FileOffset in Segment. The page must not
611 be mapped.
612
613 */
614
615 VOID
616 NTAPI
MiFreeSegmentPage(PMM_SECTION_SEGMENT Segment,PLARGE_INTEGER FileOffset)617 MiFreeSegmentPage(PMM_SECTION_SEGMENT Segment,
618 PLARGE_INTEGER FileOffset)
619 {
620 ULONG_PTR Entry;
621 PFILE_OBJECT FileObject = Segment->FileObject;
622
623 Entry = MmGetPageEntrySectionSegment(Segment, FileOffset);
624 DPRINTC("MiFreeSegmentPage(%p:%I64x -> Entry %Ix\n",
625 Segment,
626 FileOffset->QuadPart,
627 Entry);
628
629 if (Entry && !IS_SWAP_FROM_SSE(Entry))
630 {
631 // The segment is carrying a dirty page.
632 PFN_NUMBER OldPage = PFN_FROM_SSE(Entry);
633 if (IS_DIRTY_SSE(Entry) && FileObject)
634 {
635 DPRINT("MiWriteBackPage(%p,%wZ,%I64x)\n",
636 Segment,
637 &FileObject->FileName,
638 FileOffset->QuadPart);
639
640 MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage);
641 }
642 DPRINTC("Free page %Ix (off %I64x from %p) (ref ct %lu, ent %Ix, dirty? %s)\n",
643 OldPage,
644 FileOffset->QuadPart,
645 Segment,
646 MmGetReferenceCountPageWithoutLock(OldPage),
647 Entry,
648 IS_DIRTY_SSE(Entry) ? "true" : "false");
649
650 MmSetPageEntrySectionSegment(Segment, FileOffset, 0);
651 MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
652 }
653 else if (IS_SWAP_FROM_SSE(Entry))
654 {
655 DPRINT("Free swap\n");
656 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
657 }
658
659 DPRINT("Done\n");
660 }
661
662 VOID
MmFreeCacheSectionPage(PVOID Context,MEMORY_AREA * MemoryArea,PVOID Address,PFN_NUMBER Page,SWAPENTRY SwapEntry,BOOLEAN Dirty)663 MmFreeCacheSectionPage(PVOID Context,
664 MEMORY_AREA* MemoryArea,
665 PVOID Address,
666 PFN_NUMBER Page,
667 SWAPENTRY SwapEntry,
668 BOOLEAN Dirty)
669 {
670 ULONG_PTR Entry;
671 PVOID *ContextData = Context;
672 PMMSUPPORT AddressSpace;
673 PEPROCESS Process;
674 PMM_SECTION_SEGMENT Segment;
675 LARGE_INTEGER Offset;
676
677 DPRINT("MmFreeSectionPage(%p,%p,%Ix,%Ix,%u)\n",
678 MmGetAddressSpaceOwner(ContextData[0]),
679 Address,
680 Page,
681 SwapEntry,
682 Dirty);
683
684 AddressSpace = ContextData[0];
685 Process = MmGetAddressSpaceOwner(AddressSpace);
686 Address = (PVOID)PAGE_ROUND_DOWN(Address);
687 Segment = ContextData[1];
688 Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea) +
689 MemoryArea->Data.SectionData.ViewOffset.QuadPart;
690
691 Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
692
693 if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty)
694 {
695 DPRINT("Freeing section page %p:%I64x -> %Ix\n", Segment, Offset.QuadPart, Entry);
696 MmSetPageEntrySectionSegment(Segment, &Offset, DIRTY_SSE(Entry));
697 }
698 if (Page)
699 {
700 DPRINT("Removing page %p:%I64x -> %x\n", Segment, Offset.QuadPart, Entry);
701 MmSetSavedSwapEntryPage(Page, 0);
702 MmDeleteRmap(Page, Process, Address);
703 MmDeleteVirtualMapping(Process, Address, NULL, NULL);
704 MmReleasePageMemoryConsumer(MC_CACHE, Page);
705 }
706 if (SwapEntry != 0)
707 {
708 MmFreeSwapPage(SwapEntry);
709 }
710 }
711
712 #ifdef NEWCC
713 NTSTATUS
714 NTAPI
MmUnmapViewOfCacheSegment(PMMSUPPORT AddressSpace,PVOID BaseAddress)715 MmUnmapViewOfCacheSegment(PMMSUPPORT AddressSpace,
716 PVOID BaseAddress)
717 {
718 PVOID Context[2];
719 PMEMORY_AREA MemoryArea;
720 PMM_SECTION_SEGMENT Segment;
721
722 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
723 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
724 {
725 ASSERT(MemoryArea);
726 return STATUS_UNSUCCESSFUL;
727 }
728
729 MemoryArea->DeleteInProgress = TRUE;
730 Segment = MemoryArea->Data.SectionData.Segment;
731 MemoryArea->Data.SectionData.Segment = NULL;
732
733 MmLockSectionSegment(Segment);
734
735 Context[0] = AddressSpace;
736 Context[1] = Segment;
737
738 DPRINT("MmFreeMemoryArea(%p,%p)\n",
739 MmGetAddressSpaceOwner(AddressSpace),
740 MA_GetStartingAddress(MemoryArea));
741
742 MmLockAddressSpace(AddressSpace);
743
744 MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context);
745
746 MmUnlockAddressSpace(AddressSpace);
747
748 MmUnlockSectionSegment(Segment);
749
750 DPRINTC("MiUnmapViewOfSegment %p %p %p\n",
751 MmGetAddressSpaceOwner(AddressSpace),
752 BaseAddress,
753 Segment);
754
755 return STATUS_SUCCESS;
756 }
757
758 NTSTATUS
759 NTAPI
MmExtendCacheSection(PROS_SECTION_OBJECT Section,PLARGE_INTEGER NewSize,BOOLEAN ExtendFile)760 MmExtendCacheSection(PROS_SECTION_OBJECT Section,
761 PLARGE_INTEGER NewSize,
762 BOOLEAN ExtendFile)
763 {
764 LARGE_INTEGER OldSize;
765 PMM_SECTION_SEGMENT Segment = Section->Segment;
766 DPRINT("Extend Segment %p\n", Segment);
767
768 MmLockSectionSegment(Segment);
769 OldSize.QuadPart = Segment->RawLength.QuadPart;
770 MmUnlockSectionSegment(Segment);
771
772 DPRINT("OldSize 0x%I64x NewSize 0x%I64x\n",
773 OldSize.QuadPart,
774 NewSize->QuadPart);
775
776 if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart)
777 {
778 NTSTATUS Status;
779
780 Status = IoSetInformation(Segment->FileObject,
781 FileEndOfFileInformation,
782 sizeof(LARGE_INTEGER),
783 NewSize);
784
785 if (!NT_SUCCESS(Status)) return Status;
786 }
787
788 MmLockSectionSegment(Segment);
789 Segment->RawLength.QuadPart = NewSize->QuadPart;
790 Segment->Length.QuadPart = MAX(Segment->Length.QuadPart,
791 (LONG64)PAGE_ROUND_UP(Segment->RawLength.QuadPart));
792 MmUnlockSectionSegment(Segment);
793 return STATUS_SUCCESS;
794 }
795
796 NTSTATUS
797 NTAPI
MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment,OUT PVOID * MappedBase,PLARGE_INTEGER FileOffset,IN OUT PULONG ViewSize)798 MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment,
799 OUT PVOID *MappedBase,
800 PLARGE_INTEGER FileOffset,
801 IN OUT PULONG ViewSize)
802 {
803 PMMSUPPORT AddressSpace;
804 NTSTATUS Status;
805
806 DPRINT("MmMapViewInSystemSpaceAtOffset() called offset 0x%I64x\n",
807 FileOffset->QuadPart);
808
809 AddressSpace = MmGetKernelAddressSpace();
810
811 MmLockAddressSpace(AddressSpace);
812 MmLockSectionSegment(Segment);
813
814 Status = MiMapViewOfSegment(AddressSpace,
815 Segment,
816 MappedBase,
817 *ViewSize,
818 PAGE_READWRITE,
819 FileOffset,
820 0);
821
822 MmUnlockSectionSegment(Segment);
823 MmUnlockAddressSpace(AddressSpace);
824
825 return Status;
826 }
827
828 /*
829 * @implemented
830 */
831 NTSTATUS NTAPI
MmUnmapCacheViewInSystemSpace(IN PVOID MappedBase)832 MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase)
833 {
834 PMMSUPPORT AddressSpace;
835 NTSTATUS Status;
836
837 DPRINT("MmUnmapViewInSystemSpace() called\n");
838
839 AddressSpace = MmGetKernelAddressSpace();
840
841 Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase);
842
843 return Status;
844 }
845 #endif /* NEWCC */
846
847 /* EOF */
848