[NTOS:CC]
[reactos.git] / reactos / ntoskrnl / cc / copy.c
index c6ee11f..697272a 100644 (file)
@@ -17,8 +17,9 @@
 
 static PFN_NUMBER CcZeroPage = 0;
 
-#define MAX_ZERO_LENGTH        (256 * 1024)
-#define MAX_RW_LENGTH  (256 * 1024)
+#define MAX_ZERO_LENGTH    (256 * 1024)
+#define MAX_RW_LENGTH    (256 * 1024)
+C_ASSERT(MAX_RW_LENGTH <= VACB_MAPPING_GRANULARITY);
 
 ULONG CcFastMdlReadWait;
 ULONG CcFastMdlReadNotPossible;
@@ -31,160 +32,165 @@ ULONG CcFastReadResourceMiss;
 
 VOID
 NTAPI
-MiZeroPhysicalPage(
+MiZeroPhysicalPage (
     IN PFN_NUMBER PageFrameIndex
 );
 
 VOID
 NTAPI
-CcInitCacheZeroPage(VOID)
+CcInitCacheZeroPage (
+    VOID)
 {
-   NTSTATUS Status;
-
-   MI_SET_USAGE(MI_USAGE_CACHE);
-   //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
-   Status = MmRequestPageMemoryConsumer(MC_SYSTEM, TRUE, &CcZeroPage);
-   if (!NT_SUCCESS(Status))
-   {
-       DbgPrint("Can't allocate CcZeroPage.\n");
-       KeBugCheck(CACHE_MANAGER);
-   }
-   MiZeroPhysicalPage(CcZeroPage);
+    NTSTATUS Status;
+
+    MI_SET_USAGE(MI_USAGE_CACHE);
+    //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
+    Status = MmRequestPageMemoryConsumer(MC_SYSTEM, TRUE, &CcZeroPage);
+    if (!NT_SUCCESS(Status))
+    {
+        DbgPrint("Can't allocate CcZeroPage.\n");
+        KeBugCheck(CACHE_MANAGER);
+    }
+    MiZeroPhysicalPage(CcZeroPage);
 }
 
 NTSTATUS
 NTAPI
-ReadCacheSegmentChain(PBCB Bcb, ULONG ReadOffset, ULONG Length,
-                     PVOID Buffer)
+ReadCacheSegmentChain (
+    PBCB Bcb,
+    ULONG ReadOffset,
+    ULONG Length,
+    PVOID Buffer)
 {
-  PCACHE_SEGMENT head;
-  PCACHE_SEGMENT current;
-  PCACHE_SEGMENT previous;
-  IO_STATUS_BLOCK Iosb;
-  LARGE_INTEGER SegOffset;
-  NTSTATUS Status;
-  ULONG TempLength;
-  KEVENT Event;
-  PMDL Mdl;
-
-  Mdl = _alloca(MmSizeOfMdl(NULL, MAX_RW_LENGTH));
-
-  Status = CcRosGetCacheSegmentChain(Bcb, ReadOffset, Length, &head);
-  if (!NT_SUCCESS(Status))
+    PCACHE_SEGMENT head;
+    PCACHE_SEGMENT current;
+    PCACHE_SEGMENT previous;
+    IO_STATUS_BLOCK Iosb;
+    LARGE_INTEGER SegOffset;
+    NTSTATUS Status;
+    ULONG TempLength;
+    KEVENT Event;
+    PMDL Mdl;
+
+    Mdl = _alloca(MmSizeOfMdl(NULL, MAX_RW_LENGTH));
+
+    Status = CcRosGetCacheSegmentChain(Bcb, ReadOffset, Length, &head);
+    if (!NT_SUCCESS(Status))
     {
-      return(Status);
+        return Status;
     }
-  current = head;
-  while (current != NULL)
+    current = head;
+    while (current != NULL)
     {
-      /*
-       * If the current segment is valid then copy it into the
-       * user buffer.
-       */
-      if (current->Valid)
-       {
-         TempLength = min(Bcb->CacheSegmentSize, Length);
-         memcpy(Buffer, current->BaseAddress, TempLength);
-
-         Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
-
-         Length = Length - TempLength;
-         previous = current;
-         current = current->NextInChain;
-         CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
-       }
-      /*
-       * Otherwise read in as much as we can.
-       */
-      else
-       {
-         PCACHE_SEGMENT current2;
-         ULONG current_size;
-         ULONG i;
-         PPFN_NUMBER MdlPages;
-
-         /*
-          * Count the maximum number of bytes we could read starting
-          * from the current segment.
-          */
-         current2 = current;
-         current_size = 0;
-         while (current2 != NULL && !current2->Valid && current_size < MAX_RW_LENGTH)
-           {
-             current2 = current2->NextInChain;
-             current_size += Bcb->CacheSegmentSize;
-           }
-
-         /*
-          * Create an MDL which contains all their pages.
-          */
-          MmInitializeMdl(Mdl, NULL, current_size);
-         Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
-         current2 = current;
-         current_size = 0;
-         MdlPages = (PPFN_NUMBER)(Mdl + 1);
-         while (current2 != NULL && !current2->Valid && current_size < MAX_RW_LENGTH)
-           {
-             PVOID address = current2->BaseAddress;
-             for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++, address = RVA(address, PAGE_SIZE))
-               {
-                 *MdlPages++ = MmGetPfnForProcess(NULL, address);
-               }
-             current2 = current2->NextInChain;
-             current_size += Bcb->CacheSegmentSize;
-           }
-
-         /*
-          * Read in the information.
-          */
-         SegOffset.QuadPart = current->FileOffset;
-         KeInitializeEvent(&Event, NotificationEvent, FALSE);
-         Status = IoPageRead(Bcb->FileObject,
-                             Mdl,
-                             &SegOffset,
-                             &Event,
-                             &Iosb);
-         if (Status == STATUS_PENDING)
-         {
-            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
-            Status = Iosb.Status;
-         }
-          if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
-          {
-            MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
-         }
-         if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
-           {
-             while (current != NULL)
-               {
-                 previous = current;
-                 current = current->NextInChain;
-                 CcRosReleaseCacheSegment(Bcb, previous, FALSE, FALSE, FALSE);
-               }
-             return(Status);
-           }
-         current_size = 0;
-         while (current != NULL && !current->Valid && current_size < MAX_RW_LENGTH)
-           {
-             previous = current;
-             current = current->NextInChain;
-             TempLength = min(Bcb->CacheSegmentSize, Length);
-             memcpy(Buffer, previous->BaseAddress, TempLength);
-
-             Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
-
-             Length = Length - TempLength;
-             CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
-             current_size += Bcb->CacheSegmentSize;
-           }
-       }
+        /*
+         * If the current segment is valid then copy it into the
+         * user buffer.
+         */
+        if (current->Valid)
+        {
+            TempLength = min(VACB_MAPPING_GRANULARITY, Length);
+            RtlCopyMemory(Buffer, current->BaseAddress, TempLength);
+
+            Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
+
+            Length = Length - TempLength;
+            previous = current;
+            current = current->NextInChain;
+            CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
+        }
+        /*
+         * Otherwise read in as much as we can.
+         */
+        else
+        {
+            PCACHE_SEGMENT current2;
+            ULONG current_size;
+            ULONG i;
+            PPFN_NUMBER MdlPages;
+
+            /*
+             * Count the maximum number of bytes we could read starting
+             * from the current segment.
+             */
+            current2 = current;
+            current_size = 0;
+            while ((current2 != NULL) && !current2->Valid && (current_size < MAX_RW_LENGTH))
+            {
+                current2 = current2->NextInChain;
+                current_size += VACB_MAPPING_GRANULARITY;
+            }
+
+            /*
+             * Create an MDL which contains all their pages.
+             */
+            MmInitializeMdl(Mdl, NULL, current_size);
+            Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
+            current2 = current;
+            current_size = 0;
+            MdlPages = (PPFN_NUMBER)(Mdl + 1);
+            while ((current2 != NULL) && !current2->Valid && (current_size < MAX_RW_LENGTH))
+            {
+                PVOID address = current2->BaseAddress;
+                for (i = 0; i < VACB_MAPPING_GRANULARITY / PAGE_SIZE; i++, address = RVA(address, PAGE_SIZE))
+                {
+                    *MdlPages++ = MmGetPfnForProcess(NULL, address);
+                }
+                current2 = current2->NextInChain;
+                current_size += VACB_MAPPING_GRANULARITY;
+            }
+
+            /*
+             * Read in the information.
+             */
+            SegOffset.QuadPart = current->FileOffset;
+            KeInitializeEvent(&Event, NotificationEvent, FALSE);
+            Status = IoPageRead(Bcb->FileObject,
+                                Mdl,
+                                &SegOffset,
+                                &Event,
+                                &Iosb);
+            if (Status == STATUS_PENDING)
+            {
+                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+                Status = Iosb.Status;
+            }
+            if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
+            {
+                MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+            }
+            if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
+            {
+                while (current != NULL)
+                {
+                    previous = current;
+                    current = current->NextInChain;
+                    CcRosReleaseCacheSegment(Bcb, previous, FALSE, FALSE, FALSE);
+                }
+                return Status;
+            }
+            current_size = 0;
+            while (current != NULL && !current->Valid && current_size < MAX_RW_LENGTH)
+            {
+                previous = current;
+                current = current->NextInChain;
+                TempLength = min(VACB_MAPPING_GRANULARITY, Length);
+                RtlCopyMemory(Buffer, previous->BaseAddress, TempLength);
+
+                Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
+
+                Length = Length - TempLength;
+                CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
+                current_size += VACB_MAPPING_GRANULARITY;
+            }
+        }
     }
-  return(STATUS_SUCCESS);
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
 NTAPI
-ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
+ReadCacheSegment (
+    PCACHE_SEGMENT CacheSeg)
 {
     ULONG Size;
     PMDL Mdl;
@@ -195,9 +201,9 @@ ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
 
     SegOffset.QuadPart = CacheSeg->FileOffset;
     Size = (ULONG)(CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset);
-    if (Size > CacheSeg->Bcb->CacheSegmentSize)
+    if (Size > VACB_MAPPING_GRANULARITY)
     {
-        Size = CacheSeg->Bcb->CacheSegmentSize;
+        Size = VACB_MAPPING_GRANULARITY;
     }
 
     Mdl = IoAllocateMdl(CacheSeg->BaseAddress, Size, FALSE, FALSE, NULL);
@@ -205,6 +211,7 @@ ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
     {
         return STATUS_INSUFFICIENT_RESOURCES;
     }
+
     MmBuildMdlForNonPagedPool(Mdl);
     Mdl->MdlFlags |= MDL_IO_PAGE_READ;
     KeInitializeEvent(&Event, NotificationEvent, FALSE);
@@ -217,16 +224,16 @@ ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
 
     IoFreeMdl(Mdl);
 
-    if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
+    if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
     {
         DPRINT1("IoPageRead failed, Status %x\n", Status);
         return Status;
     }
 
-    if (CacheSeg->Bcb->CacheSegmentSize > Size)
+    if (Size < VACB_MAPPING_GRANULARITY)
     {
         RtlZeroMemory((char*)CacheSeg->BaseAddress + Size,
-             CacheSeg->Bcb->CacheSegmentSize - Size);
+                      VACB_MAPPING_GRANULARITY - Size);
     }
 
     return STATUS_SUCCESS;
@@ -234,7 +241,8 @@ ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
 
 NTSTATUS
 NTAPI
-WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
+WriteCacheSegment (
+    PCACHE_SEGMENT CacheSeg)
 {
     ULONG Size;
     PMDL Mdl;
@@ -246,9 +254,9 @@ WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
     CacheSeg->Dirty = FALSE;
     SegOffset.QuadPart = CacheSeg->FileOffset;
     Size = (ULONG)(CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset);
-    if (Size > CacheSeg->Bcb->CacheSegmentSize)
+    if (Size > VACB_MAPPING_GRANULARITY)
     {
-        Size = CacheSeg->Bcb->CacheSegmentSize;
+        Size = VACB_MAPPING_GRANULARITY;
     }
     //
     // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
@@ -291,244 +299,260 @@ WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
 /*
  * @unimplemented
  */
-BOOLEAN NTAPI
+BOOLEAN
+NTAPI
 CcCanIWrite (
-                       IN      PFILE_OBJECT    FileObject,
-                       IN      ULONG                   BytesToWrite,
-                       IN      BOOLEAN                 Wait,
-                       IN      BOOLEAN                 Retrying)
+    IN PFILE_OBJECT FileObject,
+    IN ULONG BytesToWrite,
+    IN BOOLEAN Wait,
+    IN BOOLEAN Retrying)
 {
-       UNIMPLEMENTED;
-       return FALSE;
+    UNIMPLEMENTED;
+    return FALSE;
 }
 
 
 /*
  * @implemented
  */
-BOOLEAN NTAPI
-CcCopyRead (IN PFILE_OBJECT FileObject,
-           IN PLARGE_INTEGER FileOffset,
-           IN ULONG Length,
-           IN BOOLEAN Wait,
-           OUT PVOID Buffer,
-           OUT PIO_STATUS_BLOCK IoStatus)
+BOOLEAN
+NTAPI
+CcCopyRead (
+    IN PFILE_OBJECT FileObject,
+    IN PLARGE_INTEGER FileOffset,
+    IN ULONG Length,
+    IN BOOLEAN Wait,
+    OUT PVOID Buffer,
+    OUT PIO_STATUS_BLOCK IoStatus)
 {
-  ULONG ReadOffset;
-  ULONG TempLength;
-  NTSTATUS Status = STATUS_SUCCESS;
-  PVOID BaseAddress;
-  PCACHE_SEGMENT CacheSeg;
-  BOOLEAN Valid;
-  ULONG ReadLength = 0;
-  PBCB Bcb;
-  KIRQL oldirql;
-  PLIST_ENTRY current_entry;
-  PCACHE_SEGMENT current;
-
-  DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
-        "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
-        FileObject, FileOffset->QuadPart, Length, Wait,
-        Buffer, IoStatus);
-
-  Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
-  ReadOffset = (ULONG)FileOffset->QuadPart;
-
-  DPRINT("AllocationSize %d, FileSize %d\n",
-         (ULONG)Bcb->AllocationSize.QuadPart,
-         (ULONG)Bcb->FileSize.QuadPart);
-
-  /*
-   * Check for the nowait case that all the cache segments that would
-   * cover this read are in memory.
-   */
-  if (!Wait)
+    ULONG ReadOffset;
+    ULONG TempLength;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PVOID BaseAddress;
+    PCACHE_SEGMENT CacheSeg;
+    BOOLEAN Valid;
+    ULONG ReadLength = 0;
+    PBCB Bcb;
+    KIRQL oldirql;
+    PLIST_ENTRY current_entry;
+    PCACHE_SEGMENT current;
+
+    DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
+           "Length %lu, Wait %u, Buffer 0x%p, IoStatus 0x%p)\n",
+           FileObject, FileOffset->QuadPart, Length, Wait,
+           Buffer, IoStatus);
+
+    Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+    ReadOffset = (ULONG)FileOffset->QuadPart;
+
+    DPRINT("AllocationSize %I64d, FileSize %I64d\n",
+           Bcb->AllocationSize.QuadPart,
+           Bcb->FileSize.QuadPart);
+
+    /*
+     * Check for the nowait case that all the cache segments that would
+     * cover this read are in memory.
+     */
+    if (!Wait)
     {
-      KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
-      current_entry = Bcb->BcbSegmentListHead.Flink;
-      while (current_entry != &Bcb->BcbSegmentListHead)
-       {
-         current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
-                                     BcbSegmentListEntry);
-         if (!current->Valid && current->FileOffset < ReadOffset + Length
-             && current->FileOffset + Bcb->CacheSegmentSize > ReadOffset)
-           {
-             KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
-             IoStatus->Status = STATUS_UNSUCCESSFUL;
-             IoStatus->Information = 0;
-             return FALSE;
-           }
-         current_entry = current_entry->Flink;
-       }
-      KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+        KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
+        /* FIXME: this loop doesn't take into account areas that don't have
+         * a segment in the list yet */
+        current_entry = Bcb->BcbSegmentListHead.Flink;
+        while (current_entry != &Bcb->BcbSegmentListHead)
+        {
+            current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
+                                        BcbSegmentListEntry);
+            if (!current->Valid &&
+                DoSegmentsIntersect(current->FileOffset, VACB_MAPPING_GRANULARITY,
+                                    ReadOffset, Length))
+            {
+                KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+                IoStatus->Status = STATUS_UNSUCCESSFUL;
+                IoStatus->Information = 0;
+                return FALSE;
+            }
+            if (current->FileOffset >= ReadOffset + Length)
+                break;
+            current_entry = current_entry->Flink;
+        }
+        KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
     }
 
-  TempLength = ReadOffset % Bcb->CacheSegmentSize;
-  if (TempLength != 0)
+    TempLength = ReadOffset % VACB_MAPPING_GRANULARITY;
+    if (TempLength != 0)
     {
-      TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
-      Status = CcRosRequestCacheSegment(Bcb,
-                                       ROUND_DOWN(ReadOffset,
-                                                  Bcb->CacheSegmentSize),
-                                       &BaseAddress, &Valid, &CacheSeg);
-      if (!NT_SUCCESS(Status))
-       {
-         IoStatus->Information = 0;
-         IoStatus->Status = Status;
-         DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
-         return FALSE;
-       }
-      if (!Valid)
-       {
-         Status = ReadCacheSegment(CacheSeg);
-         if (!NT_SUCCESS(Status))
-           {
-             IoStatus->Information = 0;
-             IoStatus->Status = Status;
-              CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
-             return FALSE;
-           }
-       }
-      memcpy (Buffer, (char*)BaseAddress + ReadOffset % Bcb->CacheSegmentSize,
-             TempLength);
-      CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
-      ReadLength += TempLength;
-      Length -= TempLength;
-      ReadOffset += TempLength;
-      Buffer = (PVOID)((char*)Buffer + TempLength);
+        TempLength = min(Length, VACB_MAPPING_GRANULARITY - TempLength);
+        Status = CcRosRequestCacheSegment(Bcb,
+                                          ROUND_DOWN(ReadOffset,
+                                                     VACB_MAPPING_GRANULARITY),
+                                          &BaseAddress, &Valid, &CacheSeg);
+        if (!NT_SUCCESS(Status))
+        {
+            IoStatus->Information = 0;
+            IoStatus->Status = Status;
+            DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
+            return FALSE;
+        }
+        if (!Valid)
+        {
+            Status = ReadCacheSegment(CacheSeg);
+            if (!NT_SUCCESS(Status))
+            {
+                IoStatus->Information = 0;
+                IoStatus->Status = Status;
+                CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
+                return FALSE;
+            }
+        }
+        RtlCopyMemory(Buffer,
+                      (char*)BaseAddress + ReadOffset % VACB_MAPPING_GRANULARITY,
+                      TempLength);
+        CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
+        ReadLength += TempLength;
+        Length -= TempLength;
+        ReadOffset += TempLength;
+        Buffer = (PVOID)((char*)Buffer + TempLength);
     }
-  while (Length > 0)
+
+    while (Length > 0)
     {
-      TempLength = min(max(Bcb->CacheSegmentSize, MAX_RW_LENGTH), Length);
-      Status = ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
-      if (!NT_SUCCESS(Status))
+        TempLength = min(VACB_MAPPING_GRANULARITY, Length);
+        Status = ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
+        if (!NT_SUCCESS(Status))
         {
-          IoStatus->Information = 0;
-          IoStatus->Status = Status;
-          DPRINT1("ReadCacheSegmentChain failed, Status %x\n", Status);
-          return FALSE;
+            IoStatus->Information = 0;
+            IoStatus->Status = Status;
+            DPRINT("ReadCacheSegmentChain failed, Status %x\n", Status);
+            return FALSE;
         }
 
-      ReadLength += TempLength;
-      Length -= TempLength;
-      ReadOffset += TempLength;
+        ReadLength += TempLength;
+        Length -= TempLength;
+        ReadOffset += TempLength;
 
-      Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
+        Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
     }
-  IoStatus->Status = STATUS_SUCCESS;
-  IoStatus->Information = ReadLength;
-  DPRINT("CcCopyRead O.K.\n");
-  return TRUE;
+
+    IoStatus->Status = STATUS_SUCCESS;
+    IoStatus->Information = ReadLength;
+    DPRINT("CcCopyRead O.K.\n");
+    return TRUE;
 }
 
 /*
  * @implemented
  */
-BOOLEAN NTAPI
-CcCopyWrite (IN PFILE_OBJECT FileObject,
-            IN PLARGE_INTEGER FileOffset,
-            IN ULONG Length,
-            IN BOOLEAN Wait,
-            IN PVOID Buffer)
+BOOLEAN
+NTAPI
+CcCopyWrite (
+    IN PFILE_OBJECT FileObject,
+    IN PLARGE_INTEGER FileOffset,
+    IN ULONG Length,
+    IN BOOLEAN Wait,
+    IN PVOID Buffer)
 {
-   NTSTATUS Status;
-   ULONG WriteOffset;
-   KIRQL oldirql;
-   PBCB Bcb;
-   PLIST_ENTRY current_entry;
-   PCACHE_SEGMENT CacheSeg;
-   ULONG TempLength;
-   PVOID BaseAddress;
-   BOOLEAN Valid;
-
-   DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
-         "Length %d, Wait %d, Buffer 0x%p)\n",
-          FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
-
-   Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
-   WriteOffset = (ULONG)FileOffset->QuadPart;
-
-   if (!Wait)
-     {
-       /* testing, if the requested datas are available */
-       KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
-       current_entry = Bcb->BcbSegmentListHead.Flink;
-       while (current_entry != &Bcb->BcbSegmentListHead)
-        {
-          CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
-                                       BcbSegmentListEntry);
-          if (!CacheSeg->Valid)
-            {
-              if ((WriteOffset >= CacheSeg->FileOffset &&
-                   WriteOffset < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
-                  || (WriteOffset + Length > CacheSeg->FileOffset &&
-                      WriteOffset + Length <= CacheSeg->FileOffset +
-                      Bcb->CacheSegmentSize))
-                {
-                  KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
-                  /* datas not available */
-                  return(FALSE);
-                }
-            }
-          current_entry = current_entry->Flink;
-        }
-       KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
-     }
-
-   TempLength = WriteOffset % Bcb->CacheSegmentSize;
-   if (TempLength != 0)
-     {
-       ULONG ROffset;
-       ROffset = ROUND_DOWN(WriteOffset, Bcb->CacheSegmentSize);
-       TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
-       Status = CcRosRequestCacheSegment(Bcb, ROffset,
-                                        &BaseAddress, &Valid, &CacheSeg);
-       if (!NT_SUCCESS(Status))
-        {
-          return(FALSE);
-        }
-       if (!Valid)
-        {
-          if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
-            {
-              return(FALSE);
-            }
-        }
-       memcpy ((char*)BaseAddress + WriteOffset % Bcb->CacheSegmentSize,
-              Buffer, TempLength);
-       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
-
-       Length -= TempLength;
-       WriteOffset += TempLength;
-
-       Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
-     }
-
-   while (Length > 0)
-     {
-       TempLength = min (Bcb->CacheSegmentSize, Length);
-       Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
-                                        &BaseAddress, &Valid, &CacheSeg);
-       if (!NT_SUCCESS(Status))
-        {
-          return(FALSE);
-        }
-       if (!Valid && TempLength < Bcb->CacheSegmentSize)
-        {
-          if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
-            {
-               CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
-              return FALSE;
-            }
-        }
-       memcpy (BaseAddress, Buffer, TempLength);
-       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
-       Length -= TempLength;
-       WriteOffset += TempLength;
-
-       Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
-     }
-   return(TRUE);
+    NTSTATUS Status;
+    ULONG WriteOffset;
+    KIRQL oldirql;
+    PBCB Bcb;
+    PLIST_ENTRY current_entry;
+    PCACHE_SEGMENT CacheSeg;
+    ULONG TempLength;
+    PVOID BaseAddress;
+    BOOLEAN Valid;
+
+    DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
+           "Length %lu, Wait %u, Buffer 0x%p)\n",
+           FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
+
+    Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+    WriteOffset = (ULONG)FileOffset->QuadPart;
+
+    if (!Wait)
+    {
+        /* testing, if the requested datas are available */
+        KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
+        /* FIXME: this loop doesn't take into account areas that don't have
+         * a segment in the list yet */
+        current_entry = Bcb->BcbSegmentListHead.Flink;
+        while (current_entry != &Bcb->BcbSegmentListHead)
+        {
+            CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
+                                         BcbSegmentListEntry);
+            if (!CacheSeg->Valid &&
+                DoSegmentsIntersect(CacheSeg->FileOffset, VACB_MAPPING_GRANULARITY,
+                                    WriteOffset, Length))
+            {
+                KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+                /* datas not available */
+                return FALSE;
+            }
+            if (CacheSeg->FileOffset >= WriteOffset + Length)
+                break;
+            current_entry = current_entry->Flink;
+        }
+        KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+    }
+
+    TempLength = WriteOffset % VACB_MAPPING_GRANULARITY;
+    if (TempLength != 0)
+    {
+        ULONG ROffset;
+        ROffset = ROUND_DOWN(WriteOffset, VACB_MAPPING_GRANULARITY);
+        TempLength = min(Length, VACB_MAPPING_GRANULARITY - TempLength);
+        Status = CcRosRequestCacheSegment(Bcb, ROffset,
+                                          &BaseAddress, &Valid, &CacheSeg);
+        if (!NT_SUCCESS(Status))
+        {
+            return FALSE;
+        }
+        if (!Valid)
+        {
+            if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
+            {
+                return FALSE;
+            }
+        }
+        RtlCopyMemory((char*)BaseAddress + WriteOffset % VACB_MAPPING_GRANULARITY,
+                      Buffer,
+                      TempLength);
+        CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
+
+        Length -= TempLength;
+        WriteOffset += TempLength;
+
+        Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
+    }
+
+    while (Length > 0)
+    {
+        TempLength = min(VACB_MAPPING_GRANULARITY, Length);
+        Status = CcRosRequestCacheSegment(Bcb,
+                                          WriteOffset,
+                                          &BaseAddress,
+                                          &Valid,
+                                          &CacheSeg);
+        if (!NT_SUCCESS(Status))
+        {
+            return FALSE;
+        }
+        if (!Valid && TempLength < VACB_MAPPING_GRANULARITY)
+        {
+            if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
+            {
+                CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
+                return FALSE;
+            }
+        }
+        RtlCopyMemory(BaseAddress, Buffer, TempLength);
+        CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
+        Length -= TempLength;
+        WriteOffset += TempLength;
+
+        Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
+    }
+    return TRUE;
 }
 
 /*
@@ -537,15 +561,14 @@ CcCopyWrite (IN PFILE_OBJECT FileObject,
 VOID
 NTAPI
 CcDeferWrite (
-       IN      PFILE_OBJECT            FileObject,
-       IN      PCC_POST_DEFERRED_WRITE PostRoutine,
-       IN      PVOID                   Context1,
-       IN      PVOID                   Context2,
-       IN      ULONG                   BytesToWrite,
-       IN      BOOLEAN                 Retrying
-       )
+    IN PFILE_OBJECT FileObject,
+    IN PCC_POST_DEFERRED_WRITE PostRoutine,
+    IN PVOID Context1,
+    IN PVOID Context2,
+    IN ULONG BytesToWrite,
+    IN BOOLEAN Retrying)
 {
-       UNIMPLEMENTED;
+    UNIMPLEMENTED;
 }
 
 /*
@@ -554,28 +577,27 @@ CcDeferWrite (
 VOID
 NTAPI
 CcFastCopyRead (
-    IN  PFILE_OBJECT FileObject,
-    IN  ULONG FileOffset,
-    IN  ULONG Length,
-    IN  ULONG PageCount,
+    IN PFILE_OBJECT FileObject,
+    IN ULONG FileOffset,
+    IN ULONG Length,
+    IN ULONG PageCount,
     OUT PVOID Buffer,
-    OUT PIO_STATUS_BLOCK IoStatus
-       )
+    OUT PIO_STATUS_BLOCK IoStatus)
 {
-       UNIMPLEMENTED;
+    UNIMPLEMENTED;
 }
 /*
  * @unimplemented
  */
 VOID
 NTAPI
-CcFastCopyWrite(
-    IN  PFILE_OBJECT FileObject,
-    IN  ULONG FileOffset,
-    IN  ULONG Length,
-    IN  PVOID Buffer)
+CcFastCopyWrite (
+    IN PFILE_OBJECT FileObject,
+    IN ULONG FileOffset,
+    IN ULONG Length,
+    IN PVOID Buffer)
 {
-       UNIMPLEMENTED;
+    UNIMPLEMENTED;
 }
 
 /*
@@ -584,174 +606,177 @@ CcFastCopyWrite(
 NTSTATUS
 NTAPI
 CcWaitForCurrentLazyWriterActivity (
-    VOID
-    )
+    VOID)
 {
-       UNIMPLEMENTED;
-       return STATUS_NOT_IMPLEMENTED;
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
 }
 
 /*
  * @implemented
  */
-BOOLEAN NTAPI
-CcZeroData (IN PFILE_OBJECT     FileObject,
-           IN PLARGE_INTEGER   StartOffset,
-           IN PLARGE_INTEGER   EndOffset,
-           IN BOOLEAN          Wait)
+BOOLEAN
+NTAPI
+CcZeroData (
+    IN PFILE_OBJECT FileObject,
+    IN PLARGE_INTEGER StartOffset,
+    IN PLARGE_INTEGER EndOffset,
+    IN BOOLEAN Wait)
 {
-  NTSTATUS Status;
-  LARGE_INTEGER WriteOffset;
-  ULONG Length;
-  ULONG CurrentLength;
-  PMDL Mdl;
-  ULONG i;
-  IO_STATUS_BLOCK Iosb;
-  KEVENT Event;
-
-  DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
-        "Wait %d)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
-        Wait);
-
-  Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
-  WriteOffset.QuadPart = StartOffset->QuadPart;
-
-  if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
+    NTSTATUS Status;
+    LARGE_INTEGER WriteOffset;
+    ULONG Length;
+    ULONG CurrentLength;
+    PMDL Mdl;
+    ULONG i;
+    IO_STATUS_BLOCK Iosb;
+    KEVENT Event;
+
+    DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
+           "Wait %u)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
+           Wait);
+
+    Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
+    WriteOffset.QuadPart = StartOffset->QuadPart;
+
+    if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
     {
-      /* File is not cached */
-
-      Mdl = _alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
-
-      while (Length > 0)
-       {
-         if (Length + WriteOffset.u.LowPart % PAGE_SIZE > MAX_ZERO_LENGTH)
-           {
-             CurrentLength = MAX_ZERO_LENGTH - WriteOffset.u.LowPart % PAGE_SIZE;
-           }
-         else
-           {
-             CurrentLength = Length;
-           }
-          MmInitializeMdl(Mdl, (PVOID)(ULONG_PTR)WriteOffset.QuadPart, CurrentLength);
-         Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
-         for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
-           {
-             ((PPFN_NUMBER)(Mdl + 1))[i] = CcZeroPage;
-           }
-          KeInitializeEvent(&Event, NotificationEvent, FALSE);
-         Status = IoSynchronousPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
-          if (Status == STATUS_PENDING)
-         {
-             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
-             Status = Iosb.Status;
-         }
-        if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
+        /* File is not cached */
+
+        Mdl = _alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
+
+        while (Length > 0)
         {
-          MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+            if (Length + WriteOffset.u.LowPart % PAGE_SIZE > MAX_ZERO_LENGTH)
+            {
+                CurrentLength = MAX_ZERO_LENGTH - WriteOffset.u.LowPart % PAGE_SIZE;
+            }
+            else
+            {
+                CurrentLength = Length;
+            }
+            MmInitializeMdl(Mdl, (PVOID)(ULONG_PTR)WriteOffset.QuadPart, CurrentLength);
+            Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
+            for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
+            {
+                ((PPFN_NUMBER)(Mdl + 1))[i] = CcZeroPage;
+            }
+            KeInitializeEvent(&Event, NotificationEvent, FALSE);
+            Status = IoSynchronousPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
+            if (Status == STATUS_PENDING)
+            {
+                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+                Status = Iosb.Status;
+            }
+            if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
+            {
+                MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+            }
+            if (!NT_SUCCESS(Status))
+            {
+                return FALSE;
+            }
+            WriteOffset.QuadPart += CurrentLength;
+            Length -= CurrentLength;
         }
-         if (!NT_SUCCESS(Status))
-           {
-             return(FALSE);
-           }
-         WriteOffset.QuadPart += CurrentLength;
-         Length -= CurrentLength;
-       }
     }
-  else
+    else
     {
-      /* File is cached */
-      KIRQL oldirql;
-      PBCB Bcb;
-      PLIST_ENTRY current_entry;
-      PCACHE_SEGMENT CacheSeg, current, previous;
-      ULONG TempLength;
-
-      Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
-      if (Wait)
-       {
-          /* testing, if the requested datas are available */
-         KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
-         current_entry = Bcb->BcbSegmentListHead.Flink;
-         while (current_entry != &Bcb->BcbSegmentListHead)
-           {
-             CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
-                                          BcbSegmentListEntry);
-             if (!CacheSeg->Valid)
-               {
-                 if ((WriteOffset.u.LowPart >= CacheSeg->FileOffset &&
-                      WriteOffset.u.LowPart < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
-                     || (WriteOffset.u.LowPart + Length > CacheSeg->FileOffset &&
-                         WriteOffset.u.LowPart + Length <=
-                         CacheSeg->FileOffset + Bcb->CacheSegmentSize))
-                   {
-                     KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
-                     /* datas not available */
-                     return(FALSE);
-                   }
-               }
-             current_entry = current_entry->Flink;
-           }
-         KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
-       }
-      while (Length > 0)
-       {
-          ULONG Offset;
-         Offset = WriteOffset.u.LowPart % Bcb->CacheSegmentSize;
-         if (Length + Offset > MAX_ZERO_LENGTH)
-           {
-             CurrentLength = MAX_ZERO_LENGTH - Offset;
-           }
-         else
-           {
-             CurrentLength = Length;
-           }
-         Status = CcRosGetCacheSegmentChain (Bcb, WriteOffset.u.LowPart - Offset,
-                                             Offset + CurrentLength, &CacheSeg);
-         if (!NT_SUCCESS(Status))
-           {
-             return FALSE;
-           }
-         current = CacheSeg;
-
-         while (current != NULL)
-           {
-             Offset = WriteOffset.u.LowPart % Bcb->CacheSegmentSize;
-             if (Offset != 0 ||
-                  Offset + CurrentLength < Bcb->CacheSegmentSize)
-               {
-                 if (!current->Valid)
-                   {
-                     /* read the segment */
-                     Status = ReadCacheSegment(current);
-                     if (!NT_SUCCESS(Status))
-                       {
-                         DPRINT1("ReadCacheSegment failed, status %x\n",
-                                 Status);
-                       }
-                   }
-                 TempLength = min (CurrentLength, Bcb->CacheSegmentSize - Offset);
-               }
-             else
-               {
-                 TempLength = Bcb->CacheSegmentSize;
-               }
-             memset ((PUCHAR)current->BaseAddress + Offset, 0, TempLength);
-
-              WriteOffset.QuadPart += TempLength;
-             CurrentLength -= TempLength;
-             Length -= TempLength;
-
-             current = current->NextInChain;
-           }
-
-          current = CacheSeg;
-         while (current != NULL)
-           {
-             previous = current;
-             current = current->NextInChain;
-             CcRosReleaseCacheSegment(Bcb, previous, TRUE, TRUE, FALSE);
-           }
-       }
+        /* File is cached */
+        KIRQL oldirql;
+        PBCB Bcb;
+        PLIST_ENTRY current_entry;
+        PCACHE_SEGMENT CacheSeg, current, previous;
+        ULONG TempLength;
+
+        Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+        if (!Wait)
+        {
+            /* testing, if the requested datas are available */
+            KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
+            /* FIXME: this loop doesn't take into account areas that don't have
+             * a segment in the list yet */
+            current_entry = Bcb->BcbSegmentListHead.Flink;
+            while (current_entry != &Bcb->BcbSegmentListHead)
+            {
+                CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
+                                             BcbSegmentListEntry);
+                if (!CacheSeg->Valid &&
+                    DoSegmentsIntersect(CacheSeg->FileOffset, VACB_MAPPING_GRANULARITY,
+                                        WriteOffset.u.LowPart, Length))
+                {
+                    KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+                    /* datas not available */
+                    return FALSE;
+                }
+                if (CacheSeg->FileOffset >= WriteOffset.u.LowPart + Length)
+                    break;
+                current_entry = current_entry->Flink;
+            }
+            KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
+        }
+
+        while (Length > 0)
+        {
+            ULONG Offset;
+            Offset = WriteOffset.u.LowPart % VACB_MAPPING_GRANULARITY;
+            if (Length + Offset > MAX_ZERO_LENGTH)
+            {
+                CurrentLength = MAX_ZERO_LENGTH - Offset;
+            }
+            else
+            {
+                CurrentLength = Length;
+            }
+            Status = CcRosGetCacheSegmentChain (Bcb, WriteOffset.u.LowPart - Offset,
+                                                Offset + CurrentLength, &CacheSeg);
+            if (!NT_SUCCESS(Status))
+            {
+                return FALSE;
+            }
+            current = CacheSeg;
+
+            while (current != NULL)
+            {
+                Offset = WriteOffset.u.LowPart % VACB_MAPPING_GRANULARITY;
+                if ((Offset != 0) ||
+                    (Offset + CurrentLength < VACB_MAPPING_GRANULARITY))
+                {
+                    if (!current->Valid)
+                    {
+                        /* read the segment */
+                        Status = ReadCacheSegment(current);
+                        if (!NT_SUCCESS(Status))
+                        {
+                            DPRINT1("ReadCacheSegment failed, status %x\n",
+                                    Status);
+                        }
+                    }
+                    TempLength = min(CurrentLength, VACB_MAPPING_GRANULARITY - Offset);
+                }
+                else
+                {
+                    TempLength = VACB_MAPPING_GRANULARITY;
+                }
+                RtlZeroMemory((PUCHAR)current->BaseAddress + Offset,
+                              TempLength);
+
+                WriteOffset.QuadPart += TempLength;
+                CurrentLength -= TempLength;
+                Length -= TempLength;
+
+                current = current->NextInChain;
+            }
+
+            current = CacheSeg;
+            while (current != NULL)
+            {
+                previous = current;
+                current = current->NextInChain;
+                CcRosReleaseCacheSegment(Bcb, previous, TRUE, TRUE, FALSE);
+            }
+        }
     }
-  return(TRUE);
+
+    return TRUE;
 }