mirror of
https://github.com/reactos/reactos.git
synced 2025-06-23 06:50:16 +00:00
[NTOSKRNL]
Implement PspSetQuotaLimits and use it in NtSetInformationProcess svn path=/trunk/; revision=62247
This commit is contained in:
parent
6a9cca1ef8
commit
9339f52e68
4 changed files with 228 additions and 3 deletions
|
@ -1767,6 +1767,17 @@ ExpCheckPoolAllocation(
|
||||||
ULONG Tag);
|
ULONG Tag);
|
||||||
|
|
||||||
|
|
||||||
|
/* mmsup.c *****************************************************************/
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
MmAdjustWorkingSetSize(
|
||||||
|
IN SIZE_T WorkingSetMinimumInBytes,
|
||||||
|
IN SIZE_T WorkingSetMaximumInBytes,
|
||||||
|
IN ULONG SystemCache,
|
||||||
|
IN BOOLEAN IncreaseOkay);
|
||||||
|
|
||||||
|
|
||||||
/* session.c *****************************************************************/
|
/* session.c *****************************************************************/
|
||||||
|
|
||||||
_IRQL_requires_max_(APC_LEVEL)
|
_IRQL_requires_max_(APC_LEVEL)
|
||||||
|
|
|
@ -300,6 +300,15 @@ PspDestroyQuotaBlock(
|
||||||
IN PEPROCESS Process
|
IN PEPROCESS Process
|
||||||
);
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
PspSetQuotaLimits(
|
||||||
|
_In_ HANDLE ProcessHandle,
|
||||||
|
_In_ ULONG Unused,
|
||||||
|
_In_ PVOID QuotaLimits,
|
||||||
|
_In_ ULONG QuotaLimitsLength,
|
||||||
|
_In_ KPROCESSOR_MODE PreviousMode);
|
||||||
|
|
||||||
#if defined(_X86_)
|
#if defined(_X86_)
|
||||||
//
|
//
|
||||||
// VDM and LDT Support
|
// VDM and LDT Support
|
||||||
|
|
|
@ -1917,9 +1917,12 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProcessQuotaLimits:
|
case ProcessQuotaLimits:
|
||||||
DPRINT1("Quota Limits not implemented\n");
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
return PspSetQuotaLimits(ProcessHandle,
|
||||||
break;
|
1,
|
||||||
|
ProcessInformation,
|
||||||
|
ProcessInformationLength,
|
||||||
|
PreviousMode);
|
||||||
|
|
||||||
case ProcessWorkingSetWatch:
|
case ProcessWorkingSetWatch:
|
||||||
DPRINT1("WS watch not implemented\n");
|
DPRINT1("WS watch not implemented\n");
|
||||||
|
|
|
@ -11,10 +11,19 @@
|
||||||
/* INCLUDES **************************************************************/
|
/* INCLUDES **************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
|
#include <ntintsafe.h>
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock;
|
EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock;
|
||||||
|
static LIST_ENTRY PspQuotaBlockList = {&PspQuotaBlockList, &PspQuotaBlockList};
|
||||||
|
static KSPIN_LOCK PspQuotaLock;
|
||||||
|
|
||||||
|
#define TAG_QUOTA_BLOCK 'bQsP'
|
||||||
|
#define VALID_QUOTA_FLAGS (QUOTA_LIMITS_HARDWS_MIN_ENABLE | \
|
||||||
|
QUOTA_LIMITS_HARDWS_MIN_DISABLE | \
|
||||||
|
QUOTA_LIMITS_HARDWS_MAX_ENABLE | \
|
||||||
|
QUOTA_LIMITS_HARDWS_MAX_DISABLE)
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS *******************************************************/
|
/* PRIVATE FUNCTIONS *******************************************************/
|
||||||
|
|
||||||
|
@ -116,15 +125,31 @@ PspInheritQuota(PEPROCESS Process, PEPROCESS ParentProcess)
|
||||||
Process->QuotaBlock = &PspDefaultQuotaBlock;
|
Process->QuotaBlock = &PspDefaultQuotaBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PspInsertQuotaBlock(
|
||||||
|
PEPROCESS_QUOTA_BLOCK QuotaBlock)
|
||||||
|
{
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
|
OldIrql = KfAcquireSpinLock(&PspQuotaLock);
|
||||||
|
InsertTailList(&PspQuotaBlockList, &QuotaBlock->QuotaList);
|
||||||
|
KfReleaseSpinLock(&PspQuotaLock, OldIrql);
|
||||||
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
PspDestroyQuotaBlock(PEPROCESS Process)
|
PspDestroyQuotaBlock(PEPROCESS Process)
|
||||||
{
|
{
|
||||||
PEPROCESS_QUOTA_BLOCK QuotaBlock = Process->QuotaBlock;
|
PEPROCESS_QUOTA_BLOCK QuotaBlock = Process->QuotaBlock;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
if (QuotaBlock != &PspDefaultQuotaBlock &&
|
if (QuotaBlock != &PspDefaultQuotaBlock &&
|
||||||
InterlockedDecrementUL(&QuotaBlock->ReferenceCount) == 0)
|
InterlockedDecrementUL(&QuotaBlock->ReferenceCount) == 0)
|
||||||
{
|
{
|
||||||
|
OldIrql = KfAcquireSpinLock(&PspQuotaLock);
|
||||||
|
RemoveEntryList(&QuotaBlock->QuotaList);
|
||||||
|
KfReleaseSpinLock(&PspQuotaLock, OldIrql);
|
||||||
ExFreePool(QuotaBlock);
|
ExFreePool(QuotaBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,4 +289,181 @@ PsReturnProcessPageFileQuota(IN PEPROCESS Process,
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
PspSetQuotaLimits(
|
||||||
|
_In_ HANDLE ProcessHandle,
|
||||||
|
_In_ ULONG Unused,
|
||||||
|
_In_ PVOID QuotaLimits,
|
||||||
|
_In_ ULONG QuotaLimitsLength,
|
||||||
|
_In_ KPROCESSOR_MODE PreviousMode)
|
||||||
|
{
|
||||||
|
QUOTA_LIMITS_EX CapturedQuotaLimits;
|
||||||
|
PEPROCESS Process;
|
||||||
|
PEPROCESS_QUOTA_BLOCK QuotaBlock, OldQuotaBlock;
|
||||||
|
BOOLEAN IncreaseOkay;
|
||||||
|
KAPC_STATE SavedApcState;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(Unused);
|
||||||
|
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
ProbeForRead(QuotaLimits, QuotaLimitsLength, sizeof(ULONG));
|
||||||
|
|
||||||
|
/* Check if we have the basic or extended structure */
|
||||||
|
if (QuotaLimitsLength == sizeof(QUOTA_LIMITS))
|
||||||
|
{
|
||||||
|
/* Copy the basic structure, zero init the remaining fields */
|
||||||
|
RtlCopyMemory(&CapturedQuotaLimits, QuotaLimits, sizeof(QUOTA_LIMITS));
|
||||||
|
CapturedQuotaLimits.WorkingSetLimit = 0;
|
||||||
|
CapturedQuotaLimits.Reserved2 = 0;
|
||||||
|
CapturedQuotaLimits.Reserved3 = 0;
|
||||||
|
CapturedQuotaLimits.Reserved4 = 0;
|
||||||
|
CapturedQuotaLimits.CpuRateLimit.RateData = 0;
|
||||||
|
CapturedQuotaLimits.Flags = 0;
|
||||||
|
}
|
||||||
|
else if (QuotaLimitsLength == sizeof(QUOTA_LIMITS_EX))
|
||||||
|
{
|
||||||
|
/* Copy the full structure */
|
||||||
|
RtlCopyMemory(&CapturedQuotaLimits, QuotaLimits, sizeof(QUOTA_LIMITS_EX));
|
||||||
|
|
||||||
|
/* Verify that the caller passed valid flags */
|
||||||
|
if ((CapturedQuotaLimits.Flags & ~VALID_QUOTA_FLAGS) ||
|
||||||
|
((CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MIN_ENABLE) &&
|
||||||
|
(CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MIN_DISABLE)) ||
|
||||||
|
((CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MAX_ENABLE) &&
|
||||||
|
(CapturedQuotaLimits.Flags & QUOTA_LIMITS_HARDWS_MAX_DISABLE)))
|
||||||
|
{
|
||||||
|
DPRINT1("Invalid quota flags: 0x%lx\n", CapturedQuotaLimits.Flags);
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that the caller didn't pass reserved values */
|
||||||
|
if ((CapturedQuotaLimits.WorkingSetLimit != 0) ||
|
||||||
|
(CapturedQuotaLimits.Reserved2 != 0) ||
|
||||||
|
(CapturedQuotaLimits.Reserved3 != 0) ||
|
||||||
|
(CapturedQuotaLimits.Reserved4 != 0) ||
|
||||||
|
(CapturedQuotaLimits.CpuRateLimit.RateData != 0))
|
||||||
|
{
|
||||||
|
DPRINT1("Invalid value: (%lx,%lx,%lx,%lx,%lx)\n",
|
||||||
|
CapturedQuotaLimits.WorkingSetLimit,
|
||||||
|
CapturedQuotaLimits.Reserved2,
|
||||||
|
CapturedQuotaLimits.Reserved3,
|
||||||
|
CapturedQuotaLimits.Reserved4,
|
||||||
|
CapturedQuotaLimits.CpuRateLimit.RateData);
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT1("Invalid quota size: 0x%lx\n", QuotaLimitsLength);
|
||||||
|
return STATUS_INFO_LENGTH_MISMATCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
DPRINT1("Exception while copying data\n");
|
||||||
|
return _SEH2_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
|
||||||
|
/* Reference the process */
|
||||||
|
Status = ObReferenceObjectByHandle(ProcessHandle,
|
||||||
|
PROCESS_SET_QUOTA,
|
||||||
|
PsProcessType,
|
||||||
|
PreviousMode,
|
||||||
|
(PVOID*)&Process,
|
||||||
|
NULL);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to reference process handle: 0x%lx\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the caller changes the working set size limits */
|
||||||
|
if ((CapturedQuotaLimits.MinimumWorkingSetSize != 0) &&
|
||||||
|
(CapturedQuotaLimits.MaximumWorkingSetSize != 0))
|
||||||
|
{
|
||||||
|
/* Check for special case: trimming the WS */
|
||||||
|
if ((CapturedQuotaLimits.MinimumWorkingSetSize == SIZE_T_MAX) &&
|
||||||
|
(CapturedQuotaLimits.MaximumWorkingSetSize == SIZE_T_MAX))
|
||||||
|
{
|
||||||
|
/* No increase allowed */
|
||||||
|
IncreaseOkay = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check if the caller has the required privilege */
|
||||||
|
IncreaseOkay = SeSinglePrivilegeCheck(SeIncreaseQuotaPrivilege,
|
||||||
|
PreviousMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attach to the target process and disable APCs */
|
||||||
|
KeStackAttachProcess(&Process->Pcb, &SavedApcState);
|
||||||
|
KeEnterGuardedRegion();
|
||||||
|
|
||||||
|
/* Call Mm to adjust the process' working set size */
|
||||||
|
Status = MmAdjustWorkingSetSize(CapturedQuotaLimits.MinimumWorkingSetSize,
|
||||||
|
CapturedQuotaLimits.MaximumWorkingSetSize,
|
||||||
|
0,
|
||||||
|
IncreaseOkay);
|
||||||
|
|
||||||
|
/* Bring back APCs and detach from the process */
|
||||||
|
KeLeaveGuardedRegion();
|
||||||
|
KeUnstackDetachProcess(&SavedApcState);
|
||||||
|
}
|
||||||
|
else if (Process->QuotaBlock == &PspDefaultQuotaBlock)
|
||||||
|
{
|
||||||
|
/* Check if the caller has the required privilege */
|
||||||
|
if (!SeSinglePrivilegeCheck(SeIncreaseQuotaPrivilege, PreviousMode))
|
||||||
|
{
|
||||||
|
ObDereferenceObject(Process);
|
||||||
|
return STATUS_PRIVILEGE_NOT_HELD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a new quota block */
|
||||||
|
QuotaBlock = ExAllocatePoolWithTag(NonPagedPool,
|
||||||
|
sizeof(EPROCESS_QUOTA_BLOCK),
|
||||||
|
TAG_QUOTA_BLOCK);
|
||||||
|
if (QuotaBlock == NULL)
|
||||||
|
{
|
||||||
|
ObDereferenceObject(Process);
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* Try to exchange the quota block, if that failed, just drop it */
|
||||||
|
OldQuotaBlock = InterlockedCompareExchangePointer(&Process->QuotaBlock,
|
||||||
|
QuotaBlock,
|
||||||
|
&PspDefaultQuotaBlock);
|
||||||
|
if (OldQuotaBlock == &PspDefaultQuotaBlock)
|
||||||
|
{
|
||||||
|
/* Success, insert the new quota block */
|
||||||
|
PspInsertQuotaBlock(QuotaBlock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Failed, free the quota block and ignore it */
|
||||||
|
ExFreePoolWithTag(QuotaBlock, TAG_QUOTA_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dereference the process and return the status */
|
||||||
|
ObDereferenceObject(Process);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue