-/* $Id: copy.c,v 1.1 2001/10/10 21:46:13 hbirr Exp $
+/* $Id: copy.c,v 1.15 2003/02/18 22:06:53 chorns Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
#define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
+static PHYSICAL_ADDRESS CcZeroPage = (PHYSICAL_ADDRESS)0LL;
+
/* FUNCTIONS *****************************************************************/
-NTSTATUS ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
+VOID
+CcInitCacheZeroPage(VOID)
+{
+ NTSTATUS Status;
+
+ Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &CcZeroPage);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("Can't allocate CcZeroPage.\n");
+ KeBugCheck(0);
+ }
+ Status = MiZeroPage(CcZeroPage);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("Can't zero out CcZeroPage.\n");
+ KeBugCheck(0);
+ }
+}
+
+NTSTATUS
+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;
+
+ Status = CcRosGetCacheSegmentChain(Bcb, ReadOffset, Length, &head);
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+ 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 += 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;
+ PMDL Mdl;
+ ULONG i;
+ ULONG offset;
+
+ /*
+ * Count the maximum number of bytes we could read starting
+ * from the current segment.
+ */
+ current2 = current;
+ current_size = 0;
+ while (current2 != NULL && !current2->Valid)
+ {
+ current2 = current2->NextInChain;
+ current_size += Bcb->CacheSegmentSize;
+ }
+
+ /*
+ * Create an MDL which contains all their pages.
+ */
+ Mdl = MmCreateMdl(NULL, NULL, current_size);
+ Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
+ current2 = current;
+ offset = 0;
+ while (current2 != NULL && !current2->Valid)
+ {
+ for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++)
+ {
+ PVOID address;
+ PHYSICAL_ADDRESS page;
+ address = current2->BaseAddress + (i * PAGE_SIZE);
+ page = MmGetPhysicalAddressForProcess(NULL, address);
+ ((PULONG)(Mdl + 1))[offset] = page.u.LowPart;
+ offset++;
+ }
+ current2 = current2->NextInChain;
+ }
+
+ /*
+ * 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 (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
+ {
+ while (current != NULL)
+ {
+ previous = current;
+ current = current->NextInChain;
+ CcRosReleaseCacheSegment(Bcb, previous, FALSE, FALSE, FALSE);
+ }
+ return(Status);
+ }
+ while (current != NULL && !current->Valid)
+ {
+ previous = current;
+ current = current->NextInChain;
+ TempLength = min(Bcb->CacheSegmentSize, Length);
+ memcpy(Buffer, previous->BaseAddress, TempLength);
+ Buffer += TempLength;
+ Length = Length - TempLength;
+ CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
+ }
+ }
+ }
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS
+ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
{
ULONG Size;
PMDL Mdl;
NTSTATUS Status;
LARGE_INTEGER SegOffset;
IO_STATUS_BLOCK IoStatus;
+ KEVENT Event;
SegOffset.QuadPart = CacheSeg->FileOffset;
Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
if (Size > CacheSeg->Bcb->CacheSegmentSize)
- {
- Size = CacheSeg->Bcb->CacheSegmentSize;
- }
+ {
+ Size = CacheSeg->Bcb->CacheSegmentSize;
+ }
Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
MmBuildMdlForNonPagedPool(Mdl);
- Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &IoStatus, TRUE);
- if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, & Event, &IoStatus);
+ if (Status == STATUS_PENDING)
{
- CcRosReleaseCacheSegment(CacheSeg->Bcb, CacheSeg, FALSE);
- DPRINT1("IoPageRead failed, Status %x\n", Status);
- return Status;
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = IoStatus.Status;
}
+
+ if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
+ {
+ CcRosReleaseCacheSegment(CacheSeg->Bcb, CacheSeg, FALSE, FALSE, FALSE);
+ DPRINT1("IoPageRead failed, Status %x\n", Status);
+ return Status;
+ }
if (CacheSeg->Bcb->CacheSegmentSize > Size)
- {
- memset (CacheSeg->BaseAddress + Size, 0, CacheSeg->Bcb->CacheSegmentSize - Size);
- }
+ {
+ memset (CacheSeg->BaseAddress + Size, 0,
+ CacheSeg->Bcb->CacheSegmentSize - Size);
+ }
return STATUS_SUCCESS;
}
-NTSTATUS WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
+NTSTATUS
+WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
{
ULONG Size;
PMDL Mdl;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
LARGE_INTEGER SegOffset;
+ KEVENT Event;
+ CacheSeg->Dirty = FALSE;
SegOffset.QuadPart = CacheSeg->FileOffset;
Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
if (Size > CacheSeg->Bcb->CacheSegmentSize)
- {
- Size = CacheSeg->Bcb->CacheSegmentSize;
- }
+ {
+ Size = CacheSeg->Bcb->CacheSegmentSize;
+ }
Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
MmBuildMdlForNonPagedPool(Mdl);
- Status = IoPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &IoStatus, TRUE);
- if (!NT_SUCCESS(Status))
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ Status = IoPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &Event, &IoStatus);
+ if (Status == STATUS_PENDING)
{
- DPRINT1("IoPageWrite failed, Status %x\n", Status);
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = IoStatus.Status;
}
- return Status;
+ if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
+ {
+ DPRINT1("IoPageWrite failed, Status %x\n", Status);
+ CacheSeg->Dirty = TRUE;
+ return(Status);
+ }
+ return(STATUS_SUCCESS);
}
BOOLEAN STDCALL
-CcCopyRead (
- IN PFILE_OBJECT FileObject,
- IN PLARGE_INTEGER FileOffset,
- IN ULONG Length,
- IN BOOLEAN Wait,
- OUT PVOID Buffer,
- OUT PIO_STATUS_BLOCK IoStatus)
+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 %x, FileOffset %x, "
- "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
- FileObject, (ULONG)FileOffset->QuadPart, Length, Wait,
- Buffer, 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 %x, FileOffset %x, "
+ "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
+ FileObject, (ULONG)FileOffset->QuadPart, Length, Wait,
+ Buffer, IoStatus);
- Bcb = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
- ReadOffset = FileOffset->QuadPart;
-
- DPRINT("AllocationSize %d, FileSize %d\n",
+ Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
+ ReadOffset = FileOffset->QuadPart;
+
+ DPRINT("AllocationSize %d, FileSize %d\n",
(ULONG)Bcb->AllocationSize.QuadPart,
(ULONG)Bcb->FileSize.QuadPart);
- if (!Wait)
- {
- KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
- current_entry = Bcb->CacheSegmentListHead.Flink;
- while (current_entry != &Bcb->CacheSegmentListHead)
- {
- current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbListEntry);
- 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);
- }
-
- TempLength = ReadOffset % Bcb->CacheSegmentSize;
- 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;
- return FALSE;
- }
- }
- memcpy (Buffer, BaseAddress + ReadOffset % Bcb->CacheSegmentSize, TempLength);
- CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
- ReadLength += TempLength;
- Length -= TempLength;
- ReadOffset += TempLength;
- Buffer += TempLength;
- }
+ /*
+ * 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);
+ }
- while (Length > 0)
- {
- TempLength = min (Bcb->CacheSegmentSize, Length);
- Status = CcRosRequestCacheSegment(Bcb, ReadOffset,
- &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;
- return FALSE;
- }
- }
- memcpy (Buffer, BaseAddress, TempLength);
- CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
- ReadLength += TempLength;
- Length -= TempLength;
- ReadOffset += TempLength;
- Buffer += TempLength;
- }
- IoStatus->Status = STATUS_SUCCESS;
- IoStatus->Information = ReadLength;
- DPRINT("CcCopyRead O.K.\n");
- return TRUE;
+ TempLength = ReadOffset % Bcb->CacheSegmentSize;
+ 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;
+ return FALSE;
+ }
+ }
+ memcpy (Buffer, BaseAddress + ReadOffset % Bcb->CacheSegmentSize,
+ TempLength);
+ CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
+ ReadLength += TempLength;
+ Length -= TempLength;
+ ReadOffset += TempLength;
+ Buffer += TempLength;
+ }
+ while (Length > 0)
+ {
+ TempLength = min(max(Bcb->CacheSegmentSize, 65536), Length);
+ ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
+ ReadLength += TempLength;
+ Length -= TempLength;
+ ReadOffset += TempLength;
+ Buffer += TempLength;
+ }
+ IoStatus->Status = STATUS_SUCCESS;
+ IoStatus->Information = ReadLength;
+ DPRINT("CcCopyRead O.K.\n");
+ return TRUE;
}
BOOLEAN STDCALL
-CcCopyWrite (
- IN PFILE_OBJECT FileObject,
- IN PLARGE_INTEGER FileOffset,
- IN ULONG Length,
- IN BOOLEAN Wait,
- IN PVOID Buffer)
+CcCopyWrite (IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN PVOID Buffer)
{
NTSTATUS Status;
ULONG WriteOffset;
BOOLEAN Valid;
DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
- "Length %d, Wait %d, Buffer %x)\n",
+ "Length %d, Wait %d, Buffer %x)\n",
FileObject, (ULONG)FileOffset->QuadPart, Length, Wait, Buffer);
- Bcb = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
+ Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
WriteOffset = (ULONG)FileOffset->QuadPart;
if (!Wait)
- {
- // testing, if the requested datas are available
- KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
- current_entry = Bcb->CacheSegmentListHead.Flink;
- while (current_entry != &Bcb->CacheSegmentListHead)
{
- CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbListEntry);
- 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;
+ /* 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);
}
- KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
- }
TempLength = WriteOffset % Bcb->CacheSegmentSize;
if (TempLength != 0)
- {
- TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
- Status = CcRosRequestCacheSegment(Bcb,
- ROUND_DOWN(WriteOffset, Bcb->CacheSegmentSize),
- &BaseAddress, &Valid, &CacheSeg);
- if (!NT_SUCCESS(Status))
- {
- return FALSE;
- }
- if (!Valid)
- {
- if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
- {
- return FALSE;
- }
- }
- memcpy (BaseAddress + WriteOffset % Bcb->CacheSegmentSize, Buffer, TempLength);
- if (!NT_SUCCESS(WriteCacheSegment(CacheSeg)))
- {
- return FALSE;
- }
- CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
-
- Length -= TempLength;
- WriteOffset += TempLength;
- Buffer += TempLength;
- }
-
+ {
+ 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 (BaseAddress + WriteOffset % Bcb->CacheSegmentSize,
+ Buffer, TempLength);
+ CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
+
+ Length -= TempLength;
+ WriteOffset += TempLength;
+ 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)))
- {
- return FALSE;
- }
- }
- memcpy (BaseAddress, Buffer, TempLength);
- if (!NT_SUCCESS(WriteCacheSegment(CacheSeg)))
- {
- return FALSE;
- }
- CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE);
- Length -= TempLength;
- WriteOffset += TempLength;
- Buffer += TempLength;
- }
- return TRUE;
+ {
+ 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)))
+ {
+ return FALSE;
+ }
+ }
+ memcpy (BaseAddress, Buffer, TempLength);
+ CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
+ Length -= TempLength;
+ WriteOffset += TempLength;
+ Buffer += TempLength;
+ }
+ return(TRUE);
}
+BOOLEAN STDCALL
+CcZeroData (IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER StartOffset,
+ IN PLARGE_INTEGER EndOffset,
+ IN BOOLEAN Wait)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER WriteOffset;
+ ULONG Length;
+ PMDL Mdl;
+ ULONG i;
+ IO_STATUS_BLOCK Iosb;
+ KEVENT Event;
+
+ DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
+ "Wait %d\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
+ Wait);
+
+ Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
+
+ if (FileObject->SectionObjectPointers->SharedCacheMap == NULL)
+ {
+ /* File is not cached */
+ WriteOffset.QuadPart = StartOffset->QuadPart;
+
+ while (Length > 0)
+ {
+ if (Length + WriteOffset.u.LowPart % PAGE_SIZE > 262144)
+ {
+ Mdl = MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart,
+ 262144 - WriteOffset.u.LowPart % PAGE_SIZE);
+ WriteOffset.QuadPart +=
+ (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
+ Length -= (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
+ }
+ else
+ {
+ Mdl =
+ MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart,
+ Length - WriteOffset.u.LowPart % PAGE_SIZE);
+ WriteOffset.QuadPart +=
+ (Length - WriteOffset.u.LowPart % PAGE_SIZE);
+ Length = 0;
+ }
+ if (Mdl == NULL)
+ {
+ return(FALSE);
+ }
+ Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
+ for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
+ {
+ ((PULONG)(Mdl + 1))[i] = CcZeroPage.u.LowPart;
+ }
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ Status = IoPageWrite(FileObject, Mdl, StartOffset, &Event, &Iosb);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = Iosb.Status;
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ return(FALSE);
+ }
+ }
+ }
+ else
+ {
+ /* File is cached */
+ KIRQL oldirql;
+ PBCB Bcb;
+ PLIST_ENTRY current_entry;
+ PCACHE_SEGMENT CacheSeg, current, previous;
+ ULONG TempLength;
+ ULONG Start;
+ ULONG count;
+ ULONG size;
+ PHYSICAL_ADDRESS page;
+
+ Start = StartOffset->u.LowPart;
+ Bcb = FileObject->SectionObjectPointers->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 ((Start >= CacheSeg->FileOffset &&
+ Start < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
+ || (Start + Length > CacheSeg->FileOffset &&
+ Start + 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 RStart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
+ WriteOffset.QuadPart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
+ if (Start % Bcb->CacheSegmentSize + Length > 262144)
+ {
+ Mdl = MmCreateMdl(NULL, NULL, 262144);
+ if (Mdl == NULL)
+ {
+ return FALSE;
+ }
+ Status = CcRosGetCacheSegmentChain (Bcb, RStart,
+ 262144, &CacheSeg);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(Mdl);
+ return(FALSE);
+ }
+ }
+ else
+ {
+ ULONG RLength;
+ RLength = Start % Bcb->CacheSegmentSize + Length;
+ RLength = ROUND_UP(RLength, Bcb->CacheSegmentSize);
+ Mdl = MmCreateMdl(NULL, (PVOID)RStart, RLength);
+ if (Mdl == NULL)
+ {
+ return(FALSE);
+ }
+ Status = CcRosGetCacheSegmentChain (Bcb, RStart, RLength,
+ &CacheSeg);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(Mdl);
+ return(FALSE);
+ }
+ }
+ Mdl->MdlFlags |= (MDL_PAGES_LOCKED|MDL_IO_PAGE_READ);
+ current = CacheSeg;
+ count = 0;
+ while (current != NULL)
+ {
+ if ((Start % Bcb->CacheSegmentSize) != 0 ||
+ Start % Bcb->CacheSegmentSize + Length <
+ Bcb->CacheSegmentSize)
+ {
+ if (!current->Valid)
+ {
+ /* Segment lesen */
+ Status = ReadCacheSegment(current);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ReadCacheSegment failed, status %x\n",
+ Status);
+ }
+ }
+ TempLength = min (Length, Bcb->CacheSegmentSize -
+ Start % Bcb->CacheSegmentSize);
+ memset (current->BaseAddress + Start % Bcb->CacheSegmentSize,
+ 0, TempLength);
+ }
+ else
+ {
+ TempLength = Bcb->CacheSegmentSize;
+ memset (current->BaseAddress, 0, Bcb->CacheSegmentSize);
+ }
+ Start += TempLength;
+ Length -= TempLength;
+
+ size = ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG));
+ for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE) &&
+ count < size; i++)
+ {
+ PVOID Address;
+ Address = current->BaseAddress + (i * PAGE_SIZE);
+ page =
+ MmGetPhysicalAddressForProcess(NULL, Address);
+ ((PULONG)(Mdl + 1))[count++] = page.u.LowPart;
+ }
+ current = current->NextInChain;
+ }
+
+ /* Write the Segment */
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ Status = IoPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = Iosb.Status;
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("IoPageWrite failed, status %x\n", Status);
+ }
+ current = CacheSeg;
+ while (current != NULL)
+ {
+ previous = current;
+ current = current->NextInChain;
+ CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
+ }
+ }
+ }
+ return(TRUE);
+}