ReactOS  0.4.15-dev-2774-gc8ce0cc
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  * Returns STATUS_QUOTA_EXCEEDED on quota limit check failure.
32  * Updates QuotaPeak as needed for specified quota type in PS_QUOTA_TYPE enum.
33  * Notes: Conceptually translation unit local/private.
34  */
36 NTAPI
38  IN PS_QUOTA_TYPE QuotaType,
40 {
41  KIRQL OldIrql;
42  ASSERT(Process);
44  ASSERT(QuotaType < PsQuotaTypes);
45  ASSERT(Process->QuotaBlock);
46 
47  /* Guard our quota in a spin lock */
49 
50  if (Process->QuotaUsage[QuotaType] + Amount >
51  Process->QuotaBlock->QuotaEntry[QuotaType].Limit)
52  {
53  DPRINT1("Quota exceeded, but ROS will let it slide...\n");
55  return STATUS_SUCCESS;
56  //return STATUS_QUOTA_EXCEEDED; /* caller raises the exception */
57  }
58 
59  InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[QuotaType], Amount);
60 
61  if (Process->QuotaPeak[QuotaType] < Process->QuotaUsage[QuotaType])
62  {
63  Process->QuotaPeak[QuotaType] = Process->QuotaUsage[QuotaType];
64  }
65 
67  return STATUS_SUCCESS;
68 }
69 
70 /*
71  * Private helper to remove quota charge from the specified process quota.
72  * Notes: Conceptually translation unit local/private.
73  */
74 VOID
75 NTAPI
77  IN PS_QUOTA_TYPE QuotaType,
79 {
80  KIRQL OldIrql;
81  ASSERT(Process);
83  ASSERT(QuotaType < PsQuotaTypes);
84  ASSERT(!(Amount & 0x80000000)); /* we need to be able to negate it */
85 
86  /* Guard our quota in a spin lock */
88 
89  if (Process->QuotaUsage[QuotaType] < Amount)
90  {
91  DPRINT1("WARNING: Process->QuotaUsage sanity check failed.\n");
92  }
93  else
94  {
95  InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[QuotaType],
96  -(LONG)Amount);
97  }
98 
100 }
101 
102 /* FUNCTIONS ***************************************************************/
103 
104 CODE_SEG("INIT")
105 VOID
106 NTAPI
108 {
113  PsGetCurrentProcess()->QuotaBlock = &PspDefaultQuotaBlock;
114 }
115 
116 VOID
117 NTAPI
119 {
120  if (ParentProcess != NULL)
121  {
122  PEPROCESS_QUOTA_BLOCK QuotaBlock = ParentProcess->QuotaBlock;
123 
124  ASSERT(QuotaBlock != NULL);
125 
127 
128  Process->QuotaBlock = QuotaBlock;
129  }
130  else
131  Process->QuotaBlock = &PspDefaultQuotaBlock;
132 }
133 
134 VOID
135 NTAPI
137  PEPROCESS_QUOTA_BLOCK QuotaBlock)
138 {
139  KIRQL OldIrql;
140 
144 }
145 
146 VOID
147 NTAPI
149 {
150  PEPROCESS_QUOTA_BLOCK QuotaBlock = Process->QuotaBlock;
151  KIRQL OldIrql;
152 
153  if (QuotaBlock != &PspDefaultQuotaBlock &&
154  InterlockedDecrementUL(&QuotaBlock->ReferenceCount) == 0)
155  {
157  RemoveEntryList(&QuotaBlock->QuotaList);
159  ExFreePool(QuotaBlock);
160  }
161 }
162 
163 /*
164  * @implemented
165  */
166 NTSTATUS
167 NTAPI
169  IN SIZE_T Amount)
170 {
171  /* Don't do anything for the system process */
173 
175 }
176 
177 /*
178  * @implemented
179  */
180 VOID
181 NTAPI
184  IN SIZE_T Amount)
185 {
188 
189  /* Don't do anything for the system process */
190  if (Process == PsInitialSystemProcess) return;
191 
192  /* Charge the usage */
195 }
196 
197 /*
198  * @implemented
199  */
200 NTSTATUS
201 NTAPI
203  IN SIZE_T Amount)
204 {
205  /* Call the general function */
207 }
208 
209 /*
210  * @implemented
211  */
212 NTSTATUS
213 NTAPI
215  IN SIZE_T Amount)
216 {
217  /* Call the general function */
219 }
220 
221 /*
222  * @implemented
223  */
224 NTSTATUS
225 NTAPI
228  IN SIZE_T Amount)
229 {
230  /* Don't do anything for the system process */
232 
235  Amount);
236 }
237 
238 /*
239  * @implemented
240  */
241 VOID
242 NTAPI
245  IN SIZE_T Amount)
246 {
247  /* Don't do anything for the system process */
248  if (Process == PsInitialSystemProcess) return;
249 
252  Amount);
253 }
254 
255 /*
256  * @implemented
257  */
258 VOID
259 NTAPI
261  IN SIZE_T Amount)
262 {
263  /* Don't do anything for the system process */
264  if (Process == PsInitialSystemProcess) return;
265 
267 }
268 
269 /*
270  * @implemented
271  */
272 VOID
273 NTAPI
275  IN SIZE_T Amount)
276 {
277  /* Don't do anything for the system process */
278  if (Process == PsInitialSystemProcess) return;
279 
281 }
282 
283 /*
284  * @implemented
285  */
286 NTSTATUS
287 NTAPI
289  IN SIZE_T Amount)
290 {
291  /* Don't do anything for the system process */
293 
295  return STATUS_SUCCESS;
296 }
297 
298 NTSTATUS
299 NTAPI
302  _In_ ULONG Unused,
303  _In_ PVOID QuotaLimits,
304  _In_ ULONG QuotaLimitsLength,
306 {
307  QUOTA_LIMITS_EX CapturedQuotaLimits;
308  PEPROCESS_QUOTA_BLOCK QuotaBlock, OldQuotaBlock;
309  BOOLEAN IncreaseOkay;
310  KAPC_STATE SavedApcState;
312 
314 
315  _SEH2_TRY
316  {
317  ProbeForRead(QuotaLimits, QuotaLimitsLength, sizeof(ULONG));
318 
319  /* Check if we have the basic or extended structure */
320  if (QuotaLimitsLength == sizeof(QUOTA_LIMITS))
321  {
322  /* Copy the basic structure, zero init the remaining fields */
323  RtlCopyMemory(&CapturedQuotaLimits, QuotaLimits, sizeof(QUOTA_LIMITS));
324  CapturedQuotaLimits.WorkingSetLimit = 0;
325  CapturedQuotaLimits.Reserved2 = 0;
326  CapturedQuotaLimits.Reserved3 = 0;
327  CapturedQuotaLimits.Reserved4 = 0;
328  CapturedQuotaLimits.CpuRateLimit.RateData = 0;
329  CapturedQuotaLimits.Flags = 0;
330  }
331  else if (QuotaLimitsLength == sizeof(QUOTA_LIMITS_EX))
332  {
333  /* Copy the full structure */
334  RtlCopyMemory(&CapturedQuotaLimits, QuotaLimits, sizeof(QUOTA_LIMITS_EX));
335 
336  /* Verify that the caller passed valid flags */
337  if ((CapturedQuotaLimits.Flags & ~VALID_QUOTA_FLAGS) ||
338  ((CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MIN_ENABLE) &&
339  (CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MIN_DISABLE)) ||
340  ((CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MAX_ENABLE) &&
341  (CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MAX_DISABLE)))
342  {
343  DPRINT1("Invalid quota flags: 0x%lx\n", CapturedQuotaLimits.Flags);
345  }
346 
347  /* Verify that the caller didn't pass reserved values */
348  if ((CapturedQuotaLimits.WorkingSetLimit != 0) ||
349  (CapturedQuotaLimits.Reserved2 != 0) ||
350  (CapturedQuotaLimits.Reserved3 != 0) ||
351  (CapturedQuotaLimits.Reserved4 != 0) ||
352  (CapturedQuotaLimits.CpuRateLimit.RateData != 0))
353  {
354  DPRINT1("Invalid value: (%lx,%lx,%lx,%lx,%lx)\n",
355  CapturedQuotaLimits.WorkingSetLimit,
356  CapturedQuotaLimits.Reserved2,
357  CapturedQuotaLimits.Reserved3,
358  CapturedQuotaLimits.Reserved4,
359  CapturedQuotaLimits.CpuRateLimit.RateData);
361  }
362  }
363  else
364  {
365  DPRINT1("Invalid quota size: 0x%lx\n", QuotaLimitsLength);
367  }
368  }
370  {
371  DPRINT1("Exception while copying data\n");
373  }
374  _SEH2_END;
375 
376  /* Check the caller changes the working set size limits */
377  if ((CapturedQuotaLimits.MinimumWorkingSetSize != 0) &&
378  (CapturedQuotaLimits.MaximumWorkingSetSize != 0))
379  {
380  /* Check for special case: trimming the WS */
381  if ((CapturedQuotaLimits.MinimumWorkingSetSize == SIZE_T_MAX) &&
382  (CapturedQuotaLimits.MaximumWorkingSetSize == SIZE_T_MAX))
383  {
384  /* No increase allowed */
385  IncreaseOkay = FALSE;
386  }
387  else
388  {
389  /* Check if the caller has the required privilege */
391  PreviousMode);
392  }
393 
394  /* Attach to the target process and disable APCs */
395  KeStackAttachProcess(&Process->Pcb, &SavedApcState);
397 
398  /* Call Mm to adjust the process' working set size */
400  CapturedQuotaLimits.MaximumWorkingSetSize,
401  0,
402  IncreaseOkay);
403 
404  /* Bring back APCs and detach from the process */
406  KeUnstackDetachProcess(&SavedApcState);
407  }
408  else if (Process->QuotaBlock == &PspDefaultQuotaBlock)
409  {
410  /* Check if the caller has the required privilege */
412  {
414  }
415 
416  /* Allocate a new quota block */
417  QuotaBlock = ExAllocatePoolWithTag(NonPagedPool,
418  sizeof(EPROCESS_QUOTA_BLOCK),
420  if (QuotaBlock == NULL)
421  {
423  return STATUS_NO_MEMORY;
424  }
425 
426  /* Initialize the quota block */
427  QuotaBlock->ReferenceCount = 1;
428  QuotaBlock->ProcessCount = 1;
429  QuotaBlock->QuotaEntry[PsNonPagedPool].Peak = Process->QuotaPeak[PsNonPagedPool];
430  QuotaBlock->QuotaEntry[PsPagedPool].Peak = Process->QuotaPeak[PsPagedPool];
431  QuotaBlock->QuotaEntry[PsPageFile].Peak = Process->QuotaPeak[PsPageFile];
435 
436  /* Try to exchange the quota block, if that failed, just drop it */
437  OldQuotaBlock = InterlockedCompareExchangePointer((PVOID*)&Process->QuotaBlock,
438  QuotaBlock,
440  if (OldQuotaBlock == &PspDefaultQuotaBlock)
441  {
442  /* Success, insert the new quota block */
443  PspInsertQuotaBlock(QuotaBlock);
444  }
445  else
446  {
447  /* Failed, free the quota block and ignore it */
448  ExFreePoolWithTag(QuotaBlock, TAG_QUOTA_BLOCK);
449  }
450 
452  }
453  else
454  {
456  }
457 
458  return Status;
459 }
460 
461 
462 /* EOF */
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
_Must_inspect_result_ typedef _In_ PVOID Unused
Definition: iotypes.h:1166
#define IN
Definition: typedefs.h:39
_Must_inspect_result_ _In_ LONGLONG _In_ LONGLONG Amount
Definition: fsrtlfuncs.h:550
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
KAPC_STATE
Definition: ketypes.h:1280
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:226
const LUID SeIncreaseQuotaPrivilege
Definition: priv.c:22
EPROCESS_QUOTA_ENTRY QuotaEntry[PsQuotaTypes]
Definition: pstypes.h:1046
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:317
#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:136
#define ExRaiseStatus
Definition: ntoskrnl.h:104
NTSTATUS NTAPI PsReturnProcessPageFileQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:288
BOOLEAN NTAPI SeSinglePrivilegeCheck(IN LUID PrivilegeValue, IN KPROCESSOR_MODE PreviousMode)
Definition: priv.c:520
#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:100
_SEH2_TRY
Definition: create.c:4226
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock
Definition: quota.c:17
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
#define FALSE
Definition: types.h:117
PEPROCESS PsInitialSystemProcess
Definition: psmgr.c:50
VOID NTAPI KeStackAttachProcess(IN PKPROCESS Process, OUT PRKAPC_STATE ApcState)
Definition: procobj.c:704
long LONG
Definition: pedump.c:60
VOID NTAPI PsChargePoolQuota(IN PEPROCESS Process, IN POOL_TYPE PoolType, IN SIZE_T Amount)
Definition: quota.c:182
NTSTATUS NTAPI PspSetQuotaLimits(_In_ PEPROCESS Process, _In_ ULONG Unused, _In_ PVOID QuotaLimits, _In_ ULONG QuotaLimitsLength, _In_ KPROCESSOR_MODE PreviousMode)
Definition: quota.c:300
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
VOID NTAPI PsReturnPoolQuota(IN PEPROCESS Process, IN POOL_TYPE PoolType, IN SIZE_T Amount)
Definition: quota.c:243
#define PsGetCurrentProcess
Definition: psfuncs.h:17
unsigned char BOOLEAN
#define KeLeaveGuardedRegion()
Definition: ke_x.h:68
#define InterlockedExchangeAdd
Definition: interlocked.h:181
Status
Definition: gdiplustypes.h:24
NTSTATUS NTAPI PsChargeProcessPageFileQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:168
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
ULONG RateData
Definition: pstypes.h:60
#define QUOTA_LIMITS_HARDWS_MIN_ENABLE
#define ASSERT(a)
Definition: mode.c:44
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
INT POOL_TYPE
Definition: typedefs.h:78
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define ObDereferenceObject
Definition: obfuncs.h:203
#define QUOTA_LIMITS_HARDWS_MAX_DISABLE
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define KeEnterGuardedRegion()
Definition: ke_x.h:39
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
PEPROCESS_QUOTA_BLOCK QuotaBlock
Definition: pstypes.h:1306
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:790
NTSTATUS NTAPI PspChargeProcessQuotaSpecifiedPool(IN PEPROCESS Process, IN PS_QUOTA_TYPE QuotaType, IN SIZE_T Amount)
Definition: quota.c:37
#define InterlockedDecrementUL(Addend)
Definition: ex.h:1522
Definition: typedefs.h:119
NTSTATUS NTAPI PsChargeProcessNonPagedPoolQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:202
VOID NTAPI PsReturnProcessNonPagedPoolQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:260
SIZE_T MaximumWorkingSetSize
Definition: pstypes.h:71
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define _In_
Definition: no_sal2.h:158
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define TAG_QUOTA_BLOCK
Definition: quota.c:21
_SEH2_END
Definition: create.c:4400
VOID NTAPI PspReturnProcessQuotaSpecifiedPool(IN PEPROCESS Process, IN PS_QUOTA_TYPE QuotaType, IN SIZE_T Amount)
Definition: quota.c:76
SIZE_T MinimumWorkingSetSize
Definition: pstypes.h:70
SIZE_T WorkingSetLimit
Definition: pstypes.h:74
VOID NTAPI KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
Definition: procobj.c:756
#define InterlockedIncrementUL(Addend)
Definition: ex.h:1525
LIST_ENTRY QuotaList
Definition: pstypes.h:1047
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
SIZE_T Limit
Definition: pstypes.h:1039
static LIST_ENTRY PspQuotaBlockList
Definition: quota.c:18
#define NULL
Definition: types.h:112
#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
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ _Strict_type_match_ POOL_TYPE PoolType
Definition: wdfdevice.h:3810
VOID NTAPI PsReturnProcessPagedPoolQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:274
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
NTSTATUS NTAPI PsChargeProcessPagedPoolQuota(IN PEPROCESS Process, IN SIZE_T Amount)
Definition: quota.c:214
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
#define STATUS_SUCCESS
Definition: shellext.h:65
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:168
SIZE_T Reserved3
Definition: pstypes.h:76
enum _PS_QUOTA_TYPE PS_QUOTA_TYPE
static CODE_SEG("PAGE")
Definition: isapnp.c:1482
VOID NTAPI PspDestroyQuotaBlock(PEPROCESS Process)
Definition: quota.c:148
SIZE_T Peak
Definition: pstypes.h:1040
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:118
VOID NTAPI PsInitializeQuotaSystem(VOID)
Definition: quota.c:107
static KSPIN_LOCK PspQuotaLock
Definition: quota.c:19