ReactOS  0.4.15-dev-2704-gd5265b0
rmap.c
Go to the documentation of this file.
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 #include <cache/section/newmm.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* TYPES ********************************************************************/
18 
19 /* GLOBALS ******************************************************************/
20 
22 
23 /* FUNCTIONS ****************************************************************/
24 
26 static
27 VOID
28 NTAPI
29 RmapListFree(
31 {
33 }
34 
35 CODE_SEG("INIT")
36 VOID
37 NTAPI
39 {
41  NULL,
42  RmapListFree,
43  0,
44  sizeof(MM_RMAP_ENTRY),
45  TAG_RMAP,
46  50);
47 }
48 
50 NTAPI
52 {
56  PVOID Address = NULL;
60  LARGE_INTEGER SegmentOffset;
61  KIRQL OldIrql;
62 
63 GetEntry:
65 
67 
68  while (entry && RMAP_IS_SEGMENT(entry->Address))
69  entry = entry->Next;
70 
71  if (entry == NULL)
72  {
74  goto WriteSegment;
75  }
76 
77  Process = entry->Process;
78  Address = entry->Address;
79 
80  if ((((ULONG_PTR)Address) & 0xFFF) != 0)
81  {
82  KeBugCheck(MEMORY_MANAGEMENT);
83  }
84 
85  /* This is for user-mode address only */
87 
88  if (!ExAcquireRundownProtection(&Process->RundownProtect))
89  {
92  }
93 
96  if (!NT_SUCCESS(Status))
97  {
98  ExReleaseRundownProtection(&Process->RundownProtect);
99  return Status;
100  }
101  AddressSpace = &Process->Vm;
102 
104 
107  {
109  ExReleaseRundownProtection(&Process->RundownProtect);
111  goto GetEntry;
112  }
113 
114 
115  /* Attach to it, if needed */
118  KeAttachProcess(&Process->Pcb);
119 
121  {
122  /* This changed in the short window where we didn't have any locks */
124  KeDetachProcess();
126  ExReleaseRundownProtection(&Process->RundownProtect);
128  goto GetEntry;
129  }
130 
132  {
134  BOOLEAN Dirty;
135  PFN_NUMBER MapPage;
137  BOOLEAN Released;
138 
139  Offset.QuadPart = MemoryArea->SectionData.ViewOffset +
141 
142  Segment = MemoryArea->SectionData.Segment;
143 
145 
147  if (Entry && MM_IS_WAIT_PTE(Entry))
148  {
149  /* The segment is being read or something. Give up */
152  KeDetachProcess();
154  ExReleaseRundownProtection(&Process->RundownProtect);
156  return(STATUS_UNSUCCESSFUL);
157  }
158 
159  /* Delete this virtual mapping in the process */
161  MmDeleteVirtualMapping(Process, Address, &Dirty, &MapPage);
162 
163  /* We checked this earlier */
164  ASSERT(MapPage == Page);
165 
166  if (Page != PFN_FROM_SSE(Entry))
167  {
168  SWAPENTRY SwapEntry;
169 
170  /* This page is private to the process */
172 
173  /* Check if we should write it back to the page file */
174  SwapEntry = MmGetSavedSwapEntryPage(Page);
175 
176  if ((SwapEntry == 0) && Dirty)
177  {
178  /* We don't have a Swap entry, yet the page is dirty. Get one */
179  SwapEntry = MmAllocSwapPage();
180  if (!SwapEntry)
181  {
183  &MemoryArea->SectionData.RegionListHead,
184  Address, NULL);
185 
186  /* We can't, so let this page in the Process VM */
190 
193  KeDetachProcess();
194  ExReleaseRundownProtection(&Process->RundownProtect);
196 
197  return STATUS_UNSUCCESSFUL;
198  }
199  }
200 
201  if (Dirty)
202  {
203  SWAPENTRY Dummy;
204 
205  /* Put a wait entry into the process and unlock */
206  MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
208 
209  Status = MmWriteToSwapPage(SwapEntry, Page);
210 
213  ASSERT(Dummy == MM_WAIT_ENTRY);
214 
215  if (!NT_SUCCESS(Status))
216  {
217  /* We failed at saving the content of this page. Keep it in */
219  &MemoryArea->SectionData.RegionListHead,
220  Address, NULL);
221 
222  /* This Swap Entry is useless to us */
224  MmFreeSwapPage(SwapEntry);
225 
226  /* We can't, so let this page in the Process VM */
230 
233  KeDetachProcess();
234  ExReleaseRundownProtection(&Process->RundownProtect);
236 
237  return STATUS_UNSUCCESSFUL;
238  }
239  }
240 
241  if (SwapEntry)
242  {
243  /* Keep this in the process VM */
246  }
247 
248  /* We can finally let this page go */
251  KeDetachProcess();
252 #if DBG
256 #endif
258 
259  ExReleaseRundownProtection(&Process->RundownProtect);
261 
262  return STATUS_SUCCESS;
263  }
264 
265  /* One less mapping referencing this segment */
267 
270  KeDetachProcess();
272 
273  ExReleaseRundownProtection(&Process->RundownProtect);
275 
276  if (Released) return STATUS_SUCCESS;
277  }
278 #ifdef NEWCC
279  else if (Type == MEMORY_AREA_CACHE)
280  {
281  /* NEWCC does locking itself */
284  }
285 #endif
286  else
287  {
288  KeBugCheck(MEMORY_MANAGEMENT);
289  }
290 
291 WriteSegment:
292  /* Now write this page to file, if needed */
293  Segment = MmGetSectionAssociation(Page, &SegmentOffset);
294  if (Segment)
295  {
296  BOOLEAN Released;
297 
299 
300  Released = MmCheckDirtySegment(Segment, &SegmentOffset, FALSE, TRUE);
301 
303 
305 
306  if (Released)
307  {
308  return STATUS_SUCCESS;
309  }
310  }
311 
312  /* If we are here, then we didn't release the page */
313  return STATUS_UNSUCCESSFUL;
314 }
315 
316 VOID
317 NTAPI
319  PVOID Address)
320 {
321  PMM_RMAP_ENTRY current_entry;
322  PMM_RMAP_ENTRY new_entry;
323  ULONG PrevSize;
324  KIRQL OldIrql;
325 
326  if (!RMAP_IS_SEGMENT(Address))
328 
329  new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
330  if (new_entry == NULL)
331  {
332  KeBugCheck(MEMORY_MANAGEMENT);
333  }
334  new_entry->Address = Address;
335  new_entry->Process = (PEPROCESS)Process;
336 #if DBG
337  new_entry->Caller = _ReturnAddress();
338 #endif
339 
340  if (
343  {
344  DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
345  "address 0x%.8X\n", Process ? Process->UniqueProcessId : 0,
346  Address,
348  Page << PAGE_SHIFT);
349  KeBugCheck(MEMORY_MANAGEMENT);
350  }
351 
353  current_entry = MmGetRmapListHeadPage(Page);
354 
355  PMM_RMAP_ENTRY previous_entry = NULL;
356  /* Keep the list sorted */
357  while (current_entry && (current_entry->Address < Address))
358  {
359  previous_entry = current_entry;
360  current_entry = current_entry->Next;
361  }
362 
363  /* In case of clash in the address, sort by process */
364  if (current_entry && (current_entry->Address == Address))
365  {
366  while (current_entry && (current_entry->Process < Process))
367  {
368  previous_entry = current_entry;
369  current_entry = current_entry->Next;
370  }
371  }
372 
373  if (current_entry && (current_entry->Address == Address) && (current_entry->Process == Process))
374  {
375 #if DBG
376  DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n", current_entry->Address);
377  DbgPrint(" current caller %p\n", new_entry->Caller);
378  DbgPrint(" previous caller %p\n", current_entry->Caller);
379 #endif
380  KeBugCheck(MEMORY_MANAGEMENT);
381  }
382 
383  new_entry->Next = current_entry;
384  if (previous_entry)
385  previous_entry->Next = new_entry;
386  else
387  MmSetRmapListHeadPage(Page, new_entry);
388 
390 
391  if (!RMAP_IS_SEGMENT(Address))
392  {
393  ASSERT(Process != NULL);
394  PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
395  if (PrevSize >= Process->Vm.PeakWorkingSetSize)
396  {
397  Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
398  }
399  }
400 }
401 
402 VOID
403 NTAPI
405  PVOID Address)
406 {
407  PMM_RMAP_ENTRY current_entry, previous_entry;
408  KIRQL OldIrql;
409 
411  previous_entry = NULL;
412  current_entry = MmGetRmapListHeadPage(Page);
413 
414  while (current_entry != NULL)
415  {
416  if (current_entry->Process == (PEPROCESS)Process &&
417  current_entry->Address == Address)
418  {
419  if (previous_entry == NULL)
420  {
421  MmSetRmapListHeadPage(Page, current_entry->Next);
422  }
423  else
424  {
425  previous_entry->Next = current_entry->Next;
426  }
428 
429  ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
430  if (!RMAP_IS_SEGMENT(Address))
431  {
432  ASSERT(Process != NULL);
433  (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
434  }
435  return;
436  }
437  previous_entry = current_entry;
438  current_entry = current_entry->Next;
439  }
440  KeBugCheck(MEMORY_MANAGEMENT);
441 }
442 
443 /*
444 
445 Return the process pointer given when a previous call to MmInsertRmap was
446 called with a process and address pointer that conform to the segment rmap
447 schema. In short, this requires the address part to be 0xffffff00 + n
448 where n is between 0 and 255. When such an rmap exists, it specifies a
449 segment rmap in which the process part is a pointer to a slice of a section
450 page table, and the low 8 bits of the address represent a page index in the
451 page table slice. Together, this information is used by
452 MmGetSectionAssociation to determine which page entry points to this page in
453 the segment page table.
454 
455 */
456 
457 PVOID
458 NTAPI
460 {
462  PMM_RMAP_ENTRY current_entry;//, previous_entry;
464 
465  //previous_entry = NULL;
466  current_entry = MmGetRmapListHeadPage(Page);
467  while (current_entry != NULL)
468  {
469  if (RMAP_IS_SEGMENT(current_entry->Address))
470  {
471  Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process;
472  *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK;
473  if (*Result->Segment->Flags & MM_SEGMENT_INDELETE)
474  {
476  return NULL;
477  }
478 
479  InterlockedIncrement64(Result->Segment->ReferenceCount);
481  return Result;
482  }
483  //previous_entry = current_entry;
484  current_entry = current_entry->Next;
485  }
487  return NULL;
488 }
489 
490 /*
491 
492 Remove the section rmap associated with the indicated page, if it exists.
493 
494 */
495 
496 VOID
497 NTAPI
499 {
500  PMM_RMAP_ENTRY current_entry, previous_entry;
502 
503  previous_entry = NULL;
504  current_entry = MmGetRmapListHeadPage(Page);
505  while (current_entry != NULL)
506  {
507  if (RMAP_IS_SEGMENT(current_entry->Address))
508  {
509  if (previous_entry == NULL)
510  {
511  MmSetRmapListHeadPage(Page, current_entry->Next);
512  }
513  else
514  {
515  previous_entry->Next = current_entry->Next;
516  }
518  ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
519  return;
520  }
521  previous_entry = current_entry;
522  current_entry = current_entry->Next;
523  }
525 }
PMM_REGION NTAPI MmFindRegion(PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID Address, PVOID *RegionBaseAddress)
Definition: region.c:257
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
VOID NTAPI MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process, PVOID Address)
Definition: rmap.c:404
#define MmGetPageEntrySectionSegment(S, O)
Definition: mm.h:1488
PEPROCESS Process
Definition: mm.h:240
struct LOOKASIDE_ALIGN _NPAGED_LOOKASIDE_LIST NPAGED_LOOKASIDE_LIST
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
ULONG Type
Definition: mm.h:223
#define PROCESS_ALL_ACCESS
Definition: nt_native.h:1324
struct _Entry Entry
Definition: kefuncs.h:627
#define DbgPrint
Definition: loader.c:25
NTKERNELAPI VOID FASTCALL ExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RunRef)
#define TRUE
Definition: types.h:120
#define MC_USER
Definition: mm.h:96
struct _MM_RMAP_ENTRY *NTAPI MmGetRmapListHeadPage(PFN_NUMBER Page)
Definition: freelist.c:458
#define PFN_FROM_SSE(E)
Definition: mm.h:1273
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2272
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1568
struct _MEMORY_AREA::@1782 SectionData
Definition: mm.h:433
LONG NTSTATUS
Definition: precomp.h:26
struct _EPROCESS * PEPROCESS
Definition: nt_native.h:30
#define ExAcquireRundownProtection
Definition: ex.h:133
NTSTATUS NTAPI MmReleasePageMemoryConsumer(ULONG Consumer, PFN_NUMBER Page)
Definition: balance.c:78
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:930
NTSTATUS NTAPI MmCreateVirtualMapping(struct _EPROCESS *Process, PVOID Address, ULONG flProtect, PFN_NUMBER Page)
NTSTATUS NTAPI MmCreatePageFileMapping(struct _EPROCESS *Process, PVOID Address, SWAPENTRY SwapEntry)
BOOLEAN NTAPI MmUnsharePageEntrySectionSegment(PMEMORY_AREA MemoryArea, PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset, BOOLEAN Dirty, BOOLEAN PageOut, ULONG_PTR *InEntry)
Definition: section.c:1085
struct _CACHE_SECTION_PAGE_TABLE * PCACHE_SECTION_PAGE_TABLE
VOID NTAPI MmDeleteSectionAssociation(PFN_NUMBER Page)
Definition: rmap.c:498
VOID NTAPI MmDeletePageFileMapping(struct _EPROCESS *Process, PVOID Address, SWAPENTRY *SwapEntry)
BOOLEAN NTAPI MmCheckDirtySegment(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset, BOOLEAN ForceDirty, BOOLEAN PageOut)
PMEMORY_AREA NTAPI MmLocateMemoryAreaByAddress(PMMSUPPORT AddressSpace, PVOID Address)
Definition: marea.c:60
#define MmLockSectionSegment(x)
Definition: mm.h:1298
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:937
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define MmSetDirtyPage(__P, __A)
Definition: mm.h:1166
PVOID NTAPI MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset)
Definition: rmap.c:459
UCHAR KIRQL
Definition: env_spec_w32.h:591
ULONG PFN_NUMBER
Definition: ke.h:9
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
PEPROCESS PsInitialSystemProcess
Definition: psmgr.c:50
_IRQL_requires_max_(DISPATCH_LEVEL)
Definition: rmap.c:25
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1427
NTSTATUS NTAPI MmpPageOutPhysicalAddress(PFN_NUMBER Page)
Definition: swapout.c:345
#define PsGetCurrentProcess
Definition: psfuncs.h:17
VOID NTAPI MmInitializeRmapList(VOID)
Definition: rmap.c:38
unsigned char BOOLEAN
static WCHAR Address[46]
Definition: ping.c:68
VOID NTAPI MmDeleteVirtualMapping(struct _EPROCESS *Process, PVOID Address, BOOLEAN *WasDirty, PPFN_NUMBER Page)
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
NTSTATUS NTAPI ObReferenceObjectByPointer(IN PVOID Object, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode)
Definition: obref.c:381
PFN_NUMBER Page
Definition: section.c:4757
CODE_SEG("INIT")
Definition: Interface.c:1810
void * PVOID
Definition: retypes.h:9
#define MM_IS_WAIT_PTE(E)
Definition: mm.h:1275
#define MEMORY_AREA_SECTION_VIEW
Definition: mm.h:75
#define MmUnlockSectionSegment(x)
Definition: mm.h:1306
VOID NTAPI MmSetRmapListHeadPage(PFN_NUMBER Page, struct _MM_RMAP_ENTRY *ListHead)
_Inout_ PVOID Segment
Definition: exfuncs.h:1101
Status
Definition: gdiplustypes.h:24
#define InterlockedIncrement64
Definition: interlocked.h:211
VOID NTAPI ExInitializeNPagedLookasideList(IN PNPAGED_LOOKASIDE_LIST Lookaside, IN PALLOCATE_FUNCTION Allocate OPTIONAL, IN PFREE_FUNCTION Free OPTIONAL, IN ULONG Flags, IN SIZE_T Size, IN ULONG Tag, IN USHORT Depth)
Definition: lookas.c:218
#define ASSERT(a)
Definition: mode.c:44
PMM_SECTION_SEGMENT NTAPI MmGetSectionAssociation(PFN_NUMBER Page, PLARGE_INTEGER Offset)
Definition: sptab.c:352
#define TAG_RMAP
Definition: tag.h:133
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
SWAPENTRY NTAPI MmAllocSwapPage(VOID)
Definition: pagefile.c:304
#define InterlockedExchangeAddUL(Addend, Value)
Definition: ex.h:1531
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:502
#define ObDereferenceObject
Definition: obfuncs.h:203
BOOLEAN DeleteInProgress
Definition: mm.h:225
#define RMAP_SEGMENT_MASK
Definition: mm.h:874
Type
Definition: Type.h:6
#define RMAP_IS_SEGMENT(x)
Definition: mm.h:875
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
VOID NTAPI KeDetachProcess(VOID)
Definition: procobj.c:618
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:790
uint32_t entry
Definition: isohybrid.c:63
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define P(row, col)
#define MA_GetStartingAddress(_MemoryArea)
Definition: mm.h:216
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define _In_
Definition: no_sal2.h:158
PFN_NUMBER NTAPI MmGetPfnForProcess(struct _EPROCESS *Process, PVOID Address)
VOID NTAPI KeAttachProcess(IN PKPROCESS Process)
Definition: procobj.c:579
ULONG_PTR SWAPENTRY
Definition: mm.h:51
#define MM_SEGMENT_INDELETE
Definition: mm.h:212
unsigned int * PULONG
Definition: retypes.h:1
VOID NTAPI MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process, PVOID Address)
Definition: rmap.c:318
#define NULL
Definition: types.h:112
#define __drv_freesMem(kind)
Definition: driverspecs.h:254
struct _MM_RMAP_ENTRY * Next
Definition: mm.h:239
#define DPRINT1
Definition: precomp.h:8
VOID NTAPI MmSetSavedSwapEntryPage(PFN_NUMBER Page, SWAPENTRY SavedSwapEntry)
Definition: freelist.c:483
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
void * _ReturnAddress(void)
unsigned int ULONG
Definition: retypes.h:1
Definition: mm.h:237
#define ULONG_PTR
Definition: config.h:101
NTSTATUS NTAPI MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
Definition: pagefile.c:130
VOID NTAPI MmDereferenceSegment(PMM_SECTION_SEGMENT Segment)
Definition: section.c:992
static NPAGED_LOOKASIDE_LIST RmapLookasideList
Definition: rmap.c:21
PVOID Address
Definition: mm.h:241
#define STATUS_SUCCESS
Definition: shellext.h:65
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
NTSTATUS NTAPI MmPageOutPhysicalAddress(PFN_NUMBER Page)
Definition: rmap.c:51
struct _MEMORY_AREA * MemoryArea
Definition: newmm.h:37
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1561
#define MmSystemRangeStart
Definition: mm.h:32
base of all file and directory entries
Definition: entries.h:82
VOID NTAPI MmFreeSwapPage(SWAPENTRY Entry)
Definition: pagefile.c:274
SWAPENTRY NTAPI MmGetSavedSwapEntryPage(PFN_NUMBER Page)
Definition: freelist.c:499