ReactOS  0.4.15-dev-4572-gde972e2
quota.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE: Process Pool Quotas Support
5  * COPYRIGHT: Copyright 2005 Alex Ionescu <alex@relsoft.net>
6  * Copyright 2007 Mike Nordell
7  * Copyright 2021 George BiČ™oc <george.bisoc@reactos.org>
8  */
9 
10 /* INCLUDES **************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
19 
20 #define VALID_QUOTA_FLAGS (QUOTA_LIMITS_HARDWS_MIN_ENABLE | \
21  QUOTA_LIMITS_HARDWS_MIN_DISABLE | \
22  QUOTA_LIMITS_HARDWS_MAX_ENABLE | \
23  QUOTA_LIMITS_HARDWS_MAX_DISABLE)
24 
25 /* PRIVATE FUNCTIONS *******************************************************/
26 
48 VOID
49 NTAPI
50 PspReturnQuotasOnDestroy(
51  _In_ PEPROCESS_QUOTA_BLOCK QuotaBlock)
52 {
53  ULONG PsQuotaTypeIndex;
55 
56  /*
57  * We must be in a dispatch level interrupt here
58  * as we should be under a spin lock.
59  */
61 
62  /* Make sure that the quota block is not plain garbage */
63  ASSERT(QuotaBlock);
64 
65  /* Loop over the Process quota types */
66  for (PsQuotaTypeIndex = PsNonPagedPool; PsQuotaTypeIndex < PsPageFile; PsQuotaTypeIndex++)
67  {
68  /* The amount needed to return to Mm is the limit and return fields */
69  QuotaToReturn = QuotaBlock->QuotaEntry[PsQuotaTypeIndex].Limit + QuotaBlock->QuotaEntry[PsQuotaTypeIndex].Return;
70  MmReturnPoolQuota(PsQuotaTypeIndex, QuotaToReturn);
71  }
72 }
73 
98 VOID
99 NTAPI
100 PspReturnExcessQuotas(
101  _In_ PS_QUOTA_TYPE QuotaType,
102  _Outptr_ PSIZE_T ReturnedQuotas)
103 {
104  PLIST_ENTRY PspQuotaList;
105  PEPROCESS_QUOTA_BLOCK QuotaBlockFromList;
106  SIZE_T AmountToReturn = 0;
107 
108  /*
109  * We must be in a dispatch level interrupt here
110  * as we should be under a spin lock.
111  */
113 
114  /*
115  * Loop over the quota block lists and reap
116  * whatever quotas we haven't returned which
117  * is needed to free up resources.
118  */
119  for (PspQuotaList = PspQuotaBlockList.Flink;
120  PspQuotaList != &PspQuotaBlockList;
121  PspQuotaList = PspQuotaList->Flink)
122  {
123  /* Gather the quota block from the list */
124  QuotaBlockFromList = CONTAINING_RECORD(PspQuotaList, EPROCESS_QUOTA_BLOCK, QuotaList);
125 
126  /*
127  * Gather any unreturned quotas and cache
128  * them to a variable.
129  */
130  AmountToReturn += InterlockedExchangeSizeT(&QuotaBlockFromList->QuotaEntry[QuotaType].Return, 0);
131 
132  /*
133  * If no other process is taking use of this
134  * block, then it means that this block has
135  * only shared pool quota and the last process
136  * no longer uses this block. If the limit is
137  * grater than the usage then trim the limit
138  * and use that as additional amount of quota
139  * to return.
140  */
141  if (QuotaBlockFromList->ProcessCount == 0)
142  {
143  if (QuotaBlockFromList->QuotaEntry[QuotaType].Usage <
144  QuotaBlockFromList->QuotaEntry[QuotaType].Limit)
145  {
146  InterlockedExchangeSizeT(&QuotaBlockFromList->QuotaEntry[QuotaType].Limit,
147  QuotaBlockFromList->QuotaEntry[QuotaType].Usage);
148  AmountToReturn += QuotaBlockFromList->QuotaEntry[QuotaType].Limit;
149  }
150  }
151  }
152 
153  /* Invoke Mm to return quotas */
154  DPRINT("PspReturnExcessQuotas(): Amount of quota released -- %lu\n", AmountToReturn);
155  MmReturnPoolQuota(QuotaType, AmountToReturn);
156  *ReturnedQuotas = AmountToReturn;
157 }
158 
193 NTSTATUS
194 NTAPI
197  _In_ PEPROCESS_QUOTA_BLOCK QuotaBlock,
198  _In_ PS_QUOTA_TYPE QuotaType,
200 {
201  KIRQL OldIrql;
202  SIZE_T ReturnedQuotas;
203  SIZE_T UpdatedLimit;
204 
205  /* Sanity checks */
206  ASSERT(QuotaType < PsQuotaTypes);
207  ASSERT((SSIZE_T)Amount >= 0);
208 
209  /* Guard ourselves in a spin lock */
211 
212  /* Are we within the bounds of quota limit? */
213  if (QuotaBlock->QuotaEntry[QuotaType].Usage + Amount >
214  QuotaBlock->QuotaEntry[QuotaType].Limit &&
215  QuotaBlock != &PspDefaultQuotaBlock)
216  {
217  /* We aren't... Is this a page file quota charging? */
218  if (QuotaType == PsPageFile)
219  {
220  /* It is, return the appropriate status code */
221  DPRINT1("PspChargeProcessQuotaSpecifiedPool(): Quota amount exceeds the limit on page file quota (limit -- %lu || amount -- %lu)\n",
222  QuotaBlock->QuotaEntry[QuotaType].Limit, Amount);
224  }
225 
226  /*
227  * This is not a page file charge. What we can do at best
228  * in this scenario is to attempt to raise (expand) the
229  * quota limit charges of the block.
230  */
231  if (!MmRaisePoolQuota(QuotaType,
232  QuotaBlock->QuotaEntry[QuotaType].Limit,
233  &UpdatedLimit))
234  {
235  /*
236  * We can't? It could be that we must free
237  * up some resources in order to raise the
238  * limit, which in that case we must return
239  * the excess of quota that hasn't been
240  * returned. If we haven't returned anything
241  * then what we're doing here is futile.
242  * Bail out...
243  */
244  PspReturnExcessQuotas(QuotaType, &ReturnedQuotas);
245  if (ReturnedQuotas == 0)
246  {
247  DPRINT1("PspChargeProcessQuotaSpecifiedPool(): Failed to free some resources in order to raise quota limits...\n");
249  return STATUS_QUOTA_EXCEEDED;
250  }
251 
252  /* Try to raise the quota limits again */
253  MmRaisePoolQuota(QuotaType,
254  QuotaBlock->QuotaEntry[QuotaType].Limit,
255  &UpdatedLimit);
256  }
257 
258  /* Enforce a new raised limit */
259  InterlockedExchangeSizeT(&QuotaBlock->QuotaEntry[QuotaType].Limit, UpdatedLimit);
260 
261  /*
262  * Now determine if the current usage and the
263  * amounting by the caller still exceeds the
264  * quota limit of the process. If it's still
265  * over the limit then there's nothing we can
266  * do, so fail.
267  */
268  if (QuotaBlock->QuotaEntry[QuotaType].Usage + Amount >
269  QuotaBlock->QuotaEntry[QuotaType].Limit)
270  {
271  DPRINT1("PspChargeProcessQuotaSpecifiedPool(): Quota amount exceeds the limit (limit -- %lu || amount -- %lu)\n",
272  QuotaBlock->QuotaEntry[QuotaType].Limit, Amount);
273  return STATUS_QUOTA_EXCEEDED;
274  }
275  }
276 
277  /* Update the quota usage */
278  InterlockedExchangeAddSizeT(&QuotaBlock->QuotaEntry[QuotaType].Usage, Amount);
279 
280  /* Update the entry peak if it's less than the usage */
281  if (QuotaBlock->QuotaEntry[QuotaType].Peak <
282  QuotaBlock->QuotaEntry[QuotaType].Usage)
283  {
284  InterlockedExchangeSizeT(&QuotaBlock->QuotaEntry[QuotaType].Peak,
285  QuotaBlock->QuotaEntry[QuotaType].Usage);
286  }
287 
288  /* Are we being given a process as well? */
289  if (Process)
290  {
291  /* We're being given, check that's not a system one */
293 
294  InterlockedExchangeAddSizeT(&Process->QuotaUsage[QuotaType], Amount);
295 
296  /*
297  * OK, we've now updated the quota usage of the process
298  * based upon the amount that the caller wanted to charge.
299  * Although the peak of process quota can be less than it was
300  * before so update the peaks as well accordingly.
301  */
302  if (Process->QuotaPeak[QuotaType] < Process->QuotaUsage[QuotaType])
303  {
304  InterlockedExchangeSizeT(&Process->QuotaPeak[QuotaType],
305  Process->QuotaUsage[QuotaType]);
306  }
307  }
308 
309  /* Release the lock */
311  return STATUS_SUCCESS;
312 }
313 
343 VOID
344 NTAPI
347  _In_ PEPROCESS_QUOTA_BLOCK QuotaBlock,
348  _In_ PS_QUOTA_TYPE QuotaType,
350 {
351  KIRQL OldIrql;
352  SIZE_T ReturnThreshold;
353  SIZE_T AmountToReturn = 0;
354 
355  /* Sanity checks */
356  ASSERT(QuotaType < PsQuotaTypes);
357  ASSERT((SSIZE_T)Amount >= 0);
358 
359  /* Guard ourselves in a spin lock */
361 
362  /* Does the caller return more quota than it was previously charged? */
363  if ((Process && Process->QuotaUsage[QuotaType] < Amount) ||
364  QuotaBlock->QuotaEntry[QuotaType].Usage < Amount)
365  {
366  /* It does, crash the system! */
367  KeBugCheckEx(QUOTA_UNDERFLOW,
369  (ULONG_PTR)QuotaType,
370  Process ? (ULONG_PTR)Process->QuotaUsage[QuotaType] :
371  QuotaBlock->QuotaEntry[QuotaType].Usage,
372  (ULONG_PTR)Amount);
373  }
374 
375  /* The return threshold can be non paged or paged */
377 
378  /*
379  * We need to trim the quota limits based on the
380  * amount we're going to return quotas back.
381  */
382  if ((QuotaType != PsPageFile && QuotaBlock != &PspDefaultQuotaBlock) &&
383  (QuotaBlock->QuotaEntry[QuotaType].Limit > QuotaBlock->QuotaEntry[QuotaType].Usage + ReturnThreshold))
384  {
385  /*
386  * If the amount to return exceeds the threshold,
387  * the new amount becomes the default, otherwise
388  * the amount is just the one given by the caller.
389  */
390  AmountToReturn = min(Amount, ReturnThreshold);
391 
392  /* Add up the lots to the Return field */
393  InterlockedExchangeAddSizeT(&QuotaBlock->QuotaEntry[QuotaType].Return, AmountToReturn);
394 
395  /*
396  * If the amount to return exceeds the threshold then
397  * we have lots of quota to return to Mm. So do it so
398  * and zerou out the Return field.
399  */
400  if (QuotaBlock->QuotaEntry[QuotaType].Return > ReturnThreshold)
401  {
402  MmReturnPoolQuota(QuotaType, QuotaBlock->QuotaEntry[QuotaType].Return);
403  InterlockedExchangeSizeT(QuotaBlock->QuotaEntry[QuotaType].Return, 0);
404  }
405 
406  /* And try to trim the limit */
407  InterlockedExchangeSizeT(&QuotaBlock->QuotaEntry[QuotaType].Limit,
408  QuotaBlock->QuotaEntry[QuotaType].Limit - AmountToReturn);
409  }
410 
411  /* Update the usage member of the block */
412  InterlockedExchangeAddSizeT(&QuotaBlock->QuotaEntry[QuotaType].Usage, -(LONG_PTR)Amount);
413 
414  /* Are we being given a process? */
415  if (Process)
416  {
417  /* We're being given, check that's not a system one */
419 
420  /* Decrease the process' quota usage */
421  InterlockedExchangeAddSizeT(&Process->QuotaUsage[QuotaType], -(LONG_PTR)Amount);
422  }
423 
424  /* We're done, release the lock */
426 }
427 
428 /* FUNCTIONS ***************************************************************/
429 
440 CODE_SEG("INIT")
441 VOID
442 NTAPI
444 {
445  /* Initialize the default block */
447 
448  /* Assign the default quota limits */
452 
453  /*
454  * Set up the count references as the
455  * default block will going to be used.
456  */
459 
460  /* Assign that block to initial process */
461  PsGetCurrentProcess()->QuotaBlock = &PspDefaultQuotaBlock;
462 }
463 
481 VOID
482 NTAPI
485  _In_opt_ PEPROCESS ParentProcess)
486 {
487  PEPROCESS_QUOTA_BLOCK QuotaBlock;
488 
489  if (ParentProcess != NULL)
490  {
491  ASSERT(ParentProcess->QuotaBlock != NULL);
492  QuotaBlock = ParentProcess->QuotaBlock;
493  }
494  else
495  {
496  QuotaBlock = &PspDefaultQuotaBlock;
497  }
498 
501 
502  Process->QuotaBlock = QuotaBlock;
503 }
504 
516 VOID
517 NTAPI
519  _In_ PEPROCESS_QUOTA_BLOCK QuotaBlock)
520 {
521  KIRQL OldIrql;
522 
524  InsertTailList(&PspQuotaBlockList, &QuotaBlock->QuotaList);
526 }
527 
551 VOID
552 NTAPI
555  _In_ PEPROCESS_QUOTA_BLOCK QuotaBlock)
556 {
557  ULONG PsQuotaTypeIndex;
558  KIRQL OldIrql;
559 
560  /* Make sure the quota block is not trash */
561  ASSERT(QuotaBlock);
562 
563  /* Iterate over the process quota types if we have a process */
564  if (Process)
565  {
566  for (PsQuotaTypeIndex = PsNonPagedPool; PsQuotaTypeIndex < PsQuotaTypes; PsQuotaTypeIndex++)
567  {
568  /*
569  * We need to make sure that the quota usage
570  * uniquely associated with the process is 0
571  * on that moment the process gets destroyed.
572  */
573  ASSERT(Process->QuotaUsage[PsQuotaTypeIndex] == 0);
574  }
575 
576  /* As the process is now gone, decrement the process count */
577  InterlockedDecrementUL(&QuotaBlock->ProcessCount);
578  }
579 
580  /* If no one is using this block, begin to destroy it */
581  if (QuotaBlock != &PspDefaultQuotaBlock &&
582  InterlockedDecrementUL(&QuotaBlock->ReferenceCount) == 0)
583  {
584  /* Acquire the quota lock */
586 
587  /* Return all the quotas back to Mm and remove the quota from list */
588  PspReturnQuotasOnDestroy(QuotaBlock);
589  RemoveEntryList(&QuotaBlock->QuotaList);
590 
591  /* Release the lock and free the block */
593  ExFreePoolWithTag(QuotaBlock, TAG_QUOTA_BLOCK);
594  }
595 }
596 
619 VOID
620 NTAPI
622  _In_ PEPROCESS_QUOTA_BLOCK QuotaBlock,
623  _In_ SIZE_T AmountToReturnPaged,
624  _In_ SIZE_T AmountToReturnNonPaged)
625 {
626  /* Sanity check */
627  ASSERT(QuotaBlock);
628 
629  /* Return the pool quotas if there're any */
630  if (AmountToReturnPaged != 0)
631  {
632  PspReturnProcessQuotaSpecifiedPool(NULL, QuotaBlock, PsPagedPool, AmountToReturnPaged);
633  }
634 
635  if (AmountToReturnNonPaged != 0)
636  {
637  PspReturnProcessQuotaSpecifiedPool(NULL, QuotaBlock, PsNonPagedPool, AmountToReturnNonPaged);
638  }
639 
640  DPRINT("PsReturnSharedPoolQuota(): Amount returned back (paged %lu -- non paged %lu)\n", AmountToReturnPaged, AmountToReturnNonPaged);
641 
642  /* Dereference the quota block */
643  PspDereferenceQuotaBlock(NULL, QuotaBlock);
644 }
645 
673 NTAPI
676  _In_ SIZE_T AmountToChargePaged,
677  _In_ SIZE_T AmountToChargeNonPaged)
678 {
680 
681  /* Sanity checks */
682  ASSERT(Process);
683  ASSERT(Process->QuotaBlock);
684 
685  /* Do we have some paged pool quota to charge? */
686  if (AmountToChargePaged != 0)
687  {
688  /* We do, charge! */
689  Status = PspChargeProcessQuotaSpecifiedPool(NULL, Process->QuotaBlock, PsPagedPool, AmountToChargePaged);
690  if (!NT_SUCCESS(Status))
691  {
692  DPRINT1("PsChargeSharedPoolQuota(): Failed to charge the shared pool quota (Status 0x%lx)\n", Status);
693  return NULL;
694  }
695  }
696 
697  /* Do we have some non paged pool quota to charge? */
698  if (AmountToChargeNonPaged != 0)
699  {
700  /* We do, charge! */
701  Status = PspChargeProcessQuotaSpecifiedPool(NULL, Process->QuotaBlock, PsNonPagedPool, AmountToChargeNonPaged);
702  if (!NT_SUCCESS(Status))
703  {
704  DPRINT1("PsChargeSharedPoolQuota(): Failed to charge the shared pool quota (Status 0x%lx). Attempting to return some paged pool back...\n", Status);
705  PspReturnProcessQuotaSpecifiedPool(NULL, Process->QuotaBlock, PsPagedPool, AmountToChargePaged);
706  return NULL;
707  }
708  }
709 
710  /* We have charged the quotas of an object, increment the reference */
711  InterlockedIncrementSizeT(&Process->QuotaBlock->ReferenceCount);
712 
713  DPRINT("PsChargeSharedPoolQuota(): Amount charged (paged %lu -- non paged %lu)\n", AmountToChargePaged, AmountToChargeNonPaged);
714  return Process->QuotaBlock;
715 }
716 
736 NTSTATUS
737 NTAPI
741 {
742  /* Don't do anything for the system process */
744 
746 }
747 
773 VOID
774 NTAPI
779 {
782 
783  /* Don't do anything for the system process */
784  if (Process == PsInitialSystemProcess) return;
785 
786  /* Charge the usage */
789 }
790 
809 NTSTATUS
810 NTAPI
814 {
815  /* Call the general function */
817 }
818 
837 NTSTATUS
838 NTAPI
842 {
843  /* Call the general function */
845 }
846 
870 NTSTATUS
871 NTAPI
876 {
877  /* Don't do anything for the system process */
879 
881  Process->QuotaBlock,
883  Amount);
884 }
885 
905 VOID
906 NTAPI
911 {
912  /* Don't do anything for the system process */
913  if (Process == PsInitialSystemProcess) return;
914 
916  Process->QuotaBlock,
918  Amount);
919 }
920 
936 VOID
937 NTAPI
941 {
942  /* Don't do anything for the system process */
943  if (Process == PsInitialSystemProcess) return;
944 
946 }
947 
963 VOID
964 NTAPI
968 {
969  /* Don't do anything for the system process */
970  if (Process == PsInitialSystemProcess) return;
971 
973 }
974 
991 NTSTATUS
992 NTAPI
996 {
997  /* Don't do anything for the system process */
999 
1001  return STATUS_SUCCESS;
1002 }
1003 
1043 NTSTATUS
1044 NTAPI
1047  _In_ ULONG Unused,
1048  _In_ PVOID QuotaLimits,
1049  _In_ ULONG QuotaLimitsLength,
1051 {
1052  QUOTA_LIMITS_EX CapturedQuotaLimits;
1053  PEPROCESS_QUOTA_BLOCK QuotaBlock, OldQuotaBlock;
1054  BOOLEAN IncreaseOkay;
1055  KAPC_STATE SavedApcState;
1056  NTSTATUS Status;
1057 
1059 
1060  _SEH2_TRY
1061  {
1062  ProbeForRead(QuotaLimits, QuotaLimitsLength, sizeof(ULONG));
1063 
1064  /* Check if we have the basic or extended structure */
1065  if (QuotaLimitsLength == sizeof(QUOTA_LIMITS))
1066  {
1067  /* Copy the basic structure, zero init the remaining fields */
1068  RtlCopyMemory(&CapturedQuotaLimits, QuotaLimits, sizeof(QUOTA_LIMITS));
1069  CapturedQuotaLimits.WorkingSetLimit = 0;
1070  CapturedQuotaLimits.Reserved2 = 0;
1071  CapturedQuotaLimits.Reserved3 = 0;
1072  CapturedQuotaLimits.Reserved4 = 0;
1073  CapturedQuotaLimits.CpuRateLimit.RateData = 0;
1074  CapturedQuotaLimits.Flags = 0;
1075  }
1076  else if (QuotaLimitsLength == sizeof(QUOTA_LIMITS_EX))
1077  {
1078  /* Copy the full structure */
1079  RtlCopyMemory(&CapturedQuotaLimits, QuotaLimits, sizeof(QUOTA_LIMITS_EX));
1080 
1081  /* Verify that the caller passed valid flags */
1082  if ((CapturedQuotaLimits.Flags & ~VALID_QUOTA_FLAGS) ||
1083  ((CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MIN_ENABLE) &&
1084  (CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MIN_DISABLE)) ||
1085  ((CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MAX_ENABLE) &&
1086  (CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MAX_DISABLE)))
1087  {
1088  DPRINT1("Invalid quota flags: 0x%lx\n", CapturedQuotaLimits.Flags);
1090  }
1091 
1092  /* Verify that the caller didn't pass reserved values */
1093  if ((CapturedQuotaLimits.WorkingSetLimit != 0) ||
1094  (CapturedQuotaLimits.Reserved2 != 0) ||
1095  (CapturedQuotaLimits.Reserved3 != 0) ||
1096  (CapturedQuotaLimits.Reserved4 != 0) ||
1097  (CapturedQuotaLimits.CpuRateLimit.RateData != 0))
1098  {
1099  DPRINT1("Invalid value: (%lx,%lx,%lx,%lx,%lx)\n",
1100  CapturedQuotaLimits.WorkingSetLimit,
1101  CapturedQuotaLimits.Reserved2,
1102  CapturedQuotaLimits.Reserved3,
1103  CapturedQuotaLimits.Reserved4,
1104  CapturedQuotaLimits.CpuRateLimit.RateData);
1106  }
1107  }
1108  else
1109  {
1110  DPRINT1("Invalid quota size: 0x%lx\n", QuotaLimitsLength);
1112  }
1113  }
1115  {
1116  DPRINT1("Exception while copying data\n");
1118  }
1119  _SEH2_END;
1120 
1121  /* Check the caller changes the working set size limits */
1122  if ((CapturedQuotaLimits.MinimumWorkingSetSize != 0) &&
1123  (CapturedQuotaLimits.MaximumWorkingSetSize != 0))
1124  {
1125  /* Check for special case: trimming the WS */
1126  if ((CapturedQuotaLimits.MinimumWorkingSetSize == SIZE_T_MAX) &&
1127  (CapturedQuotaLimits.MaximumWorkingSetSize == SIZE_T_MAX))
1128  {
1129  /* No increase allowed */
1130  IncreaseOkay = FALSE;
1131  }
1132  else
1133  {
1134  /* Check if the caller has the required privilege */
1136  PreviousMode);
1137  }
1138 
1139  /* Attach to the target process and disable APCs */
1140  KeStackAttachProcess(&Process->Pcb, &SavedApcState);
1142 
1143  /* Call Mm to adjust the process' working set size */
1144  Status = MmAdjustWorkingSetSize(CapturedQuotaLimits.MinimumWorkingSetSize,
1145  CapturedQuotaLimits.MaximumWorkingSetSize,
1146  0,
1147  IncreaseOkay);
1148 
1149  /* Bring back APCs and detach from the process */
1151  KeUnstackDetachProcess(&SavedApcState);
1152  }
1153  else if (Process->QuotaBlock == &PspDefaultQuotaBlock)
1154  {
1155  /* Check if the caller has the required privilege */
1157  {
1159  }
1160 
1161  /* Allocate a new quota block */
1162  QuotaBlock = ExAllocatePoolWithTag(NonPagedPool,
1163  sizeof(EPROCESS_QUOTA_BLOCK),
1164  TAG_QUOTA_BLOCK);
1165  if (QuotaBlock == NULL)
1166  {
1168  return STATUS_NO_MEMORY;
1169  }
1170 
1171  /* Initialize the quota block */
1172  QuotaBlock->ReferenceCount = 1;
1173  QuotaBlock->ProcessCount = 1;
1174  QuotaBlock->QuotaEntry[PsNonPagedPool].Peak = Process->QuotaPeak[PsNonPagedPool];
1175  QuotaBlock->QuotaEntry[PsPagedPool].Peak = Process->QuotaPeak[PsPagedPool];
1176  QuotaBlock->QuotaEntry[PsPageFile].Peak = Process->QuotaPeak[PsPageFile];
1180 
1181  /* Try to exchange the quota block, if that failed, just drop it */
1182  OldQuotaBlock = InterlockedCompareExchangePointer((PVOID*)&Process->QuotaBlock,
1183  QuotaBlock,
1185  if (OldQuotaBlock == &PspDefaultQuotaBlock)
1186  {
1187  /* Success, insert the new quota block */
1188  PspInsertQuotaBlock(QuotaBlock);
1189  }
1190  else
1191  {
1192  /* Failed, free the quota block and ignore it */
1193  ExFreePoolWithTag(QuotaBlock, TAG_QUOTA_BLOCK);
1194  }
1195 
1197  }
1198  else
1199  {
1201  }
1202 
1203  return Status;
1204 }
1205 
1206 /* EOF */
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
VOID NTAPI PspInsertQuotaBlock(_In_ PEPROCESS_QUOTA_BLOCK QuotaBlock)
Inserts the new quota block into the quota list.
Definition: quota.c:518
#define STATUS_PAGEFILE_QUOTA_EXCEEDED
Definition: ntstatus.h:536
_Must_inspect_result_ typedef _In_ PVOID Unused
Definition: iotypes.h:1166
_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:1285
#define STATUS_QUOTA_EXCEEDED
Definition: ntstatus.h:304
#define _In_opt_
Definition: ms_sal.h:309
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
NTSTATUS NTAPI PsChargeProcessNonPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Charges the non paged pool quota of a given process.
Definition: quota.c:811
const LUID SeIncreaseQuotaPrivilege
Definition: priv.c:24
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
NTSTATUS NTAPI PsChargeProcessPageFileQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Charges the process page file quota. The function is used internally by the kernel.
Definition: quota.c:738
#define ASSERT_IRQL_EQUAL(x)
Definition: debug.h:43
#define VALID_QUOTA_FLAGS
Definition: quota.c:20
#define _Outptr_
Definition: ms_sal.h:427
LONG NTSTATUS
Definition: precomp.h:26
#define QUOTA_LIMITS_HARDWS_MIN_DISABLE
VOID NTAPI KeAcquireSpinLock(PKSPIN_LOCK SpinLock, PKIRQL OldIrql)
Definition: spinlock.c:50
#define ExRaiseStatus
Definition: ntoskrnl.h:108
LONG_PTR SSIZE_T
Definition: basetsd.h:183
VOID NTAPI PsReturnPoolQuota(_In_ PEPROCESS Process, _In_ POOL_TYPE PoolType, _In_ SIZE_T Amount)
Returns the pool quota that the process was taking up.
Definition: quota.c:907
#define InsertTailList(ListHead, Entry)
#define PSP_PAGED_POOL_QUOTA_THRESHOLD
Definition: ps.h:77
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:118
SIZE_T Return
Definition: pstypes.h:1041
_SEH2_TRY
Definition: create.c:4226
uint32_t ULONG_PTR
Definition: typedefs.h:65
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock
Definition: quota.c:16
UCHAR KIRQL
Definition: env_spec_w32.h:591
ULONG_PTR * PSIZE_T
Definition: typedefs.h:80
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
#define InterlockedIncrementSizeT(a)
Definition: interlocked.h:220
NTSTATUS NTAPI PspSetQuotaLimits(_In_ PEPROCESS Process, _In_ ULONG Unused, _In_ PVOID QuotaLimits, _In_ ULONG QuotaLimitsLength, _In_ KPROCESSOR_MODE PreviousMode)
This function adjusts the working set limits of a process and sets up new quota limits when necessary...
Definition: quota.c:1045
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
#define PsGetCurrentProcess
Definition: psfuncs.h:17
unsigned char BOOLEAN
#define KeLeaveGuardedRegion()
Definition: ke_x.h:68
#define _In_
Definition: ms_sal.h:308
VOID NTAPI PspReturnProcessQuotaSpecifiedPool(_In_opt_ PEPROCESS Process, _In_ PEPROCESS_QUOTA_BLOCK QuotaBlock, _In_ PS_QUOTA_TYPE QuotaType, _In_ SIZE_T Amount)
Internal kernel function that provides the bulk logic of process quota returning. It returns (takes a...
Definition: quota.c:345
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
Status
Definition: gdiplustypes.h:24
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
_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
VOID NTAPI PsReturnSharedPoolQuota(_In_ PEPROCESS_QUOTA_BLOCK QuotaBlock, _In_ SIZE_T AmountToReturnPaged, _In_ SIZE_T AmountToReturnNonPaged)
Returns the shared (paged and non paged) pool quotas. The function is used exclusively by the Object ...
Definition: quota.c:621
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
INT POOL_TYPE
Definition: typedefs.h:78
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define ObDereferenceObject
Definition: obfuncs.h:203
#define QUOTA_LIMITS_HARDWS_MAX_DISABLE
VOID NTAPI PsReturnProcessPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Returns the paged pool quota that the process was taking up.
Definition: quota.c:965
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
_Requires_lock_held_(PspQuotaLock)
Returns pool quotas back to the Memory Manager when the pool quota block is no longer being used by a...
Definition: quota.c:47
#define InterlockedExchangeAddSizeT(a, b)
Definition: interlocked.h:196
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:792
VOID NTAPI PsChargePoolQuota(_In_ PEPROCESS Process, _In_ POOL_TYPE PoolType, _In_ SIZE_T Amount)
Charges the pool quota of a given process. The kind of pool quota to charge is determined by the Pool...
Definition: quota.c:775
#define InterlockedDecrementUL(Addend)
Definition: ex.h:1522
Definition: typedefs.h:119
NTSTATUS NTAPI PsReturnProcessPageFileQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Returns the page file quota that the process was taking up. The function is used exclusively by the k...
Definition: quota.c:993
NTSTATUS NTAPI PsChargeProcessPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Charges the paged pool quota of a given process.
Definition: quota.c:839
SIZE_T MaximumWorkingSetSize
Definition: pstypes.h:71
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
ULONG_PTR SIZE_T
Definition: typedefs.h:80
VOID NTAPI PspDereferenceQuotaBlock(_In_opt_ PEPROCESS Process, _In_ PEPROCESS_QUOTA_BLOCK QuotaBlock)
De-references a quota block when quotas have been returned back because of an object de-allocation or...
Definition: quota.c:553
_SEH2_END
Definition: create.c:4400
SIZE_T Usage
Definition: pstypes.h:1038
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 STATUS_NO_MEMORY
Definition: ntstatus.h:260
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
SIZE_T Limit
Definition: pstypes.h:1039
VOID NTAPI PspInheritQuota(_In_ PEPROCESS Process, _In_opt_ PEPROCESS ParentProcess)
Inherits the quota block to another newborn (child) process. If there's no parent process,...
Definition: quota.c:483
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
static LIST_ENTRY PspQuotaBlockList
Definition: quota.c:17
#define min(a, b)
Definition: monoChain.cc:55
#define NULL
Definition: types.h:112
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
_In_ SIZE_T QuotaToReturn
Definition: mm.h:675
#define InterlockedExchangeSizeT(Target, Value)
Definition: ex.h:1544
#define DPRINT1
Definition: precomp.h:8
BOOLEAN NTAPI SeSinglePrivilegeCheck(_In_ LUID PrivilegeValue, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a single privilege is present in the context of the calling thread.
Definition: priv.c:744
NTSTATUS NTAPI PspChargeProcessQuotaSpecifiedPool(_In_opt_ PEPROCESS Process, _In_ PEPROCESS_QUOTA_BLOCK QuotaBlock, _In_ PS_QUOTA_TYPE QuotaType, _In_ SIZE_T Amount)
Internal kernel function that provides the bulk logic of process quota charging, necessary for export...
Definition: quota.c:195
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
#define TAG_QUOTA_BLOCK
Definition: tag.h:134
RATE_QUOTA_LIMIT CpuRateLimit
Definition: pstypes.h:79
PEPROCESS_QUOTA_BLOCK NTAPI PsChargeSharedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T AmountToChargePaged, _In_ SIZE_T AmountToChargeNonPaged)
Charges the shared (paged and non paged) pool quotas. The function is used exclusively by the Object ...
Definition: quota.c:674
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ _Strict_type_match_ POOL_TYPE PoolType
Definition: wdfdevice.h:3810
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
NTSTATUS NTAPI PsChargeProcessPoolQuota(_In_ PEPROCESS Process, _In_ POOL_TYPE PoolType, _In_ SIZE_T Amount)
Charges the process' quota pool. The type of quota to be charged depends upon the PoolType parameter.
Definition: quota.c:872
#define STATUS_SUCCESS
Definition: shellext.h:65
#define PSP_NON_PAGED_POOL_QUOTA_THRESHOLD
Definition: ps.h:76
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:168
#define DPRINT
Definition: sndvol32.h:71
VOID NTAPI PsReturnProcessNonPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Returns the non paged quota pool that the process was taking up.
Definition: quota.c:938
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
SIZE_T Reserved3
Definition: pstypes.h:76
enum _PS_QUOTA_TYPE PS_QUOTA_TYPE
static CODE_SEG("PAGE")
Definition: isapnp.c:1482
SIZE_T Peak
Definition: pstypes.h:1040
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
SIZE_T Reserved4
Definition: pstypes.h:77
VOID NTAPI PsInitializeQuotaSystem(VOID)
Initializes the quota system during boot phase of the system, which sets up the default quota block t...
Definition: quota.c:443
static KSPIN_LOCK PspQuotaLock
Definition: quota.c:18