[NTOS:CC] Don't read past the end of the file in CcPerformReadAhead.
[reactos.git] / ntoskrnl / cc / copy.c
index 4089702..496cef6 100644 (file)
@@ -517,6 +517,16 @@ CcPerformReadAhead(
     /* Remember it's locked */
     Locked = TRUE;
 
+    /* Don't read past the end of the file */
+    if (CurrentOffset >= SharedCacheMap->FileSize.QuadPart)
+    {
+        goto Clear;
+    }
+    if (CurrentOffset + Length > SharedCacheMap->FileSize.QuadPart)
+    {
+        Length = SharedCacheMap->FileSize.QuadPart - CurrentOffset;
+    }
+
     /* Next of the algorithm will lock like CcCopyData with the slight
      * difference that we don't copy data back to an user-backed buffer
      * We just bring data into Cc
@@ -594,10 +604,10 @@ Clear:
     {
         /* Mark read ahead as unactive */
         KeAcquireSpinLockAtDpcLevel(&PrivateCacheMap->ReadAheadSpinLock);
-        InterlockedAnd((volatile long *)&PrivateCacheMap->UlongFlags, 0xFFFEFFFF);
+        InterlockedAnd((volatile long *)&PrivateCacheMap->UlongFlags, ~PRIVATE_CACHE_MAP_READ_AHEAD_ACTIVE);
         KeReleaseSpinLockFromDpcLevel(&PrivateCacheMap->ReadAheadSpinLock);
     }
-    KeReleaseSpinLock(&PrivateCacheMap->ReadAheadSpinLock, OldIrql);
+    KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
 
     /* If file was locked, release it */
     if (Locked)
@@ -697,10 +707,16 @@ CcCanIWrite (
     /* So, now allow write if:
      * - Not the first try or we have no throttling yet
      * AND:
-     * - We don't execeed threshold!
+     * - We don't exceed threshold!
+     * - We don't exceed what Mm can allow us to use
+     *   + If we're above top, that's fine
+     *   + If we're above bottom with limited modified pages, that's fine
+     *   + Otherwise, throttle!
      */
     if ((TryContext != FirstTry || IsListEmpty(&CcDeferredWrites)) &&
         CcTotalDirtyPages + Pages < CcDirtyPageThreshold &&
+        (MmAvailablePages > MmThrottleTop ||
+         (MmModifiedPageListHead.Total < 1000 && MmAvailablePages > MmThrottleBottom)) &&
         !PerFileDefer)
     {
         return TRUE;