ReactOS  0.4.14-dev-98-gb0d4763
quota.c
Go to the documentation of this file.
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 
20 
21 #define TAG_QUOTA_BLOCK 'bQsP'
22 #define VALID_QUOTA_FLAGS (QUOTA_LIMITS_HARDWS_MIN_ENABLE | \
23  QUOTA_LIMITS_HARDWS_MIN_DISABLE | \
24  QUOTA_LIMITS_HARDWS_MAX_ENABLE | \
25  QUOTA_LIMITS_HARDWS_MAX_DISABLE)
26 
27 /* PRIVATE FUNCTIONS *******************************************************/
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  */
38 NTAPI
40  IN UCHAR PoolIndex,
42 {
43  ASSERT(Process);
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  DPRINT1("Quota exceeded, but ROS will let it slide...\n");
53  return STATUS_SUCCESS;
54  //return STATUS_QUOTA_EXCEEDED; /* caller raises the exception */
55  }
56 
57  InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[PoolIndex], Amount);
58 
59  /* Note: Race warning. TODO: Needs to add/use lock for this */
60  if (Process->QuotaPeak[PoolIndex] < Process->QuotaUsage[PoolIndex])
61  {
62  Process->QuotaPeak[PoolIndex] = Process->QuotaUsage[PoolIndex];
63  }
64 
65  return STATUS_SUCCESS;
66 }
67 
68 /*
69  * Private helper to remove quota charge from the specified process quota.
70  * TODO: Research and possibly add (the undocumented) enum type PS_QUOTA_TYPE
71  * to replace UCHAR for 'PoolIndex'.
72  * Notes: Conceptually translation unit local/private.
73  */
74 VOID
75 NTAPI
77  IN UCHAR PoolIndex,
79 {
80  ASSERT(Process);
82  ASSERT(PoolIndex <= 2);
83  ASSERT(!(Amount & 0x80000000)); /* we need to be able to negate it */
84  if (Process->QuotaUsage[PoolIndex] < Amount)
85  {
86  DPRINT1("WARNING: Process->QuotaUsage sanity check failed.\n");
87  }
88  else
89  {
90  InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[PoolIndex],
91  -(LONG)Amount);
92  }
93 }
94 
95 /* FUNCTIONS ***************************************************************/
96 
97 INIT_FUNCTION
98 VOID
99 NTAPI
101 {
105  PspDefaultQuotaBlock.QuotaEntry[2].Limit = (SIZE_T)-1; /* Page file */
106  PsGetCurrentProcess()->QuotaBlock = &PspDefaultQuotaBlock;
107 }
108 
109 VOID
110 NTAPI
112 {
113  if (ParentProcess != NULL)
114  {
115  PEPROCESS_QUOTA_BLOCK QuotaBlock = ParentProcess->QuotaBlock;
116 
117  ASSERT(QuotaBlock != NULL);
118 
120 
121  Process->QuotaBlock = QuotaBlock;
122  }
123  else
124  Process->QuotaBlock = &PspDefaultQuotaBlock;
125 }
126 
127 VOID
128 NTAPI
130  PEPROCESS_QUOTA_BLOCK QuotaBlock)
131 {
132  KIRQL OldIrql;
133 
137 }
138 
139 VOID
140 NTAPI
142 {
143  PEPROCESS_QUOTA_BLOCK QuotaBlock = Process->QuotaBlock;
144  KIRQL OldIrql;
145 
146  if (QuotaBlock != &PspDefaultQuotaBlock &&
147  InterlockedDecrementUL(&QuotaBlock->ReferenceCount) == 0)
148  {
150  RemoveEntryList(&QuotaBlock->QuotaList);
152  ExFreePool(QuotaBlock);
153  }
154 }
155 
156 /*
157  * @implemented
158  */
159 NTSTATUS
160 NTAPI
162  IN SIZE_T Amount)
163 {
164  /* Don't do anything for the system process */
166 
168 }
169 
170 /*
171  * @implemented
172  */
173 VOID
174 NTAPI
177  IN SIZE_T Amount)
178 {
181 
182  /* Don't do anything for the system process */
183  if (Process == PsInitialSystemProcess) return;
184 
185  /* Charge the usage */
188 }
189 
190 /*
191  * @implemented
192  */
193 NTSTATUS
194 NTAPI
196  IN SIZE_T Amount)
197 {
198  /* Call the general function */
200 }
201 
202 /*
203  * @implemented
204  */
205 NTSTATUS
206 NTAPI
208  IN SIZE_T Amount)
209 {
210  /* Call the general function */
212 }
213 
214 /*
215  * @implemented
216  */
217 NTSTATUS
218 NTAPI
221  IN SIZE_T Amount)
222 {
223  /* Don't do anything for the system process */
225 
228  Amount);
229 }
230 
231 /*
232  * @implemented
233  */
234 VOID
235 NTAPI
238  IN SIZE_T Amount)
239 {
240  /* Don't do anything for the system process */
241  if (Process == PsInitialSystemProcess) return;
242 
245  Amount);
246 }
247 
248 /*
249  * @implemented
250  */
251 VOID
252 NTAPI
254  IN SIZE_T Amount)
255 {
256  /* Don't do anything for the system process */
257  if (Process == PsInitialSystemProcess) return;
258 
260 }
261 
262 /*
263  * @implemented
264  */
265 VOID
266 NTAPI
268  IN SIZE_T Amount)
269 {
270  /* Don't do anything for the system process */
271  if (Process == PsInitialSystemProcess) return;
272 
274 }
275 
276 /*
277  * @implemented
278  */
279 NTSTATUS
280 NTAPI
282  IN SIZE_T Amount)
283 {
284  /* Don't do anything for the system process */
286 
288  return STATUS_SUCCESS;
289 }
290 
291 NTSTATUS
292 NTAPI
295  _In_ ULONG Unused,
296  _In_ PVOID QuotaLimits,
297  _In_ ULONG QuotaLimitsLength,
299 {
300  QUOTA_LIMITS_EX CapturedQuotaLimits;
301  PEPROCESS_QUOTA_BLOCK QuotaBlock, OldQuotaBlock;
302  BOOLEAN IncreaseOkay;
303  KAPC_STATE SavedApcState;
305 
307 
308  _SEH2_TRY
309  {
310  ProbeForRead(QuotaLimits, QuotaLimitsLength, sizeof(ULONG));
311 
312  /* Check if we have the basic or extended structure */
313  if (QuotaLimitsLength == sizeof(QUOTA_LIMITS))
314  {
315  /* Copy the basic structure, zero init the remaining fields */
316  RtlCopyMemory(&CapturedQuotaLimits, QuotaLimits, sizeof(QUOTA_LIMITS));
317  CapturedQuotaLimits.WorkingSetLimit = 0;
318  CapturedQuotaLimits.Reserved2 = 0;
319  CapturedQuotaLimits.Reserved3 = 0;
320  CapturedQuotaLimits.Reserved4 = 0;
321  CapturedQuotaLimits.CpuRateLimit.RateData = 0;
322  CapturedQuotaLimits.Flags = 0;
323  }
324  else if (QuotaLimitsLength == sizeof(QUOTA_LIMITS_EX))
325  {
326  /* Copy the full structure */
327  RtlCopyMemory(&CapturedQuotaLimits, QuotaLimits, sizeof(QUOTA_LIMITS_EX));
328 
329  /* Verify that the caller passed valid flags */
330  if ((CapturedQuotaLimits.Flags & ~VALID_QUOTA_FLAGS) ||
331  ((CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MIN_ENABLE) &&
332  (CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MIN_DISABLE)) ||
333  ((CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MAX_ENABLE) &&
334  (CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MAX_DISABLE)))
335  {
336  DPRINT1("Invalid quota flags: 0x%lx\n", CapturedQuotaLimits.Flags);
338  }
339 
340  /* Verify that the caller didn't pass reserved values */
341  if ((CapturedQuotaLimits.WorkingSetLimit != 0) ||
342  (CapturedQuotaLimits.Reserved2 != 0) ||
343  (CapturedQuotaLimits.Reserved3 != 0) ||
344  (CapturedQuotaLimits.Reserved4 != 0) ||
345  (CapturedQuotaLimits.CpuRateLimit.RateData != 0))
346  {
347  DPRINT1("Invalid value: (%lx,%lx,%lx,%lx,%lx)\n",
348  CapturedQuotaLimits.WorkingSetLimit,
349  CapturedQuotaLimits.Reserved2,
350  CapturedQuotaLimits.Reserved3,
351  CapturedQuotaLimits.Reserved4,
352  CapturedQuotaLimits.CpuRateLimit.RateData);
354  }
355  }
356  else
357  {
358  DPRINT1("Invalid quota size: 0x%lx\n", QuotaLimitsLength);
360  }
361  }
363  {
364  DPRINT1("Exception while copying data\n");
366  }
367  _SEH2_END;
368 
369  /* Check the caller changes the working set size limits */
370  if ((CapturedQuotaLimits.MinimumWorkingSetSize != 0) &&
371  (CapturedQuotaLimits.MaximumWorkingSetSize != 0))
372  {
373  /* Check for special case: trimming the WS */
374  if ((CapturedQuotaLimits.MinimumWorkingSetSize == SIZE_T_MAX) &&
375  (CapturedQuotaLimits.MaximumWorkingSetSize == SIZE_T_MAX))
376  {
377  /* No increase allowed */
378  IncreaseOkay = FALSE;
379  }
380  else
381  {
382  /* Check if the caller has the required privilege */
384  PreviousMode);
385  }
386 
387  /* Attach to the target process and disable APCs */
388  KeStackAttachProcess(&Process->Pcb, &SavedApcState);
390 
391  /* Call Mm to adjust the process' working set size */
393  CapturedQuotaLimits.MaximumWorkingSetSize,
394  0,
395  IncreaseOkay);
396 
397  /* Bring back APCs and detach from the process */
399  KeUnstackDetachProcess(&SavedApcState);
400  }
401  else if (Process->QuotaBlock == &PspDefaultQuotaBlock)
402  {
403  /* Check if the caller has the required privilege */
405  {
407  }
408 
409  /* Allocate a new quota block */
410  QuotaBlock = ExAllocatePoolWithTag(NonPagedPool,
411  sizeof(EPROCESS_QUOTA_BLOCK),
413  if (QuotaBlock == NULL)
414  {
416  return STATUS_NO_MEMORY;
417  }
418 
419  /* Initialize the quota block */
420  QuotaBlock->ReferenceCount = 1;
421  QuotaBlock->ProcessCount = 1;
422  QuotaBlock->QuotaEntry[0].Peak = Process->QuotaPeak[0];
423  QuotaBlock->QuotaEntry[1].Peak = Process->QuotaPeak[1];
424  QuotaBlock->QuotaEntry[2].Peak = Process->QuotaPeak[2];
428 
429  /* Try to exchange the quota block, if that failed, just drop it */
430  OldQuotaBlock = InterlockedCompareExchangePointer((PVOID*)&Process->QuotaBlock,
431  QuotaBlock,
433  if (OldQuotaBlock == &PspDefaultQuotaBlock)
434  {
435  /* Success, insert the new quota block */
436  PspInsertQuotaBlock(QuotaBlock);
437  }
438  else
439  {
440  /* Failed, free the quota block and ignore it */
441  ExFreePoolWithTag(QuotaBlock, TAG_QUOTA_BLOCK);
442  }
443 
445  }
446  else
447  {
449  }
450 
451  return Status;
452 }
453 
454 
455 /* EOF */
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
_Must_inspect_result_ typedef _In_ PVOID Unused
Definition: iotypes.h:1129
#define IN
Definition: typedefs.h:38
_Must_inspect_result_ _In_ LONGLONG _In_ LONGLONG Amount
Definition: fsrtlfuncs.h:550
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
KAPC_STATE
Definition: ketypes.h:1273
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
NTSTATUS NTAPI PsChargeProcessPoolQuota(IN PEPROCESS Process, IN POOL_TYPE PoolType, IN SIZE_T Amount)
Definition: quota.c:219
const LUID SeIncreaseQuotaPrivilege
Definition: priv.c:26
SIZE_T Reserved2
Definition: pstypes.h:75
#define QUOTA_LIMITS_HARDWS_MAX_ENABLE
#define SIZE_T_MAX
Definition: dhcpd.h:91
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define VALID_QUOTA_FLAGS
Definition: quota.c:22
LONG NTSTATUS
Definition: precomp.h:26
#define QUOTA_LIMITS_HARDWS_MIN_DISABLE
VOID NTAPI PspInsertQuotaBlock(PEPROCESS_QUOTA_BLOCK QuotaBlock)
Definition: quota.c:129
#define ExRaiseStatus
Definition: ntoskrnl.h:95
NTSTATUS NTAPI PsReturnProcessPageFileQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:281
BOOLEAN NTAPI SeSinglePrivilegeCheck(IN LUID PrivilegeValue, IN KPROCESSOR_MODE PreviousMode)
Definition: priv.c:524
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
#define InsertTailList(ListHead, Entry)
NTSTATUS NTAPI MmAdjustWorkingSetSize(IN SIZE_T WorkingSetMinimumInBytes, IN SIZE_T WorkingSetMaximumInBytes, IN ULONG SystemCache, IN BOOLEAN IncreaseOkay)
Definition: mmsup.c:44
#define PAGED_POOL_MASK
Definition: mm.h:98
_SEH2_TRY
Definition: create.c:4250
EPROCESS_QUOTA_ENTRY QuotaEntry[3]
Definition: pstypes.h:977
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock
Definition: quota.c:17
VOID NTAPI PspReturnProcessQuotaSpecifiedPool(IN PEPROCESS Process, IN UCHAR PoolIndex, IN SIZE_T Amount)
Definition: quota.c:76
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
PEPROCESS PsInitialSystemProcess
Definition: psmgr.c:50
VOID NTAPI KeStackAttachProcess(IN PKPROCESS Process, OUT PRKAPC_STATE ApcState)
Definition: procobj.c:701
long LONG
Definition: pedump.c:60
VOID NTAPI PsChargePoolQuota(IN PEPROCESS Process, IN POOL_TYPE PoolType, IN SIZE_T Amount)
Definition: quota.c:175
NTSTATUS NTAPI PspSetQuotaLimits(_In_ PEPROCESS Process, _In_ ULONG Unused, _In_ PVOID QuotaLimits, _In_ ULONG QuotaLimitsLength, _In_ KPROCESSOR_MODE PreviousMode)
Definition: quota.c:293
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
VOID NTAPI PsReturnPoolQuota(IN PEPROCESS Process, IN POOL_TYPE PoolType, IN SIZE_T Amount)
Definition: quota.c:236
#define PsGetCurrentProcess
Definition: psfuncs.h:17
INIT_FUNCTION VOID NTAPI PsInitializeQuotaSystem(VOID)
Definition: quota.c:100
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define KeLeaveGuardedRegion()
Definition: ke_x.h:63
#define InterlockedExchangeAdd
Definition: interlocked.h:181
NTSTATUS NTAPI PsChargeProcessPageFileQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:161
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
ULONG RateData
Definition: pstypes.h:60
#define QUOTA_LIMITS_HARDWS_MIN_ENABLE
#define _SEH2_YIELD(STMT_)
Definition: pseh2_64.h:8
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
INT POOL_TYPE
Definition: typedefs.h:76
NTSTATUS NTAPI PspChargeProcessQuotaSpecifiedPool(IN PEPROCESS Process, IN UCHAR PoolIndex, IN SIZE_T Amount)
Definition: quota.c:39
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define QUOTA_LIMITS_HARDWS_MAX_DISABLE
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define KeEnterGuardedRegion()
Definition: ke_x.h:34
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
PEPROCESS_QUOTA_BLOCK QuotaBlock
Definition: pstypes.h:1237
unsigned char UCHAR
Definition: xmlstorage.h:181
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#define InterlockedDecrementUL(Addend)
Definition: ex.h:1510
Definition: typedefs.h:117
NTSTATUS NTAPI PsChargeProcessNonPagedPoolQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:195
VOID NTAPI PsReturnProcessNonPagedPoolQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:253
Status
Definition: gdiplustypes.h:24
SIZE_T MaximumWorkingSetSize
Definition: pstypes.h:71
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define _In_
Definition: no_sal2.h:204
ULONG_PTR SIZE_T
Definition: typedefs.h:78
#define TAG_QUOTA_BLOCK
Definition: quota.c:21
_SEH2_END
Definition: create.c:4424
SIZE_T MinimumWorkingSetSize
Definition: pstypes.h:70
SIZE_T WorkingSetLimit
Definition: pstypes.h:74
VOID NTAPI KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
Definition: procobj.c:753
#define InterlockedIncrementUL(Addend)
Definition: ex.h:1513
LIST_ENTRY QuotaList
Definition: pstypes.h:978
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
SIZE_T Limit
Definition: pstypes.h:970
static LIST_ENTRY PspQuotaBlockList
Definition: quota.c:18
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define DPRINT1
Definition: precomp.h:8
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
RATE_QUOTA_LIMIT CpuRateLimit
Definition: pstypes.h:79
VOID NTAPI PsReturnProcessPagedPoolQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:267
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
NTSTATUS NTAPI PsChargeProcessPagedPoolQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:207
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
return STATUS_SUCCESS
Definition: btrfs.c:2966
_Must_inspect_result_ _In_ FLT_CONTEXT_TYPE _In_ SIZE_T _In_ POOL_TYPE PoolType
Definition: fltkernel.h:1444
SIZE_T Reserved3
Definition: pstypes.h:76
VOID NTAPI PspDestroyQuotaBlock(PEPROCESS Process)
Definition: quota.c:141
SIZE_T Peak
Definition: pstypes.h:971
SIZE_T Reserved4
Definition: pstypes.h:77
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
VOID NTAPI PspInheritQuota(PEPROCESS Process, PEPROCESS ParentProcess)
Definition: quota.c:111
static KSPIN_LOCK PspQuotaLock
Definition: quota.c:19