[KMTESTS:CC]
authorPierre Schweitzer <pierre@reactos.org>
Sat, 28 May 2016 19:59:10 +0000 (19:59 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Sat, 28 May 2016 19:59:10 +0000 (19:59 +0000)
Introduce tests for Cc :-)
Currently, we only test CcCopyRead for specific alignment matters. It shows that under certain conditions, our Cc doesn't align reads it does, leading to later failure in disk.sys.
This reproduces an error observed with MS FastFAT in ReactOS.

CORE-11003

svn path=/trunk/; revision=71445

rostests/kmtests/CMakeLists.txt
rostests/kmtests/kmtest/testlist.c
rostests/kmtests/ntos_cc/CMakeLists.txt [new file with mode: 0644]
rostests/kmtests/ntos_cc/CcCopyRead_drv.c [new file with mode: 0644]
rostests/kmtests/ntos_cc/CcCopyRead_user.c [new file with mode: 0644]

index 7691f3e..13da6de 100644 (file)
@@ -6,6 +6,7 @@ include_directories(include)
 #
 add_subdirectory(example)
 add_subdirectory(kernel32)
 #
 add_subdirectory(example)
 add_subdirectory(kernel32)
+add_subdirectory(ntos_cc)
 add_subdirectory(ntos_io)
 add_subdirectory(ntos_po)
 add_subdirectory(tcpip)
 add_subdirectory(ntos_io)
 add_subdirectory(ntos_po)
 add_subdirectory(tcpip)
@@ -118,6 +119,7 @@ list(APPEND KMTEST_SOURCE
 
     example/Example_user.c
     kernel32/FindFile_user.c
 
     example/Example_user.c
     kernel32/FindFile_user.c
+    ntos_cc/CcCopyRead_user.c
     ntos_io/IoCreateFile_user.c
     ntos_io/IoDeviceObject_user.c
     ntos_io/IoReadWrite_user.c
     ntos_io/IoCreateFile_user.c
     ntos_io/IoDeviceObject_user.c
     ntos_io/IoReadWrite_user.c
index 360e120..7c5eda8 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <kmt_test.h>
 
 
 #include <kmt_test.h>
 
+KMT_TESTFUNC Test_CcCopyRead;
 KMT_TESTFUNC Test_Example;
 KMT_TESTFUNC Test_FindFile;
 KMT_TESTFUNC Test_IoCreateFile;
 KMT_TESTFUNC Test_Example;
 KMT_TESTFUNC Test_FindFile;
 KMT_TESTFUNC Test_IoCreateFile;
@@ -27,6 +28,7 @@ KMT_TESTFUNC Test_TcpIpConnect;
 /* tests with a leading '-' will not be listed */
 const KMT_TEST TestList[] =
 {
 /* tests with a leading '-' will not be listed */
 const KMT_TEST TestList[] =
 {
+    { "CcCopyRead",         Test_CcCopyRead },
     { "-Example",           Test_Example },
     { "FindFile",           Test_FindFile },
     { "IoCreateFile",       Test_IoCreateFile },
     { "-Example",           Test_Example },
     { "FindFile",           Test_FindFile },
     { "IoCreateFile",       Test_IoCreateFile },
diff --git a/rostests/kmtests/ntos_cc/CMakeLists.txt b/rostests/kmtests/ntos_cc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6d09262
--- /dev/null
@@ -0,0 +1,17 @@
+
+include_directories(../include)
+
+#
+# IoCreateFile
+#
+list(APPEND CCCOPYREAD_DRV_SOURCE
+    ../kmtest_drv/kmtest_standalone.c
+    CcCopyRead_drv.c)
+
+add_library(cccopyread_drv SHARED ${CCCOPYREAD_DRV_SOURCE})
+set_module_type(cccopyread_drv kernelmodedriver)
+target_link_libraries(cccopyread_drv kmtest_printf ${PSEH_LIB})
+add_importlibs(cccopyread_drv ntoskrnl hal)
+add_target_compile_definitions(cccopyread_drv KMT_STANDALONE_DRIVER)
+#add_pch(cccopyread_drv ../include/kmt_test.h)
+add_cd_file(TARGET cccopyread_drv DESTINATION reactos/bin FOR all)
diff --git a/rostests/kmtests/ntos_cc/CcCopyRead_drv.c b/rostests/kmtests/ntos_cc/CcCopyRead_drv.c
new file mode 100644 (file)
index 0000000..3213457
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Test driver for CcCopyRead function
+ * PROGRAMMER:      Pierre Schweitzer <pierre@reactos.org>
+ */
+
+#include <kmt_test.h>
+
+#define NDEBUG
+#include <debug.h>
+
+typedef struct _TEST_FCB
+{
+    FSRTL_ADVANCED_FCB_HEADER Header;
+    SECTION_OBJECT_POINTERS SectionObjectPointers;
+    FAST_MUTEX HeaderMutex;
+} TEST_FCB, *PTEST_FCB;
+
+static PFILE_OBJECT TestFileObject;
+static PDEVICE_OBJECT TestDeviceObject;
+static KMT_IRP_HANDLER TestIrpHandler;
+static FAST_IO_DISPATCH TestFastIoDispatch;
+
+static
+BOOLEAN
+NTAPI
+FastIoRead(
+    _In_ PFILE_OBJECT FileObject,
+    _In_ PLARGE_INTEGER FileOffset,
+    _In_ ULONG Length,
+    _In_ BOOLEAN Wait,
+    _In_ ULONG LockKey,
+    _Out_ PVOID Buffer,
+    _Out_ PIO_STATUS_BLOCK IoStatus,
+    _In_ PDEVICE_OBJECT DeviceObject)
+{
+    IoStatus->Status = STATUS_NOT_SUPPORTED;
+    return FALSE;
+}
+
+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);
+
+    *DeviceName = L"CcCopyRead";
+    *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE |
+             TESTENTRY_BUFFERED_IO_DEVICE |
+             TESTENTRY_NO_READONLY_DEVICE;
+
+    KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler);
+    KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler);
+    KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler);
+
+    TestFastIoDispatch.FastIoRead = FastIoRead;
+    DriverObject->FastIoDispatch = &TestFastIoDispatch;
+
+
+    return Status;
+}
+
+VOID
+TestUnload(
+    _In_ PDRIVER_OBJECT DriverObject)
+{
+    PAGED_CODE();
+}
+
+BOOLEAN
+NTAPI
+AcquireForLazyWrite(
+    _In_ PVOID Context,
+    _In_ BOOLEAN Wait)
+{
+    return TRUE;
+}
+
+VOID
+NTAPI
+ReleaseFromLazyWrite(
+    _In_ PVOID Context)
+{
+    return;
+}
+
+BOOLEAN
+NTAPI
+AcquireForReadAhead(
+    _In_ PVOID Context,
+    _In_ BOOLEAN Wait)
+{
+    return TRUE;
+}
+
+VOID
+NTAPI
+ReleaseFromReadAhead(
+    _In_ PVOID Context)
+{
+    return;
+}
+
+static CACHE_MANAGER_CALLBACKS Callbacks = {
+    AcquireForLazyWrite,
+    ReleaseFromLazyWrite,
+    AcquireForReadAhead,
+    ReleaseFromReadAhead,
+};
+
+static
+PVOID
+MapUserBuffer(
+    _In_ _Out_ PIRP Irp)
+{
+    if (Irp->MdlAddress == NULL)
+    {
+        return Irp->UserBuffer;
+    }
+    else
+    {
+        return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+    }
+}
+
+
+static
+NTSTATUS
+TestIrpHandler(
+    _In_ PDEVICE_OBJECT DeviceObject,
+    _In_ PIRP Irp,
+    _In_ PIO_STACK_LOCATION IoStack)
+{
+    NTSTATUS Status;
+    PTEST_FCB Fcb;
+    CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
+
+    PAGED_CODE();
+
+    DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction);
+    ASSERT(IoStack->MajorFunction == IRP_MJ_CLEANUP ||
+           IoStack->MajorFunction == IRP_MJ_CREATE ||
+           IoStack->MajorFunction == IRP_MJ_READ);
+
+    Status = STATUS_NOT_SUPPORTED;
+    Irp->IoStatus.Information = 0;
+
+    if (IoStack->MajorFunction == IRP_MJ_CREATE)
+    {
+        if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR))
+        {
+            TestDeviceObject = DeviceObject;
+            TestFileObject = IoStack->FileObject;
+        }
+        Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI');
+        RtlZeroMemory(Fcb, sizeof(*Fcb));
+        ExInitializeFastMutex(&Fcb->HeaderMutex);
+        FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
+        if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
+            IoStack->FileObject->FileName.Buffer[1] == 'B')
+        {
+            Fcb->Header.AllocationSize.QuadPart = 1000000;
+            Fcb->Header.FileSize.QuadPart = 1000000;
+            Fcb->Header.ValidDataLength.QuadPart = 1000000;
+        }
+        else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
+                 IoStack->FileObject->FileName.Buffer[1] == 'S')
+        {
+            Fcb->Header.AllocationSize.QuadPart = 3000;
+            Fcb->Header.FileSize.QuadPart = 3000;
+            Fcb->Header.ValidDataLength.QuadPart = 3000;
+        }
+        else
+        {
+            Fcb->Header.AllocationSize.QuadPart = 512;
+            Fcb->Header.FileSize.QuadPart = 512;
+            Fcb->Header.ValidDataLength.QuadPart = 512;
+        }
+        Fcb->Header.IsFastIoPossible = FALSE;
+        IoStack->FileObject->FsContext = Fcb;
+        IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
+
+        CcInitializeCacheMap(IoStack->FileObject, 
+                             (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
+                             FALSE, &Callbacks, NULL);
+
+        Irp->IoStatus.Information = FILE_OPENED;
+        Status = STATUS_SUCCESS;
+    }
+    else if (IoStack->MajorFunction == IRP_MJ_READ)
+    {
+        BOOLEAN Ret;
+        ULONG Length;
+        PVOID Buffer;
+        LARGE_INTEGER Offset;
+
+        Offset = IoStack->Parameters.Read.ByteOffset;
+        Length = IoStack->Parameters.Read.Length;
+        Fcb = IoStack->FileObject->FsContext;
+
+        ok_eq_pointer(DeviceObject, TestDeviceObject);
+        ok_eq_pointer(IoStack->FileObject, TestFileObject);
+
+        if (!FlagOn(Irp->Flags, IRP_NOCACHE))
+        {
+            ok(Offset.QuadPart % 512 != 0, "Offset is aligned: %I64i\n", Offset.QuadPart);
+            ok(Length % 512 != 0, "Length is aligned: %I64i\n", Length);
+
+            Buffer = MapUserBuffer(Irp);
+            ok(Buffer != NULL, "Null pointer!\n");
+
+            _SEH2_TRY
+            {
+                Ret = CcCopyRead(IoStack->FileObject, &Offset, Length, TRUE, Buffer,
+                                 &Irp->IoStatus);
+                ok_bool_true(Ret, "CcCopyRead");
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                Irp->IoStatus.Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            Status = Irp->IoStatus.Status;
+        }
+        else
+        {
+            ok(Offset.QuadPart % 512 == 0, "Offset is not aligned: %I64i\n", Offset.QuadPart);
+            ok(Length % 512 == 0, "Length is not aligned: %I64i\n", Length);
+
+            Status = STATUS_SUCCESS;
+        }
+
+        if (NT_SUCCESS(Status))
+        {
+            Irp->IoStatus.Information = Length;
+            IoStack->FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
+        }
+    }
+    else if (IoStack->MajorFunction == IRP_MJ_CLEANUP)
+    {
+        KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
+        CcUninitializeCacheMap(IoStack->FileObject, NULL, &CacheUninitEvent);
+        KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
+        Fcb = IoStack->FileObject->FsContext;
+        ExFreePoolWithTag(Fcb, 'FwrI');
+        IoStack->FileObject->FsContext = NULL;
+        Status = STATUS_SUCCESS;
+    }
+
+    if (Status == STATUS_PENDING)
+    {
+        IoMarkIrpPending(Irp);
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        Status = STATUS_PENDING;
+    }
+    else
+    {
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+
+    return Status;
+}
diff --git a/rostests/kmtests/ntos_cc/CcCopyRead_user.c b/rostests/kmtests/ntos_cc/CcCopyRead_user.c
new file mode 100644 (file)
index 0000000..18bfb2c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         Kernel-Mode Test Suite CcCopyRead test user-mode part
+ * PROGRAMMER:      Pierre Schweitzer <pierre@reactos.org>
+ */
+
+#include <kmt_test.h>
+
+START_TEST(CcCopyRead)
+{
+    HANDLE Handle;
+    NTSTATUS Status;
+    LARGE_INTEGER ByteOffset;
+    IO_STATUS_BLOCK IoStatusBlock;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    PVOID Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, 1024);
+    UNICODE_STRING BigAlignmentTest = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-CcCopyRead\\BigAlignmentTest");
+    UNICODE_STRING SmallAlignmentTest = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-CcCopyRead\\SmallAlignmentTest");
+    
+    KmtLoadDriver(L"CcCopyRead", FALSE);
+    KmtOpenDriver();
+
+    InitializeObjectAttributes(&ObjectAttributes, &SmallAlignmentTest, OBJ_CASE_INSENSITIVE, NULL, NULL);
+    Status = NtOpenFile(&Handle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    ByteOffset.QuadPart = 3;
+    Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 3, &ByteOffset, NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    ByteOffset.QuadPart = 514;
+    Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 514, &ByteOffset, NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    NtClose(Handle);
+
+    InitializeObjectAttributes(&ObjectAttributes, &BigAlignmentTest, OBJ_CASE_INSENSITIVE, NULL, NULL);
+    Status = NtOpenFile(&Handle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    ByteOffset.QuadPart = 3;
+    Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 3, &ByteOffset, NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    ByteOffset.QuadPart = 514;
+    Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 514, &ByteOffset, NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    ByteOffset.QuadPart = 300000;
+    Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 10, &ByteOffset, NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    NtClose(Handle);
+
+    RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+    KmtCloseDriver();
+    KmtUnloadDriver();
+}