static PFN_NUMBER CcZeroPage = 0;
#define MAX_ZERO_LENGTH (256 * 1024)
-#define MAX_RW_LENGTH (256 * 1024)
-C_ASSERT(MAX_RW_LENGTH <= VACB_MAPPING_GRANULARITY);
+
+typedef enum _CC_COPY_OPERATION
+{
+ CcOperationRead,
+ CcOperationWrite,
+ CcOperationZero
+} CC_COPY_OPERATION;
ULONG CcFastMdlReadWait;
ULONG CcFastMdlReadNotPossible;
MiZeroPhysicalPage(CcZeroPage);
}
-NTSTATUS
-NTAPI
-ReadVacbChain (
- PROS_SHARED_CACHE_MAP SharedCacheMap,
- ULONG ReadOffset,
- ULONG Length,
- PVOID Buffer)
-{
- PROS_VACB head;
- PROS_VACB current;
- PROS_VACB previous;
- IO_STATUS_BLOCK Iosb;
- NTSTATUS Status;
- ULONG TempLength;
- KEVENT Event;
- PMDL Mdl;
-
- Mdl = _alloca(MmSizeOfMdl(NULL, MAX_RW_LENGTH));
-
- Status = CcRosGetVacbChain(SharedCacheMap, ReadOffset, Length, &head);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
- current = head;
- while (current != NULL)
- {
- /*
- * If the current VACB 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;
- CcRosReleaseVacb(SharedCacheMap, previous, TRUE, FALSE, FALSE);
- }
- /*
- * Otherwise read in as much as we can.
- */
- else
- {
- PROS_VACB current2;
- ULONG current_size;
- ULONG i;
- PPFN_NUMBER MdlPages;
-
- /*
- * Count the maximum number of bytes we could read starting
- * from the current VACB.
- */
- 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.
- */
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- Status = IoPageRead(SharedCacheMap->FileObject,
- Mdl,
- ¤t->FileOffset,
- &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;
- CcRosReleaseVacb(SharedCacheMap, 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;
- CcRosReleaseVacb(SharedCacheMap, previous, TRUE, FALSE, FALSE);
- current_size += VACB_MAPPING_GRANULARITY;
- }
- }
- }
- return STATUS_SUCCESS;
-}
-
NTSTATUS
NTAPI
CcReadVirtualAddress (
return STATUS_SUCCESS;
}
-
-/*
- * @unimplemented
- */
-BOOLEAN
-NTAPI
-CcCanIWrite (
- IN PFILE_OBJECT FileObject,
- IN ULONG BytesToWrite,
- IN BOOLEAN Wait,
- IN BOOLEAN Retrying)
+NTSTATUS
+ReadWriteOrZero(
+ _Inout_ PVOID BaseAddress,
+ _Inout_opt_ PVOID Buffer,
+ _In_ ULONG Length,
+ _In_ CC_COPY_OPERATION Operation)
{
- UNIMPLEMENTED;
- return FALSE;
-}
+ 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;
+}
-/*
- * @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)
+CcCopyData (
+ _In_ PFILE_OBJECT FileObject,
+ _In_ LONGLONG FileOffset,
+ _Inout_ PVOID Buffer,
+ _In_ ULONG Length,
+ _In_ CC_COPY_OPERATION Operation,
+ _In_ BOOLEAN Wait,
+ _Out_ PIO_STATUS_BLOCK IoStatus)
{
- ULONG ReadOffset;
- ULONG TempLength;
- NTSTATUS Status = STATUS_SUCCESS;
- PVOID BaseAddress;
+ 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;
- ULONG ReadLength = 0;
- PROS_SHARED_CACHE_MAP SharedCacheMap;
- KIRQL oldirql;
- PLIST_ENTRY current_entry;
- PROS_VACB 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);
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
- ReadOffset = (ULONG)FileOffset->QuadPart;
+ CurrentOffset = FileOffset;
+ BytesCopied = 0;
- DPRINT("SectionSize %I64d, FileSize %I64d\n",
- SharedCacheMap->SectionSize.QuadPart,
- SharedCacheMap->FileSize.QuadPart);
-
- /*
- * Check for the nowait case that all the cache VACBs that would
- * cover this read are in memory.
- */
if (!Wait)
{
- KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
+ /* 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 */
- current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
- while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
+ ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink;
+ while (ListEntry != &SharedCacheMap->CacheMapVacbListHead)
{
- current = CONTAINING_RECORD(current_entry,
- ROS_VACB,
- CacheMapVacbListEntry);
- if (!current->Valid &&
- DoRangesIntersect(current->FileOffset.QuadPart,
+ Vacb = CONTAINING_RECORD(ListEntry,
+ ROS_VACB,
+ CacheMapVacbListEntry);
+ ListEntry = ListEntry->Flink;
+ if (!Vacb->Valid &&
+ DoRangesIntersect(Vacb->FileOffset.QuadPart,
VACB_MAPPING_GRANULARITY,
- ReadOffset, Length))
+ CurrentOffset, Length))
{
- KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
- IoStatus->Status = STATUS_UNSUCCESSFUL;
- IoStatus->Information = 0;
+ KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
+ /* data not available */
return FALSE;
}
- if (current->FileOffset.QuadPart >= ReadOffset + Length)
+ if (Vacb->FileOffset.QuadPart >= CurrentOffset + Length)
break;
- current_entry = current_entry->Flink;
}
- KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
+ KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
}
- TempLength = ReadOffset % VACB_MAPPING_GRANULARITY;
- if (TempLength != 0)
+ PartialLength = CurrentOffset % VACB_MAPPING_GRANULARITY;
+ if (PartialLength != 0)
{
- TempLength = min(Length, VACB_MAPPING_GRANULARITY - TempLength);
+ PartialLength = min(Length, VACB_MAPPING_GRANULARITY - PartialLength);
Status = CcRosRequestVacb(SharedCacheMap,
- ROUND_DOWN(ReadOffset,
+ ROUND_DOWN(CurrentOffset,
VACB_MAPPING_GRANULARITY),
- &BaseAddress, &Valid, &Vacb);
+ &BaseAddress,
+ &Valid,
+ &Vacb);
if (!NT_SUCCESS(Status))
- {
- IoStatus->Information = 0;
- IoStatus->Status = Status;
- DPRINT("CcRosRequestVacb failed, Status %x\n", Status);
- return FALSE;
- }
+ ExRaiseStatus(Status);
if (!Valid)
{
Status = CcReadVirtualAddress(Vacb);
if (!NT_SUCCESS(Status))
{
- IoStatus->Information = 0;
- IoStatus->Status = Status;
CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
- return FALSE;
+ ExRaiseStatus(Status);
}
}
- RtlCopyMemory(Buffer,
- (char*)BaseAddress + ReadOffset % VACB_MAPPING_GRANULARITY,
- TempLength);
- CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
- ReadLength += TempLength;
- Length -= TempLength;
- ReadOffset += TempLength;
- Buffer = (PVOID)((char*)Buffer + TempLength);
+ 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 (Buffer)
+ Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
}
while (Length > 0)
{
- TempLength = min(VACB_MAPPING_GRANULARITY, Length);
- Status = ReadVacbChain(SharedCacheMap, ReadOffset, TempLength, Buffer);
+ 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))
{
- IoStatus->Information = 0;
- IoStatus->Status = Status;
- DPRINT("ReadVacbChain failed, Status %x\n", Status);
- return FALSE;
+ Status = CcReadVirtualAddress(Vacb);
+ if (!NT_SUCCESS(Status))
+ {
+ CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
+ ExRaiseStatus(Status);
+ }
}
+ Status = ReadWriteOrZero(BaseAddress, Buffer, PartialLength, Operation);
- ReadLength += TempLength;
- Length -= TempLength;
- ReadOffset += TempLength;
+ CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
- Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
- }
+ if (!NT_SUCCESS(Status))
+ ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
+
+ Length -= PartialLength;
+ CurrentOffset += PartialLength;
+ BytesCopied += PartialLength;
+ if (Buffer)
+ Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
+ }
IoStatus->Status = STATUS_SUCCESS;
- IoStatus->Information = ReadLength;
- DPRINT("CcCopyRead O.K.\n");
+ IoStatus->Information = BytesCopied;
return TRUE;
}
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+CcCanIWrite (
+ IN PFILE_OBJECT FileObject,
+ IN ULONG BytesToWrite,
+ IN BOOLEAN Wait,
+ IN BOOLEAN Retrying)
+{
+ 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)
+{
+ 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);
+}
+
/*
* @implemented
*/
IN BOOLEAN Wait,
IN PVOID Buffer)
{
- NTSTATUS Status;
- ULONG WriteOffset;
- KIRQL oldirql;
- PROS_SHARED_CACHE_MAP SharedCacheMap;
- PLIST_ENTRY current_entry;
- PROS_VACB Vacb;
- ULONG TempLength;
- PVOID BaseAddress;
- BOOLEAN Valid;
+ IO_STATUS_BLOCK IoStatus;
DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
"Length %lu, Wait %u, Buffer 0x%p)\n",
FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
- SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
- WriteOffset = (ULONG)FileOffset->QuadPart;
-
- if (!Wait)
- {
- /* testing, if the requested datas are available */
- KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
- /* FIXME: this loop doesn't take into account areas that don't have
- * a VACB in the list yet */
- current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
- while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
- {
- Vacb = CONTAINING_RECORD(current_entry,
- ROS_VACB,
- CacheMapVacbListEntry);
- if (!Vacb->Valid &&
- DoRangesIntersect(Vacb->FileOffset.QuadPart,
- VACB_MAPPING_GRANULARITY,
- WriteOffset, Length))
- {
- KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
- /* datas not available */
- return FALSE;
- }
- if (Vacb->FileOffset.QuadPart >= WriteOffset + Length)
- break;
- current_entry = current_entry->Flink;
- }
- KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, 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 = CcRosRequestVacb(SharedCacheMap, ROffset,
- &BaseAddress, &Valid, &Vacb);
- if (!NT_SUCCESS(Status))
- {
- return FALSE;
- }
- if (!Valid)
- {
- if (!NT_SUCCESS(CcReadVirtualAddress(Vacb)))
- {
- return FALSE;
- }
- }
- RtlCopyMemory((char*)BaseAddress + WriteOffset % VACB_MAPPING_GRANULARITY,
+ return CcCopyData(FileObject,
+ FileOffset->QuadPart,
Buffer,
- TempLength);
- CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, TRUE, FALSE);
-
- Length -= TempLength;
- WriteOffset += TempLength;
-
- Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
- }
-
- while (Length > 0)
- {
- TempLength = min(VACB_MAPPING_GRANULARITY, Length);
- Status = CcRosRequestVacb(SharedCacheMap,
- WriteOffset,
- &BaseAddress,
- &Valid,
- &Vacb);
- if (!NT_SUCCESS(Status))
- {
- return FALSE;
- }
- if (!Valid && TempLength < VACB_MAPPING_GRANULARITY)
- {
- if (!NT_SUCCESS(CcReadVirtualAddress(Vacb)))
- {
- CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
- return FALSE;
- }
- }
- RtlCopyMemory(BaseAddress, Buffer, TempLength);
- CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, TRUE, FALSE);
- Length -= TempLength;
- WriteOffset += TempLength;
-
- Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
- }
- return TRUE;
+ Length,
+ CcOperationWrite,
+ Wait,
+ &IoStatus);
}
/*
}
else
{
- /* File is cached */
- KIRQL oldirql;
- PROS_SHARED_CACHE_MAP SharedCacheMap;
- PLIST_ENTRY current_entry;
- PROS_VACB Vacb, current, previous;
- ULONG TempLength;
-
- SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
- if (!Wait)
- {
- /* testing, if the requested datas are available */
- KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
- /* FIXME: this loop doesn't take into account areas that don't have
- * a VACB in the list yet */
- current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
- while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
- {
- Vacb = CONTAINING_RECORD(current_entry,
- ROS_VACB,
- CacheMapVacbListEntry);
- if (!Vacb->Valid &&
- DoRangesIntersect(Vacb->FileOffset.QuadPart,
- VACB_MAPPING_GRANULARITY,
- WriteOffset.u.LowPart, Length))
- {
- KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
- /* datas not available */
- return FALSE;
- }
- if (Vacb->FileOffset.QuadPart >= WriteOffset.u.LowPart + Length)
- break;
- current_entry = current_entry->Flink;
- }
- KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, 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 = CcRosGetVacbChain(SharedCacheMap, WriteOffset.u.LowPart - Offset,
- Offset + CurrentLength, &Vacb);
- if (!NT_SUCCESS(Status))
- {
- return FALSE;
- }
- current = Vacb;
-
- while (current != NULL)
- {
- Offset = WriteOffset.u.LowPart % VACB_MAPPING_GRANULARITY;
- if ((Offset != 0) ||
- (Offset + CurrentLength < VACB_MAPPING_GRANULARITY))
- {
- if (!current->Valid)
- {
- /* read the block */
- Status = CcReadVirtualAddress(current);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("CcReadVirtualAddress 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 = Vacb;
- while (current != NULL)
- {
- previous = current;
- current = current->NextInChain;
- CcRosReleaseVacb(SharedCacheMap, previous, TRUE, TRUE, FALSE);
- }
- }
+ IO_STATUS_BLOCK IoStatus;
+
+ return CcCopyData(FileObject,
+ WriteOffset.QuadPart,
+ NULL,
+ Length,
+ CcOperationZero,
+ Wait,
+ &IoStatus);
}
return TRUE;