Index: cc/copy.c =================================================================== --- ntoskrnl/cc/copy.c (revision 63837) +++ ntoskrnl/cc/copy.c (working copy) @@ -18,8 +18,12 @@ 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; @@ -56,136 +60,6 @@ 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 ( PROS_VACB Vacb) { @@ -224,7 +98,7 @@ DPRINT1("IoPageRead failed, Status %x\n", Status); return Status; } - +ASSERT(Status != STATUS_END_OF_FILE); if (Size < VACB_MAPPING_GRANULARITY) { RtlZeroMemory((char*)Vacb->BaseAddress + Size, @@ -288,273 +162,244 @@ return STATUS_SUCCESS; } - -/* - * @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, +NTSTATUS +ReadWriteOrZero( + IN OUT PVOID BaseAddress, + IN OUT PVOID Buffer OPTIONAL, IN ULONG Length, - IN BOOLEAN Wait, - OUT PVOID Buffer, - OUT PIO_STATUS_BLOCK IoStatus) + IN CC_COPY_OPERATION Operation) { - ULONG ReadOffset; - ULONG TempLength; NTSTATUS Status = STATUS_SUCCESS; - PVOID BaseAddress; - PROS_VACB Vacb; - 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; - - 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) + if (Operation == CcOperationZero) { - 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) - { - current = CONTAINING_RECORD(current_entry, - ROS_VACB, - CacheMapVacbListEntry); - if (!current->Valid && - DoRangesIntersect(current->FileOffset.QuadPart, - VACB_MAPPING_GRANULARITY, - ReadOffset, Length)) - { - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql); - IoStatus->Status = STATUS_UNSUCCESSFUL; - IoStatus->Information = 0; - return FALSE; - } - if (current->FileOffset.QuadPart >= ReadOffset + Length) - break; - current_entry = current_entry->Flink; - } - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql); + /* Zero */ + RtlZeroMemory(BaseAddress, Length); } - - TempLength = ReadOffset % VACB_MAPPING_GRANULARITY; - if (TempLength != 0) + else { - TempLength = min(Length, VACB_MAPPING_GRANULARITY - TempLength); - Status = CcRosRequestVacb(SharedCacheMap, - ROUND_DOWN(ReadOffset, - VACB_MAPPING_GRANULARITY), - &BaseAddress, &Valid, &Vacb); - if (!NT_SUCCESS(Status)) + _SEH2_TRY { - IoStatus->Information = 0; - IoStatus->Status = Status; - DPRINT("CcRosRequestVacb failed, Status %x\n", Status); - return FALSE; + if (Operation == CcOperationWrite) + RtlCopyMemory(BaseAddress, Buffer, Length); + else + RtlCopyMemory(Buffer, BaseAddress, Length); } - if (!Valid) + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - Status = CcReadVirtualAddress(Vacb); - if (!NT_SUCCESS(Status)) - { - IoStatus->Information = 0; - IoStatus->Status = Status; - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - return FALSE; - } + Status = _SEH2_GetExceptionCode(); } - 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); + _SEH2_END; } - - while (Length > 0) - { - TempLength = min(VACB_MAPPING_GRANULARITY, Length); - Status = ReadVacbChain(SharedCacheMap, ReadOffset, TempLength, Buffer); - if (!NT_SUCCESS(Status)) - { - IoStatus->Information = 0; - IoStatus->Status = Status; - DPRINT("ReadVacbChain failed, Status %x\n", Status); - return FALSE; - } - - ReadLength += TempLength; - Length -= TempLength; - ReadOffset += TempLength; - - Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength); - } - - IoStatus->Status = STATUS_SUCCESS; - IoStatus->Information = ReadLength; - DPRINT("CcCopyRead O.K.\n"); - return TRUE; + return Status; } -/* - * @implemented - */ BOOLEAN -NTAPI -CcCopyWrite ( +CcCopyData ( IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, + IN LONGLONG FileOffset, + IN OUT PVOID Buffer, IN ULONG Length, + IN CC_COPY_OPERATION Operation, IN BOOLEAN Wait, - IN PVOID Buffer) + OUT PIO_STATUS_BLOCK IoStatus) { NTSTATUS Status; - ULONG WriteOffset; - KIRQL oldirql; + LONGLONG CurrentOffset; + ULONG BytesCopied; + KIRQL OldIrql; PROS_SHARED_CACHE_MAP SharedCacheMap; - PLIST_ENTRY current_entry; + PLIST_ENTRY ListEntry; PROS_VACB Vacb; - ULONG TempLength; + ULONG PartialLength; 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); - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - WriteOffset = (ULONG)FileOffset->QuadPart; + CurrentOffset = FileOffset; + BytesCopied = 0; if (!Wait) { - /* testing, if the requested datas are available */ - 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) { - Vacb = CONTAINING_RECORD(current_entry, + Vacb = CONTAINING_RECORD(ListEntry, ROS_VACB, CacheMapVacbListEntry); + ListEntry = ListEntry->Flink; if (!Vacb->Valid && DoRangesIntersect(Vacb->FileOffset.QuadPart, VACB_MAPPING_GRANULARITY, - WriteOffset, Length)) + CurrentOffset, Length)) { - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql); - /* datas not available */ + KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); + /* data not available */ return FALSE; } - if (Vacb->FileOffset.QuadPart >= WriteOffset + Length) + if (Vacb->FileOffset.QuadPart >= CurrentOffset + Length) break; - current_entry = current_entry->Flink; } - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql); + KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); } - TempLength = WriteOffset % VACB_MAPPING_GRANULARITY; - if (TempLength != 0) + PartialLength = CurrentOffset % VACB_MAPPING_GRANULARITY; + if (PartialLength != 0) { - ULONG ROffset; - ROffset = ROUND_DOWN(WriteOffset, VACB_MAPPING_GRANULARITY); - TempLength = min(Length, VACB_MAPPING_GRANULARITY - TempLength); - Status = CcRosRequestVacb(SharedCacheMap, ROffset, - &BaseAddress, &Valid, &Vacb); + PartialLength = min(Length, VACB_MAPPING_GRANULARITY - PartialLength); + Status = CcRosRequestVacb(SharedCacheMap, + ROUND_DOWN(CurrentOffset, + VACB_MAPPING_GRANULARITY), + &BaseAddress, + &Valid, + &Vacb); if (!NT_SUCCESS(Status)) - { - return FALSE; - } + ExRaiseStatus(Status); if (!Valid) { - if (!NT_SUCCESS(CcReadVirtualAddress(Vacb))) + Status = CcReadVirtualAddress(Vacb); + if (!NT_SUCCESS(Status)) { - return FALSE; + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, TRUE, FALSE); + ExRaiseStatus(Status); } } - RtlCopyMemory((char*)BaseAddress + WriteOffset % VACB_MAPPING_GRANULARITY, - Buffer, - TempLength); + Status = ReadWriteOrZero((PUCHAR)BaseAddress + CurrentOffset % VACB_MAPPING_GRANULARITY, + Buffer, + PartialLength, + Operation); + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, TRUE, FALSE); - Length -= TempLength; - WriteOffset += TempLength; + if (!NT_SUCCESS(Status)) + ExRaiseStatus(STATUS_INVALID_USER_BUFFER); - Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength); + Length -= PartialLength; + CurrentOffset += PartialLength; + BytesCopied += PartialLength; + + if (Buffer) + Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength); } while (Length > 0) { - TempLength = min(VACB_MAPPING_GRANULARITY, Length); + ASSERT(CurrentOffset % VACB_MAPPING_GRANULARITY == 0); + PartialLength = min(VACB_MAPPING_GRANULARITY, Length); Status = CcRosRequestVacb(SharedCacheMap, - WriteOffset, + CurrentOffset, &BaseAddress, &Valid, &Vacb); if (!NT_SUCCESS(Status)) + ExRaiseStatus(Status); + if (!Valid && + (Operation == CcOperationRead || + PartialLength < VACB_MAPPING_GRANULARITY)) { - return FALSE; - } - if (!Valid && TempLength < VACB_MAPPING_GRANULARITY) - { - if (!NT_SUCCESS(CcReadVirtualAddress(Vacb))) + Status = CcReadVirtualAddress(Vacb); + if (!NT_SUCCESS(Status)) { CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - return FALSE; + ExRaiseStatus(Status); } } - RtlCopyMemory(BaseAddress, Buffer, TempLength); + Status = ReadWriteOrZero(BaseAddress, Buffer, PartialLength, Operation); + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, TRUE, FALSE); - Length -= TempLength; - WriteOffset += TempLength; - 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 = 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 + */ +BOOLEAN +NTAPI +CcCopyWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN PVOID Buffer) +{ + 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); + + return CcCopyData(FileObject, + FileOffset->QuadPart, + Buffer, + Length, + CcOperationWrite, + Wait, + &IoStatus); +} + +/* + * @unimplemented + */ VOID NTAPI CcDeferWrite ( @@ -679,102 +524,15 @@ } else { - /* File is cached */ - KIRQL oldirql; - PROS_SHARED_CACHE_MAP SharedCacheMap; - PLIST_ENTRY current_entry; - PROS_VACB Vacb, current, previous; - ULONG TempLength; + IO_STATUS_BLOCK IoStatus; - 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); - } - } + return CcCopyData(FileObject, + WriteOffset.QuadPart, + NULL, + Length, + CcOperationZero, + Wait, + &IoStatus); } return TRUE; Index: cc/fs.c =================================================================== --- ntoskrnl/cc/fs.c (revision 63837) +++ ntoskrnl/cc/fs.c (working copy) @@ -87,6 +87,7 @@ /* Call old ROS cache init function */ CcRosInitializeFileCache(FileObject, + FileSizes, CallBacks, LazyWriterContext); } @@ -234,12 +235,12 @@ IN PLARGE_INTEGER TruncateSize OPTIONAL, IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL) { -#if 0 - UNIMPLEMENTED; - return FALSE; -#else - return NT_SUCCESS(CcRosReleaseFileCache(FileObject)); -#endif + NTSTATUS Status; + + Status = CcRosReleaseFileCache(FileObject); + if (UninitializeCompleteEvent) + KeSetEvent(&UninitializeCompleteEvent->Event, IO_NO_INCREMENT, FALSE); + return NT_SUCCESS(Status); } BOOLEAN Index: cc/view.c =================================================================== --- ntoskrnl/cc/view.c (revision 63837) +++ ntoskrnl/cc/view.c (working copy) @@ -727,73 +727,6 @@ NTSTATUS NTAPI -CcRosGetVacbChain ( - PROS_SHARED_CACHE_MAP SharedCacheMap, - ULONG FileOffset, - ULONG Length, - PROS_VACB *Vacb) -{ - PROS_VACB current; - ULONG i; - PROS_VACB *VacbList; - PROS_VACB Previous = NULL; - - ASSERT(SharedCacheMap); - - DPRINT("CcRosGetVacbChain()\n"); - - Length = ROUND_UP(Length, VACB_MAPPING_GRANULARITY); - - VacbList = _alloca(sizeof(PROS_VACB) * - (Length / VACB_MAPPING_GRANULARITY)); - - /* - * Look for a VACB already mapping the same data. - */ - for (i = 0; i < (Length / VACB_MAPPING_GRANULARITY); i++) - { - ULONG CurrentOffset = FileOffset + (i * VACB_MAPPING_GRANULARITY); - current = CcRosLookupVacb(SharedCacheMap, CurrentOffset); - if (current != NULL) - { - KeAcquireGuardedMutex(&ViewLock); - - /* Move to tail of LRU list */ - RemoveEntryList(¤t->VacbLruListEntry); - InsertTailList(&VacbLruListHead, ¤t->VacbLruListEntry); - - KeReleaseGuardedMutex(&ViewLock); - - VacbList[i] = current; - } - else - { - CcRosCreateVacb(SharedCacheMap, CurrentOffset, ¤t); - VacbList[i] = current; - } - } - - for (i = 0; i < Length / VACB_MAPPING_GRANULARITY; i++) - { - if (i == 0) - { - *Vacb = VacbList[i]; - Previous = VacbList[i]; - } - else - { - Previous->NextInChain = VacbList[i]; - Previous = VacbList[i]; - } - } - ASSERT(Previous); - Previous->NextInChain = NULL; - - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI CcRosGetVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, ULONG FileOffset, @@ -1187,6 +1120,7 @@ NTAPI CcRosInitializeFileCache ( PFILE_OBJECT FileObject, + PCC_FILE_SIZES FileSizes, PCACHE_MANAGER_CALLBACKS CallBacks, PVOID LazyWriterContext) /* @@ -1216,13 +1150,8 @@ SharedCacheMap->FileObject = FileObject; SharedCacheMap->Callbacks = CallBacks; SharedCacheMap->LazyWriteContext = LazyWriterContext; - if (FileObject->FsContext) - { - SharedCacheMap->SectionSize = - ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->AllocationSize; - SharedCacheMap->FileSize = - ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize; - } + SharedCacheMap->SectionSize = FileSizes->AllocationSize; + SharedCacheMap->FileSize = FileSizes->FileSize; KeInitializeSpinLock(&SharedCacheMap->CacheMapLock); InitializeListHead(&SharedCacheMap->CacheMapVacbListHead); FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap; Index: include/internal/cc.h =================================================================== --- ntoskrnl/include/internal/cc.h (revision 63837) +++ ntoskrnl/include/internal/cc.h (working copy) @@ -145,7 +145,6 @@ /* Pointer to the shared cache map for the file which this view maps data for. */ PROS_SHARED_CACHE_MAP SharedCacheMap; /* Pointer to the next VACB in a chain. */ - struct _ROS_VACB *NextInChain; } ROS_VACB, *PROS_VACB; typedef struct _INTERNAL_BCB @@ -223,15 +222,6 @@ ULONG FileOffset ); -NTSTATUS -NTAPI -CcRosGetVacbChain( - PROS_SHARED_CACHE_MAP SharedCacheMap, - ULONG FileOffset, - ULONG Length, - PROS_VACB *Vacb -); - VOID NTAPI CcInitCacheZeroPage(VOID); @@ -287,6 +277,7 @@ NTAPI CcRosInitializeFileCache( PFILE_OBJECT FileObject, + PCC_FILE_SIZES FileSizes, PCACHE_MANAGER_CALLBACKS CallBacks, PVOID LazyWriterContext ); Index: CMakeLists.txt =================================================================== --- modules/rostests/kmtests/CMakeLists.txt (revision 63811) +++ modules/rostests/kmtests/CMakeLists.txt (working copy) @@ -6,6 +6,7 @@ # add_subdirectory(example) add_subdirectory(kernel32) +add_subdirectory(ntos_cc) add_subdirectory(ntos_io) list(APPEND COMMON_SOURCE @@ -107,6 +108,7 @@ example/Example_user.c kernel32/FindFile_user.c + ntos_cc/CcCacheMap_user.c ntos_io/IoDeviceObject_user.c ${COMMON_SOURCE} @@ -128,6 +130,7 @@ add_custom_target(kmtest_drivers) add_dependencies(kmtest_drivers kmtest_drv + cccachemap_drv example_drv iodeviceobject_drv iohelper_drv) Index: include/kmt_platform.h =================================================================== --- modules/rostests/kmtests/include/kmt_platform.h (revision 63811) +++ modules/rostests/kmtests/include/kmt_platform.h (working copy) @@ -19,10 +19,12 @@ #if defined KMT_KERNEL_MODE || defined KMT_STANDALONE_DRIVER #include #include +#include #include #include #include #include +#include #include #include Index: include/kmt_test.h =================================================================== --- modules/rostests/kmtests/include/kmt_test.h (revision 63811) +++ modules/rostests/kmtests/include/kmt_test.h (working copy) @@ -209,7 +209,12 @@ (expected) ? "TRUE" : "FALSE") #define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected) #define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected) -#define ok_eq_tag(value, expected) ok_eq_print(value, expected, "0x%08lx") +#define ok_eq_tag(value, expected) ok_eq_print(value, (ULONG)(expected), "0x%08lx") +#define ok_eq_list(list, flink, blink) do \ + { \ + ok_eq_pointer((list)->Flink, flink); \ + ok_eq_pointer((list)->Blink, blink); \ + } while (0) #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \ 0xC00 + (ControlCode), \ Index: kmtest/testlist.c =================================================================== --- modules/rostests/kmtests/kmtest/testlist.c (revision 63811) +++ modules/rostests/kmtests/kmtest/testlist.c (working copy) @@ -8,6 +8,7 @@ #include KMT_TESTFUNC Test_Example; +KMT_TESTFUNC Test_CcCacheMap; KMT_TESTFUNC Test_FindFile; KMT_TESTFUNC Test_IoDeviceObject; KMT_TESTFUNC Test_RtlAvlTree; @@ -22,6 +23,7 @@ const KMT_TEST TestList[] = { { "-Example", Test_Example }, + { "CcCacheMap", Test_CcCacheMap }, { "FindFile", Test_FindFile }, { "IoDeviceObject", Test_IoDeviceObject }, { "RtlAvlTree", Test_RtlAvlTree }, Index: ntos_cc/CcCacheMap_drv.c =================================================================== --- modules/rostests/kmtests/ntos_cc/CcCacheMap_drv.c (revision 0) +++ modules/rostests/kmtests/ntos_cc/CcCacheMap_drv.c (working copy) @@ -0,0 +1,736 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory + * PURPOSE: Kernel-Mode Test Suite Cache Map Test Driver + * PROGRAMMER: Thomas Faber + */ + +#include + +#define CACHE_NTC_OBCB 0x2fa // TAG_OBCB +#define CACHE_NTC_MBCB 0x2fb // TAG_BCB +#define CACHE_NTC_BCB 0x2fd // TAG_BCB +#define CACHE_NTC_PRIVATE_CACHE_MAP 0x2fe // TAG_PRIVATE_CACHE_MAP +#define CACHE_NTC_SHARED_CACHE_MAP 0x2ff // TAG_SHARED_CACHE_MAP + +#define TAG_SHARED_CACHE_MAP 'cScC' +#define TAG_PRIVATE_CACHE_MAP 'cPcC' + +#ifndef VACB_MAPPING_GRANULARITY +#define VACB_MAPPING_GRANULARITY (0x40000ULL) +#endif + +#define CheckObject(Handle, Pointers, Handles) do \ +{ \ + PUBLIC_OBJECT_BASIC_INFORMATION _ObjectInfo; \ + NTSTATUS _Status; \ + _Status = ZwQueryObject(Handle, ObjectBasicInformation, \ + &_ObjectInfo, sizeof(_ObjectInfo), NULL); \ + ok_eq_hex(_Status, STATUS_SUCCESS); \ + ok_eq_ulong(_ObjectInfo.PointerCount, Pointers); \ + ok_eq_ulong(_ObjectInfo.HandleCount, Handles); \ +} while (0) + +static PDEVICE_OBJECT TestDeviceObject; +static PFILE_OBJECT EncounteredFileObject; +static ULONG CreateCount; +static ULONG CleanupCount; +static ULONG CloseCount; +static ULONG TestContext; + +#define ok_counts(file, create, cleanup, close) do \ + { \ + ok_eq_pointer(EncounteredFileObject, file); \ + ok_eq_ulong(CreateCount, create); \ + ok_eq_ulong(CleanupCount, cleanup); \ + ok_eq_ulong(CloseCount, close); \ + EncounteredFileObject = NULL; \ + CreateCount = 0; \ + CleanupCount = 0; \ + CloseCount = 0; \ + } while (0) + +static +VOID +TestIoCreateStreamFileObject(VOID) +{ + PFILE_OBJECT FileObject; + PFILE_OBJECT FileObject2; + HANDLE FileHandle; + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + ok_irql(PASSIVE_LEVEL); + + // Crash. Windows holds LockQueueIoDatabaseLock while incrementing the device object refcount + //IoCreateStreamFileObject(NULL, NULL); + + ok_counts(NULL, 0UL, 0UL, 0UL); + KmtStartSeh() + FileObject = IoCreateStreamFileObject(NULL, TestDeviceObject); + KmtEndSeh(STATUS_SUCCESS); + ok(FileObject != NULL, "FileObject = NULL\n"); + ok_counts(FileObject, 0UL, 1UL, 0UL); + ObDereferenceObject(FileObject); + ok_counts(FileObject, 0UL, 0UL, 1UL); + + ok_counts(NULL, 0UL, 0UL, 0UL); + KmtStartSeh() + FileObject = IoCreateStreamFileObjectLite(NULL, TestDeviceObject); + KmtEndSeh(STATUS_SUCCESS); + ok(FileObject != NULL, "FileObject = NULL\n"); + ok_counts(NULL, 0UL, 0UL, 0UL); + ObDereferenceObject(FileObject); + ok_counts(FileObject, 0UL, 0UL, 1UL); + + ok_counts(NULL, 0UL, 0UL, 0UL); + KmtStartSeh() + FileObject = IoCreateStreamFileObjectEx(NULL, TestDeviceObject, NULL); + KmtEndSeh(STATUS_SUCCESS); + ok(FileObject != NULL, "FileObject = NULL\n"); + ok_counts(FileObject, 0UL, 1UL, 0UL); + ObDereferenceObject(FileObject); + ok_counts(FileObject, 0UL, 0UL, 1UL); + + FileHandle = NULL; + ok_counts(NULL, 0UL, 0UL, 0UL); + KmtStartSeh() + FileObject = IoCreateStreamFileObjectEx(NULL, TestDeviceObject, &FileHandle); + KmtEndSeh(STATUS_SUCCESS); + ok(FileObject != NULL, "FileObject = NULL\n"); + ok(FileHandle != NULL, "FileHandle = NULL\n"); + // yes, the pointer does not get an associated reference! + CheckObject(FileHandle, 2UL, 1UL); + ok_counts(NULL, 0UL, 0UL, 0UL); + ObCloseHandle(FileHandle, KernelMode); + ok_counts(FileObject, 0UL, 1UL, 1UL); + + FileHandle = NULL; + ok_counts(NULL, 0UL, 0UL, 0UL); + KmtStartSeh() + FileObject = IoCreateStreamFileObjectEx(NULL, TestDeviceObject, &FileHandle); + KmtEndSeh(STATUS_SUCCESS); + ok(FileObject != NULL, "FileObject = NULL\n"); + ok(FileHandle != NULL, "FileHandle = NULL\n"); + CheckObject(FileHandle, 2UL, 1UL); + ObReferenceObject(FileObject); + CheckObject(FileHandle, 3UL, 1UL); + ok_counts(NULL, 0UL, 0UL, 0UL); + ObCloseHandle(FileHandle, KernelMode); + ok_counts(FileObject, 0UL, 1UL, 0UL); + ObDereferenceObject(FileObject); + ok_counts(FileObject, 0UL, 0UL, 1UL); + + /* Pass a FileObject instead of a DeviceObject */ + FileObject = IoCreateStreamFileObject(FileObject, TestDeviceObject); // TODO: wtf + ok(FileObject != NULL, "FileObject = NULL\n"); + ok_counts(FileObject, 0UL, 1UL, 0UL); + + ok_counts(NULL, 0UL, 0UL, 0UL); + KmtStartSeh() + FileObject2 = IoCreateStreamFileObject(FileObject, KmtInvalidPointer); + KmtEndSeh(STATUS_SUCCESS); + ok(FileObject2 != NULL, "FileObject2 = NULL\n"); + ok_counts(FileObject2, 0UL, 1UL, 0UL); + ObDereferenceObject(FileObject2); + ok_counts(FileObject2, 0UL, 0UL, 1UL); + + ok_counts(NULL, 0UL, 0UL, 0UL); + KmtStartSeh() + FileObject2 = IoCreateStreamFileObjectLite(FileObject, KmtInvalidPointer); + KmtEndSeh(STATUS_SUCCESS); + ok(FileObject2 != NULL, "FileObject2 = NULL\n"); + ok_counts(NULL, 0UL, 0UL, 0UL); + ObDereferenceObject(FileObject2); + ok_counts(FileObject2, 0UL, 0UL, 1UL); + + ObDereferenceObject(FileObject); + ok_counts(FileObject, 0UL, 0UL, 1UL); +} + +static +BOOLEAN +NTAPI +AcquireForLazyWrite( + _In_ PVOID Context, + _In_ BOOLEAN Wait) +{ + ok_eq_pointer(Context, &TestContext); + ok(0, "Unexpected call to AcquireForLazyWrite\n"); + return TRUE; +} + +static +VOID +NTAPI +ReleaseFromLazyWrite( + _In_ PVOID Context) +{ + ok_eq_pointer(Context, &TestContext); + ok(0, "Unexpected call to ReleaseFromLazyWrite\n"); +} + +static +BOOLEAN +NTAPI +AcquireForReadAhead( + _In_ PVOID Context, + _In_ BOOLEAN Wait) +{ + ok_eq_pointer(Context, &TestContext); + ok(0, "Unexpected call to AcquireForReadAhead\n"); + return TRUE; +} + +static +VOID +NTAPI +ReleaseFromReadAhead( + _In_ PVOID Context) +{ + ok_eq_pointer(Context, &TestContext); + ok(0, "Unexpected call to ReleaseFromReadAhead\n"); +} + +#define CheckFileObject(FileObject, sop, fsc, pcm) do \ + { \ + ok_eq_int(FileObject->Type, IO_TYPE_FILE); \ + ok_eq_int(FileObject->Size, (INT)RTL_SIZEOF_THROUGH_FIELD(FILE_OBJECT, \ + CompletionContext)); \ + ok_eq_pointer(FileObject->DeviceObject, TestDeviceObject); \ + ok_eq_pointer(FileObject->Vpb, NULL); \ + ok_eq_pointer(FileObject->FsContext, fsc); \ + ok_eq_pointer(FileObject->FsContext2, NULL); \ + ok_eq_pointer(FileObject->SectionObjectPointer, sop); \ + ok_eq_pointer(FileObject->PrivateCacheMap, pcm); \ + ok_eq_hex(FileObject->FinalStatus, STATUS_SUCCESS); \ + ok_eq_pointer(FileObject->RelatedFileObject, NULL); \ + ok_eq_uint(FileObject->LockOperation, FALSE); \ + ok_eq_uint(FileObject->DeletePending, FALSE); \ + ok_eq_uint(FileObject->ReadAccess, FALSE); \ + ok_eq_uint(FileObject->WriteAccess, FALSE); \ + ok_eq_uint(FileObject->DeleteAccess, FALSE); \ + ok_eq_uint(FileObject->SharedRead, FALSE); \ + ok_eq_uint(FileObject->SharedWrite, FALSE); \ + ok_eq_uint(FileObject->SharedDelete, FALSE); \ + ok_eq_hex(FileObject->Flags, (ULONG)(FO_STREAM_FILE | FO_HANDLE_CREATED)); \ + ok_eq_pointer(FileObject->FileName.Buffer, NULL); \ + ok_eq_uint(FileObject->FileName.Length, 0); \ + ok_eq_uint(FileObject->FileName.MaximumLength, 0); \ + } while (0) + +#define CheckSectionObjectPointers(sop, dso, scm, iso) do \ + { \ + ok_eq_pointer((sop)->DataSectionObject, dso); \ + ok_eq_pointer((sop)->SharedCacheMap, scm); \ + ok_eq_pointer((sop)->ImageSectionObject, iso); \ + } while (0) + +#define CheckCacheMaps(fo, pfo, ram) CheckCacheMaps_(fo, pfo, ram, 0, VACB_MAPPING_GRANULARITY, 0, __FILE__, __LINE__) +#define CheckCacheMapsWithSize(fo, pfo, ram, fs, ss, vdl) CheckCacheMaps_(fo, pfo, ram, fs, ss, vdl, __FILE__, __LINE__) +static +VOID +CheckCacheMaps_( + _In_ PFILE_OBJECT FileObject, + _In_ PFILE_OBJECT PreviousFileObject, + _In_ ULONG ReadAheadMask, + _In_ LONGLONG FileSize, + _In_ LONGLONG SectionSize, + _In_ LONGLONG ValidDataLength, + _In_ PCSTR File, + _In_ INT Line) +{ +#undef ok +#undef trace +#undef skip + PSHARED_CACHE_MAP SharedCacheMap; + PPRIVATE_CACHE_MAP PrivateCacheMap; + PPRIVATE_CACHE_MAP PreviousPrivateCacheMap; + PVOID DataSectionObject; + CHAR FileLineBuffer[256]; +return; + snprintf(FileLineBuffer, sizeof(FileLineBuffer), "%s:%d", File, Line); +#define ok(test, ...) KmtOk(test, FileLineBuffer, __VA_ARGS__) +#define trace(...) KmtTrace( FileLineBuffer, __VA_ARGS__) +#define skip(test, ...) KmtSkip(test, FileLineBuffer, __VA_ARGS__) + + DataSectionObject = FileObject->SectionObjectPointer->DataSectionObject; + ok(DataSectionObject != NULL, "DataSectionObject = NULL\n"); + SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; + CheckSectionObjectPointers(FileObject->SectionObjectPointer, DataSectionObject, SharedCacheMap, NULL); + + ok(SharedCacheMap != NULL, "SharedCacheMap = NULL\n"); + if (!skip(SharedCacheMap != NULL, "No SharedCacheMap\n")) + { + ok_eq_tag(KmtGetPoolTag(SharedCacheMap), TAG_SHARED_CACHE_MAP); + ok_eq_int(KmtGetPoolType(SharedCacheMap) - 1, NonPagedPoolCacheAligned); + ok_eq_int(SharedCacheMap->NodeTypeCode, CACHE_NTC_SHARED_CACHE_MAP); + ok_eq_longlong(SharedCacheMap->FileSize.QuadPart, FileSize); + ok_eq_longlong(SharedCacheMap->SectionSize.QuadPart, SectionSize); + ok_eq_longlong(SharedCacheMap->ValidDataLength.QuadPart, ValidDataLength); + ok_eq_longlong(SharedCacheMap->ValidDataGoal.QuadPart, ValidDataLength); + } + + PrivateCacheMap = FileObject->PrivateCacheMap; + ok(PrivateCacheMap != NULL, "PrivateCacheMap = NULL\n"); + if (!skip(PrivateCacheMap != NULL, "No PrivateCacheMap\n")) + { + if (PreviousFileObject) + { + ok_eq_tag(KmtGetPoolTag(PrivateCacheMap), TAG_PRIVATE_CACHE_MAP); + ok_eq_int(KmtGetPoolType(PrivateCacheMap) - 1, NonPagedPool); + } + else + { + ok_eq_pointer(PrivateCacheMap, &SharedCacheMap->PrivateCacheMap); + } + ok_eq_int(PrivateCacheMap->NodeTypeCode, CACHE_NTC_PRIVATE_CACHE_MAP); + ok_eq_int(PrivateCacheMap->Flags.ReadAheadActive, 0); + ok_eq_int(PrivateCacheMap->Flags.ReadAheadEnabled, 0); + ok_eq_int(PrivateCacheMap->Flags.Available, 0); + ok_eq_ulong(PrivateCacheMap->ReadAheadMask, ReadAheadMask); + ok_eq_pointer(PrivateCacheMap->FileObject, FileObject); + ok_eq_longlong(PrivateCacheMap->FileOffset1.QuadPart, 0LL); + //ok_eq_longlong(PrivateCacheMap->BeyondLastByte1.QuadPart, 0LL); + ok_eq_longlong(PrivateCacheMap->FileOffset2.QuadPart, 0LL); + ok_eq_longlong(PrivateCacheMap->BeyondLastByte2.QuadPart, 0LL); + ok_eq_longlong(PrivateCacheMap->ReadAheadOffset[0].QuadPart, 0LL); + ok_eq_longlong(PrivateCacheMap->ReadAheadOffset[1].QuadPart, 0LL); + ok_eq_ulong(PrivateCacheMap->ReadAheadLength[0], 0UL); + ok_eq_ulong(PrivateCacheMap->ReadAheadLength[1], 0UL); + if (PreviousFileObject) + { + PreviousPrivateCacheMap = PreviousFileObject->PrivateCacheMap; + ok_eq_list(&SharedCacheMap->PrivateList, + &PreviousPrivateCacheMap->PrivateLinks, + &PrivateCacheMap->PrivateLinks); + + ok_eq_list(&PreviousPrivateCacheMap->PrivateLinks, + &PrivateCacheMap->PrivateLinks, + &SharedCacheMap->PrivateList); + + ok_eq_list(&PrivateCacheMap->PrivateLinks, + &SharedCacheMap->PrivateList, + &PreviousPrivateCacheMap->PrivateLinks); + + } + else + { + ok_eq_pointer(PrivateCacheMap->PrivateLinks.Flink, &SharedCacheMap->PrivateList); + ok_eq_pointer(PrivateCacheMap->PrivateLinks.Blink, &SharedCacheMap->PrivateList); + ok_eq_pointer(SharedCacheMap->PrivateList.Flink, &PrivateCacheMap->PrivateLinks); + ok_eq_pointer(SharedCacheMap->PrivateList.Blink, &PrivateCacheMap->PrivateLinks); + } + } +#undef ok +#undef trace +#undef skip +#define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__) +#define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__) +#define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__) +} + +static +VOID +TestCcCacheMap(VOID) +{ + PFILE_OBJECT FileObject; + CC_FILE_SIZES FileSizes; + CACHE_MANAGER_CALLBACKS Callbacks; + SECTION_OBJECT_POINTERS SectionObjectPointers; + FSRTL_ADVANCED_FCB_HEADER FcbHeader; + FAST_MUTEX FcbHeaderMutex; + CACHE_UNINITIALIZE_EVENT Event; + BOOLEAN Success; + PPRIVATE_CACHE_MAP PrivateCacheMap; + NTSTATUS Status; + + FileObject = IoCreateStreamFileObject(NULL, TestDeviceObject); + ok(FileObject != NULL, "FileObject = NULL\n"); + ok_counts(FileObject, 0UL, 1UL, 0UL); + if (skip(FileObject != NULL, "No file object\n")) + return; + + CheckFileObject(FileObject, NULL, NULL, NULL); + // Crash because SectionObjectPointer is NULL, holding CcMasterSpinLock + //CcUninitializeCacheMap(FileObject, NULL, NULL); + + FileSizes.AllocationSize.QuadPart = 0; + FileSizes.FileSize.QuadPart = 0; + FileSizes.ValidDataLength.QuadPart = 0; + Callbacks.AcquireForLazyWrite = AcquireForLazyWrite; + Callbacks.ReleaseFromLazyWrite = ReleaseFromLazyWrite; + Callbacks.AcquireForReadAhead = AcquireForReadAhead; + Callbacks.ReleaseFromReadAhead = ReleaseFromReadAhead; + KmtStartSeh() + CcInitializeCacheMap(FileObject, + &FileSizes, + FALSE, + &Callbacks, + &TestContext); + KmtEndSeh(STATUS_ACCESS_VIOLATION); + + CheckFileObject(FileObject, NULL, NULL, NULL); + + // TODO: SectionObjectPointers but no FsContext? + + // try again with SectionObjectPointers and FsContext set + RtlZeroMemory(&SectionObjectPointers, sizeof(SectionObjectPointers)); + FileObject->SectionObjectPointer = &SectionObjectPointers; + FcbHeader.AllocationSize.QuadPart = 0x5555555555555555ULL; + FcbHeader.FileSize.QuadPart = 0x5555555555555555ULL; + FcbHeader.ValidDataLength.QuadPart = 0x5555555555555555ULL; + ExInitializeFastMutex(&FcbHeaderMutex); + FsRtlSetupAdvancedHeader(&FcbHeader, &FcbHeaderMutex); + FileObject->FsContext = &FcbHeader; + ok_eq_longlong(FcbHeader.AllocationSize.QuadPart, 0x5555555555555555ULL); + ok_eq_longlong(FcbHeader.FileSize.QuadPart, 0x5555555555555555ULL); + ok_eq_longlong(FcbHeader.ValidDataLength.QuadPart, 0x5555555555555555ULL); + + KmtStartSeh() + Success = CcUninitializeCacheMap(FileObject, NULL, NULL); + ok_bool_false(Success, "CcUninitializeCacheMap returned"); + KmtEndSeh(STATUS_SUCCESS); + + KmtStartSeh() + CcInitializeCacheMap(FileObject, + &FileSizes, + FALSE, + &Callbacks, + &TestContext); + KmtEndSeh(STATUS_SUCCESS); + + ok_eq_longlong(FcbHeader.AllocationSize.QuadPart, 0x5555555555555555ULL); + ok_eq_longlong(FcbHeader.FileSize.QuadPart, 0x5555555555555555ULL); + ok_eq_longlong(FcbHeader.ValidDataLength.QuadPart, 0x5555555555555555ULL); + + PrivateCacheMap = FileObject->PrivateCacheMap; + ok(PrivateCacheMap != NULL, "PrivateCacheMap = NULL\n"); + CheckFileObject(FileObject, &SectionObjectPointers, &FcbHeader, PrivateCacheMap); + + CheckCacheMaps(FileObject, NULL, 4095); + CcSetAdditionalCacheAttributes(FileObject, FALSE, FALSE); + CheckCacheMaps(FileObject, NULL, 4095); + CcSetAdditionalCacheAttributes(FileObject, FALSE, TRUE); + CheckCacheMaps(FileObject, NULL, 4095); + CcSetAdditionalCacheAttributes(FileObject, TRUE, FALSE); + CheckCacheMaps(FileObject, NULL, 4095); + CcSetAdditionalCacheAttributes(FileObject, TRUE, TRUE); + CheckCacheMaps(FileObject, NULL, 4095); + if (1) // ROS will assert once this is implemented + { + CcSetReadAheadGranularity(FileObject, 0); + CheckCacheMaps(FileObject, NULL, (ULONG)-1); + CcSetReadAheadGranularity(FileObject, 1); + CheckCacheMaps(FileObject, NULL, 0); + CcSetReadAheadGranularity(FileObject, 4095); + CheckCacheMaps(FileObject, NULL, 4094); + } + CcSetReadAheadGranularity(FileObject, 4096); + CheckCacheMaps(FileObject, NULL, 4095); + if (1) // ROS will assert once this is implemented + { + CcSetReadAheadGranularity(FileObject, 4097); + CheckCacheMaps(FileObject, NULL, 4096); + CcSetReadAheadGranularity(FileObject, 8191); + CheckCacheMaps(FileObject, NULL, 8190); + } + CcSetReadAheadGranularity(FileObject, 8192); + CheckCacheMaps(FileObject, NULL, 8191); + + + KeInitializeEvent(&Event.Event, NotificationEvent, FALSE); + Success = CcUninitializeCacheMap(FileObject, NULL, &Event); + ok_bool_true(Success, "CcUninitializeCacheMap returned"); + Status = KeWaitForSingleObject(&Event.Event, Executive, KernelMode, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + CheckFileObject(FileObject, &SectionObjectPointers, &FcbHeader, NULL); + FsRtlTeardownPerStreamContexts(&FcbHeader); + + ObDereferenceObject(FileObject); + ok_counts(FileObject, 0UL, 0UL, 1UL); + +} + +static +VOID +TestCcCopyReadWrite(VOID) +{ + PFILE_OBJECT FileObject; + CC_FILE_SIZES FileSizes; + CACHE_MANAGER_CALLBACKS Callbacks; + SECTION_OBJECT_POINTERS SectionObjectPointers; + FSRTL_ADVANCED_FCB_HEADER FcbHeader; + FAST_MUTEX FcbHeaderMutex; + CACHE_UNINITIALIZE_EVENT Event; + BOOLEAN Success; + PUCHAR Buffer; + ULONG BufferSize; + LARGE_INTEGER FileOffset, TruncateSize; + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status; + + FileObject = IoCreateStreamFileObject(NULL, TestDeviceObject); + ok(FileObject != NULL, "FileObject = NULL\n"); + ok_counts(FileObject, 0UL, 1UL, 0UL); + if (skip(FileObject != NULL, "No file object\n")) + return; + + CheckFileObject(FileObject, NULL, NULL, NULL); + + FileSizes.AllocationSize.QuadPart = PAGE_SIZE; + FileSizes.FileSize.QuadPart = PAGE_SIZE; + FileSizes.ValidDataLength.QuadPart = 0; + Callbacks.AcquireForLazyWrite = AcquireForLazyWrite; + Callbacks.ReleaseFromLazyWrite = ReleaseFromLazyWrite; + Callbacks.AcquireForReadAhead = AcquireForReadAhead; + Callbacks.ReleaseFromReadAhead = ReleaseFromReadAhead; + RtlZeroMemory(&SectionObjectPointers, sizeof(SectionObjectPointers)); + FileObject->SectionObjectPointer = &SectionObjectPointers; + ExInitializeFastMutex(&FcbHeaderMutex); + FsRtlSetupAdvancedHeader(&FcbHeader, &FcbHeaderMutex); + FileObject->FsContext = &FcbHeader; + + KmtStartSeh() + CcInitializeCacheMap(FileObject, + &FileSizes, + FALSE, + &Callbacks, + &TestContext); + KmtEndSeh(STATUS_SUCCESS); + CcSetAdditionalCacheAttributes(FileObject, TRUE, TRUE); + CheckCacheMapsWithSize(FileObject, NULL, 4095, PAGE_SIZE, VACB_MAPPING_GRANULARITY, 0); + + BufferSize = FileSizes.FileSize.LowPart; + Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, 'cCmK'); + if (Buffer) + { + //RtlFillMemory(Buffer, BufferSize, 0x55); + //RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); + //FileOffset.QuadPart = 0; + //KmtStartSeh() + // Success = CcCopyRead(FileObject, &FileOffset, BufferSize, FALSE, Buffer, &IoStatus); + // ok_bool_false(Success, "CcCopyRead returned"); + //KmtEndSeh(STATUS_SUCCESS); + + RtlFillMemory(Buffer, BufferSize, 0x66); + FileOffset.QuadPart = 0; + KmtStartSeh() + Success = CcCopyWrite(FileObject, &FileOffset, BufferSize, FALSE, Buffer); + ok_bool_true(Success, "CcCopyWrite returned"); + KmtEndSeh(STATUS_SUCCESS); + + RtlFillMemory(Buffer, BufferSize, 0x55); + RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); + FileOffset.QuadPart = 0; + KmtStartSeh() + Success = CcCopyRead(FileObject, &FileOffset, BufferSize, FALSE, Buffer, &IoStatus); + ok_bool_true(Success, "CcCopyRead returned"); + ok_eq_hex(IoStatus.Status, STATUS_SUCCESS); + ok_eq_ulongptr(IoStatus.Information, BufferSize); + KmtEndSeh(STATUS_SUCCESS); + + { + ULONG i; + for (i = 0; i < BufferSize; i++) + if (Buffer[i] != 0x66) + break; + ok_eq_ulong(i, BufferSize); + } + + /* NULL IoStatus */ + FileOffset.QuadPart = 0; + KmtStartSeh() + CcCopyRead(FileObject, &FileOffset, BufferSize, FALSE, Buffer, NULL); + KmtEndSeh(STATUS_ACCESS_VIOLATION); + + IoStatus.Status = 0xadeafbee; + IoStatus.Information = 0xadeafbee; + FileOffset.QuadPart = 0; + KmtStartSeh() + CcCopyRead(FileObject, &FileOffset, BufferSize, FALSE, NULL, &IoStatus); + KmtEndSeh(STATUS_INVALID_USER_BUFFER); + ok_eq_hex(IoStatus.Status, 0xadeafbee); + ok_eq_ulongptr(IoStatus.Information, 0xadeafbee); + + FileOffset.QuadPart = 0; + KmtStartSeh() + Success = CcCopyRead(FileObject, &FileOffset, 0, FALSE, NULL, &IoStatus); + ok_bool_true(Success, "CcCopyRead returned"); + ok_eq_hex(IoStatus.Status, STATUS_SUCCESS); + ok_eq_ulongptr(IoStatus.Information, 0); + KmtEndSeh(STATUS_SUCCESS); + + FileOffset.QuadPart = 0; + KmtStartSeh() + CcCopyWrite(FileObject, &FileOffset, BufferSize, FALSE, NULL); + KmtEndSeh(STATUS_INVALID_USER_BUFFER); + + FileOffset.QuadPart = 0; + KmtStartSeh() + Success = CcCopyWrite(FileObject, &FileOffset, 0, FALSE, NULL); + ok_bool_true(Success, "CcCopyWrite returned"); + KmtEndSeh(STATUS_SUCCESS); + + FileSizes.AllocationSize.QuadPart = 2 * VACB_MAPPING_GRANULARITY; + FileSizes.FileSize.QuadPart = 2 * VACB_MAPPING_GRANULARITY; + FileSizes.ValidDataLength.QuadPart = 2 * VACB_MAPPING_GRANULARITY; + KmtStartSeh() + CcSetFileSizes(FileObject, &FileSizes); + KmtEndSeh(STATUS_SUCCESS); +if (0){ + __debugbreak(); + RtlFillMemory(Buffer, BufferSize, 0x77); + FileOffset.QuadPart = VACB_MAPPING_GRANULARITY - PAGE_SIZE / 2; + KmtStartSeh() + Success = CcCopyRead(FileObject, &FileOffset, PAGE_SIZE, TRUE, Buffer, &IoStatus); + ok_bool_true(Success, "CcCopyRead returned"); + KmtEndSeh(STATUS_SUCCESS); + + __debugbreak(); + RtlFillMemory(Buffer, BufferSize, 0x77); + FileOffset.QuadPart = VACB_MAPPING_GRANULARITY - PAGE_SIZE; + KmtStartSeh() + Success = CcCopyRead(FileObject, &FileOffset, 2 * PAGE_SIZE, TRUE, Buffer, &IoStatus); + ok_bool_true(Success, "CcCopyRead returned"); + KmtEndSeh(STATUS_SUCCESS); + + __debugbreak(); + RtlFillMemory(Buffer, BufferSize, 0x77); + FileOffset.QuadPart = VACB_MAPPING_GRANULARITY; + KmtStartSeh() + Success = CcCopyRead(FileObject, &FileOffset, VACB_MAPPING_GRANULARITY, TRUE, Buffer, &IoStatus); + ok_bool_true(Success, "CcCopyRead returned"); + KmtEndSeh(STATUS_SUCCESS); +} + ExFreePoolWithTag(Buffer, 'cCmK'); + } + + FileSizes.AllocationSize.QuadPart = 0; + FileSizes.FileSize.QuadPart = 0; + FileSizes.ValidDataLength.QuadPart = 0; + KmtStartSeh() + CcSetFileSizes(FileObject, &FileSizes); + KmtEndSeh(STATUS_SUCCESS); + CheckCacheMaps(FileObject, NULL, 4095); + + Success = CcPurgeCacheSection(&SectionObjectPointers, NULL, 0, FALSE); + ok_bool_true(Success, "CcPurgeCacheSection returned"); + + //CcFlushCache(&SectionObjectPointers, NULL, 0, &IoStatus); + //ok_eq_hex(IoStatus.Status, STATUS_SUCCESS); + //ok_eq_ulongptr(IoStatus.Information, BufferSize); + + TruncateSize.QuadPart = 0; + KeInitializeEvent(&Event.Event, NotificationEvent, FALSE); + Success = CcUninitializeCacheMap(FileObject, &TruncateSize, &Event); + ok_bool_true(Success, "CcUninitializeCacheMap returned"); + Status = KeWaitForSingleObject(&Event.Event, Executive, KernelMode, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + + CheckFileObject(FileObject, &SectionObjectPointers, &FcbHeader, NULL); + FsRtlTeardownPerStreamContexts(&FcbHeader); + + ObDereferenceObject(FileObject); + ok_counts(FileObject, 0UL, 0UL, 1UL); +} + +static +NTSTATUS +TestDispatch( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_ PIO_STACK_LOCATION IoStackLocation) +{ + static BOOLEAN TestHasRun = FALSE; + NTSTATUS Status = STATUS_SUCCESS; + + if (DeviceObject == TestDeviceObject) + { + ok(EncounteredFileObject == NULL || + EncounteredFileObject == IoStackLocation->FileObject, + "EncounteredFileObject = %p, but got %p\n", + EncounteredFileObject, IoStackLocation->FileObject); + EncounteredFileObject = IoStackLocation->FileObject; + if (IoStackLocation->MajorFunction == IRP_MJ_CREATE) + CreateCount++; + else if (IoStackLocation->MajorFunction == IRP_MJ_CLEANUP) + CleanupCount++; + else if (IoStackLocation->MajorFunction == IRP_MJ_CLOSE) + CloseCount++; + else if (IoStackLocation->MajorFunction == IRP_MJ_READ) + { + trace("FileOffset 0x%I64x, Length 0x%lx\n", IoStackLocation->Parameters.Read.ByteOffset.QuadPart, IoStackLocation->Parameters.Read.Length); + if (Irp->MdlAddress) + { + RtlFillMemory(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority), + MmGetMdlByteCount(Irp->MdlAddress), + 0x88); + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = MmGetMdlByteCount(Irp->MdlAddress); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + } + } + else if (!TestHasRun) + { + TestHasRun = TRUE; + TestIoCreateStreamFileObject(); + if (0) + TestCcCacheMap(); + TestCcCopyReadWrite(); + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + +NTSTATUS +TestEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PCUNICODE_STRING RegistryPath, + _Out_ PCWSTR *DeviceName, + _Inout_ INT *Flags) +{ + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(RegistryPath); + UNREFERENCED_PARAMETER(Flags); + + *DeviceName = L"CcCacheMap"; + + Status = IoCreateDevice(DriverObject, + 0, + NULL, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN | FILE_READ_ONLY_DEVICE, + FALSE, + &TestDeviceObject); + ok_eq_hex(Status, STATUS_SUCCESS); + + KmtRegisterIrpHandler(IRP_MJ_CREATE, TestDeviceObject, TestDispatch); + KmtRegisterIrpHandler(IRP_MJ_CLEANUP, TestDeviceObject, TestDispatch); + KmtRegisterIrpHandler(IRP_MJ_CLOSE, TestDeviceObject, TestDispatch); + KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestDispatch); + KmtRegisterIrpHandler(IRP_MJ_READ, TestDeviceObject, TestDispatch); + + return Status; +} + +VOID +TestUnload( + _In_ PDRIVER_OBJECT DriverObject) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(DriverObject); + + if (TestDeviceObject) + IoDeleteDevice(TestDeviceObject); +} Index: ntos_cc/CcCacheMap_user.c =================================================================== --- modules/rostests/kmtests/ntos_cc/CcCacheMap_user.c (revision 0) +++ modules/rostests/kmtests/ntos_cc/CcCacheMap_user.c (working copy) @@ -0,0 +1,16 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory + * PURPOSE: Kernel-Mode Test Suite Cache Map Test user-mode part + * PROGRAMMER: Thomas Faber + */ + +#include + +START_TEST(CcCacheMap) +{ + KmtLoadDriver(L"CcCacheMap", TRUE); + KmtOpenDriver(); + KmtCloseDriver(); + KmtUnloadDriver(); +} Index: ntos_cc/CMakeLists.txt =================================================================== --- modules/rostests/kmtests/ntos_cc/CMakeLists.txt (revision 0) +++ modules/rostests/kmtests/ntos_cc/CMakeLists.txt (working copy) @@ -0,0 +1,16 @@ +include_directories( + ../include) + +list(APPEND CCCACHEMAP_DRV_SOURCE + ../kmtest_drv/kmtest_standalone.c + CcCacheMap_drv.c) + +add_library(cccachemap_drv SHARED ${CCCACHEMAP_DRV_SOURCE}) + +set_module_type(cccachemap_drv kernelmodedriver) +target_link_libraries(cccachemap_drv kmtest_printf ${PSEH_LIB}) +add_importlibs(cccachemap_drv ntoskrnl hal) +add_target_compile_definitions(cccachemap_drv KMT_STANDALONE_DRIVER) +#add_pch(cccachemap_drv ../include/kmt_test.h) + +add_cd_file(TARGET cccachemap_drv DESTINATION reactos/bin FOR all)