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