From 6170b574f0fb00460da7a3e547cec7e9fa41b621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?George=20Bi=C8=99oc?= Date: Tue, 2 Mar 2021 20:09:58 +0100 Subject: [PATCH] [NTOS:PS] Implement PS_QUOTA_TYPE and let the quota code use it (#3389) This will replace the PoolIndex variable and as such we'll only be using the PS_QUOTA_TYPE enumeration, as Windows does. Both QuotaEntry, QuotaUsage and QuotaPeak depend explicitly or implicitly on this enumeration. Further details about this enum can be found in the following articles. https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ps/psquota/type.htm?tx=68,143 https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ps/psquota/block.htm?tx=68,142,143 https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/ps/eprocess/index.htm (see QuotaPeak and QuotaUsage) --- ntoskrnl/ex/sysinfo.c | 12 ++++----- ntoskrnl/ps/query.c | 12 ++++----- ntoskrnl/ps/quota.c | 52 ++++++++++++++++++--------------------- sdk/include/ndk/pstypes.h | 23 ++++++++++++++--- 4 files changed, 56 insertions(+), 43 deletions(-) diff --git a/ntoskrnl/ex/sysinfo.c b/ntoskrnl/ex/sysinfo.c index ffb8ddc906d..f02f0a1cce1 100644 --- a/ntoskrnl/ex/sysinfo.c +++ b/ntoskrnl/ex/sysinfo.c @@ -1025,12 +1025,12 @@ QSI_DEF(SystemProcessInformation) SpiCurrent->PageFaultCount = Process->Vm.PageFaultCount; SpiCurrent->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize; SpiCurrent->WorkingSetSize = Process->Vm.WorkingSetSize; - SpiCurrent->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0]; - SpiCurrent->QuotaPagedPoolUsage = Process->QuotaUsage[0]; - SpiCurrent->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1]; - SpiCurrent->QuotaNonPagedPoolUsage = Process->QuotaUsage[1]; - SpiCurrent->PagefileUsage = Process->QuotaUsage[2]; - SpiCurrent->PeakPagefileUsage = Process->QuotaPeak[2]; + SpiCurrent->QuotaPeakPagedPoolUsage = Process->QuotaPeak[PsPagedPool]; + SpiCurrent->QuotaPagedPoolUsage = Process->QuotaUsage[PsPagedPool]; + SpiCurrent->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[PsNonPagedPool]; + SpiCurrent->QuotaNonPagedPoolUsage = Process->QuotaUsage[PsNonPagedPool]; + SpiCurrent->PagefileUsage = Process->QuotaUsage[PsPageFile]; + SpiCurrent->PeakPagefileUsage = Process->QuotaPeak[PsPageFile]; SpiCurrent->PrivatePageCount = Process->CommitCharge; ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(SpiCurrent + 1); diff --git a/ntoskrnl/ps/query.c b/ntoskrnl/ps/query.c index 60f440ab9bc..cad72c4d60a 100644 --- a/ntoskrnl/ps/query.c +++ b/ntoskrnl/ps/query.c @@ -460,12 +460,12 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle, VmCounters->PageFaultCount = Process->Vm.PageFaultCount; VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize; VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize; - VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0]; - VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0]; - VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1]; - VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1]; - VmCounters->PagefileUsage = Process->QuotaUsage[2] << PAGE_SHIFT; - VmCounters->PeakPagefileUsage = Process->QuotaPeak[2] << PAGE_SHIFT; + VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[PsPagedPool]; + VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[PsPagedPool]; + VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[PsNonPagedPool]; + VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[PsNonPagedPool]; + VmCounters->PagefileUsage = Process->QuotaUsage[PsPageFile] << PAGE_SHIFT; + VmCounters->PeakPagefileUsage = Process->QuotaPeak[PsPageFile] << PAGE_SHIFT; //VmCounters->PrivateUsage = Process->CommitCharge << PAGE_SHIFT; // diff --git a/ntoskrnl/ps/quota.c b/ntoskrnl/ps/quota.c index 6d3751090ca..0645654a320 100644 --- a/ntoskrnl/ps/quota.c +++ b/ntoskrnl/ps/quota.c @@ -28,38 +28,36 @@ static KSPIN_LOCK PspQuotaLock; /* * Private helper to charge the specified process quota. - * ReturnsSTATUS_QUOTA_EXCEEDED on quota limit check failure. - * Updates QuotaPeak as needed for specified PoolIndex. - * TODO: Research and possibly add (the undocumented) enum type PS_QUOTA_TYPE - * to replace UCHAR for 'PoolIndex'. + * Returns STATUS_QUOTA_EXCEEDED on quota limit check failure. + * Updates QuotaPeak as needed for specified quota type in PS_QUOTA_TYPE enum. * Notes: Conceptually translation unit local/private. */ NTSTATUS NTAPI PspChargeProcessQuotaSpecifiedPool(IN PEPROCESS Process, - IN UCHAR PoolIndex, + IN PS_QUOTA_TYPE QuotaType, IN SIZE_T Amount) { ASSERT(Process); ASSERT(Process != PsInitialSystemProcess); - ASSERT(PoolIndex <= 2); + ASSERT(QuotaType < PsQuotaTypes); ASSERT(Process->QuotaBlock); /* Note: Race warning. TODO: Needs to add/use lock for this */ - if (Process->QuotaUsage[PoolIndex] + Amount > - Process->QuotaBlock->QuotaEntry[PoolIndex].Limit) + if (Process->QuotaUsage[QuotaType] + Amount > + Process->QuotaBlock->QuotaEntry[QuotaType].Limit) { DPRINT1("Quota exceeded, but ROS will let it slide...\n"); return STATUS_SUCCESS; //return STATUS_QUOTA_EXCEEDED; /* caller raises the exception */ } - InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[PoolIndex], Amount); + InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[QuotaType], Amount); /* Note: Race warning. TODO: Needs to add/use lock for this */ - if (Process->QuotaPeak[PoolIndex] < Process->QuotaUsage[PoolIndex]) + if (Process->QuotaPeak[QuotaType] < Process->QuotaUsage[QuotaType]) { - Process->QuotaPeak[PoolIndex] = Process->QuotaUsage[PoolIndex]; + Process->QuotaPeak[QuotaType] = Process->QuotaUsage[QuotaType]; } return STATUS_SUCCESS; @@ -67,27 +65,25 @@ PspChargeProcessQuotaSpecifiedPool(IN PEPROCESS Process, /* * Private helper to remove quota charge from the specified process quota. - * TODO: Research and possibly add (the undocumented) enum type PS_QUOTA_TYPE - * to replace UCHAR for 'PoolIndex'. * Notes: Conceptually translation unit local/private. */ VOID NTAPI PspReturnProcessQuotaSpecifiedPool(IN PEPROCESS Process, - IN UCHAR PoolIndex, + IN PS_QUOTA_TYPE QuotaType, IN SIZE_T Amount) { ASSERT(Process); ASSERT(Process != PsInitialSystemProcess); - ASSERT(PoolIndex <= 2); + ASSERT(QuotaType < PsQuotaTypes); ASSERT(!(Amount & 0x80000000)); /* we need to be able to negate it */ - if (Process->QuotaUsage[PoolIndex] < Amount) + if (Process->QuotaUsage[QuotaType] < Amount) { DPRINT1("WARNING: Process->QuotaUsage sanity check failed.\n"); } else { - InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[PoolIndex], + InterlockedExchangeAdd((LONG*)&Process->QuotaUsage[QuotaType], -(LONG)Amount); } } @@ -100,9 +96,9 @@ NTAPI PsInitializeQuotaSystem(VOID) { RtlZeroMemory(&PspDefaultQuotaBlock, sizeof(PspDefaultQuotaBlock)); - PspDefaultQuotaBlock.QuotaEntry[PagedPool].Limit = (SIZE_T)-1; - PspDefaultQuotaBlock.QuotaEntry[NonPagedPool].Limit = (SIZE_T)-1; - PspDefaultQuotaBlock.QuotaEntry[2].Limit = (SIZE_T)-1; /* Page file */ + PspDefaultQuotaBlock.QuotaEntry[PsNonPagedPool].Limit = (SIZE_T)-1; + PspDefaultQuotaBlock.QuotaEntry[PsPagedPool].Limit = (SIZE_T)-1; + PspDefaultQuotaBlock.QuotaEntry[PsPageFile].Limit = (SIZE_T)-1; PsGetCurrentProcess()->QuotaBlock = &PspDefaultQuotaBlock; } @@ -164,7 +160,7 @@ PsChargeProcessPageFileQuota(IN PEPROCESS Process, /* Don't do anything for the system process */ if (Process == PsInitialSystemProcess) return STATUS_SUCCESS; - return PspChargeProcessQuotaSpecifiedPool(Process, 2, Amount); + return PspChargeProcessQuotaSpecifiedPool(Process, PsPageFile, Amount); } /* @@ -284,7 +280,7 @@ PsReturnProcessPageFileQuota(IN PEPROCESS Process, /* Don't do anything for the system process */ if (Process == PsInitialSystemProcess) return STATUS_SUCCESS; - PspReturnProcessQuotaSpecifiedPool(Process, 2, Amount); + PspReturnProcessQuotaSpecifiedPool(Process, PsPageFile, Amount); return STATUS_SUCCESS; } @@ -419,12 +415,12 @@ PspSetQuotaLimits( /* Initialize the quota block */ QuotaBlock->ReferenceCount = 1; QuotaBlock->ProcessCount = 1; - QuotaBlock->QuotaEntry[0].Peak = Process->QuotaPeak[0]; - QuotaBlock->QuotaEntry[1].Peak = Process->QuotaPeak[1]; - QuotaBlock->QuotaEntry[2].Peak = Process->QuotaPeak[2]; - QuotaBlock->QuotaEntry[0].Limit = PspDefaultQuotaBlock.QuotaEntry[0].Limit; - QuotaBlock->QuotaEntry[1].Limit = PspDefaultQuotaBlock.QuotaEntry[1].Limit; - QuotaBlock->QuotaEntry[2].Limit = PspDefaultQuotaBlock.QuotaEntry[2].Limit; + QuotaBlock->QuotaEntry[PsNonPagedPool].Peak = Process->QuotaPeak[PsNonPagedPool]; + QuotaBlock->QuotaEntry[PsPagedPool].Peak = Process->QuotaPeak[PsPagedPool]; + QuotaBlock->QuotaEntry[PsPageFile].Peak = Process->QuotaPeak[PsPageFile]; + QuotaBlock->QuotaEntry[PsNonPagedPool].Limit = PspDefaultQuotaBlock.QuotaEntry[PsNonPagedPool].Limit; + QuotaBlock->QuotaEntry[PsPagedPool].Limit = PspDefaultQuotaBlock.QuotaEntry[PsPagedPool].Limit; + QuotaBlock->QuotaEntry[PsPageFile].Limit = PspDefaultQuotaBlock.QuotaEntry[PsPageFile].Limit; /* Try to exchange the quota block, if that failed, just drop it */ OldQuotaBlock = InterlockedCompareExchangePointer((PVOID*)&Process->QuotaBlock, diff --git a/sdk/include/ndk/pstypes.h b/sdk/include/ndk/pstypes.h index d10199097a3..a1868e1d59a 100644 --- a/sdk/include/ndk/pstypes.h +++ b/sdk/include/ndk/pstypes.h @@ -972,6 +972,23 @@ typedef struct _JOB_SET_ARRAY ULONG Flags; } JOB_SET_ARRAY, *PJOB_SET_ARRAY; +// +// Process Quota Type +// +typedef enum _PS_QUOTA_TYPE +{ + PsNonPagedPool = 0, + PsPagedPool, + PsPageFile, +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + PsWorkingSet, +#endif +#if (NTDDI_VERSION == NTDDI_LONGHORN) + PsCpuRate, +#endif + PsQuotaTypes +} PS_QUOTA_TYPE; + // // EPROCESS Quota Structures // @@ -985,7 +1002,7 @@ typedef struct _EPROCESS_QUOTA_ENTRY typedef struct _EPROCESS_QUOTA_BLOCK { - EPROCESS_QUOTA_ENTRY QuotaEntry[3]; + EPROCESS_QUOTA_ENTRY QuotaEntry[PsQuotaTypes]; LIST_ENTRY QuotaList; ULONG ReferenceCount; ULONG ProcessCount; @@ -1208,8 +1225,8 @@ typedef struct _EPROCESS EX_RUNDOWN_REF RundownProtect; HANDLE UniqueProcessId; LIST_ENTRY ActiveProcessLinks; - SIZE_T QuotaUsage[3]; /* 0=PagedPool, 1=NonPagedPool, 2=Pagefile */ - SIZE_T QuotaPeak[3]; /* ditto */ + SIZE_T QuotaUsage[PsQuotaTypes]; + SIZE_T QuotaPeak[PsQuotaTypes]; SIZE_T CommitCharge; SIZE_T PeakVirtualSize; SIZE_T VirtualSize;