sync with trunk r49322
[reactos.git] / 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 #define NDEBUG
14 #include <debug.h>
15
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, MmInitializeRmapList)
18 #endif
19
20 /* TYPES ********************************************************************/
21
22 /* GLOBALS ******************************************************************/
23
24 static FAST_MUTEX RmapListLock;
25 static NPAGED_LOOKASIDE_LIST RmapLookasideList;
26
27 /* FUNCTIONS ****************************************************************/
28
29 VOID
30 INIT_FUNCTION
31 NTAPI
32 MmInitializeRmapList(VOID)
33 {
34 ExInitializeFastMutex(&RmapListLock);
35 ExInitializeNPagedLookasideList (&RmapLookasideList,
36 NULL,
37 NULL,
38 0,
39 sizeof(MM_RMAP_ENTRY),
40 TAG_RMAP,
41 50);
42 }
43
44 NTSTATUS
45 NTAPI
46 MmPageOutPhysicalAddress(PFN_NUMBER Page)
47 {
48 PMM_RMAP_ENTRY entry;
49 PMEMORY_AREA MemoryArea;
50 PMMSUPPORT AddressSpace;
51 ULONG Type;
52 PVOID Address;
53 PEPROCESS Process;
54 PMM_PAGEOP PageOp;
55 ULONG Offset;
56 NTSTATUS Status = STATUS_SUCCESS;
57
58 ExAcquireFastMutex(&RmapListLock);
59 entry = MmGetRmapListHeadPage(Page);
60 if (entry == NULL)
61 {
62 ExReleaseFastMutex(&RmapListLock);
63 return(STATUS_UNSUCCESSFUL);
64 }
65 Process = entry->Process;
66
67 Address = entry->Address;
68 if ((((ULONG_PTR)Address) & 0xFFF) != 0)
69 {
70 KeBugCheck(MEMORY_MANAGEMENT);
71 }
72
73 if (Address < MmSystemRangeStart)
74 {
75 if (!ExAcquireRundownProtection(&Process->RundownProtect))
76 {
77 ExReleaseFastMutex(&RmapListLock);
78 return STATUS_PROCESS_IS_TERMINATING;
79 }
80
81 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
82 ExReleaseFastMutex(&RmapListLock);
83 if (!NT_SUCCESS(Status))
84 {
85 ExReleaseRundownProtection(&Process->RundownProtect);
86 return Status;
87 }
88 AddressSpace = &Process->Vm;
89 }
90 else
91 {
92 ExReleaseFastMutex(&RmapListLock);
93 AddressSpace = MmGetKernelAddressSpace();
94 }
95
96 MmLockAddressSpace(AddressSpace);
97 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
98 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
99 {
100 MmUnlockAddressSpace(AddressSpace);
101 if (Address < MmSystemRangeStart)
102 {
103 ExReleaseRundownProtection(&Process->RundownProtect);
104 ObDereferenceObject(Process);
105 }
106 return(STATUS_UNSUCCESSFUL);
107 }
108 Type = MemoryArea->Type;
109 if (Type == MEMORY_AREA_SECTION_VIEW)
110 {
111 Offset = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
112 + MemoryArea->Data.SectionData.ViewOffset;
113
114 /*
115 * Get or create a pageop
116 */
117 PageOp = MmGetPageOp(MemoryArea, NULL, 0,
118 MemoryArea->Data.SectionData.Segment,
119 Offset, MM_PAGEOP_PAGEOUT, TRUE);
120 if (PageOp == NULL)
121 {
122 MmUnlockAddressSpace(AddressSpace);
123 if (Address < MmSystemRangeStart)
124 {
125 ExReleaseRundownProtection(&Process->RundownProtect);
126 ObDereferenceObject(Process);
127 }
128 return(STATUS_UNSUCCESSFUL);
129 }
130
131 /*
132 * Release locks now we have a page op.
133 */
134 MmUnlockAddressSpace(AddressSpace);
135
136 /*
137 * Do the actual page out work.
138 */
139 Status = MmPageOutSectionView(AddressSpace, MemoryArea,
140 Address, PageOp);
141 }
142 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
143 {
144 PageOp = MmGetPageOp(MemoryArea, Address < MmSystemRangeStart ? Process->UniqueProcessId : NULL,
145 Address, NULL, 0, MM_PAGEOP_PAGEOUT, TRUE);
146 if (PageOp == NULL)
147 {
148 MmUnlockAddressSpace(AddressSpace);
149 if (Address < MmSystemRangeStart)
150 {
151 ExReleaseRundownProtection(&Process->RundownProtect);
152 ObDereferenceObject(Process);
153 }
154 return(STATUS_UNSUCCESSFUL);
155 }
156
157 /*
158 * Release locks now we have a page op.
159 */
160 MmUnlockAddressSpace(AddressSpace);
161
162 /*
163 * Do the actual page out work.
164 */
165 Status = MmPageOutVirtualMemory(AddressSpace, MemoryArea,
166 Address, PageOp);
167 }
168 else
169 {
170 KeBugCheck(MEMORY_MANAGEMENT);
171 }
172
173 if (Address < MmSystemRangeStart)
174 {
175 ExReleaseRundownProtection(&Process->RundownProtect);
176 ObDereferenceObject(Process);
177 }
178 return(Status);
179 }
180
181 VOID
182 NTAPI
183 MmSetCleanAllRmaps(PFN_NUMBER Page)
184 {
185 PMM_RMAP_ENTRY current_entry;
186
187 ExAcquireFastMutex(&RmapListLock);
188 current_entry = MmGetRmapListHeadPage(Page);
189 if (current_entry == NULL)
190 {
191 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
192 KeBugCheck(MEMORY_MANAGEMENT);
193 }
194 while (current_entry != NULL)
195 {
196 MmSetCleanPage(current_entry->Process, current_entry->Address);
197 current_entry = current_entry->Next;
198 }
199 ExReleaseFastMutex(&RmapListLock);
200 }
201
202 VOID
203 NTAPI
204 MmSetDirtyAllRmaps(PFN_NUMBER Page)
205 {
206 PMM_RMAP_ENTRY current_entry;
207
208 ExAcquireFastMutex(&RmapListLock);
209 current_entry = MmGetRmapListHeadPage(Page);
210 if (current_entry == NULL)
211 {
212 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
213 KeBugCheck(MEMORY_MANAGEMENT);
214 }
215 while (current_entry != NULL)
216 {
217 MmSetDirtyPage(current_entry->Process, current_entry->Address);
218 current_entry = current_entry->Next;
219 }
220 ExReleaseFastMutex(&RmapListLock);
221 }
222
223 BOOLEAN
224 NTAPI
225 MmIsDirtyPageRmap(PFN_NUMBER Page)
226 {
227 PMM_RMAP_ENTRY current_entry;
228
229 ExAcquireFastMutex(&RmapListLock);
230 current_entry = MmGetRmapListHeadPage(Page);
231 if (current_entry == NULL)
232 {
233 ExReleaseFastMutex(&RmapListLock);
234 return(FALSE);
235 }
236 while (current_entry != NULL)
237 {
238 if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
239 {
240 ExReleaseFastMutex(&RmapListLock);
241 return(TRUE);
242 }
243 current_entry = current_entry->Next;
244 }
245 ExReleaseFastMutex(&RmapListLock);
246 return(FALSE);
247 }
248
249 VOID
250 NTAPI
251 MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process,
252 PVOID Address)
253 {
254 PMM_RMAP_ENTRY current_entry;
255 PMM_RMAP_ENTRY new_entry;
256 ULONG PrevSize;
257
258 Address = (PVOID)PAGE_ROUND_DOWN(Address);
259
260 new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
261 if (new_entry == NULL)
262 {
263 KeBugCheck(MEMORY_MANAGEMENT);
264 }
265 new_entry->Address = Address;
266 new_entry->Process = (PEPROCESS)Process;
267 #if DBG
268 #ifdef __GNUC__
269 new_entry->Caller = __builtin_return_address(0);
270 #else
271 new_entry->Caller = _ReturnAddress();
272 #endif
273 #endif
274
275 if (MmGetPfnForProcess(Process, Address) != Page)
276 {
277 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
278 "address 0x%.8X\n", Process->UniqueProcessId, Address,
279 MmGetPfnForProcess(Process, Address) << PAGE_SHIFT,
280 Page << PAGE_SHIFT);
281 KeBugCheck(MEMORY_MANAGEMENT);
282 }
283
284 ExAcquireFastMutex(&RmapListLock);
285 current_entry = MmGetRmapListHeadPage(Page);
286 new_entry->Next = current_entry;
287 #if DBG
288 while (current_entry)
289 {
290 if (current_entry->Address == new_entry->Address && current_entry->Process == new_entry->Process)
291 {
292 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
293 current_entry->Address);
294 DbgPrint("%p", new_entry->Caller);
295 DbgPrint("\n previous caller ");
296 DbgPrint("%p", current_entry->Caller);
297 DbgPrint("\n");
298 KeBugCheck(MEMORY_MANAGEMENT);
299 }
300 current_entry = current_entry->Next;
301 }
302 #endif
303 MmSetRmapListHeadPage(Page, new_entry);
304 ExReleaseFastMutex(&RmapListLock);
305 if (Process == NULL)
306 {
307 Process = PsInitialSystemProcess;
308 }
309 if (Process)
310 {
311 PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
312 if (PrevSize >= Process->Vm.PeakWorkingSetSize)
313 {
314 Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
315 }
316 }
317 }
318
319 VOID
320 NTAPI
321 MmDeleteAllRmaps(PFN_NUMBER Page, PVOID Context,
322 VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
323 PVOID Address))
324 {
325 PMM_RMAP_ENTRY current_entry;
326 PMM_RMAP_ENTRY previous_entry;
327 PEPROCESS Process;
328
329 ExAcquireFastMutex(&RmapListLock);
330 current_entry = MmGetRmapListHeadPage(Page);
331 if (current_entry == NULL)
332 {
333 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
334 KeBugCheck(MEMORY_MANAGEMENT);
335 }
336 MmSetRmapListHeadPage(Page, NULL);
337 ExReleaseFastMutex(&RmapListLock);
338 while (current_entry != NULL)
339 {
340 previous_entry = current_entry;
341 current_entry = current_entry->Next;
342 if (DeleteMapping)
343 {
344 DeleteMapping(Context, previous_entry->Process,
345 previous_entry->Address);
346 }
347 Process = previous_entry->Process;
348 ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
349 if (Process == NULL)
350 {
351 Process = PsInitialSystemProcess;
352 }
353 if (Process)
354 {
355 (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
356 }
357 }
358 }
359
360 VOID
361 NTAPI
362 MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process,
363 PVOID Address)
364 {
365 PMM_RMAP_ENTRY current_entry, previous_entry;
366
367 ExAcquireFastMutex(&RmapListLock);
368 previous_entry = NULL;
369 current_entry = MmGetRmapListHeadPage(Page);
370
371 while (current_entry != NULL)
372 {
373 if (current_entry->Process == (PEPROCESS)Process &&
374 current_entry->Address == Address)
375 {
376 if (previous_entry == NULL)
377 {
378 MmSetRmapListHeadPage(Page, current_entry->Next);
379 }
380 else
381 {
382 previous_entry->Next = current_entry->Next;
383 }
384 ExReleaseFastMutex(&RmapListLock);
385 ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
386 if (Process == NULL)
387 {
388 Process = PsInitialSystemProcess;
389 }
390 if (Process)
391 {
392 (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
393 }
394 return;
395 }
396 previous_entry = current_entry;
397 current_entry = current_entry->Next;
398 }
399 KeBugCheck(MEMORY_MANAGEMENT);
400 }