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