Sync with trunk head (r48786)
[reactos.git] / ntoskrnl / ps / quota.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/quota.c
5 * PURPOSE: Process Pool Quotas
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * Mike Nordell
9 */
10
11 /* INCLUDES **************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock;
18
19
20 /* Define this macro to enable quota code testing. Once quota code is */
21 /* stable and verified, remove this macro and checks for it. */
22 /*#define PS_QUOTA_ENABLE_QUOTA_CODE*/
23
24
25 /* PRIVATE FUNCTIONS *******************************************************/
26
27 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
28
29 /*
30 * Private helper to charge the specified process quota.
31 * ReturnsSTATUS_QUOTA_EXCEEDED on quota limit check failure.
32 * Updates QuotaPeak as needed for specified PoolIndex.
33 * TODO: Research and possibly add (the undocumented) enum type PS_QUOTA_TYPE
34 * to replace UCHAR for 'PoolIndex'.
35 * Notes: Conceptually translation unit local/private.
36 */
37 NTSTATUS
38 NTAPI
39 PspChargeProcessQuotaSpecifiedPool(IN PEPROCESS Process,
40 IN UCHAR PoolIndex,
41 IN SIZE_T Amount)
42 {
43 ASSERT(Process);
44 ASSERT(Process != PsInitialSystemProcess);
45 ASSERT(PoolIndex <= 2);
46 ASSERT(Process->QuotaBlock);
47
48 /* Note: Race warning. TODO: Needs to add/use lock for this */
49 if (Process->QuotaUsage[PoolIndex] + Amount >
50 Process->QuotaBlock->QuotaEntry[PoolIndex].Limit)
51 {
52 return STATUS_QUOTA_EXCEEDED; /* caller raises the exception */
53 }
54
55 InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[PoolIndex], Amount);
56
57 /* Note: Race warning. TODO: Needs to add/use lock for this */
58 if (Process->QuotaPeak[PoolIndex] < Process->QuotaUsage[PoolIndex])
59 {
60 Process->QuotaPeak[PoolIndex] = Process->QuotaUsage[PoolIndex];
61 }
62
63 return STATUS_SUCCESS;
64 }
65
66
67 /*
68 * Private helper to remove quota charge from the specified process quota.
69 * TODO: Research and possibly add (the undocumented) enum type PS_QUOTA_TYPE
70 * to replace UCHAR for 'PoolIndex'.
71 * Notes: Conceptually translation unit local/private.
72 */
73 VOID
74 NTAPI
75 PspReturnProcessQuotaSpecifiedPool(IN PEPROCESS Process,
76 IN UCHAR PoolIndex,
77 IN SIZE_T Amount)
78 {
79 ASSERT(Process);
80 ASSERT(Process != PsInitialSystemProcess);
81 ASSERT(PoolIndex <= 2);
82 ASSERT(!(Amount & 0x80000000)); /* we need to be able to negate it */
83 if (Process->QuotaUsage[PoolIndex] < Amount)
84 {
85 DPRINT1("WARNING: Process->QuotaUsage sanity check failed.\n");
86 }
87 else
88 {
89 InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[PoolIndex],
90 -(LONG)Amount);
91 }
92 }
93
94 #endif /* PS_QUOTA_ENABLE_QUOTA_CODE */
95
96
97 /* FUNCTIONS ***************************************************************/
98
99 VOID
100 NTAPI
101 PsInitializeQuotaSystem(VOID)
102 {
103 RtlZeroMemory(&PspDefaultQuotaBlock, sizeof(PspDefaultQuotaBlock));
104 PspDefaultQuotaBlock.QuotaEntry[PagedPool].Limit = (SIZE_T)-1;
105 PspDefaultQuotaBlock.QuotaEntry[NonPagedPool].Limit = (SIZE_T)-1;
106 PspDefaultQuotaBlock.QuotaEntry[2].Limit = (SIZE_T)-1; /* Page file */
107 PsGetCurrentProcess()->QuotaBlock = &PspDefaultQuotaBlock;
108 }
109
110 VOID
111 NTAPI
112 PspInheritQuota(PEPROCESS Process, PEPROCESS ParentProcess)
113 {
114 if (ParentProcess != NULL)
115 {
116 PEPROCESS_QUOTA_BLOCK QuotaBlock = ParentProcess->QuotaBlock;
117
118 ASSERT(QuotaBlock != NULL);
119
120 (void)InterlockedIncrementUL(&QuotaBlock->ReferenceCount);
121
122 Process->QuotaBlock = QuotaBlock;
123 }
124 else
125 Process->QuotaBlock = &PspDefaultQuotaBlock;
126 }
127
128 VOID
129 NTAPI
130 PspDestroyQuotaBlock(PEPROCESS Process)
131 {
132 PEPROCESS_QUOTA_BLOCK QuotaBlock = Process->QuotaBlock;
133
134 if (QuotaBlock != &PspDefaultQuotaBlock &&
135 InterlockedDecrementUL(&QuotaBlock->ReferenceCount) == 0)
136 {
137 ExFreePool(QuotaBlock);
138 }
139 }
140
141 NTSTATUS
142 NTAPI
143 PsChargeProcessPageFileQuota(IN PEPROCESS Process,
144 IN SIZE_T Amount)
145 {
146 /* Don't do anything for the system process */
147 if (Process == PsInitialSystemProcess) return STATUS_SUCCESS;
148
149 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
150 return PspChargeProcessQuotaSpecifiedPool(Process, 2, Amount);
151 #else
152 /* Otherwise, not implemented */
153 UNIMPLEMENTED;
154 return STATUS_SUCCESS;
155 #endif
156 }
157
158 /*
159 * @implemented
160 */
161 VOID
162 NTAPI
163 PsChargePoolQuota(IN PEPROCESS Process,
164 IN POOL_TYPE PoolType,
165 IN SIZE_T Amount)
166 {
167 NTSTATUS Status;
168
169 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
170 /* MS-documented IRQL requirement. Not yet enabled as it */
171 /* needs verification that it does not break ReactOS, */
172 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
173 #endif
174
175 /* Don't do anything for the system process */
176 if (Process == PsInitialSystemProcess) return;
177
178 /* Charge the usage */
179 Status = PsChargeProcessPoolQuota(Process, PoolType, Amount);
180 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
181 }
182
183 /*
184 * @implemented
185 */
186 NTSTATUS
187 NTAPI
188 PsChargeProcessNonPagedPoolQuota(IN PEPROCESS Process,
189 IN SIZE_T Amount)
190 {
191 /* Call the general function */
192 return PsChargeProcessPoolQuota(Process, NonPagedPool, Amount);
193 }
194
195 /*
196 * @implemented
197 */
198 NTSTATUS
199 NTAPI
200 PsChargeProcessPagedPoolQuota(IN PEPROCESS Process,
201 IN SIZE_T Amount)
202 {
203 /* Call the general function */
204 return PsChargeProcessPoolQuota(Process, PagedPool, Amount);
205 }
206
207 /*
208 * @implemented
209 */
210 NTSTATUS
211 NTAPI
212 PsChargeProcessPoolQuota(IN PEPROCESS Process,
213 IN POOL_TYPE PoolType,
214 IN SIZE_T Amount)
215 {
216 /* Don't do anything for the system process */
217 if (Process == PsInitialSystemProcess) return STATUS_SUCCESS;
218
219 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
220 return PspChargeProcessQuotaSpecifiedPool(Process,
221 (PoolType & PAGED_POOL_MASK),
222 Amount);
223 #else
224 UNIMPLEMENTED;
225 return STATUS_SUCCESS;
226 #endif
227 }
228
229 /*
230 * @unimplemented
231 */
232 VOID
233 NTAPI
234 PsReturnPoolQuota(IN PEPROCESS Process,
235 IN POOL_TYPE PoolType,
236 IN SIZE_T Amount)
237 {
238 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
239 /* MS-documented IRQL requirement. Not yet enabled as it */
240 /* needs verification that it does not break ReactOS, */
241 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
242 #endif
243
244 /* Don't do anything for the system process */
245 if (Process == PsInitialSystemProcess) return;
246
247 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
248 PspReturnProcessQuotaSpecifiedPool(Process,
249 (PoolType & PAGED_POOL_MASK),
250 Amount);
251 #else
252 UNIMPLEMENTED;
253 #endif
254 }
255
256 /*
257 * @unimplemented
258 */
259 VOID
260 NTAPI
261 PsReturnProcessNonPagedPoolQuota(IN PEPROCESS Process,
262 IN SIZE_T Amount)
263 {
264 /* Don't do anything for the system process */
265 if (Process == PsInitialSystemProcess) return;
266
267 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
268 PsReturnPoolQuota(Process, NonPagedPool, Amount);
269 #else
270 UNIMPLEMENTED;
271 #endif
272 }
273
274 /*
275 * @unimplemented
276 */
277 VOID
278 NTAPI
279 PsReturnProcessPagedPoolQuota(IN PEPROCESS Process,
280 IN SIZE_T Amount)
281 {
282 /* Don't do anything for the system process */
283 if (Process == PsInitialSystemProcess) return;
284
285 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
286 PsReturnPoolQuota(Process, PagedPool, Amount);
287 #else
288 UNIMPLEMENTED;
289 #endif
290 }
291
292 NTSTATUS
293 NTAPI
294 PsReturnProcessPageFileQuota(IN PEPROCESS Process,
295 IN SIZE_T Amount)
296 {
297 /* Don't do anything for the system process */
298 if (Process == PsInitialSystemProcess) return STATUS_SUCCESS;
299
300 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
301 PspReturnProcessQuotaSpecifiedPool(Process, 2, Amount);
302 #else
303 /* Otherwise, not implemented */
304 UNIMPLEMENTED;
305 #endif
306 return STATUS_SUCCESS;
307 }
308
309 /* EOF */