Do the required flush when the last reference to a cache stripe is released.
[reactos.git] / reactos / ntoskrnl / mm / rmap.c
1 /*
2 * COPYRIGHT: See COPYING in the top directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/rmap.c
5 * PURPOSE: Kernel memory managment functions
6 *
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #ifdef NEWCC
14 #include "../cache/section/newmm.h"
15 #endif
16 #define NDEBUG
17 #include <debug.h>
18
19 #if defined (ALLOC_PRAGMA)
20 #pragma alloc_text(INIT, MmInitializeRmapList)
21 #endif
22
23 /* TYPES ********************************************************************/
24
25 /* GLOBALS ******************************************************************/
26
27 static NPAGED_LOOKASIDE_LIST RmapLookasideList;
28 FAST_MUTEX RmapListLock;
29
30 /* FUNCTIONS ****************************************************************/
31
32 VOID
33 INIT_FUNCTION
34 NTAPI
35 MmInitializeRmapList(VOID)
36 {
37 ExInitializeFastMutex(&RmapListLock);
38 ExInitializeNPagedLookasideList (&RmapLookasideList,
39 NULL,
40 NULL,
41 0,
42 sizeof(MM_RMAP_ENTRY),
43 TAG_RMAP,
44 50);
45 }
46
47 NTSTATUS
48 NTAPI
49 MmPageOutPhysicalAddress(PFN_NUMBER Page)
50 {
51 PMM_RMAP_ENTRY entry;
52 PMEMORY_AREA MemoryArea;
53 PMMSUPPORT AddressSpace;
54 ULONG Type;
55 PVOID Address;
56 PEPROCESS Process;
57 PMM_PAGEOP PageOp;
58 ULONG Offset;
59 NTSTATUS Status = STATUS_SUCCESS;
60
61 ExAcquireFastMutex(&RmapListLock);
62 entry = MmGetRmapListHeadPage(Page);
63 if (entry == NULL)
64 {
65 ExReleaseFastMutex(&RmapListLock);
66 return(STATUS_UNSUCCESSFUL);
67 }
68 Process = entry->Process;
69
70 Address = entry->Address;
71
72 if ((((ULONG_PTR)Address) & 0xFFF) != 0)
73 {
74 KeBugCheck(MEMORY_MANAGEMENT);
75 }
76
77 if (Address < MmSystemRangeStart)
78 {
79 if (!ExAcquireRundownProtection(&Process->RundownProtect))
80 {
81 ExReleaseFastMutex(&RmapListLock);
82 return STATUS_PROCESS_IS_TERMINATING;
83 }
84
85 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
86 ExReleaseFastMutex(&RmapListLock);
87 if (!NT_SUCCESS(Status))
88 {
89 ExReleaseRundownProtection(&Process->RundownProtect);
90 return Status;
91 }
92 AddressSpace = &Process->Vm;
93 }
94 else
95 {
96 ExReleaseFastMutex(&RmapListLock);
97 AddressSpace = MmGetKernelAddressSpace();
98 }
99
100 MmLockAddressSpace(AddressSpace);
101 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
102 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
103 {
104 MmUnlockAddressSpace(AddressSpace);
105 if (Address < MmSystemRangeStart)
106 {
107 ExReleaseRundownProtection(&Process->RundownProtect);
108 ObDereferenceObject(Process);
109 }
110 return(STATUS_UNSUCCESSFUL);
111 }
112 Type = MemoryArea->Type;
113 if (Type == MEMORY_AREA_SECTION_VIEW)
114 {
115 Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
116 + MemoryArea->Data.SectionData.ViewOffset;
117
118 /*
119 * Get or create a pageop
120 */
121 PageOp = MmGetPageOp(MemoryArea, NULL, 0,
122 MemoryArea->Data.SectionData.Segment,
123 Offset, MM_PAGEOP_PAGEOUT, TRUE);
124 if (PageOp == NULL)
125 {
126 MmUnlockAddressSpace(AddressSpace);
127 if (Address < MmSystemRangeStart)
128 {
129 ExReleaseRundownProtection(&Process->RundownProtect);
130 ObDereferenceObject(Process);
131 }
132 return(STATUS_UNSUCCESSFUL);
133 }
134
135 /*
136 * Release locks now we have a page op.
137 */
138 MmUnlockAddressSpace(AddressSpace);
139
140 /*
141 * Do the actual page out work.
142 */
143 Status = MmPageOutSectionView(AddressSpace, MemoryArea,
144 Address, PageOp);
145 }
146 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
147 {
148 PageOp = MmGetPageOp(MemoryArea, Address < MmSystemRangeStart ? Process->UniqueProcessId : NULL,
149 Address, NULL, 0, MM_PAGEOP_PAGEOUT, TRUE);
150 if (PageOp == NULL)
151 {
152 MmUnlockAddressSpace(AddressSpace);
153 if (Address < MmSystemRangeStart)
154 {
155 ExReleaseRundownProtection(&Process->RundownProtect);
156 ObDereferenceObject(Process);
157 }
158 return(STATUS_UNSUCCESSFUL);
159 }
160
161 /*
162 * Release locks now we have a page op.
163 */
164 MmUnlockAddressSpace(AddressSpace);
165
166 /*
167 * Do the actual page out work.
168 */
169 Status = MmPageOutVirtualMemory(AddressSpace, MemoryArea,
170 Address, PageOp);
171 }
172 else
173 {
174 KeBugCheck(MEMORY_MANAGEMENT);
175 }
176
177 if (Address < MmSystemRangeStart)
178 {
179 ExReleaseRundownProtection(&Process->RundownProtect);
180 ObDereferenceObject(Process);
181 }
182 return(Status);
183 }
184
185 VOID
186 NTAPI
187 MmSetCleanAllRmaps(PFN_NUMBER Page)
188 {
189 PMM_RMAP_ENTRY current_entry;
190
191 ExAcquireFastMutex(&RmapListLock);
192 current_entry = MmGetRmapListHeadPage(Page);
193 if (current_entry == NULL)
194 {
195 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
196 KeBugCheck(MEMORY_MANAGEMENT);
197 }
198 while (current_entry != NULL)
199 {
200 #ifdef NEWCC
201 if (!RMAP_IS_SEGMENT(current_entry->Address))
202 #endif
203 MmSetCleanPage(current_entry->Process, current_entry->Address);
204 current_entry = current_entry->Next;
205 }
206 ExReleaseFastMutex(&RmapListLock);
207 }
208
209 VOID
210 NTAPI
211 MmSetDirtyAllRmaps(PFN_NUMBER Page)
212 {
213 PMM_RMAP_ENTRY current_entry;
214
215 ExAcquireFastMutex(&RmapListLock);
216 current_entry = MmGetRmapListHeadPage(Page);
217 if (current_entry == NULL)
218 {
219 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
220 KeBugCheck(MEMORY_MANAGEMENT);
221 }
222 while (current_entry != NULL)
223 {
224 #ifdef NEWCC
225 if (!RMAP_IS_SEGMENT(current_entry->Address))
226 #endif
227 MmSetDirtyPage(current_entry->Process, current_entry->Address);
228 current_entry = current_entry->Next;
229 }
230 ExReleaseFastMutex(&RmapListLock);
231 }
232
233 BOOLEAN
234 NTAPI
235 MmIsDirtyPageRmap(PFN_NUMBER Page)
236 {
237 PMM_RMAP_ENTRY current_entry;
238
239 ExAcquireFastMutex(&RmapListLock);
240 current_entry = MmGetRmapListHeadPage(Page);
241 if (current_entry == NULL)
242 {
243 ExReleaseFastMutex(&RmapListLock);
244 return(FALSE);
245 }
246 while (current_entry != NULL)
247 {
248 if (
249 #ifdef NEWCC
250 !RMAP_IS_SEGMENT(current_entry->Address) &&
251 #endif
252 MmIsDirtyPage(current_entry->Process, current_entry->Address))
253 {
254 ExReleaseFastMutex(&RmapListLock);
255 return(TRUE);
256 }
257 current_entry = current_entry->Next;
258 }
259 ExReleaseFastMutex(&RmapListLock);
260 return(FALSE);
261 }
262
263 VOID
264 NTAPI
265 MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process,
266 PVOID Address)
267 {
268 PMM_RMAP_ENTRY current_entry;
269 PMM_RMAP_ENTRY new_entry;
270 ULONG PrevSize;
271 #ifdef NEWCC
272 if (!RMAP_IS_SEGMENT(Address))
273 #endif
274 Address = (PVOID)PAGE_ROUND_DOWN(Address);
275
276 new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
277 if (new_entry == NULL)
278 {
279 KeBugCheck(MEMORY_MANAGEMENT);
280 }
281 new_entry->Address = Address;
282 new_entry->Process = (PEPROCESS)Process;
283 #if DBG
284 #ifdef __GNUC__
285 new_entry->Caller = __builtin_return_address(0);
286 #else
287 new_entry->Caller = _ReturnAddress();
288 #endif
289 #endif
290
291 if (
292 #ifdef NEWCC
293 !RMAP_IS_SEGMENT(Address) &&
294 #endif
295 MmGetPfnForProcess(Process, Address) != Page)
296 {
297 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
298 "address 0x%.8X\n", Process->UniqueProcessId, Address,
299 MmGetPfnForProcess(Process, Address) << PAGE_SHIFT,
300 Page << PAGE_SHIFT);
301 KeBugCheck(MEMORY_MANAGEMENT);
302 }
303
304 ExAcquireFastMutex(&RmapListLock);
305 current_entry = MmGetRmapListHeadPage(Page);
306 new_entry->Next = current_entry;
307 #if DBG
308 while (current_entry)
309 {
310 if (current_entry->Address == new_entry->Address && current_entry->Process == new_entry->Process)
311 {
312 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
313 current_entry->Address);
314 DbgPrint("%p", new_entry->Caller);
315 DbgPrint("\n previous caller ");
316 DbgPrint("%p", current_entry->Caller);
317 DbgPrint("\n");
318 KeBugCheck(MEMORY_MANAGEMENT);
319 }
320 current_entry = current_entry->Next;
321 }
322 #endif
323 MmSetRmapListHeadPage(Page, new_entry);
324 ExReleaseFastMutex(&RmapListLock);
325 #ifdef NEWCC
326 if (!RMAP_IS_SEGMENT(Address))
327 #endif
328 {
329 if (Process == NULL)
330 {
331 Process = PsInitialSystemProcess;
332 }
333 if (Process)
334 {
335 PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
336 if (PrevSize >= Process->Vm.PeakWorkingSetSize)
337 {
338 Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
339 }
340 }
341 }
342 }
343
344 VOID
345 NTAPI
346 MmDeleteAllRmaps(PFN_NUMBER Page, PVOID Context,
347 VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
348 PVOID Address))
349 {
350 PMM_RMAP_ENTRY current_entry;
351 PMM_RMAP_ENTRY previous_entry;
352 PEPROCESS Process;
353
354 ExAcquireFastMutex(&RmapListLock);
355 current_entry = MmGetRmapListHeadPage(Page);
356 if (current_entry == NULL)
357 {
358 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
359 KeBugCheck(MEMORY_MANAGEMENT);
360 }
361 MmSetRmapListHeadPage(Page, NULL);
362 ExReleaseFastMutex(&RmapListLock);
363 while (current_entry != NULL)
364 {
365 previous_entry = current_entry;
366 current_entry = current_entry->Next;
367 #ifdef NEWCC
368 if (!RMAP_IS_SEGMENT(previous_entry->Address))
369 #endif
370 {
371 if (DeleteMapping)
372 {
373 DeleteMapping(Context, previous_entry->Process,
374 previous_entry->Address);
375 }
376 Process = previous_entry->Process;
377 ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
378 if (Process == NULL)
379 {
380 Process = PsInitialSystemProcess;
381 }
382 if (Process)
383 {
384 (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
385 }
386 }
387 #ifdef NEWCC
388 else
389 {
390 ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
391 }
392 #endif
393 }
394 }
395
396 VOID
397 NTAPI
398 MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process,
399 PVOID Address)
400 {
401 PMM_RMAP_ENTRY current_entry, previous_entry;
402
403 ExAcquireFastMutex(&RmapListLock);
404 previous_entry = NULL;
405 current_entry = MmGetRmapListHeadPage(Page);
406
407 while (current_entry != NULL)
408 {
409 if (current_entry->Process == (PEPROCESS)Process &&
410 current_entry->Address == Address)
411 {
412 if (previous_entry == NULL)
413 {
414 MmSetRmapListHeadPage(Page, current_entry->Next);
415 }
416 else
417 {
418 previous_entry->Next = current_entry->Next;
419 }
420 ExReleaseFastMutex(&RmapListLock);
421 ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
422 #ifdef NEWCC
423 if (!RMAP_IS_SEGMENT(Address))
424 #endif
425 {
426 if (Process == NULL)
427 {
428 Process = PsInitialSystemProcess;
429 }
430 if (Process)
431 {
432 (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
433 }
434 }
435 return;
436 }
437 previous_entry = current_entry;
438 current_entry = current_entry->Next;
439 }
440 KeBugCheck(MEMORY_MANAGEMENT);
441 }
442
443 #ifdef NEWCC
444 PVOID
445 NTAPI
446 MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset)
447 {
448 PCACHE_SECTION_PAGE_TABLE Result = NULL;
449 PMM_RMAP_ENTRY current_entry, previous_entry;
450
451 ExAcquireFastMutex(&RmapListLock);
452 previous_entry = NULL;
453 current_entry = MmGetRmapListHeadPage(Page);
454 while (current_entry != NULL)
455 {
456 if (RMAP_IS_SEGMENT(current_entry->Address))
457 {
458 Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process;
459 *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK;
460 InterlockedIncrementUL(&Result->Segment->ReferenceCount);
461 ExReleaseFastMutex(&RmapListLock);
462 return Result;
463 }
464 previous_entry = current_entry;
465 current_entry = current_entry->Next;
466 }
467 ExReleaseFastMutex(&RmapListLock);
468 return NULL;
469 }
470
471 VOID
472 NTAPI
473 MmDeleteSectionAssociation(PFN_NUMBER Page)
474 {
475 PMM_RMAP_ENTRY current_entry, previous_entry;
476
477 ExAcquireFastMutex(&RmapListLock);
478 previous_entry = NULL;
479 current_entry = MmGetRmapListHeadPage(Page);
480 while (current_entry != NULL)
481 {
482 if (RMAP_IS_SEGMENT(current_entry->Address))
483 {
484 if (previous_entry == NULL)
485 {
486 MmSetRmapListHeadPage(Page, current_entry->Next);
487 }
488 else
489 {
490 previous_entry->Next = current_entry->Next;
491 }
492 ExReleaseFastMutex(&RmapListLock);
493 ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
494 return;
495 }
496 previous_entry = current_entry;
497 current_entry = current_entry->Next;
498 }
499 ExReleaseFastMutex(&RmapListLock);
500 }
501 #endif