* FILE: ntoskrnl/cc/copy.c
* PURPOSE: Implements cache managers copy interface
*
- * PROGRAMMERS:
+ * PROGRAMMERS: Some people?
+ * Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES ******************************************************************/
static PFN_NUMBER CcZeroPage = 0;
-#define MAX_ZERO_LENGTH (256 * 1024)
-#define MAX_RW_LENGTH (256 * 1024)
+#define MAX_ZERO_LENGTH (256 * 1024)
+typedef enum _CC_COPY_OPERATION
+{
+ CcOperationRead,
+ CcOperationWrite,
+ CcOperationZero
+} CC_COPY_OPERATION;
+
+ULONG CcRosTraceLevel = 0;
ULONG CcFastMdlReadWait;
ULONG CcFastMdlReadNotPossible;
ULONG CcFastReadNotPossible;
ULONG CcFastReadNoWait;
ULONG CcFastReadResourceMiss;
+extern KEVENT iLazyWriterNotify;
+
/* FUNCTIONS *****************************************************************/
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;
-NTSTATUS
-NTAPI
-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))
+ MI_SET_USAGE(MI_USAGE_CACHE);
+ //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
+ Status = MmRequestPageMemoryConsumer(MC_SYSTEM, TRUE, &CcZeroPage);
+ if (!NT_SUCCESS(Status))
{
- return(Status);
+ DbgPrint("Can't allocate CcZeroPage.\n");
+ KeBugCheck(CACHE_MANAGER);
}
- 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;
- }
- }
- }
- return(STATUS_SUCCESS);
+ MiZeroPhysicalPage(CcZeroPage);
}
NTSTATUS
NTAPI
-ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
+CcReadVirtualAddress (
+ PROS_VACB Vacb)
{
- ULONG Size;
+ ULONG Size, Pages;
PMDL Mdl;
NTSTATUS Status;
- LARGE_INTEGER SegOffset;
IO_STATUS_BLOCK IoStatus;
KEVENT Event;
- SegOffset.QuadPart = CacheSeg->FileOffset;
- Size = (ULONG)(CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset);
- if (Size > CacheSeg->Bcb->CacheSegmentSize)
+ Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
+ if (Size > VACB_MAPPING_GRANULARITY)
{
- Size = CacheSeg->Bcb->CacheSegmentSize;
+ Size = VACB_MAPPING_GRANULARITY;
}
- Mdl = IoAllocateMdl(CacheSeg->BaseAddress, Size, FALSE, FALSE, NULL);
+ Pages = BYTES_TO_PAGES(Size);
+ ASSERT(Pages * PAGE_SIZE <= VACB_MAPPING_GRANULARITY);
+
+ Mdl = IoAllocateMdl(Vacb->BaseAddress, Pages * PAGE_SIZE, FALSE, FALSE, NULL);
if (!Mdl)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
- MmBuildMdlForNonPagedPool(Mdl);
- Mdl->MdlFlags |= MDL_IO_PAGE_READ;
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &Event, &IoStatus);
- if (Status == STATUS_PENDING)
+
+ Status = STATUS_SUCCESS;
+ _SEH2_TRY
+ {
+ MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess);
+ }
+ _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ KeBugCheck(CACHE_MANAGER);
+ } _SEH2_END;
+
+ if (NT_SUCCESS(Status))
{
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
- Status = IoStatus.Status;
+ Mdl->MdlFlags |= MDL_IO_PAGE_READ;
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ Status = IoPageRead(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = IoStatus.Status;
+ }
+
+ MmUnlockPages(Mdl);
}
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);
+ RtlZeroMemory((char*)Vacb->BaseAddress + Size,
+ VACB_MAPPING_GRANULARITY - Size);
}
return STATUS_SUCCESS;
NTSTATUS
NTAPI
-WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
+CcWriteVirtualAddress (
+ PROS_VACB Vacb)
{
ULONG Size;
PMDL Mdl;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
- LARGE_INTEGER SegOffset;
KEVENT Event;
- CacheSeg->Dirty = FALSE;
- SegOffset.QuadPart = CacheSeg->FileOffset;
- Size = (ULONG)(CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset);
- if (Size > CacheSeg->Bcb->CacheSegmentSize)
+ Vacb->Dirty = FALSE;
+ Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
+ if (Size > VACB_MAPPING_GRANULARITY)
{
- Size = CacheSeg->Bcb->CacheSegmentSize;
+ Size = VACB_MAPPING_GRANULARITY;
}
//
// Nonpaged pool PDEs in ReactOS must actually be synchronized between the
ULONG i = 0;
do
{
- MmGetPfnForProcess(NULL, (PVOID)((ULONG_PTR)CacheSeg->BaseAddress + (i << PAGE_SHIFT)));
+ MmGetPfnForProcess(NULL, (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i << PAGE_SHIFT)));
} while (++i < (Size >> PAGE_SHIFT));
}
- Mdl = IoAllocateMdl(CacheSeg->BaseAddress, Size, FALSE, FALSE, NULL);
+ Mdl = IoAllocateMdl(Vacb->BaseAddress, Size, FALSE, FALSE, NULL);
if (!Mdl)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
- MmBuildMdlForNonPagedPool(Mdl);
- Mdl->MdlFlags |= MDL_IO_PAGE_READ;
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- Status = IoSynchronousPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &Event, &IoStatus);
- if (Status == STATUS_PENDING)
+
+ Status = STATUS_SUCCESS;
+ _SEH2_TRY
+ {
+ MmProbeAndLockPages(Mdl, KernelMode, IoReadAccess);
+ }
+ _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
{
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
- Status = IoStatus.Status;
+ Status = _SEH2_GetExceptionCode();
+ KeBugCheck(CACHE_MANAGER);
+ } _SEH2_END;
+
+ if (NT_SUCCESS(Status))
+ {
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ Status = IoSynchronousPageWrite(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = IoStatus.Status;
+ }
+
+ MmUnlockPages(Mdl);
}
IoFreeMdl(Mdl);
if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
{
DPRINT1("IoPageWrite failed, Status %x\n", Status);
- CacheSeg->Dirty = TRUE;
+ Vacb->Dirty = TRUE;
return Status;
}
return STATUS_SUCCESS;
}
+NTSTATUS
+ReadWriteOrZero(
+ _Inout_ PVOID BaseAddress,
+ _Inout_opt_ PVOID Buffer,
+ _In_ ULONG Length,
+ _In_ CC_COPY_OPERATION Operation)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (Operation == CcOperationZero)
+ {
+ /* Zero */
+ RtlZeroMemory(BaseAddress, Length);
+ }
+ else
+ {
+ _SEH2_TRY
+ {
+ if (Operation == CcOperationWrite)
+ RtlCopyMemory(BaseAddress, Buffer, Length);
+ else
+ RtlCopyMemory(Buffer, BaseAddress, Length);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ }
+ return Status;
+}
+
+BOOLEAN
+CcCopyData (
+ _In_ PFILE_OBJECT FileObject,
+ _In_ LONGLONG FileOffset,
+ _Inout_ PVOID Buffer,
+ _In_ LONGLONG Length,
+ _In_ CC_COPY_OPERATION Operation,
+ _In_ BOOLEAN Wait,
+ _Out_ PIO_STATUS_BLOCK IoStatus)
+{
+ NTSTATUS Status;
+ LONGLONG CurrentOffset;
+ ULONG BytesCopied;
+ KIRQL OldIrql;
+ PROS_SHARED_CACHE_MAP SharedCacheMap;
+ PLIST_ENTRY ListEntry;
+ PROS_VACB Vacb;
+ ULONG PartialLength;
+ PVOID BaseAddress;
+ BOOLEAN Valid;
+
+ SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
+ CurrentOffset = FileOffset;
+ BytesCopied = 0;
+
+ if (!Wait)
+ {
+ /* test if the requested data is available */
+ KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
+ /* FIXME: this loop doesn't take into account areas that don't have
+ * a VACB in the list yet */
+ ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink;
+ while (ListEntry != &SharedCacheMap->CacheMapVacbListHead)
+ {
+ Vacb = CONTAINING_RECORD(ListEntry,
+ ROS_VACB,
+ CacheMapVacbListEntry);
+ ListEntry = ListEntry->Flink;
+ if (!Vacb->Valid &&
+ DoRangesIntersect(Vacb->FileOffset.QuadPart,
+ VACB_MAPPING_GRANULARITY,
+ CurrentOffset, Length))
+ {
+ KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
+ /* data not available */
+ return FALSE;
+ }
+ if (Vacb->FileOffset.QuadPart >= CurrentOffset + Length)
+ break;
+ }
+ KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
+ }
+
+ PartialLength = CurrentOffset % VACB_MAPPING_GRANULARITY;
+ if (PartialLength != 0)
+ {
+ PartialLength = min(Length, VACB_MAPPING_GRANULARITY - PartialLength);
+ Status = CcRosRequestVacb(SharedCacheMap,
+ ROUND_DOWN(CurrentOffset,
+ VACB_MAPPING_GRANULARITY),
+ &BaseAddress,
+ &Valid,
+ &Vacb);
+ if (!NT_SUCCESS(Status))
+ ExRaiseStatus(Status);
+ if (!Valid)
+ {
+ Status = CcReadVirtualAddress(Vacb);
+ if (!NT_SUCCESS(Status))
+ {
+ CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
+ ExRaiseStatus(Status);
+ }
+ }
+ Status = ReadWriteOrZero((PUCHAR)BaseAddress + CurrentOffset % VACB_MAPPING_GRANULARITY,
+ Buffer,
+ PartialLength,
+ Operation);
+
+ CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
+
+ if (!NT_SUCCESS(Status))
+ ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
+
+ Length -= PartialLength;
+ CurrentOffset += PartialLength;
+ BytesCopied += PartialLength;
+
+ if (Operation != CcOperationZero)
+ Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
+ }
+
+ while (Length > 0)
+ {
+ ASSERT(CurrentOffset % VACB_MAPPING_GRANULARITY == 0);
+ PartialLength = min(VACB_MAPPING_GRANULARITY, Length);
+ Status = CcRosRequestVacb(SharedCacheMap,
+ CurrentOffset,
+ &BaseAddress,
+ &Valid,
+ &Vacb);
+ if (!NT_SUCCESS(Status))
+ ExRaiseStatus(Status);
+ if (!Valid &&
+ (Operation == CcOperationRead ||
+ PartialLength < VACB_MAPPING_GRANULARITY))
+ {
+ Status = CcReadVirtualAddress(Vacb);
+ if (!NT_SUCCESS(Status))
+ {
+ CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
+ ExRaiseStatus(Status);
+ }
+ }
+ Status = ReadWriteOrZero(BaseAddress, Buffer, PartialLength, Operation);
+
+ CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
+
+ if (!NT_SUCCESS(Status))
+ ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
+
+ Length -= PartialLength;
+ CurrentOffset += PartialLength;
+ BytesCopied += PartialLength;
+
+ if (Operation != CcOperationZero)
+ Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
+ }
+ IoStatus->Status = STATUS_SUCCESS;
+ IoStatus->Information = BytesCopied;
+ return TRUE;
+}
/*
* @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;
-}
+ PFSRTL_COMMON_FCB_HEADER Fcb;
+ PROS_SHARED_CACHE_MAP SharedCacheMap;
+ CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
+ FileObject, BytesToWrite, Wait, Retrying);
-/*
- * @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)
-{
- 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)
+ /* We cannot write if dirty pages count is above threshold */
+ if (CcTotalDirtyPages > CcDirtyPageThreshold)
{
- 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);
+ return FALSE;
}
- TempLength = ReadOffset % Bcb->CacheSegmentSize;
- if (TempLength != 0)
+ /* We cannot write if dirty pages count will bring use above
+ * XXX: Might not be accurate
+ */
+ if (CcTotalDirtyPages + (BytesToWrite / PAGE_SIZE) > CcDirtyPageThreshold)
{
- 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);
+ return FALSE;
}
- while (Length > 0)
+
+ /* Is there a limit per file object? */
+ Fcb = FileObject->FsContext;
+ SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
+ if (!BooleanFlagOn(Fcb->Flags, FSRTL_FLAG_LIMIT_MODIFIED_PAGES) ||
+ SharedCacheMap->DirtyPageThreshold == 0)
{
- TempLength = min(max(Bcb->CacheSegmentSize, MAX_RW_LENGTH), Length);
- Status = ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
- if (!NT_SUCCESS(Status))
- {
- IoStatus->Information = 0;
- IoStatus->Status = Status;
- DPRINT("ReadCacheSegmentChain failed, Status %x\n", Status);
- return FALSE;
- }
+ /* Nope, so that's fine, allow write operation */
+ return TRUE;
+ }
- ReadLength += TempLength;
- Length -= TempLength;
- ReadOffset += TempLength;
+ /* Is dirty page count above local threshold? */
+ if (SharedCacheMap->DirtyPages > SharedCacheMap->DirtyPageThreshold)
+ {
+ return FALSE;
+ }
- Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
+ /* We cannot write if dirty pages count will bring use above
+ * XXX: Might not be accurate
+ */
+ if (SharedCacheMap->DirtyPages + (BytesToWrite / PAGE_SIZE) > SharedCacheMap->DirtyPageThreshold)
+ {
+ return FALSE;
}
- IoStatus->Status = STATUS_SUCCESS;
- IoStatus->Information = ReadLength;
- DPRINT("CcCopyRead O.K.\n");
- return TRUE;
+
+ 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
+CcCopyRead (
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ OUT PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus)
{
- 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);
+ CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d\n",
+ FileObject, FileOffset->QuadPart, Length, Wait);
+
+ 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);
+
+ return CcCopyData(FileObject,
+ FileOffset->QuadPart,
+ Buffer,
+ Length,
+ CcOperationRead,
+ Wait,
+ IoStatus);
}
/*
- * @unimplemented
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+CcCopyWrite (
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN PVOID Buffer)
+{
+ IO_STATUS_BLOCK IoStatus;
+
+ CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d Buffer=%p\n",
+ FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
+
+ DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
+ "Length %lu, Wait %u, Buffer 0x%p)\n",
+ FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
+
+ return CcCopyData(FileObject,
+ FileOffset->QuadPart,
+ Buffer,
+ Length,
+ CcOperationWrite,
+ Wait,
+ &IoStatus);
+}
+
+/*
+ * @implemented
*/
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;
+ PROS_DEFERRED_WRITE_CONTEXT Context;
+
+ CCTRACE(CC_API_DEBUG, "FileObject=%p PostRoutine=%p Context1=%p Context2=%p BytesToWrite=%lu Retrying=%d\n",
+ FileObject, PostRoutine, Context1, Context2, BytesToWrite, Retrying);
+
+ /* Try to allocate a context for queueing the write operation */
+ Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(ROS_DEFERRED_WRITE_CONTEXT), 'CcDw');
+ /* If it failed, immediately execute the operation! */
+ if (Context == NULL)
+ {
+ PostRoutine(Context1, Context2);
+ return;
+ }
+
+ /* Otherwise, initialize the context */
+ Context->FileObject = FileObject;
+ Context->PostRoutine = PostRoutine;
+ Context->Context1 = Context1;
+ Context->Context2 = Context2;
+ Context->BytesToWrite = BytesToWrite;
+ Context->Retrying = Retrying;
+
+ /* And queue it */
+ if (Retrying)
+ {
+ /* To the top, if that's a retry */
+ ExInterlockedInsertHeadList(&CcDeferredWrites,
+ &Context->CcDeferredWritesEntry,
+ &CcDeferredWriteSpinLock);
+ }
+ else
+ {
+ /* To the bottom, if that's a first time */
+ ExInterlockedInsertTailList(&CcDeferredWrites,
+ &Context->CcDeferredWritesEntry,
+ &CcDeferredWriteSpinLock);
+ }
}
/*
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;
+ LARGE_INTEGER LargeFileOffset;
+ BOOLEAN Success;
+
+ CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu PageCount=%lu Buffer=%p\n",
+ FileObject, FileOffset, Length, PageCount, Buffer);
+
+ DBG_UNREFERENCED_PARAMETER(PageCount);
+
+ LargeFileOffset.QuadPart = FileOffset;
+ Success = CcCopyRead(FileObject,
+ &LargeFileOffset,
+ Length,
+ TRUE,
+ Buffer,
+ IoStatus);
+ ASSERT(Success == TRUE);
}
+
/*
* @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;
+ LARGE_INTEGER LargeFileOffset;
+ BOOLEAN Success;
+
+ CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu Buffer=%p\n",
+ FileObject, FileOffset, Length, Buffer);
+
+ LargeFileOffset.QuadPart = FileOffset;
+ Success = CcCopyWrite(FileObject,
+ &LargeFileOffset,
+ Length,
+ TRUE,
+ Buffer);
+ ASSERT(Success == TRUE);
}
/*
- * @unimplemented
+ * @implemented
*/
NTSTATUS
NTAPI
CcWaitForCurrentLazyWriterActivity (
- VOID
- )
+ VOID)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS Status;
+
+ /* Lazy writer is done when its event is set */
+ Status = KeWaitForSingleObject(&iLazyWriterNotify,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ return STATUS_SUCCESS;
}
/*
* @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;
+ LONGLONG Length;
+ ULONG CurrentLength;
+ PMDL Mdl;
+ ULONG i;
+ IO_STATUS_BLOCK Iosb;
+ KEVENT Event;
+
+ CCTRACE(CC_API_DEBUG, "FileObject=%p StartOffset=%I64u EndOffset=%I64u Wait=%d\n",
+ FileObject, StartOffset->QuadPart, EndOffset->QuadPart, Wait);
+
+ DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
+ "Wait %u)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
+ Wait);
+
+ Length = EndOffset->QuadPart - StartOffset->QuadPart;
+ 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.QuadPart % PAGE_SIZE > MAX_ZERO_LENGTH)
+ {
+ CurrentLength = MAX_ZERO_LENGTH - WriteOffset.QuadPart % 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);
- }
- }
+ IO_STATUS_BLOCK IoStatus;
+
+ return CcCopyData(FileObject,
+ WriteOffset.QuadPart,
+ NULL,
+ Length,
+ CcOperationZero,
+ Wait,
+ &IoStatus);
}
- return(TRUE);
+
+ return TRUE;
}