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