Sync with trunk (r47116), hopefully without breaking anything.
[reactos.git] / ntoskrnl / mm / pageop.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/pageop.c
5 * PURPOSE: No purpose listed.
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, MmInitializePageOp)
18 #endif
19
20
21 /* GLOBALS *******************************************************************/
22
23 #define PAGEOP_HASH_TABLE_SIZE (32)
24
25 static KSPIN_LOCK MmPageOpHashTableLock;
26 static PMM_PAGEOP MmPageOpHashTable[PAGEOP_HASH_TABLE_SIZE];
27 static NPAGED_LOOKASIDE_LIST MmPageOpLookasideList;
28
29 /* FUNCTIONS *****************************************************************/
30
31 VOID
32 NTAPI
33 MmReleasePageOp(PMM_PAGEOP PageOp)
34 /*
35 * FUNCTION: Release a reference to a page operation descriptor
36 */
37 {
38 KIRQL oldIrql;
39 PMM_PAGEOP PrevPageOp;
40
41 KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
42 PageOp->ReferenceCount--;
43 if (PageOp->ReferenceCount > 0)
44 {
45 KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
46 return;
47 }
48 (void)InterlockedDecrementUL(&PageOp->MArea->PageOpCount);
49 PrevPageOp = MmPageOpHashTable[PageOp->Hash];
50 if (PrevPageOp == PageOp)
51 {
52 MmPageOpHashTable[PageOp->Hash] = PageOp->Next;
53 KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
54 ExFreeToNPagedLookasideList(&MmPageOpLookasideList, PageOp);
55 return;
56 }
57 while (PrevPageOp->Next != NULL)
58 {
59 if (PrevPageOp->Next == PageOp)
60 {
61 PrevPageOp->Next = PageOp->Next;
62 KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
63 ExFreeToNPagedLookasideList(&MmPageOpLookasideList, PageOp);
64 return;
65 }
66 PrevPageOp = PrevPageOp->Next;
67 }
68 KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
69 KeBugCheck(MEMORY_MANAGEMENT);
70 }
71
72 PMM_PAGEOP
73 NTAPI
74 MmCheckForPageOp(PMEMORY_AREA MArea, HANDLE Pid, PVOID Address,
75 PMM_SECTION_SEGMENT Segment, ULONG Offset)
76 {
77 ULONG_PTR Hash;
78 KIRQL oldIrql;
79 PMM_PAGEOP PageOp;
80
81 /*
82 * Calcuate the hash value for pageop structure
83 */
84 if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
85 {
86 Hash = (((ULONG_PTR)Segment) | (((ULONG_PTR)Offset) / PAGE_SIZE));
87 }
88 else
89 {
90 Hash = (((ULONG_PTR)Pid) | (((ULONG_PTR)Address) / PAGE_SIZE));
91 }
92 Hash = Hash % PAGEOP_HASH_TABLE_SIZE;
93
94 KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
95
96 /*
97 * Check for an existing pageop structure
98 */
99 PageOp = MmPageOpHashTable[Hash];
100 while (PageOp != NULL)
101 {
102 if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
103 {
104 if (PageOp->Segment == Segment &&
105 PageOp->Offset == Offset)
106 {
107 break;
108 }
109 }
110 else
111 {
112 if (PageOp->Pid == Pid &&
113 PageOp->Address == Address)
114 {
115 break;
116 }
117 }
118 PageOp = PageOp->Next;
119 }
120
121 /*
122 * If we found an existing pageop then increment the reference count
123 * and return it.
124 */
125 if (PageOp != NULL)
126 {
127 PageOp->ReferenceCount++;
128 KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
129 return(PageOp);
130 }
131 KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
132 return(NULL);
133 }
134
135 PMM_PAGEOP
136 NTAPI
137 MmGetPageOp(PMEMORY_AREA MArea, HANDLE Pid, PVOID Address,
138 PMM_SECTION_SEGMENT Segment, ULONG Offset, ULONG OpType, BOOLEAN First)
139 /*
140 * FUNCTION: Get a page operation descriptor corresponding to
141 * the memory area and either the segment, offset pair or the
142 * pid, address pair.
143 */
144 {
145 ULONG_PTR Hash;
146 KIRQL oldIrql;
147 PMM_PAGEOP PageOp;
148
149 /*
150 * Calcuate the hash value for pageop structure
151 */
152 if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
153 {
154 Hash = (((ULONG_PTR)Segment) | (((ULONG_PTR)Offset) / PAGE_SIZE));
155 }
156 else
157 {
158 Hash = (((ULONG_PTR)Pid) | (((ULONG_PTR)Address) / PAGE_SIZE));
159 }
160 Hash = Hash % PAGEOP_HASH_TABLE_SIZE;
161
162 KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
163
164 /*
165 * Check for an existing pageop structure
166 */
167 PageOp = MmPageOpHashTable[Hash];
168 while (PageOp != NULL)
169 {
170 if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
171 {
172 if (PageOp->Segment == Segment &&
173 PageOp->Offset == Offset)
174 {
175 break;
176 }
177 }
178 else
179 {
180 if (PageOp->Pid == Pid &&
181 PageOp->Address == Address)
182 {
183 break;
184 }
185 }
186 PageOp = PageOp->Next;
187 }
188
189 /*
190 * If we found an existing pageop then increment the reference count
191 * and return it.
192 */
193 if (PageOp != NULL)
194 {
195 if (First)
196 {
197 PageOp = NULL;
198 }
199 else
200 {
201 PageOp->ReferenceCount++;
202 }
203 KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
204 return(PageOp);
205 }
206
207 /*
208 * Otherwise add a new pageop.
209 */
210 PageOp = ExAllocateFromNPagedLookasideList(&MmPageOpLookasideList);
211 if (PageOp == NULL)
212 {
213 KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
214 KeBugCheck(MEMORY_MANAGEMENT);
215 return(NULL);
216 }
217
218 if (MArea->Type != MEMORY_AREA_SECTION_VIEW)
219 {
220 PageOp->Pid = Pid;
221 PageOp->Address = Address;
222 }
223 else
224 {
225 PageOp->Segment = Segment;
226 PageOp->Offset = Offset;
227 }
228 PageOp->ReferenceCount = 1;
229 PageOp->Next = MmPageOpHashTable[Hash];
230 PageOp->Hash = Hash;
231 PageOp->Thread = PsGetCurrentThread();
232 PageOp->Abandoned = FALSE;
233 PageOp->Status = STATUS_PENDING;
234 PageOp->OpType = OpType;
235 PageOp->MArea = MArea;
236 KeInitializeEvent(&PageOp->CompletionEvent, NotificationEvent, FALSE);
237 MmPageOpHashTable[Hash] = PageOp;
238 (void)InterlockedIncrementUL(&MArea->PageOpCount);
239
240 KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
241 return(PageOp);
242 }
243
244 VOID
245 INIT_FUNCTION
246 NTAPI
247 MmInitializePageOp(VOID)
248 {
249 memset(MmPageOpHashTable, 0, sizeof(MmPageOpHashTable));
250 KeInitializeSpinLock(&MmPageOpHashTableLock);
251
252 ExInitializeNPagedLookasideList (&MmPageOpLookasideList,
253 NULL,
254 NULL,
255 0,
256 sizeof(MM_PAGEOP),
257 TAG_MM_PAGEOP,
258 50);
259 }
260
261
262
263
264
265
266
267
268