[NTOSKRNL] When growing a file, invalid the last VACB so that it can be refreshed
authorPierre Schweitzer <pierre@reactos.org>
Sun, 23 Dec 2018 10:08:01 +0000 (11:08 +0100)
committerPierre Schweitzer <pierre@reactos.org>
Sun, 23 Dec 2018 10:19:14 +0000 (11:19 +0100)
This will avoid corruption when a file size is little grown and read afterwards.
Up to now, FSD where reading 0es instead of expected data, causing corruption.

This fixes MS FastFAT not being able to mount a FAT volume in ReactOS, corrupting
the FAT.
This also fixes the CcSetFileSizes kmtest tests.

This is based on a patch by Thomas Faber.

CORE-11819

ntoskrnl/cc/fs.c

index e31a17b..5798f56 100644 (file)
@@ -301,6 +301,43 @@ CcSetFileSizes (
                             0,
                             FALSE);
     }
+    else
+    {
+        PROS_VACB LastVacb;
+
+        /*
+         * If file (allocation) size has increased, then we need to check whether
+         * it just grows in a single VACB (the last one).
+         * If so, we must mark the VACB as invalid to trigger a read to the
+         * FSD at the next VACB usage, and thus avoid returning garbage
+         */
+
+        /* Check for allocation size and the last VACB */
+        if (SharedCacheMap->SectionSize.QuadPart < FileSizes->AllocationSize.QuadPart &&
+            SharedCacheMap->SectionSize.QuadPart % VACB_MAPPING_GRANULARITY)
+        {
+            LastVacb = CcRosLookupVacb(SharedCacheMap,
+                                       SharedCacheMap->SectionSize.QuadPart);
+            if (LastVacb != NULL)
+            {
+                /* Mark it as invalid */
+                CcRosReleaseVacb(SharedCacheMap, LastVacb, LastVacb->Dirty ? LastVacb->Valid : FALSE, FALSE, FALSE);
+            }
+        }
+
+        /* Check for file size and the last VACB */
+        if (SharedCacheMap->FileSize.QuadPart < FileSizes->FileSize.QuadPart &&
+            SharedCacheMap->FileSize.QuadPart % VACB_MAPPING_GRANULARITY)
+        {
+            LastVacb = CcRosLookupVacb(SharedCacheMap,
+                                       SharedCacheMap->FileSize.QuadPart);
+            if (LastVacb != NULL)
+            {
+                /* Mark it as invalid */
+                CcRosReleaseVacb(SharedCacheMap, LastVacb, LastVacb->Dirty ? LastVacb->Valid : FALSE, FALSE, FALSE);
+            }
+        }
+    }
 
     KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
     SharedCacheMap->SectionSize = FileSizes->AllocationSize;