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