diff --git a/NTOSKRNL/CC/ccutil.cpp b/NTOSKRNL/CC/ccutil.cpp index 335a013..13f5a6e 100644 --- a/NTOSKRNL/CC/ccutil.cpp +++ b/NTOSKRNL/CC/ccutil.cpp @@ -130,12 +130,120 @@ CcCanIWrite( _In_ PFILE_OBJECT FileObject, _In_ ULONG BytesToWrite, _In_ BOOLEAN Wait, - _In_ BOOLEAN IsRetrying) + _In_ UCHAR Retrying) { - NT_DBGBREAK("UNIMPLEMENTED\n"); -} + PFSRTL_COMMON_FCB_HEADER FsContext; + PSHARED_CACHE_MAP SharedCacheMap; + DEFERRED_WRITE DeferredWrite; + KEVENT Event; + ULONG WriteSize; + ULONG Pages; + KIRQL OldIrql; + BOOLEAN IsSmallThreshold = FALSE; + /* Quick checks for immediate return */ + if (FileObject->Flags & FO_WRITE_THROUGH) + return TRUE; + + if (IoIsFileOriginRemote(FileObject) && Retrying < 0xFD) + return TRUE; + + /* Calculate size and pages */ + WriteSize = min(BytesToWrite, 0x40000); + Pages = ROUND_UP(WriteSize, PAGE_SIZE) / PAGE_SIZE; + + FsContext = FileObject->FsContext; + + /* Check threshold conditions */ + if (Retrying >= 0xFE || (FsContext->Flags & FSRTL_FLAG_LIMIT_MODIFIED_PAGES)) + { + if (Retrying != 0xFF) + { + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + } + + if (FileObject->SectionObjectPointer) + { + SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; + if (SharedCacheMap && + SharedCacheMap->DirtyPageThreshold && + SharedCacheMap->DirtyPages) + { + if (SharedCacheMap->DirtyPageThreshold < (SharedCacheMap->DirtyPages + Pages)) + { + IsSmallThreshold = TRUE; + } + } + } + + if (Retrying != 0xFF) + { + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + } + } + + /* Check if we can write immediately */ + if ((Retrying || IsListEmpty(&CcDeferredWrites)) && + (CcDirtyPageThreshold > (CcTotalDirtyPages + Pages))) + { + if ((MmAvailablePages > MmThrottleTop && !IsSmallThreshold) || + (MmModifiedPageListHead.Total < 1000 && + MmAvailablePages > MmThrottleBottom && + !IsSmallThreshold)) + { + return TRUE; + } + } + + if (!Wait) + return FALSE; + + /* Initialize deferred write */ + if (IsListEmpty(&CcDeferredWrites)) + { + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + CcScheduleLazyWriteScan(TRUE); + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + } + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + DeferredWrite.NodeTypeCode = NODE_TYPE_DEFERRED_WRITE; + DeferredWrite.NodeByteSize = sizeof(DEFERRED_WRITE); + DeferredWrite.FileObject = FileObject; + DeferredWrite.BytesToWrite = BytesToWrite; + DeferredWrite.Event = &Event; + DeferredWrite.LimitModifiedPages = (FsContext->Flags & FSRTL_FLAG_LIMIT_MODIFIED_PAGES) != 0; + + /* Insert into deferred writes list */ + /* Insert into deferred writes list */ + if (Retrying) + { + ExInterlockedInsertHeadList(&CcDeferredWrites, + &DeferredWrite.DeferredWriteLinks, + &CcDeferredWriteSpinLock); + } + else + { + ExInterlockedInsertTailList(&CcDeferredWrites, + &DeferredWrite.DeferredWriteLinks, + &CcDeferredWriteSpinLock); + } + + /* Wait for the write to complete */ + do + { + CcPostDeferredWrites(); + } while (KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + &CcIdleDelay) != STATUS_SUCCESS); + + return TRUE; +} + BOOLEAN NTAPI @@ -165,18 +273,53 @@ CcCopyWrite( VOID -NTAPI -CcDeferWrite(IN PFILE_OBJECT FileObject, - IN PCC_POST_DEFERRED_WRITE PostRoutine, - IN PVOID Context1, - IN PVOID Context2, - IN ULONG BytesToWrite, - IN BOOLEAN Retrying) +CcDeferWrite( + _In_ PFILE_OBJECT FileObject, + _In_ PCC_POST_DEFERRED_WRITE PostRoutine, + _In_ PVOID Context1, + _In_ PVOID Context2, + _In_ ULONG BytesToWrite, + _In_ BOOLEAN Retrying + ) { - NT_DBGBREAK("UNIMPLEMENTED\n"); -} + + KIRQL OldIrql; + PDEFERRED_WRITE DeferredWrite = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(DEFERRED_WRITE), 'wDcC'); + if (DeferredWrite != nullptr) + { + RtlZeroMemory(DeferredWrite, sizeof(DEFERRED_WRITE)); + + DeferredWrite->NodeTypeCode = NODE_TYPE_DEFERRED_WRITE; + DeferredWrite->NodeByteSize = sizeof(DEFERRED_WRITE); + DeferredWrite->FileObject = FileObject; + DeferredWrite->BytesToWrite = BytesToWrite; + DeferredWrite->PostRoutine = PostRoutine; + DeferredWrite->Context1 = Context1; + DeferredWrite->Context2 = Context2; + + if (Retrying) + ExInterlockedInsertHeadList(&CcDeferredWrites, + &DeferredWrite->DeferredWriteLinks, + &CcDeferredWriteSpinLock); + else + ExInterlockedInsertTailList(&CcDeferredWrites, + &DeferredWrite->DeferredWriteLinks, + &CcDeferredWriteSpinLock); + + CcPostDeferredWrites(); + + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + CcScheduleLazyWriteScan(TRUE); + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + } + else + { + PostRoutine(Context1, Context2); + } +} + VOID NTAPI CcFastCopyRead(