/* * 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; }