https://git.reactos.org/?p=reactos.git;a=commitdiff;h=1649a89cfaa38a5843d823db87b2291f57a5e213

commit 1649a89cfaa38a5843d823db87b2291f57a5e213
Author:     George Bișoc <[email protected]>
AuthorDate: Thu Dec 30 21:00:52 2021 +0100
Commit:     George Bișoc <[email protected]>
CommitDate: Tue Jan 11 10:11:09 2022 +0100

    [NTOS:MM] Implement Raise/Return pool quota functions
    
    This implements both MmRaisePoolQuota and MmReturnPoolQuota functions, 
which serve exclusively for quota pool management. The process manager 
communicates with the memory manager in a call of need to charge or return pool 
quota limits.
---
 ntoskrnl/mm/ARM3/pool.c | 192 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 177 insertions(+), 15 deletions(-)

diff --git a/ntoskrnl/mm/ARM3/pool.c b/ntoskrnl/mm/ARM3/pool.c
index fe8d6cd1a74..8ab8ae293a4 100644
--- a/ntoskrnl/mm/ARM3/pool.c
+++ b/ntoskrnl/mm/ARM3/pool.c
@@ -24,6 +24,8 @@ PFN_NUMBER MiStartOfInitialPoolFrame, MiEndOfInitialPoolFrame;
 KGUARDED_MUTEX MmPagedPoolMutex;
 MM_PAGED_POOL_INFO MmPagedPoolInfo;
 SIZE_T MmAllocatedNonPagedPool;
+SIZE_T MmTotalNonPagedPoolQuota;
+SIZE_T MmTotalPagedPoolQuota;
 ULONG MmSpecialPoolTag;
 ULONG MmConsumedPoolPercentage;
 BOOLEAN MmProtectFreedNonPagedPool;
@@ -1269,21 +1271,6 @@ MiFreePoolPages(IN PVOID StartingVa)
     return NumberOfPages;
 }
 
-
-BOOLEAN
-NTAPI
-MiRaisePoolQuota(IN POOL_TYPE PoolType,
-                 IN ULONG CurrentMaxQuota,
-                 OUT PULONG NewMaxQuota)
-{
-    //
-    // Not implemented
-    //
-    UNIMPLEMENTED;
-    *NewMaxQuota = CurrentMaxQuota + 65536;
-    return TRUE;
-}
-
 NTSTATUS
 NTAPI
 MiInitializeSessionPool(VOID)
@@ -1388,6 +1375,181 @@ MiInitializeSessionPool(VOID)
     return STATUS_SUCCESS;
 }
 
+/**
+ * @brief
+ * Raises the quota limit, depending on the given
+ * pool type of the quota in question. The routine
+ * is used exclusively by Process Manager for
+ * quota handling.
+ *
+ * @param[in] PoolType
+ * The type of quota pool which the quota in question
+ * has to be raised.
+ *
+ * @param[in] CurrentMaxQuota
+ * The current maximum limit of quota threshold.
+ *
+ * @param[out] NewMaxQuota
+ * The newly raised maximum limit of quota threshold,
+ * returned to the caller.
+ *
+ * @return
+ * Returns TRUE if quota raising procedure has succeeded
+ * without problems, FALSE otherwise.
+ *
+ * @remarks
+ * A spin lock must be held when raising the pool quota
+ * limit to avoid race occurences.
+ */
+_Requires_lock_held_(PspQuotaLock)
+BOOLEAN
+NTAPI
+MmRaisePoolQuota(
+    _In_ POOL_TYPE PoolType,
+    _In_ SIZE_T CurrentMaxQuota,
+    _Out_ PSIZE_T NewMaxQuota)
+{
+    /*
+     * We must be in dispatch level interrupt here
+     * as we should be under a spin lock at this point.
+     */
+    ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
+
+    switch (PoolType)
+    {
+        case NonPagedPool:
+        {
+            /*
+             * When concerning with a raise (charge) of quota
+             * in a non paged pool scenario, make sure that
+             * we've got at least 200 pages necessary to provide.
+             */
+            if (MmAvailablePages < MI_QUOTA_NON_PAGED_NEEDED_PAGES)
+            {
+                DPRINT1("MmRaisePoolQuota(): Not enough pages available 
(current pages -- %lu)\n", MmAvailablePages);
+                return FALSE;
+            }
+
+            /*
+             * Check if there's at least some space available
+             * in the non paged pool area.
+             */
+            if (MmMaximumNonPagedPoolInPages < (MmAllocatedNonPagedPool >> 
PAGE_SHIFT))
+            {
+                /* There's too much allocated space, bail out */
+                DPRINT1("MmRaisePoolQuota(): Failed to increase pool quota, 
not enough non paged pool space (current size -- %lu || allocated size -- 
%lu)\n",
+                        MmMaximumNonPagedPoolInPages, MmAllocatedNonPagedPool);
+                return FALSE;
+            }
+
+            /* Do we have enough resident pages to increase our quota? */
+            if (MmResidentAvailablePages < 
MI_NON_PAGED_QUOTA_MIN_RESIDENT_PAGES)
+            {
+                DPRINT1("MmRaisePoolQuota(): Failed to increase pool quota, 
not enough resident pages available (current available pages -- %lu)\n",
+                        MmResidentAvailablePages);
+                return FALSE;
+            }
+
+            /*
+             * Raise the non paged pool quota indicator and set
+             * up new maximum limit of quota for the process.
+             */
+            MmTotalNonPagedPoolQuota += MI_CHARGE_NON_PAGED_POOL_QUOTA;
+            *NewMaxQuota = CurrentMaxQuota + MI_CHARGE_NON_PAGED_POOL_QUOTA;
+            DPRINT("MmRaisePoolQuota(): Non paged pool quota increased (before 
-- %lu || after -- %lu)\n", CurrentMaxQuota, NewMaxQuota);
+            return TRUE;
+        }
+
+        case PagedPool:
+        {
+            /*
+             * Before raising the quota limit of a paged quota
+             * pool, make sure we've got enough space that is available.
+             * On Windows it seems it wants to check for at least 1 MB of space
+             * needed so that it would be possible to raise the paged pool 
quota.
+             */
+            if (MmSizeOfPagedPoolInPages < (MmPagedPoolInfo.AllocatedPagedPool 
>> PAGE_SHIFT))
+            {
+                /* We haven't gotten enough space, bail out */
+                DPRINT1("MmRaisePoolQuota(): Failed to increase pool quota, 
not enough paged pool space (current size -- %lu || allocated size -- %lu)\n",
+                        MmSizeOfPagedPoolInPages, 
MmPagedPoolInfo.AllocatedPagedPool >> PAGE_SHIFT);
+                return FALSE;
+            }
+
+            /*
+             * Raise the paged pool quota indicator and set
+             * up new maximum limit of quota for the process.
+             */
+            MmTotalPagedPoolQuota += MI_CHARGE_PAGED_POOL_QUOTA;
+            *NewMaxQuota = CurrentMaxQuota + MI_CHARGE_PAGED_POOL_QUOTA;
+            DPRINT("MmRaisePoolQuota(): Paged pool quota increased (before -- 
%lu || after -- %lu)\n", CurrentMaxQuota, NewMaxQuota);
+            return TRUE;
+        }
+
+        /* Only NonPagedPool and PagedPool are used */
+        DEFAULT_UNREACHABLE;
+    }
+}
+
+/**
+ * @brief
+ * Returns the quota, depending on the given
+ * pool type of the quota in question. The routine
+ * is used exclusively by Process Manager for quota
+ * handling.
+ *
+ * @param[in] PoolType
+ * The type of quota pool which the quota in question
+ * has to be raised.
+ *
+ * @param[in] CurrentMaxQuota
+ * The current maximum limit of quota threshold.
+ *
+ * @return
+ * Nothing.
+ *
+ * @remarks
+ * A spin lock must be held when raising the pool quota
+ * limit to avoid race occurences.
+ */
+_Requires_lock_held_(PspQuotaLock)
+VOID
+NTAPI
+MmReturnPoolQuota(
+    _In_ POOL_TYPE PoolType,
+    _In_ SIZE_T QuotaToReturn)
+{
+    /*
+     * We must be in dispatch level interrupt here
+     * as we should be under a spin lock at this point.
+     */
+    ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
+
+    switch (PoolType)
+    {
+        case NonPagedPool:
+        {
+            /* This is a non paged pool type, decrease the non paged quota */
+            ASSERT(MmTotalNonPagedPoolQuota >= QuotaToReturn);
+            MmTotalNonPagedPoolQuota -= QuotaToReturn;
+            DPRINT("MmReturnPoolQuota(): Non paged pool quota returned 
(current size -- %lu)\n", MmTotalNonPagedPoolQuota);
+            break;
+        }
+
+        case PagedPool:
+        {
+            /* This is a paged pool type, decrease the paged quota */
+            ASSERT(MmTotalPagedPoolQuota >= QuotaToReturn);
+            MmTotalPagedPoolQuota -= QuotaToReturn;
+            DPRINT("MmReturnPoolQuota(): Paged pool quota returned (current 
size -- %lu)\n", MmTotalPagedPoolQuota);
+            break;
+        }
+
+        /* Only NonPagedPool and PagedPool are used */
+        DEFAULT_UNREACHABLE;
+    }
+}
+
 /* PUBLIC FUNCTIONS 
***********************************************************/
 
 /*

Reply via email to