[NTOS:CC] Rewrite CcPostDeferredWrites

This allows to post small writes if there are any, and avoid holding the list lock for a long time.
This commit is contained in:
Jérôme Gardou 2021-02-18 11:36:14 +01:00
parent b13a696513
commit 5c54fb9179

View File

@ -72,74 +72,57 @@ CcInitCacheZeroPage (
VOID
CcPostDeferredWrites(VOID)
{
ULONG WrittenBytes;
LIST_ENTRY ToInsertBack;
InitializeListHead(&ToInsertBack);
/* We'll try to write as much as we can */
WrittenBytes = 0;
while (TRUE)
{
KIRQL OldIrql;
PLIST_ENTRY ListEntry;
PDEFERRED_WRITE DeferredWrite;
PLIST_ENTRY ListEntry;
DeferredWrite = NULL;
/* Lock our deferred writes list */
KeAcquireSpinLock(&CcDeferredWriteSpinLock, &OldIrql);
for (ListEntry = CcDeferredWrites.Flink;
ListEntry != &CcDeferredWrites;
ListEntry = ListEntry->Flink)
ListEntry = ExInterlockedRemoveHeadList(&CcDeferredWrites, &CcDeferredWriteSpinLock);
if (!ListEntry)
break;
DeferredWrite = CONTAINING_RECORD(ListEntry, DEFERRED_WRITE, DeferredWriteLinks);
/* Check if we can write */
if (CcCanIWrite(DeferredWrite->FileObject, DeferredWrite->BytesToWrite, FALSE, RetryForceCheckPerFile))
{
/* Extract an entry */
DeferredWrite = CONTAINING_RECORD(ListEntry, DEFERRED_WRITE, DeferredWriteLinks);
/* Compute the modified bytes, based on what we already wrote */
WrittenBytes += DeferredWrite->BytesToWrite;
/* We overflowed, give up */
if (WrittenBytes < DeferredWrite->BytesToWrite)
/* If we have an event, set it and go along */
if (DeferredWrite->Event)
{
DeferredWrite = NULL;
break;
KeSetEvent(DeferredWrite->Event, IO_NO_INCREMENT, FALSE);
}
/* Check we can write */
if (CcCanIWrite(DeferredWrite->FileObject, WrittenBytes, FALSE, RetryForceCheckPerFile))
/* Otherwise, call the write routine and free the context */
else
{
/* We can, so remove it from the list and stop looking for entry */
RemoveEntryList(&DeferredWrite->DeferredWriteLinks);
break;
DeferredWrite->PostRoutine(DeferredWrite->Context1, DeferredWrite->Context2);
ExFreePoolWithTag(DeferredWrite, 'CcDw');
}
/* If we don't accept modified pages, stop here */
if (!DeferredWrite->LimitModifiedPages)
{
DeferredWrite = NULL;
break;
}
/* Reset count as nothing was written yet */
WrittenBytes -= DeferredWrite->BytesToWrite;
DeferredWrite = NULL;
continue;
}
KeReleaseSpinLock(&CcDeferredWriteSpinLock, OldIrql);
/* Nothing to write found, give up */
if (DeferredWrite == NULL)
/* Keep it for later */
InsertHeadList(&ToInsertBack, &DeferredWrite->DeferredWriteLinks);
/* If we don't accept modified pages, stop here */
if (!DeferredWrite->LimitModifiedPages)
{
break;
}
}
/* If we have an event, set it and quit */
if (DeferredWrite->Event)
{
KeSetEvent(DeferredWrite->Event, IO_NO_INCREMENT, FALSE);
}
/* Otherwise, call the write routine and free the context */
else
{
DeferredWrite->PostRoutine(DeferredWrite->Context1, DeferredWrite->Context2);
ExFreePoolWithTag(DeferredWrite, 'CcDw');
}
/* Insert what we couldn't write back in the list */
while (!IsListEmpty(&ToInsertBack))
{
PLIST_ENTRY ListEntry = RemoveTailList(&ToInsertBack);
ExInterlockedInsertHeadList(&CcDeferredWrites, ListEntry, &CcDeferredWriteSpinLock);
}
}