[NTOSKRNL:CC] Implement Extarnal Cache Directives

Implemented::
CcDeductDirtyPagesFromExternalCache
CcAddDirtyPagesToExternalCache:: Exported 
CcAddExternalCache
CcRegisterExternalCache:: Exported 
CcRemoveExternalCache
CcUnregisterExternalCache :: Exported
This commit is contained in:
Dibyamartanda Samanta 2024-08-18 11:11:36 +02:00 committed by CodingWorkshop Signing Team
parent d0d6097d57
commit 08d017171d
Signed by: CodingWorkshop Signing Team
GPG Key ID: 6DC88369C82795D2

View File

@ -0,0 +1,210 @@
/*
* PROJECT: Alcyone System Kernel
* LICENSE: BSD Clause 3
* PURPOSE: Cache Controller:: External Cache Compatibility Layer
* NT KERNEL: 5.11.9360
* COPYRIGHT: 2023-2029 Dibymartanda Samanta <>
*/
NOTE::Alcyone will not notify,in case of Empty External Cache at the moment, feature is planned for threadpool revamp
/* Move Typedef later cctypes.hpp */
typedef struct alignas(24) _DIRTY_PAGE_STATISTICS {
ULONGLONG DirtyPages; // 0x0
ULONGLONG DirtyPagesLastScan; // 0x8
ULONG DirtyPagesScheduledLastScan; // 0x10
} DIRTY_PAGE_STATISTICS, *PDIRTY_PAGE_STATISTICS; // 0x18 bytes (sizeof)
typedef struct alignas(30) _CC_EXTERNAL_CACHE_INFO {
VOID (*Callback)(VOID* arg1, ULONGLONG arg2, ULONG arg3); // 0x0
struct _DIRTY_PAGE_STATISTICS DirtyPageStatistics; // 0x8
struct _LIST_ENTRY Links; // 0x20
} CC_EXTERNAL_CACHE_INFO, *PCC_EXTERNAL_CACHE_INFO; // 0x30 bytes (sizeof)
VOID
NTAPI
CcDeductDirtyPagesFromExternalCache(
IN PCC_EXTERNAL_CACHE_INFO ExternalCacheContext,
IN ULONG Pages
)
{
KIRQL OldIrql ={0};
ULONG PagesToDeduct = {0};
if (Pages > 0)
{
/* Acquire the master lock */
KeAcquireQueuedSpinLock(LockQueueMasterLock, &OldIrql);
/* Calculate the number of pages to deduct */
PagesToDeduct = min(Pages, ExternalCacheContext->DirtyPageStatistics.DirtyPages);
/* Deduct the pages from the external cache context */
ExternalCacheContext->DirtyPageStatistics.DirtyPages -= PagesToDeduct;
/* Deduct the pages from the global statistics */
CcTotalDirtyPages -= PagesToDeduct;
/* Release the master lock */
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
}
/* Check if there are any deferred writes and post them if necessary */
if (!IsListEmpty(&CcDeferredWrites))
{
CcPostDeferredWrites();
}
}
VOID
NTAPI
CcAddExternalCache(
IN PCC_EXTERNAL_CACHE_INFO CacheInfo
)
{
KLOCK_QUEUE_HANDLE LockHandle ={0};
/* Acquire the external cache list lock */
KeAcquireInStackQueuedSpinLock(&CcExternalCacheListLock,&LockHandle);
/* Insert the new cache info at the end of the list */
InsertTailList(&CcExternalCacheList, &CacheInfo->Links);
/* Increment the number of external caches */
if (_InterlockedIncrement(&CcNumberOfExternalCaches) <= 0)
{
/* Overflow occurred, bug check */
KeBugCheckEx(CACHE_MANAGER,0,STATUS_INTEGER_OVERFLOW,0,0);
}
/* Release the external cache list lock */
KeReleaseInStackQueuedSpinLock(&LockHandle);
}
VOID
NTAPI
CcRemoveExternalCache(
IN PCC_EXTERNAL_CACHE_INFO CacheInfo
)
{
KLOCK_QUEUE_HANDLE LockHandle ={0};
/* Acquire the external cache list lock */
KeAcquireInStackQueuedSpinLock(&CcExternalCacheListLock,&LockHandle);
/* Remove the entry from the list */
RemoveTailList(&CacheInfo->Links.Blink);
/* Decrement the number of external caches */
if (_InterlockedDecrement(&CcNumberOfExternalCaches) < 0)
{
/* Underflow occurred, bug check */
KeBugCheckEx(CACHE_MANAGER,0,STATUS_INTEGER_OVERFLOW,0,0);
}
/* Release the external cache list lock */
KeReleaseInStackQueuedSpinLock(&LockHandle);
}
/*Exported */
VOID
NTAPI
CcAddDirtyPagesToExternalCache(
IN PCC_EXTERNAL_CACHE_INFO ExternalCacheContext,
IN ULONG Pages
)
{
KIRQL OldIrql ={0};
/* Only proceed if there are pages to add */
if (Pages == 0)
{
return;
}
/* Acquire the master lock */
KeAcquireQueuedSpinLock(LockQueueMasterLock, &OldIrql);
/* If this is the first dirty page, schedule a lazy write scan */
if (ExternalCacheContext->DirtyPageStatistics.DirtyPages == 0)
{
CcScheduleLazyWriteScan(FALSE, NULL);
}
/* Increment the dirty page count */
ExternalCacheContext->DirtyPageStatistics.DirtyPages += Pages;
/* Charge the dirty pages */
CcChargeDirtyPages(NULL, NULL, NULL, Pages);
/* Release the master lock */
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
}
VOID
NTAPI
CcUnregisterExternalCache(
IN PCC_EXTERNAL_CACHE_INFO ExternalCacheContext
)
{
/* Remove the external cache from the list */
CcRemoveExternalCache(ExternalCacheContext);
/* Deduct any remaining dirty pages */
if (ExternalCacheContext->DirtyPageStatistics.DirtyPages > 0)
{
CcDeductDirtyPagesFromExternalCache(ExternalCacheContext,ExternalCacheContext->DirtyPageStatistics.DirtyPages);
}
/* Free the external cache context */
ExFreePoolWithTag(ExternalCacheContext, CC_EXTERNAL_CACHE_INFO_TAG);
}
NTSTATUS
NTAPI
CcRegisterExternalCache(
IN PCC_EXTERNAL_CACHE_CALLBACK Callback,
OUT PVOID *ExternalCacheContext
)
{
NTSTATUS Status = STATUS_SUCCESS;
PCC_EXTERNAL_CACHE_INFO CacheInfo;
/* Ensure the Cache Manager is initialized */
if (!CcInitializationComplete)
{
KeBugCheckEx(CACHE_MANAGER,0,STATUS_UNSUCCESSFUL,0,0);
}
/* Allocate memory for the external cache info structure */
CacheInfo = ExAllocatePoolWithTag(NonPagedPool,
sizeof(CC_EXTERNAL_CACHE_INFO),
CC_EXTERNAL_CACHE_INFO_TAG);
if (CacheInfo == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Initialize the cache info structure */
RtlZeroMemory(CacheInfo, sizeof(CC_EXTERNAL_CACHE_INFO));
CacheInfo->Callback = Callback;
/* Add the external cache to the list */
CcAddExternalCache(CacheInfo);
/* Return the cache info as the context */
*ExternalCacheContext = CacheInfo;
return Status;
}