* PURPOSE: Cache manager
*
* PROGRAMMERS: David Welch (welch@mcmail.com)
+ * Pierre Schweitzer (pierre@reactos.org)
*/
/* NOTES **********************************************************************
/* Internal vars (MS):
* - Threshold above which lazy writer will start action
* - Amount of dirty pages
+ * - List for deferred writes
+ * - Spinlock when dealing with the deferred list
+ * - List for "clean" shared cache maps
*/
ULONG CcDirtyPageThreshold = 0;
ULONG CcTotalDirtyPages = 0;
+LIST_ENTRY CcDeferredWrites;
+KSPIN_LOCK CcDeferredWriteSpinLock;
+LIST_ENTRY CcCleanSharedCacheMapList;
/* Internal vars (ROS):
* - Event to notify lazy writer to shutdown
* - Event to inform watchers lazy writer is done for this loop
+ * - Lock for the CcCleanSharedCacheMapList list
*/
KEVENT iLazyWriterShutdown;
KEVENT iLazyWriterNotify;
+KSPIN_LOCK iSharedCacheMapLock;
#if DBG
static void CcRosVacbIncRefCount_(PROS_VACB vacb, const char* file, int line)
while (TRUE)
{
NTSTATUS Status;
+ PLIST_ENTRY ListEntry;
ULONG Target, Count = 0;
/* One per second or until we have to stop */
/* We're not sleeping anymore */
KeClearEvent(&iLazyWriterNotify);
- /* Only start operations if above threshold */
- DPRINT("TS: %lu, Count: %lu\n", CcDirtyPageThreshold, CcTotalDirtyPages);
- if (CcTotalDirtyPages > CcDirtyPageThreshold)
+ /* Our target is one-eighth of the dirty pages */
+ Target = CcTotalDirtyPages / 8;
+ if (Target != 0)
{
- /* Our target is one-eighth of the dirty pages */
- Target = CcTotalDirtyPages / 8;
- if (Target != 0)
- {
- /* Flush! */
- DPRINT("Lazy writer starting (%d)\n", Target);
- CcRosFlushDirtyPages(Target, &Count, FALSE, TRUE);
-
- /* And update stats */
- CcLazyWritePages += Count;
- ++CcLazyWriteIos;
- DPRINT("Lazy writer done (%d)\n", Count);
- }
+ /* Flush! */
+ DPRINT("Lazy writer starting (%d)\n", Target);
+ CcRosFlushDirtyPages(Target, &Count, FALSE, TRUE);
+
+ /* And update stats */
+ CcLazyWritePages += Count;
+ ++CcLazyWriteIos;
+ DPRINT("Lazy writer done (%d)\n", Count);
}
/* Inform people waiting on us that we're done */
KeSetEvent(&iLazyWriterNotify, IO_DISK_INCREMENT, FALSE);
+
+ /* Likely not optimal, but let's handle one deferred write now! */
+ ListEntry = ExInterlockedRemoveHeadList(&CcDeferredWrites, &CcDeferredWriteSpinLock);
+ if (ListEntry != NULL)
+ {
+ PROS_DEFERRED_WRITE_CONTEXT Context;
+
+ /* Extract the context */
+ Context = CONTAINING_RECORD(ListEntry, ROS_DEFERRED_WRITE_CONTEXT, CcDeferredWritesEntry);
+
+ /* Can we write now? */
+ if (CcCanIWrite(Context->FileObject, Context->BytesToWrite, FALSE, Context->Retrying))
+ {
+ /* Yes! Do it, and destroy the associated context */
+ Context->PostRoutine(Context->Context1, Context->Context2);
+ ExFreePoolWithTag(Context, 'CcDw');
+ }
+ else
+ {
+ /* Otherwise, requeue it, but in tail, so that it doesn't block others
+ * This is clearly to improve, but given the poor algorithm used now
+ * It's better than nothing!
+ */
+ ExInterlockedInsertTailList(&CcDeferredWrites,
+ &Context->CcDeferredWritesEntry,
+ &CcDeferredWriteSpinLock);
+ }
+ }
}
}
return NULL;
}
-NTSTATUS
+VOID
NTAPI
CcRosMarkDirtyVacb (
- PROS_SHARED_CACHE_MAP SharedCacheMap,
- LONGLONG FileOffset)
+ PROS_VACB Vacb)
{
- PROS_VACB Vacb;
KIRQL oldIrql;
+ PROS_SHARED_CACHE_MAP SharedCacheMap;
- ASSERT(SharedCacheMap);
-
- DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
- SharedCacheMap, FileOffset);
-
- Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset);
- if (Vacb == NULL)
- {
- KeBugCheck(CACHE_MANAGER);
- }
+ SharedCacheMap = Vacb->SharedCacheMap;
KeAcquireGuardedMutex(&ViewLock);
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
KeReleaseGuardedMutex(&ViewLock);
+}
+
+NTSTATUS
+NTAPI
+CcRosMarkDirtyFile (
+ PROS_SHARED_CACHE_MAP SharedCacheMap,
+ LONGLONG FileOffset)
+{
+ PROS_VACB Vacb;
+
+ ASSERT(SharedCacheMap);
+
+ DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
+ SharedCacheMap, FileOffset);
+
+ Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset);
+ if (Vacb == NULL)
+ {
+ KeBugCheck(CACHE_MANAGER);
+ }
+
+ CcRosMarkDirtyVacb(Vacb);
+
+
CcRosReleaseVacbLock(Vacb);
return STATUS_SUCCESS;
SharedCacheMap->OpenCount--;
if (SharedCacheMap->OpenCount == 0)
{
+ KIRQL OldIrql;
+
FileObject->SectionObjectPointer->SharedCacheMap = NULL;
/*
current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry);
CcRosInternalFreeVacb(current);
}
+
+ KeAcquireSpinLock(&iSharedCacheMapLock, &OldIrql);
+ RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks);
+ KeReleaseSpinLock(&iSharedCacheMapLock, OldIrql);
+
ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap);
KeAcquireGuardedMutex(&ViewLock);
}
KeAcquireGuardedMutex(&ViewLock);
if (SharedCacheMap == NULL)
{
+ KIRQL OldIrql;
+
SharedCacheMap = ExAllocateFromNPagedLookasideList(&SharedCacheMapLookasideList);
if (SharedCacheMap == NULL)
{
SharedCacheMap->SectionSize = FileSizes->AllocationSize;
SharedCacheMap->FileSize = FileSizes->FileSize;
SharedCacheMap->PinAccess = PinAccess;
+ SharedCacheMap->DirtyPageThreshold = 0;
KeInitializeSpinLock(&SharedCacheMap->CacheMapLock);
InitializeListHead(&SharedCacheMap->CacheMapVacbListHead);
FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap;
+
+ KeAcquireSpinLock(&iSharedCacheMapLock, &OldIrql);
+ InsertTailList(&CcCleanSharedCacheMapList, &SharedCacheMap->SharedCacheMapLinks);
+ KeReleaseSpinLock(&iSharedCacheMapLock, OldIrql);
}
if (FileObject->PrivateCacheMap == NULL)
{
{
HANDLE LazyWriter;
NTSTATUS Status;
+ KPRIORITY Priority;
OBJECT_ATTRIBUTES ObjectAttributes;
DPRINT("CcInitView()\n");
InitializeListHead(&DirtyVacbListHead);
InitializeListHead(&VacbLruListHead);
+ InitializeListHead(&CcDeferredWrites);
+ InitializeListHead(&CcCleanSharedCacheMapList);
+ KeInitializeSpinLock(&CcDeferredWriteSpinLock);
+ KeInitializeSpinLock(&iSharedCacheMapLock);
KeInitializeGuardedMutex(&ViewLock);
ExInitializeNPagedLookasideList(&iBcbLookasideList,
NULL,
return FALSE;
}
+ Priority = 27;
+ Status = NtSetInformationThread(LazyWriter,
+ ThreadPriority,
+ &Priority,
+ sizeof(Priority));
+ ASSERT(NT_SUCCESS(Status));
+
/* Handle is not needed */
ObCloseHandle(LazyWriter, KernelMode);