[MSI]
[reactos.git] / reactos / 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 INIT_FUNCTION
102 PsInitializeQuotaSystem(VOID)
103 {
104 RtlZeroMemory(&PspDefaultQuotaBlock, sizeof(PspDefaultQuotaBlock));
105 PspDefaultQuotaBlock.QuotaEntry[PagedPool].Limit = (SIZE_T)-1;
106 PspDefaultQuotaBlock.QuotaEntry[NonPagedPool].Limit = (SIZE_T)-1;
107 PspDefaultQuotaBlock.QuotaEntry[2].Limit = (SIZE_T)-1; /* Page file */
108 PsGetCurrentProcess()->QuotaBlock = &PspDefaultQuotaBlock;
109 }
110
111 VOID
112 NTAPI
113 PspInheritQuota(PEPROCESS Process, PEPROCESS ParentProcess)
114 {
115 if (ParentProcess != NULL)
116 {
117 PEPROCESS_QUOTA_BLOCK QuotaBlock = ParentProcess->QuotaBlock;
118
119 ASSERT(QuotaBlock != NULL);
120
121 (void)InterlockedIncrementUL(&QuotaBlock->ReferenceCount);
122
123 Process->QuotaBlock = QuotaBlock;
124 }
125 else
126 Process->QuotaBlock = &PspDefaultQuotaBlock;
127 }
128
129 VOID
130 NTAPI
131 PspDestroyQuotaBlock(PEPROCESS Process)
132 {
133 PEPROCESS_QUOTA_BLOCK QuotaBlock = Process->QuotaBlock;
134
135 if (QuotaBlock != &PspDefaultQuotaBlock &&
136 InterlockedDecrementUL(&QuotaBlock->ReferenceCount) == 0)
137 {
138 ExFreePool(QuotaBlock);
139 }
140 }
141
142 NTSTATUS
143 NTAPI
144 PsChargeProcessPageFileQuota(IN PEPROCESS Process,
145 IN SIZE_T Amount)
146 {
147 /* Don't do anything for the system process */
148 if (Process == PsInitialSystemProcess) return STATUS_SUCCESS;
149
150 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
151 return PspChargeProcessQuotaSpecifiedPool(Process, 2, Amount);
152 #else
153 /* Otherwise, not implemented */
154 UNIMPLEMENTED;
155 return STATUS_SUCCESS;
156 #endif
157 }
158
159 /*
160 * @implemented
161 */
162 VOID
163 NTAPI
164 PsChargePoolQuota(IN PEPROCESS Process,
165 IN POOL_TYPE PoolType,
166 IN SIZE_T Amount)
167 {
168 NTSTATUS Status;
169
170 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
171 /* MS-documented IRQL requirement. Not yet enabled as it */
172 /* needs verification that it does not break ReactOS, */
173 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
174 #endif
175
176 /* Don't do anything for the system process */
177 if (Process == PsInitialSystemProcess) return;
178
179 /* Charge the usage */
180 Status = PsChargeProcessPoolQuota(Process, PoolType, Amount);
181 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
182 }
183
184 /*
185 * @implemented
186 */
187 NTSTATUS
188 NTAPI
189 PsChargeProcessNonPagedPoolQuota(IN PEPROCESS Process,
190 IN SIZE_T Amount)
191 {
192 /* Call the general function */
193 return PsChargeProcessPoolQuota(Process, NonPagedPool, Amount);
194 }
195
196 /*
197 * @implemented
198 */
199 NTSTATUS
200 NTAPI
201 PsChargeProcessPagedPoolQuota(IN PEPROCESS Process,
202 IN SIZE_T Amount)
203 {
204 /* Call the general function */
205 return PsChargeProcessPoolQuota(Process, PagedPool, Amount);
206 }
207
208 /*
209 * @implemented
210 */
211 NTSTATUS
212 NTAPI
213 PsChargeProcessPoolQuota(IN PEPROCESS Process,
214 IN POOL_TYPE PoolType,
215 IN SIZE_T Amount)
216 {
217 /* Don't do anything for the system process */
218 if (Process == PsInitialSystemProcess) return STATUS_SUCCESS;
219
220 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
221 return PspChargeProcessQuotaSpecifiedPool(Process,
222 (PoolType & PAGED_POOL_MASK),
223 Amount);
224 #else
225 UNIMPLEMENTED;
226 return STATUS_SUCCESS;
227 #endif
228 }
229
230 /*
231 * @unimplemented
232 */
233 VOID
234 NTAPI
235 PsReturnPoolQuota(IN PEPROCESS Process,
236 IN POOL_TYPE PoolType,
237 IN SIZE_T Amount)
238 {
239 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
240 /* MS-documented IRQL requirement. Not yet enabled as it */
241 /* needs verification that it does not break ReactOS, */
242 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
243 #endif
244
245 /* Don't do anything for the system process */
246 if (Process == PsInitialSystemProcess) return;
247
248 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
249 PspReturnProcessQuotaSpecifiedPool(Process,
250 (PoolType & PAGED_POOL_MASK),
251 Amount);
252 #else
253 UNIMPLEMENTED;
254 #endif
255 }
256
257 /*
258 * @unimplemented
259 */
260 VOID
261 NTAPI
262 PsReturnProcessNonPagedPoolQuota(IN PEPROCESS Process,
263 IN SIZE_T Amount)
264 {
265 /* Don't do anything for the system process */
266 if (Process == PsInitialSystemProcess) return;
267
268 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
269 PsReturnPoolQuota(Process, NonPagedPool, Amount);
270 #else
271 UNIMPLEMENTED;
272 #endif
273 }
274
275 /*
276 * @unimplemented
277 */
278 VOID
279 NTAPI
280 PsReturnProcessPagedPoolQuota(IN PEPROCESS Process,
281 IN SIZE_T Amount)
282 {
283 /* Don't do anything for the system process */
284 if (Process == PsInitialSystemProcess) return;
285
286 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
287 PsReturnPoolQuota(Process, PagedPool, Amount);
288 #else
289 UNIMPLEMENTED;
290 #endif
291 }
292
293 NTSTATUS
294 NTAPI
295 PsReturnProcessPageFileQuota(IN PEPROCESS Process,
296 IN SIZE_T Amount)
297 {
298 /* Don't do anything for the system process */
299 if (Process == PsInitialSystemProcess) return STATUS_SUCCESS;
300
301 #ifdef PS_QUOTA_ENABLE_QUOTA_CODE
302 PspReturnProcessQuotaSpecifiedPool(Process, 2, Amount);
303 #else
304 /* Otherwise, not implemented */
305 UNIMPLEMENTED;
306 #endif
307 return STATUS_SUCCESS;
308 }
309
310 /* EOF */