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