[NTOSKRNL] Add an helper for marking a VACB clean (ie, not dirty).
[reactos.git] / ntoskrnl / cc / fs.c
index e2e4c2d..38c9ae5 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
-#ifndef VACB_MAPPING_GRANULARITY
-#define VACB_MAPPING_GRANULARITY (256 * 1024)
-#endif
-
 /* GLOBALS   *****************************************************************/
 
 extern KGUARDED_MUTEX ViewLock;
-extern ULONG DirtyPageCount;
 
-NTSTATUS CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg);
+NTSTATUS CcRosInternalFreeVacb(PROS_VACB Vacb);
 
 /* FUNCTIONS *****************************************************************/
 
@@ -32,16 +27,19 @@ NTSTATUS CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg);
 LARGE_INTEGER
 NTAPI
 CcGetDirtyPages (
-       IN      PVOID                   LogHandle,
-       IN      PDIRTY_PAGE_ROUTINE     DirtyPageRoutine,
-       IN      PVOID                   Context1,
-       IN      PVOID                   Context2
-       )
+    IN PVOID LogHandle,
+    IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine,
+    IN PVOID Context1,
+    IN PVOID Context2)
 {
-       LARGE_INTEGER i;
-       UNIMPLEMENTED;
-       i.QuadPart = 0;
-       return i;
+    LARGE_INTEGER i;
+
+    CCTRACE(CC_API_DEBUG, "LogHandle=%p DirtyPageRoutine=%p Context1=%p Context2=%p\n",
+        LogHandle, DirtyPageRoutine, Context1, Context2);
+
+    UNIMPLEMENTED;
+    i.QuadPart = 0;
+    return i;
 }
 
 /*
@@ -50,11 +48,13 @@ CcGetDirtyPages (
 PFILE_OBJECT
 NTAPI
 CcGetFileObjectFromBcb (
-       IN      PVOID   Bcb
-       )
+    IN PVOID Bcb)
 {
-       PINTERNAL_BCB iBcb = (PINTERNAL_BCB)Bcb;
-       return iBcb->CacheSegment->Bcb->FileObject;
+    PINTERNAL_BCB iBcb = (PINTERNAL_BCB)Bcb;
+
+    CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb);
+
+    return iBcb->Vacb->SharedCacheMap->FileObject;
 }
 
 /*
@@ -63,14 +63,16 @@ CcGetFileObjectFromBcb (
 LARGE_INTEGER
 NTAPI
 CcGetLsnForFileObject (
-       IN      PFILE_OBJECT    FileObject,
-       OUT     PLARGE_INTEGER  OldestLsn OPTIONAL
-       )
+    IN PFILE_OBJECT FileObject,
+    OUT PLARGE_INTEGER OldestLsn OPTIONAL)
 {
-       LARGE_INTEGER i;
-       UNIMPLEMENTED;
-       i.QuadPart = 0;
-       return i;
+    LARGE_INTEGER i;
+
+    CCTRACE(CC_API_DEBUG, "FileObject=%p\n", FileObject);
+
+    UNIMPLEMENTED;
+    i.QuadPart = 0;
+    return i;
 }
 
 /*
@@ -79,33 +81,76 @@ CcGetLsnForFileObject (
 VOID
 NTAPI
 CcInitializeCacheMap (
-       IN      PFILE_OBJECT                    FileObject,
-       IN      PCC_FILE_SIZES                  FileSizes,
-       IN      BOOLEAN                         PinAccess,
-       IN      PCACHE_MANAGER_CALLBACKS        CallBacks,
-       IN      PVOID                           LazyWriterContext
-       )
+    IN PFILE_OBJECT FileObject,
+    IN PCC_FILE_SIZES FileSizes,
+    IN BOOLEAN PinAccess,
+    IN PCACHE_MANAGER_CALLBACKS CallBacks,
+    IN PVOID LazyWriterContext)
 {
+    NTSTATUS Status;
+
     ASSERT(FileObject);
     ASSERT(FileSizes);
 
+    CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p PinAccess=%d CallBacks=%p LazyWriterContext=%p\n",
+        FileObject, FileSizes, PinAccess, CallBacks, LazyWriterContext);
+
     /* Call old ROS cache init function */
-    CcRosInitializeFileCache(FileObject,
-        /*PAGE_SIZE*/ VACB_MAPPING_GRANULARITY, CallBacks,
-        LazyWriterContext);
+    Status = CcRosInitializeFileCache(FileObject,
+                                      FileSizes,
+                                      PinAccess,
+                                      CallBacks,
+                                      LazyWriterContext);
+    if (!NT_SUCCESS(Status))
+        ExRaiseStatus(Status);
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOLEAN
 NTAPI
 CcIsThereDirtyData (
-       IN      PVPB    Vpb
-       )
+    IN PVPB Vpb)
 {
-       UNIMPLEMENTED;
-       return FALSE;
+    PROS_VACB Vacb;
+    PLIST_ENTRY Entry;
+    /* Assume no dirty data */
+    BOOLEAN Dirty = FALSE;
+
+    CCTRACE(CC_API_DEBUG, "Vpb=%p\n", Vpb);
+
+    KeAcquireGuardedMutex(&ViewLock);
+
+    /* Browse dirty VACBs */
+    for (Entry = DirtyVacbListHead.Flink; Entry != &DirtyVacbListHead; Entry = Entry->Flink)
+    {
+        Vacb = CONTAINING_RECORD(Entry, ROS_VACB, DirtyVacbListEntry);
+        /* Look for these associated with our volume */
+        if (Vacb->SharedCacheMap->FileObject->Vpb != Vpb)
+        {
+            continue;
+        }
+
+        /* From now on, we are associated with our VPB */
+
+        /* Temporary files are not counted as dirty */
+        if (BooleanFlagOn(Vacb->SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE))
+        {
+            continue;
+        }
+
+        /* A single dirty VACB is enough to have dirty data */
+        if (Vacb->Dirty)
+        {
+            Dirty = TRUE;
+            break;
+        }
+    }
+
+    KeReleaseGuardedMutex(&ViewLock);
+
+    return Dirty;
 }
 
 /*
@@ -114,14 +159,97 @@ CcIsThereDirtyData (
 BOOLEAN
 NTAPI
 CcPurgeCacheSection (
-       IN      PSECTION_OBJECT_POINTERS        SectionObjectPointer,
-       IN      PLARGE_INTEGER                  FileOffset OPTIONAL,
-       IN      ULONG                           Length,
-       IN      BOOLEAN                         UninitializeCacheMaps
-       )
+    IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
+    IN PLARGE_INTEGER FileOffset OPTIONAL,
+    IN ULONG Length,
+    IN BOOLEAN UninitializeCacheMaps)
 {
-       //UNIMPLEMENTED;
-       return FALSE;
+    PROS_SHARED_CACHE_MAP SharedCacheMap;
+    LONGLONG StartOffset;
+    LONGLONG EndOffset;
+    LIST_ENTRY FreeList;
+    KIRQL OldIrql;
+    PLIST_ENTRY ListEntry;
+    PROS_VACB Vacb;
+    LONGLONG ViewEnd;
+    BOOLEAN Success;
+
+    CCTRACE(CC_API_DEBUG, "SectionObjectPointer=%p\n FileOffset=%p Length=%lu UninitializeCacheMaps=%d",
+        SectionObjectPointer, FileOffset, Length, UninitializeCacheMaps);
+
+    if (UninitializeCacheMaps)
+    {
+        DPRINT1("FIXME: CcPurgeCacheSection not uninitializing private cache maps\n");
+    }
+
+    SharedCacheMap = SectionObjectPointer->SharedCacheMap;
+    if (!SharedCacheMap)
+        return FALSE;
+
+    StartOffset = FileOffset != NULL ? FileOffset->QuadPart : 0;
+    if (Length == 0 || FileOffset == NULL)
+    {
+        EndOffset = MAXLONGLONG;
+    }
+    else
+    {
+        EndOffset = StartOffset + Length;
+        ASSERT(EndOffset > StartOffset);
+    }
+
+    InitializeListHead(&FreeList);
+
+    /* Assume success */
+    Success = TRUE;
+
+    KeAcquireGuardedMutex(&ViewLock);
+    KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
+    ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink;
+    while (ListEntry != &SharedCacheMap->CacheMapVacbListHead)
+    {
+        Vacb = CONTAINING_RECORD(ListEntry, ROS_VACB, CacheMapVacbListEntry);
+        ListEntry = ListEntry->Flink;
+
+        /* Skip VACBs outside the range, or only partially in range */
+        if (Vacb->FileOffset.QuadPart < StartOffset)
+        {
+            continue;
+        }
+        ViewEnd = min(Vacb->FileOffset.QuadPart + VACB_MAPPING_GRANULARITY,
+                      SharedCacheMap->SectionSize.QuadPart);
+        if (ViewEnd >= EndOffset)
+        {
+            break;
+        }
+
+        /* Still in use, it cannot be purged, fail */
+        if (Vacb->ReferenceCount != 0 && !Vacb->Dirty)
+        {
+            Success = FALSE;
+            break;
+        }
+
+        /* This VACB is in range, so unlink it and mark for free */
+        RemoveEntryList(&Vacb->VacbLruListEntry);
+        if (Vacb->Dirty)
+        {
+            CcRosUnmarkDirtyVacb(Vacb, FALSE);
+        }
+        RemoveEntryList(&Vacb->CacheMapVacbListEntry);
+        InsertHeadList(&FreeList, &Vacb->CacheMapVacbListEntry);
+    }
+    KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
+    KeReleaseGuardedMutex(&ViewLock);
+
+    while (!IsListEmpty(&FreeList))
+    {
+        Vacb = CONTAINING_RECORD(RemoveHeadList(&FreeList),
+                                 ROS_VACB,
+                                 CacheMapVacbListEntry);
+        CcRosInternalFreeVacb(Vacb);
+    }
+
+    return Success;
 }
 
 
@@ -129,91 +257,44 @@ CcPurgeCacheSection (
  * @implemented
  */
 VOID NTAPI
-CcSetFileSizes (IN PFILE_OBJECT FileObject,
-               IN PCC_FILE_SIZES FileSizes)
+CcSetFileSizes (
+    IN PFILE_OBJECT FileObject,
+    IN PCC_FILE_SIZES FileSizes)
 {
-  KIRQL oldirql;
-  PBCB Bcb;
-  PLIST_ENTRY current_entry;
-  PCACHE_SEGMENT current;
-  LIST_ENTRY FreeListHead;
-  NTSTATUS Status;
-
-  DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n",
-        FileObject, FileSizes);
-  DPRINT("AllocationSize %d, FileSize %d, ValidDataLength %d\n",
-         (ULONG)FileSizes->AllocationSize.QuadPart,
-         (ULONG)FileSizes->FileSize.QuadPart,
-         (ULONG)FileSizes->ValidDataLength.QuadPart);
-
-  Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
-
-  /*
-   * It is valid to call this function on file objects that weren't
-   * initialized for caching. In this case it's simple no-op.
-   */
-  if (Bcb == NULL)
-     return;
-
-  if (FileSizes->AllocationSize.QuadPart < Bcb->AllocationSize.QuadPart)
-  {
-     InitializeListHead(&FreeListHead);
-     KeAcquireGuardedMutex(&ViewLock);
-     KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
-
-     current_entry = Bcb->BcbSegmentListHead.Flink;
-     while (current_entry != &Bcb->BcbSegmentListHead)
-     {
-       current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
-       current_entry = current_entry->Flink;
-       if (current->FileOffset > FileSizes->AllocationSize.QuadPart ||
-           (current->FileOffset == 0 && FileSizes->AllocationSize.QuadPart == 0))
-       {
-           if (current->ReferenceCount == 0 || (current->ReferenceCount == 1 && current->Dirty))
-          {
-              RemoveEntryList(&current->BcbSegmentListEntry);
-              RemoveEntryList(&current->CacheSegmentListEntry);
-              RemoveEntryList(&current->CacheSegmentLRUListEntry);
-              if (current->Dirty)
-              {
-                 RemoveEntryList(&current->DirtySegmentListEntry);
-                 DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
-              }
-             InsertHeadList(&FreeListHead, &current->BcbSegmentListEntry);
-          }
-          else
-          {
-             DPRINT1("Anyone has referenced a cache segment behind the new size.\n");
-             KeBugCheck(CACHE_MANAGER);
-          }
-       }
-     }
-
-     Bcb->AllocationSize = FileSizes->AllocationSize;
-     Bcb->FileSize = FileSizes->FileSize;
-     KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
-     KeReleaseGuardedMutex(&ViewLock);
-
-     current_entry = FreeListHead.Flink;
-     while(current_entry != &FreeListHead)
-     {
-        current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
-        current_entry = current_entry->Flink;
-        Status = CcRosInternalFreeCacheSegment(current);
-        if (!NT_SUCCESS(Status))
-        {
-           DPRINT1("CcRosInternalFreeCacheSegment failed, status = %x\n", Status);
-          KeBugCheck(CACHE_MANAGER);
-        }
-     }
-  }
-  else
-  {
-     KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
-     Bcb->AllocationSize = FileSizes->AllocationSize;
-     Bcb->FileSize = FileSizes->FileSize;
-     KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
-  }
+    KIRQL oldirql;
+    PROS_SHARED_CACHE_MAP SharedCacheMap;
+
+    CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p\n",
+        FileObject, FileSizes);
+
+    DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n",
+           FileObject, FileSizes);
+    DPRINT("AllocationSize %I64d, FileSize %I64d, ValidDataLength %I64d\n",
+           FileSizes->AllocationSize.QuadPart,
+           FileSizes->FileSize.QuadPart,
+           FileSizes->ValidDataLength.QuadPart);
+
+    SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
+
+    /*
+     * It is valid to call this function on file objects that weren't
+     * initialized for caching. In this case it's simple no-op.
+     */
+    if (SharedCacheMap == NULL)
+        return;
+
+    if (FileSizes->AllocationSize.QuadPart < SharedCacheMap->SectionSize.QuadPart)
+    {
+        CcPurgeCacheSection(FileObject->SectionObjectPointer,
+                            &FileSizes->AllocationSize,
+                            0,
+                            FALSE);
+    }
+
+    KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
+    SharedCacheMap->SectionSize = FileSizes->AllocationSize;
+    SharedCacheMap->FileSize = FileSizes->FileSize;
+    KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
 }
 
 /*
@@ -222,12 +303,14 @@ CcSetFileSizes (IN PFILE_OBJECT FileObject,
 VOID
 NTAPI
 CcSetLogHandleForFile (
-       IN      PFILE_OBJECT    FileObject,
-       IN      PVOID           LogHandle,
-       IN      PFLUSH_TO_LSN   FlushToLsnRoutine
-       )
+    IN PFILE_OBJECT FileObject,
+    IN PVOID LogHandle,
+    IN PFLUSH_TO_LSN FlushToLsnRoutine)
 {
-       UNIMPLEMENTED;
+    CCTRACE(CC_API_DEBUG, "FileObject=%p LogHandle=%p FlushToLsnRoutine=%p\n",
+        FileObject, LogHandle, FlushToLsnRoutine);
+
+    UNIMPLEMENTED;
 }
 
 /*
@@ -236,33 +319,55 @@ CcSetLogHandleForFile (
 BOOLEAN
 NTAPI
 CcUninitializeCacheMap (
-       IN      PFILE_OBJECT                    FileObject,
-       IN      PLARGE_INTEGER                  TruncateSize OPTIONAL,
-       IN      PCACHE_UNINITIALIZE_EVENT       UninitializeCompleteEvent OPTIONAL
-       )
+    IN PFILE_OBJECT FileObject,
+    IN PLARGE_INTEGER TruncateSize OPTIONAL,
+    IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL)
 {
-#if 0
-       UNIMPLEMENTED;
-       return FALSE;
-#else
-    return NT_SUCCESS(CcRosReleaseFileCache(FileObject));
-#endif
+    NTSTATUS Status;
+    PROS_SHARED_CACHE_MAP SharedCacheMap;
+    KIRQL OldIrql;
+
+    CCTRACE(CC_API_DEBUG, "FileObject=%p TruncateSize=%p UninitializeCompleteEvent=%p\n",
+        FileObject, TruncateSize, UninitializeCompleteEvent);
+
+    if (TruncateSize != NULL &&
+        FileObject->SectionObjectPointer->SharedCacheMap != NULL)
+    {
+        SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
+        KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
+        if (SharedCacheMap->FileSize.QuadPart > TruncateSize->QuadPart)
+        {
+            SharedCacheMap->FileSize = *TruncateSize;
+        }
+        KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
+        CcPurgeCacheSection(FileObject->SectionObjectPointer,
+                            TruncateSize,
+                            0,
+                            FALSE);
+    }
+
+    Status = CcRosReleaseFileCache(FileObject);
+    if (UninitializeCompleteEvent)
+    {
+        KeSetEvent(&UninitializeCompleteEvent->Event, IO_NO_INCREMENT, FALSE);
+    }
+    return NT_SUCCESS(Status);
 }
 
 BOOLEAN
 NTAPI
-CcGetFileSizes
-(IN PFILE_OBJECT FileObject,
- IN PCC_FILE_SIZES FileSizes)
+CcGetFileSizes (
+    IN PFILE_OBJECT FileObject,
   IN PCC_FILE_SIZES FileSizes)
 {
-  PBCB Bcb;
-       
-  Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+    PROS_SHARED_CACHE_MAP SharedCacheMap;
+
+    SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
 
-  if (!Bcb)
-         return FALSE;
+    if (!SharedCacheMap)
+        return FALSE;
 
-  FileSizes->AllocationSize = Bcb->AllocationSize;
-  FileSizes->FileSize = FileSizes->ValidDataLength = Bcb->FileSize;
-  return TRUE;
+    FileSizes->AllocationSize = SharedCacheMap->SectionSize;
+    FileSizes->FileSize = FileSizes->ValidDataLength = SharedCacheMap->FileSize;
+    return TRUE;
 }