mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 20:23:34 +00:00
[NTOSKRNL] Rewrite CcCanIWrite() to make it more accurate and handle specific callers
This commit is contained in:
parent
f51b74ca61
commit
945ff8ea2e
1 changed files with 70 additions and 37 deletions
|
@ -27,6 +27,14 @@ typedef enum _CC_COPY_OPERATION
|
||||||
CcOperationZero
|
CcOperationZero
|
||||||
} CC_COPY_OPERATION;
|
} CC_COPY_OPERATION;
|
||||||
|
|
||||||
|
typedef enum _CC_CAN_WRITE_RETRY
|
||||||
|
{
|
||||||
|
FirstTry = 0,
|
||||||
|
RetryAllowRemote = 253,
|
||||||
|
RetryForceCheckPerFile = 254,
|
||||||
|
RetryMasterLocked = 255,
|
||||||
|
} CC_CAN_WRITE_RETRY;
|
||||||
|
|
||||||
ULONG CcRosTraceLevel = 0;
|
ULONG CcRosTraceLevel = 0;
|
||||||
ULONG CcFastMdlReadWait;
|
ULONG CcFastMdlReadWait;
|
||||||
ULONG CcFastMdlReadNotPossible;
|
ULONG CcFastMdlReadNotPossible;
|
||||||
|
@ -414,7 +422,7 @@ CcPostDeferredWrites(VOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check we can write */
|
/* Check we can write */
|
||||||
if (CcCanIWrite(DeferredWrite->FileObject, WrittenBytes, FALSE, TRUE))
|
if (CcCanIWrite(DeferredWrite->FileObject, WrittenBytes, FALSE, RetryForceCheckPerFile))
|
||||||
{
|
{
|
||||||
/* We can, so remove it from the list and stop looking for entry */
|
/* We can, so remove it from the list and stop looking for entry */
|
||||||
RemoveEntryList(&DeferredWrite->DeferredWriteLinks);
|
RemoveEntryList(&DeferredWrite->DeferredWriteLinks);
|
||||||
|
@ -614,9 +622,13 @@ CcCanIWrite (
|
||||||
IN BOOLEAN Wait,
|
IN BOOLEAN Wait,
|
||||||
IN BOOLEAN Retrying)
|
IN BOOLEAN Retrying)
|
||||||
{
|
{
|
||||||
|
KIRQL OldIrql;
|
||||||
KEVENT WaitEvent;
|
KEVENT WaitEvent;
|
||||||
|
ULONG Length, Pages;
|
||||||
|
BOOLEAN PerFileDefer;
|
||||||
DEFERRED_WRITE Context;
|
DEFERRED_WRITE Context;
|
||||||
PFSRTL_COMMON_FCB_HEADER Fcb;
|
PFSRTL_COMMON_FCB_HEADER Fcb;
|
||||||
|
CC_CAN_WRITE_RETRY TryContext;
|
||||||
PROS_SHARED_CACHE_MAP SharedCacheMap;
|
PROS_SHARED_CACHE_MAP SharedCacheMap;
|
||||||
|
|
||||||
CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
|
CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
|
||||||
|
@ -628,53 +640,74 @@ CcCanIWrite (
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We cannot write if dirty pages count is above threshold */
|
TryContext = Retrying;
|
||||||
if (CcTotalDirtyPages > CcDirtyPageThreshold)
|
/* Allow remote file if not from posted */
|
||||||
|
if (IoIsFileOriginRemote(FileObject) && TryContext < RetryAllowRemote)
|
||||||
{
|
{
|
||||||
/* Can the caller wait till it's possible to write? */
|
|
||||||
goto CanIWait;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We cannot write if dirty pages count will bring use above
|
|
||||||
* XXX: Might not be accurate
|
|
||||||
*/
|
|
||||||
if (CcTotalDirtyPages + (BytesToWrite / PAGE_SIZE) > CcDirtyPageThreshold)
|
|
||||||
{
|
|
||||||
/* Can the caller wait till it's possible to write? */
|
|
||||||
goto CanIWait;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is there a limit per file object? */
|
|
||||||
Fcb = FileObject->FsContext;
|
|
||||||
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
|
|
||||||
if (!BooleanFlagOn(Fcb->Flags, FSRTL_FLAG_LIMIT_MODIFIED_PAGES) ||
|
|
||||||
SharedCacheMap->DirtyPageThreshold == 0)
|
|
||||||
{
|
|
||||||
/* Nope, so that's fine, allow write operation */
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is dirty page count above local threshold? */
|
/* Don't exceed max tolerated size */
|
||||||
if (SharedCacheMap->DirtyPages > SharedCacheMap->DirtyPageThreshold)
|
Length = MAX_ZERO_LENGTH;
|
||||||
|
if (BytesToWrite < MAX_ZERO_LENGTH)
|
||||||
{
|
{
|
||||||
/* Can the caller wait till it's possible to write? */
|
Length = BytesToWrite;
|
||||||
goto CanIWait;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We cannot write if dirty pages count will bring use above
|
/* Convert it to pages count */
|
||||||
* XXX: Might not be accurate
|
Pages = (Length + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
/* By default, assume limits per file won't be hit */
|
||||||
|
PerFileDefer = FALSE;
|
||||||
|
Fcb = FileObject->FsContext;
|
||||||
|
/* Do we have to check for limits per file? */
|
||||||
|
if (TryContext >= RetryForceCheckPerFile ||
|
||||||
|
BooleanFlagOn(Fcb->Flags, FSRTL_FLAG_LIMIT_MODIFIED_PAGES))
|
||||||
|
{
|
||||||
|
/* If master is not locked, lock it now */
|
||||||
|
if (TryContext != RetryMasterLocked)
|
||||||
|
{
|
||||||
|
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let's not assume the file is cached... */
|
||||||
|
if (FileObject->SectionObjectPointer != NULL &&
|
||||||
|
FileObject->SectionObjectPointer->SharedCacheMap != NULL)
|
||||||
|
{
|
||||||
|
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
|
||||||
|
/* Do we have limits per file set? */
|
||||||
|
if (SharedCacheMap->DirtyPageThreshold != 0 &&
|
||||||
|
SharedCacheMap->DirtyPages != 0)
|
||||||
|
{
|
||||||
|
/* Yes, check whether they are blocking */
|
||||||
|
if (Pages + SharedCacheMap->DirtyPages > SharedCacheMap->DirtyPageThreshold)
|
||||||
|
{
|
||||||
|
PerFileDefer = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And don't forget to release master */
|
||||||
|
if (TryContext != RetryMasterLocked)
|
||||||
|
{
|
||||||
|
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* So, now allow write if:
|
||||||
|
* - Not the first try or we have no throttling yet
|
||||||
|
* AND:
|
||||||
|
* - We don't execeed threshold!
|
||||||
*/
|
*/
|
||||||
if (SharedCacheMap->DirtyPages + (BytesToWrite / PAGE_SIZE) > SharedCacheMap->DirtyPageThreshold)
|
if ((TryContext != FirstTry || IsListEmpty(&CcDeferredWrites)) &&
|
||||||
|
CcTotalDirtyPages + Pages < CcDirtyPageThreshold &&
|
||||||
|
!PerFileDefer)
|
||||||
{
|
{
|
||||||
/* Can the caller wait till it's possible to write? */
|
return TRUE;
|
||||||
goto CanIWait;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
/* If we can wait, we'll start the wait loop for waiting till we can
|
||||||
|
* write for real
|
||||||
CanIWait:
|
|
||||||
/* If we reached that point, it means caller cannot write
|
|
||||||
* If he cannot wait, then fail and deny write
|
|
||||||
*/
|
*/
|
||||||
if (!Wait)
|
if (!Wait)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue