#include <debug.h>
#define MODULE_INVOLVED_IN_ARM3
-#include "../ARM3/miarm.h"
+#include <mm/ARM3/miarm.h>
#undef ExAllocatePoolWithQuota
#undef ExAllocatePoolWithQuotaTag
return (Result >> 24) ^ (Result >> 16) ^ (Result >> 8) ^ Result;
}
+#if DBG
+FORCEINLINE
+BOOLEAN
+ExpTagAllowPrint(CHAR Tag)
+{
+ if ((Tag >= 'a' && Tag <= 'z') ||
+ (Tag >= 'A' && Tag <= 'Z') ||
+ (Tag >= '0' && Tag <= '9') ||
+ Tag == ' ' || Tag == '=' ||
+ Tag == '?' || Tag == '@')
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#ifdef KDBG
+#define MiDumperPrint(dbg, fmt, ...) \
+ if (dbg) KdbpPrint(fmt, ##__VA_ARGS__); \
+ else DPRINT1(fmt, ##__VA_ARGS__)
+#else
+#define MiDumperPrint(dbg, fmt, ...) \
+ DPRINT1(fmt, ##__VA_ARGS__)
+#endif
+
+VOID
+MiDumpPoolConsumers(BOOLEAN CalledFromDbg, ULONG Tag, ULONG Mask, ULONG Flags)
+{
+ SIZE_T i;
+ BOOLEAN Verbose;
+
+ //
+ // Only print header if called from OOM situation
+ //
+ if (!CalledFromDbg)
+ {
+ DPRINT1("---------------------\n");
+ DPRINT1("Out of memory dumper!\n");
+ }
+#ifdef KDBG
+ else
+ {
+ KdbpPrint("Pool Used:\n");
+ }
+#endif
+
+ //
+ // Remember whether we'll have to be verbose
+ // This is the only supported flag!
+ //
+ Verbose = BooleanFlagOn(Flags, 1);
+
+ //
+ // Print table header
+ //
+ if (Verbose)
+ {
+ MiDumperPrint(CalledFromDbg, "\t\t\t\tNonPaged\t\t\t\t\t\t\tPaged\n");
+ MiDumperPrint(CalledFromDbg, "Tag\t\tAllocs\t\tFrees\t\tDiff\t\tUsed\t\tAllocs\t\tFrees\t\tDiff\t\tUsed\n");
+ }
+ else
+ {
+ MiDumperPrint(CalledFromDbg, "\t\tNonPaged\t\t\tPaged\n");
+ MiDumperPrint(CalledFromDbg, "Tag\t\tAllocs\t\tUsed\t\tAllocs\t\tUsed\n");
+ }
+
+ //
+ // We'll extract allocations for all the tracked pools
+ //
+ for (i = 0; i < PoolTrackTableSize; ++i)
+ {
+ PPOOL_TRACKER_TABLE TableEntry;
+
+ TableEntry = &PoolTrackTable[i];
+
+ //
+ // We only care about tags which have allocated memory
+ //
+ if (TableEntry->NonPagedBytes != 0 || TableEntry->PagedBytes != 0)
+ {
+ //
+ // If there's a tag, attempt to do a pretty print
+ // only if it matches the caller's tag, or if
+ // any tag is allowed
+ // For checking whether it matches caller's tag,
+ // use the mask to make sure not to mess with the wildcards
+ //
+ if (TableEntry->Key != 0 && TableEntry->Key != TAG_NONE &&
+ (Tag == 0 || (TableEntry->Key & Mask) == (Tag & Mask)))
+ {
+ CHAR Tag[4];
+
+ //
+ // Extract each 'component' and check whether they are printable
+ //
+ Tag[0] = TableEntry->Key & 0xFF;
+ Tag[1] = TableEntry->Key >> 8 & 0xFF;
+ Tag[2] = TableEntry->Key >> 16 & 0xFF;
+ Tag[3] = TableEntry->Key >> 24 & 0xFF;
+
+ if (ExpTagAllowPrint(Tag[0]) && ExpTagAllowPrint(Tag[1]) && ExpTagAllowPrint(Tag[2]) && ExpTagAllowPrint(Tag[3]))
+ {
+ //
+ // Print in direct order to make !poolused TAG usage easier
+ //
+ if (Verbose)
+ {
+ MiDumperPrint(CalledFromDbg, "'%c%c%c%c'\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", Tag[0], Tag[1], Tag[2], Tag[3],
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
+ (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedFrees,
+ (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
+ }
+ else
+ {
+ MiDumperPrint(CalledFromDbg, "'%c%c%c%c'\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", Tag[0], Tag[1], Tag[2], Tag[3],
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedBytes);
+ }
+ }
+ else
+ {
+ if (Verbose)
+ {
+ MiDumperPrint(CalledFromDbg, "%x\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", TableEntry->Key,
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
+ (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedFrees,
+ (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
+ }
+ else
+ {
+ MiDumperPrint(CalledFromDbg, "%x\t%ld\t\t%ld\t\t%ld\t\t%ld\n", TableEntry->Key,
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedBytes);
+ }
+ }
+ }
+ else if (Tag == 0 || (Tag & Mask) == (TAG_NONE & Mask))
+ {
+ if (Verbose)
+ {
+ MiDumperPrint(CalledFromDbg, "Anon\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n",
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
+ (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedFrees,
+ (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
+ }
+ else
+ {
+ MiDumperPrint(CalledFromDbg, "Anon\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n",
+ TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
+ TableEntry->PagedAllocs, TableEntry->PagedBytes);
+ }
+ }
+ }
+ }
+
+ if (!CalledFromDbg)
+ {
+ DPRINT1("---------------------\n");
+ }
+}
+#endif
+
/* PRIVATE FUNCTIONS **********************************************************/
+INIT_FUNCTION
VOID
NTAPI
-INIT_FUNCTION
ExpSeedHotTags(VOID)
{
ULONG i, Key, Hash, Index;
DPRINT1("Out of pool tag space, ignoring...\n");
}
+INIT_FUNCTION
VOID
NTAPI
-INIT_FUNCTION
ExInitializePoolDescriptor(IN PPOOL_DESCRIPTOR PoolDescriptor,
IN POOL_TYPE PoolType,
IN ULONG PoolIndex,
ASSERT(PoolType != PagedPoolSession);
}
+INIT_FUNCTION
VOID
NTAPI
-INIT_FUNCTION
InitializePool(IN POOL_TYPE PoolType,
IN ULONG Threshold)
{
}
//
- // Finally, add one entry, compute the hash, and zero the table
+ // Add one entry, compute the hash, and zero the table
//
PoolTrackTableSize++;
PoolTrackTableMask = PoolTrackTableSize - 2;
RtlZeroMemory(PoolTrackTable,
PoolTrackTableSize * sizeof(POOL_TRACKER_TABLE));
+ //
+ // Finally, add the most used tags to speed up those allocations
+ //
+ ExpSeedHotTags();
+
//
// We now do the exact same thing with the tracker table for big pages
//
//
// During development, print this out so we can see what's happening
//
- DPRINT1("EXPOOL: Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
+ DPRINT("EXPOOL: Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
PoolTrackTable, PoolTrackTableSize * sizeof(POOL_TRACKER_TABLE));
- DPRINT1("EXPOOL: Big Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
+ DPRINT("EXPOOL: Big Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
PoolBigPageTable, PoolBigPageTableSize * sizeof(POOL_TRACKER_BIG_PAGES));
//
InterlockedIncrementUL(&ExpPoolBigEntriesInUse);
if ((i >= 16) && (ExpPoolBigEntriesInUse > (TableSize / 4)))
{
- DPRINT1("Should attempt expansion since we now have %lu entries\n",
+ DPRINT("Should attempt expansion since we now have %lu entries\n",
ExpPoolBigEntriesInUse);
}
#endif
//
- // FIXME: Not yet supported
+ // Get the amount of hits in the system lookaside lists
//
- *NonPagedPoolLookasideHits += 0;
- *PagedPoolLookasideHits += 0;
+ if (!IsListEmpty(&ExPoolLookasideListHead))
+ {
+ PLIST_ENTRY ListEntry;
+
+ for (ListEntry = ExPoolLookasideListHead.Flink;
+ ListEntry != &ExPoolLookasideListHead;
+ ListEntry = ListEntry->Flink)
+ {
+ PGENERAL_LOOKASIDE Lookaside;
+
+ Lookaside = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
+
+ if (Lookaside->Type == NonPagedPool)
+ {
+ *NonPagedPoolLookasideHits += Lookaside->AllocateHits;
+ }
+ else
+ {
+ *PagedPoolLookasideHits += Lookaside->AllocateHits;
+ }
+ }
+ }
+}
+
+VOID
+NTAPI
+ExReturnPoolQuota(IN PVOID P)
+{
+ PPOOL_HEADER Entry;
+ POOL_TYPE PoolType;
+ USHORT BlockSize;
+ PEPROCESS Process;
+
+ if ((ExpPoolFlags & POOL_FLAG_SPECIAL_POOL) &&
+ (MmIsSpecialPoolAddress(P)))
+ {
+ return;
+ }
+
+ Entry = P;
+ Entry--;
+ ASSERT((ULONG_PTR)Entry % POOL_BLOCK_SIZE == 0);
+
+ PoolType = Entry->PoolType - 1;
+ BlockSize = Entry->BlockSize;
+
+ if (PoolType & QUOTA_POOL_MASK)
+ {
+ Process = ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1];
+ ASSERT(Process != NULL);
+ if (Process)
+ {
+ if (Process->Pcb.Header.Type != ProcessObject)
+ {
+ DPRINT1("Object %p is not a process. Type %u, pool type 0x%x, block size %u\n",
+ Process, Process->Pcb.Header.Type, Entry->PoolType, BlockSize);
+ KeBugCheckEx(BAD_POOL_CALLER,
+ 0x0D,
+ (ULONG_PTR)P,
+ Entry->PoolTag,
+ (ULONG_PTR)Process);
+ }
+ ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = NULL;
+ PsReturnPoolQuota(Process,
+ PoolType & BASE_POOL_TYPE_MASK,
+ BlockSize * POOL_BLOCK_SIZE);
+ ObDereferenceObject(Process);
+ }
+ }
}
/* PUBLIC FUNCTIONS ***********************************************************/
Entry = MiAllocatePoolPages(OriginalType, NumberOfBytes);
if (!Entry)
{
+#if DBG
+ //
+ // Out of memory, display current consumption
+ // Let's consider that if the caller wanted more
+ // than a hundred pages, that's a bogus caller
+ // and we are not out of memory
+ //
+ if (NumberOfBytes < 100 * PAGE_SIZE)
+ {
+ MiDumpPoolConsumers(FALSE, 0, 0, 0);
+ }
+#endif
+
//
// Must succeed pool is deprecated, but still supported. These allocation
// failures must cause an immediate bugcheck
//
if (ExpPoolFlags & POOL_FLAG_DBGPRINT_ON_FAILURE)
{
- DPRINT1("EX: ExAllocatePool (%p, 0x%x) returning NULL\n",
+ DPRINT1("EX: ExAllocatePool (%lu, 0x%x) returning NULL\n",
NumberOfBytes,
OriginalType);
if (ExpPoolFlags & POOL_FLAG_CRASH_ON_FAILURE) DbgBreakPoint();
{
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
}
+
+ return NULL;
}
//
// Get the real entry, write down its pool type, and track it
//
Entry--;
- Entry->PoolType = PoolType + 1;
+ Entry->PoolType = OriginalType + 1;
ExpInsertPoolTracker(Tag,
Entry->BlockSize * POOL_BLOCK_SIZE,
OriginalType);
// We have found an entry for this allocation, so set the pool type
// and release the lock since we're done
//
- Entry->PoolType = PoolType + 1;
+ Entry->PoolType = OriginalType + 1;
ExpCheckPoolBlocks(Entry);
ExUnlockPool(PoolDesc, OldIrql);
//
// There were no free entries left, so we have to allocate a new fresh page
//
- Entry = MiAllocatePoolPages(PoolType, PAGE_SIZE);
+ Entry = MiAllocatePoolPages(OriginalType, PAGE_SIZE);
if (!Entry)
{
+#if DBG
+ //
+ // Out of memory, display current consumption
+ // Let's consider that if the caller wanted more
+ // than a hundred pages, that's a bogus caller
+ // and we are not out of memory
+ //
+ if (NumberOfBytes < 100 * PAGE_SIZE)
+ {
+ MiDumpPoolConsumers(FALSE, 0, 0, 0);
+ }
+#endif
+
//
// Must succeed pool is deprecated, but still supported. These allocation
// failures must cause an immediate bugcheck
//
if (ExpPoolFlags & POOL_FLAG_DBGPRINT_ON_FAILURE)
{
- DPRINT1("EX: ExAllocatePool (%p, 0x%x) returning NULL\n",
+ DPRINT1("EX: ExAllocatePool (%lu, 0x%x) returning NULL\n",
NumberOfBytes,
OriginalType);
if (ExpPoolFlags & POOL_FLAG_CRASH_ON_FAILURE) DbgBreakPoint();
//
Entry->Ulong1 = 0;
Entry->BlockSize = i;
- Entry->PoolType = PoolType + 1;
+ Entry->PoolType = OriginalType + 1;
//
// This page will have two entries -- one for the allocation (which we just
InterlockedIncrement((PLONG)&PoolDesc->RunningAllocs);
ExpInsertPoolTracker(Tag,
Entry->BlockSize * POOL_BLOCK_SIZE,
- PoolType);
+ OriginalType);
//
// And return the pool allocation
ExAllocatePool(POOL_TYPE PoolType,
SIZE_T NumberOfBytes)
{
- //
- // Use a default tag of "None"
- //
- return ExAllocatePoolWithTag(PoolType, NumberOfBytes, TAG_NONE);
+ ULONG Tag = TAG_NONE;
+#if 0 && DBG
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+
+ /* Use the first four letters of the driver name, or "None" if unavailable */
+ LdrEntry = KeGetCurrentIrql() <= APC_LEVEL
+ ? MiLookupDataTableEntry(_ReturnAddress())
+ : NULL;
+ if (LdrEntry)
+ {
+ ULONG i;
+ Tag = 0;
+ for (i = 0; i < min(4, LdrEntry->BaseDllName.Length / sizeof(WCHAR)); i++)
+ Tag = Tag >> 8 | (LdrEntry->BaseDllName.Buffer[i] & 0xff) << 24;
+ for (; i < 4; i++)
+ Tag = Tag >> 8 | ' ' << 24;
+ }
+#endif
+ return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
}
/*
PFN_NUMBER PageCount, RealPageCount;
PKPRCB Prcb = KeGetCurrentPrcb();
PGENERAL_LOOKASIDE LookasideList;
+ PEPROCESS Process;
//
// Check if any of the debug flags are enabled
//
Entry = P;
Entry--;
+ ASSERT((ULONG_PTR)Entry % POOL_BLOCK_SIZE == 0);
//
// Get the size of the entry, and it's pool type, then load the descriptor
BlockSize * POOL_BLOCK_SIZE,
Entry->PoolType - 1);
+ //
+ // Release pool quota, if any
+ //
+ if ((Entry->PoolType - 1) & QUOTA_POOL_MASK)
+ {
+ Process = ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1];
+ if (Process)
+ {
+ if (Process->Pcb.Header.Type != ProcessObject)
+ {
+ DPRINT1("Object %p is not a process. Type %u, pool type 0x%x, block size %u\n",
+ Process, Process->Pcb.Header.Type, Entry->PoolType, BlockSize);
+ KeBugCheckEx(BAD_POOL_CALLER,
+ 0x0D,
+ (ULONG_PTR)P,
+ Tag,
+ (ULONG_PTR)Process);
+ }
+ PsReturnPoolQuota(Process, PoolType, BlockSize * POOL_BLOCK_SIZE);
+ ObDereferenceObject(Process);
+ }
+ }
+
//
// Is this allocation small enough to have come from a lookaside list?
//
//
// Allocate the pool
//
- return ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, 'enoN');
+ return ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, TAG_NONE);
}
/*
IN ULONG Tag,
IN EX_POOL_PRIORITY Priority)
{
+ PVOID Buffer;
+
//
// Allocate the pool
//
- UNIMPLEMENTED;
- return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
+ Buffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
+ if (Buffer == NULL)
+ {
+ UNIMPLEMENTED;
+ }
+
+ return Buffer;
}
/*
IN SIZE_T NumberOfBytes,
IN ULONG Tag)
{
- //
- // Allocate the pool
- //
- UNIMPLEMENTED;
- return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
-}
-
-#if DBG && KDBG
-
-BOOLEAN
-ExpKdbgExtPool(
- ULONG Argc,
- PCHAR Argv[])
-{
- ULONG_PTR Address = 0, Flags = 0;
- PVOID PoolPage;
+ BOOLEAN Raise = TRUE;
+ PVOID Buffer;
PPOOL_HEADER Entry;
- BOOLEAN ThisOne;
- PULONG Data;
+ NTSTATUS Status;
+ PEPROCESS Process = PsGetCurrentProcess();
- if (Argc > 1)
+ //
+ // Check if we should fail instead of raising an exception
+ //
+ if (PoolType & POOL_QUOTA_FAIL_INSTEAD_OF_RAISE)
{
- /* Get address */
- if (!KdbpGetHexNumber(Argv[1], &Address))
- {
- KdbpPrint("Invalid parameter: %s\n", Argv[0]);
- return TRUE;
- }
+ Raise = FALSE;
+ PoolType &= ~POOL_QUOTA_FAIL_INSTEAD_OF_RAISE;
}
- if (Argc > 2)
- {
- /* Get address */
- if (!KdbpGetHexNumber(Argv[1], &Flags))
- {
- KdbpPrint("Invalid parameter: %s\n", Argv[0]);
- return TRUE;
- }
- }
+ //
+ // Inject the pool quota mask
+ //
+ PoolType += QUOTA_POOL_MASK;
- /* Check if we got an address */
- if (Address != 0)
+ //
+ // Check if we have enough space to add the quota owner process, as long as
+ // this isn't the system process, which never gets charged quota
+ //
+ ASSERT(NumberOfBytes != 0);
+ if ((NumberOfBytes <= (PAGE_SIZE - POOL_BLOCK_SIZE - sizeof(PVOID))) &&
+ (Process != PsInitialSystemProcess))
{
- /* Get the base page */
- PoolPage = PAGE_ALIGN(Address);
+ //
+ // Add space for our EPROCESS pointer
+ //
+ NumberOfBytes += sizeof(PEPROCESS);
}
else
{
- KdbpPrint("Heap is unimplemented\n");
- return TRUE;
- }
-
- /* No paging support! */
- if (!MmIsAddressValid(PoolPage))
- {
- KdbpPrint("Address not accessible!\n");
- return TRUE;
+ //
+ // We won't be able to store the pointer, so don't use quota for this
+ //
+ PoolType -= QUOTA_POOL_MASK;
}
- /* Get pool type */
- if ((Address >= (ULONG_PTR)MmPagedPoolStart) && (Address <= (ULONG_PTR)MmPagedPoolEnd))
- KdbpPrint("Allocation is from PagedPool region\n");
- else if ((Address >= (ULONG_PTR)MmNonPagedPoolStart) && (Address <= (ULONG_PTR)MmNonPagedPoolEnd))
- KdbpPrint("Allocation is from NonPagedPool region\n");
- else
- {
- KdbpPrint("Address 0x%p is not within any pool!\n", (PVOID)Address);
- return TRUE;
- }
+ //
+ // Allocate the pool buffer now
+ //
+ Buffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
- /* Loop all entries of that page */
- Entry = PoolPage;
- do
+ //
+ // If the buffer is page-aligned, this is a large page allocation and we
+ // won't touch it
+ //
+ if (PAGE_ALIGN(Buffer) != Buffer)
{
- /* Check if the address is within that entry */
- ThisOne = ((Address >= (ULONG_PTR)Entry) &&
- (Address < (ULONG_PTR)(Entry + Entry->BlockSize)));
-
- if (!(Flags & 1) || ThisOne)
+ //
+ // Also if special pool is enabled, and this was allocated from there,
+ // we won't touch it either
+ //
+ if ((ExpPoolFlags & POOL_FLAG_SPECIAL_POOL) &&
+ (MmIsSpecialPoolAddress(Buffer)))
{
- /* Print the line */
- KdbpPrint("%c%p size: %4d previous size: %4d %s %.4s\n",
- ThisOne ? '*' : ' ', Entry, Entry->BlockSize, Entry->PreviousSize,
- (Flags & 0x80000000) ? "" : (Entry->PoolType ? "(Allocated)" : "(Free) "),
- (Flags & 0x80000000) ? "" : (PCHAR)&Entry->PoolTag);
+ return Buffer;
}
- if (Flags & 1)
+ //
+ // If it wasn't actually allocated with quota charges, ignore it too
+ //
+ if (!(PoolType & QUOTA_POOL_MASK)) return Buffer;
+
+ //
+ // If this is the system process, we don't charge quota, so ignore
+ //
+ if (Process == PsInitialSystemProcess) return Buffer;
+
+ //
+ // Actually go and charge quota for the process now
+ //
+ Entry = POOL_ENTRY(Buffer);
+ Status = PsChargeProcessPoolQuota(Process,
+ PoolType & BASE_POOL_TYPE_MASK,
+ Entry->BlockSize * POOL_BLOCK_SIZE);
+ if (!NT_SUCCESS(Status))
{
- Data = (PULONG)(Entry + 1);
- KdbpPrint(" %p %08lx %08lx %08lx %08lx\n"
- " %p %08lx %08lx %08lx %08lx\n",
- &Data[0], Data[0], Data[1], Data[2], Data[3],
- &Data[4], Data[4], Data[5], Data[6], Data[7]);
+ //
+ // Quota failed, back out the allocation, clear the owner, and fail
+ //
+ ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = NULL;
+ ExFreePoolWithTag(Buffer, Tag);
+ if (Raise) RtlRaiseStatus(Status);
+ return NULL;
}
- /* Go to next entry */
- Entry = POOL_BLOCK(Entry, Entry->BlockSize);
+ //
+ // Quota worked, write the owner and then reference it before returning
+ //
+ ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = Process;
+ ObReferenceObject(Process);
+ }
+ else if (!(Buffer) && (Raise))
+ {
+ //
+ // The allocation failed, raise an error if we are in raise mode
+ //
+ RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
}
- while ((Entry->BlockSize != 0) && ((ULONG_PTR)Entry < (ULONG_PTR)PoolPage + PAGE_SIZE));
- return TRUE;
+ //
+ // Return the allocated buffer
+ //
+ return Buffer;
}
-#endif // DBG && KDBG
-
/* EOF */