2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test driver for CcPinRead function
5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
13 #define IOCTL_START_TEST 1
14 #define IOCTL_FINISH_TEST 2
16 typedef struct _TEST_FCB
18 FSRTL_ADVANCED_FCB_HEADER Header
;
19 SECTION_OBJECT_POINTERS SectionObjectPointers
;
20 FAST_MUTEX HeaderMutex
;
21 } TEST_FCB
, *PTEST_FCB
;
23 typedef struct _TEST_CONTEXT
28 } TEST_CONTEXT
, *PTEST_CONTEXT
;
30 static ULONG TestTestId
= -1;
31 static PFILE_OBJECT TestFileObject
;
32 static PDEVICE_OBJECT TestDeviceObject
;
33 static KMT_IRP_HANDLER TestIrpHandler
;
34 static KMT_MESSAGE_HANDLER TestMessageHandler
;
38 _In_ PDRIVER_OBJECT DriverObject
,
39 _In_ PCUNICODE_STRING RegistryPath
,
40 _Out_ PCWSTR
*DeviceName
,
43 NTSTATUS Status
= STATUS_SUCCESS
;
47 UNREFERENCED_PARAMETER(RegistryPath
);
49 *DeviceName
= L
"CcPinRead";
50 *Flags
= TESTENTRY_NO_EXCLUSIVE_DEVICE
|
51 TESTENTRY_BUFFERED_IO_DEVICE
|
52 TESTENTRY_NO_READONLY_DEVICE
;
54 KmtRegisterIrpHandler(IRP_MJ_READ
, NULL
, TestIrpHandler
);
55 KmtRegisterMessageHandler(0, NULL
, TestMessageHandler
);
63 _In_ PDRIVER_OBJECT DriverObject
)
102 static CACHE_MANAGER_CALLBACKS Callbacks
= {
104 ReleaseFromLazyWrite
,
106 ReleaseFromReadAhead
,
109 static CC_FILE_SIZES FileSizes
= {
110 RTL_CONSTANT_LARGE_INTEGER((LONGLONG
)0x4000), // .AllocationSize
111 RTL_CONSTANT_LARGE_INTEGER((LONGLONG
)0x4000), // .FileSize
112 RTL_CONSTANT_LARGE_INTEGER((LONGLONG
)0x4000) // .ValidDataLength
117 MapAndLockUserBuffer(
119 _In_ ULONG BufferLength
)
123 if (Irp
->MdlAddress
== NULL
)
125 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
133 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, IoWriteAccess
);
135 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
138 Irp
->MdlAddress
= NULL
;
139 _SEH2_YIELD(return NULL
);
144 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
150 PinInAnotherThread(IN PVOID Context
)
155 LARGE_INTEGER Offset
;
156 PTEST_CONTEXT TestContext
;
158 ok(TestFileObject
!= NULL
, "Called in invalid context!\n");
159 ok_eq_ulong(TestTestId
, 3);
161 TestContext
= Context
;
162 ok(TestContext
!= NULL
, "Called in invalid context!\n");
163 ok(TestContext
->Bcb
!= NULL
, "Called in invalid context!\n");
164 ok(TestContext
->Buffer
!= NULL
, "Called in invalid context!\n");
165 ok(TestContext
->Length
!= 0, "Called in invalid context!\n");
168 Offset
.QuadPart
= 0x1000;
170 Ret
= CcPinRead(TestFileObject
, &Offset
, TestContext
->Length
, PIN_WAIT
, &Bcb
, (PVOID
*)&Buffer
);
171 KmtEndSeh(STATUS_SUCCESS
);
173 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
175 ok(*(PUSHORT
)Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)Bcb
);
176 ok_eq_pointer(Bcb
, TestContext
->Bcb
);
177 ok_eq_pointer(Buffer
, TestContext
->Buffer
);
183 Ret
= CcPinRead(TestFileObject
, &Offset
, TestContext
->Length
, PIN_WAIT
| PIN_IF_BCB
, &Bcb
, (PVOID
*)&Buffer
);
184 KmtEndSeh(STATUS_SUCCESS
);
186 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
188 ok(*(PUSHORT
)Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)Bcb
);
189 ok_eq_pointer(Bcb
, TestContext
->Bcb
);
190 ok_eq_pointer(Buffer
, TestContext
->Buffer
);
196 Ret
= CcPinRead(TestFileObject
, &Offset
, TestContext
->Length
, PIN_EXCLUSIVE
, &Bcb
, (PVOID
*)&Buffer
);
197 KmtEndSeh(STATUS_SUCCESS
);
199 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
201 ok(*(PUSHORT
)Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)Bcb
);
202 ok_eq_pointer(Bcb
, TestContext
->Bcb
);
203 ok_eq_pointer(Buffer
, TestContext
->Buffer
);
209 Ret
= CcMapData(TestFileObject
, &Offset
, TestContext
->Length
, MAP_WAIT
, &Bcb
, (PVOID
*)&Buffer
);
210 KmtEndSeh(STATUS_SUCCESS
);
212 if (!skip(Ret
== TRUE
, "CcMapData failed\n"))
214 ok(Bcb
!= TestContext
->Bcb
, "Returned same BCB!\n");
215 ok_eq_pointer(Buffer
, TestContext
->Buffer
);
220 Offset
.QuadPart
= 0x1500;
221 TestContext
->Length
-= 0x500;
224 Ret
= CcPinRead(TestFileObject
, &Offset
, TestContext
->Length
, PIN_WAIT
| PIN_IF_BCB
, &Bcb
, (PVOID
*)&Buffer
);
225 KmtEndSeh(STATUS_SUCCESS
);
227 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
229 ok(*(PUSHORT
)Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)Bcb
);
230 ok_eq_pointer(Bcb
, TestContext
->Bcb
);
231 ok_eq_pointer(Buffer
, (PVOID
)((ULONG_PTR
)TestContext
->Buffer
+ 0x500));
237 Ret
= CcPinRead(TestFileObject
, &Offset
, TestContext
->Length
, PIN_WAIT
, &Bcb
, (PVOID
*)&Buffer
);
238 KmtEndSeh(STATUS_SUCCESS
);
240 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
242 ok(*(PUSHORT
)Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)Bcb
);
243 ok_eq_pointer(Bcb
, TestContext
->Bcb
);
244 ok_eq_pointer(Buffer
, (PVOID
)((ULONG_PTR
)TestContext
->Buffer
+ 0x500));
250 Ret
= CcPinRead(TestFileObject
, &Offset
, TestContext
->Length
, PIN_EXCLUSIVE
, &Bcb
, (PVOID
*)&Buffer
);
251 KmtEndSeh(STATUS_SUCCESS
);
253 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
255 ok(*(PUSHORT
)Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)Bcb
);
256 ok_eq_pointer(Bcb
, TestContext
->Bcb
);
257 ok_eq_pointer(Buffer
, (PVOID
)((ULONG_PTR
)TestContext
->Buffer
+ 0x500));
268 PinInAnotherThreadExclusive(IN PVOID Context
)
273 LARGE_INTEGER Offset
;
274 PTEST_CONTEXT TestContext
;
276 ok(TestFileObject
!= NULL
, "Called in invalid context!\n");
277 ok_eq_ulong(TestTestId
, 3);
279 TestContext
= Context
;
280 ok(TestContext
!= NULL
, "Called in invalid context!\n");
281 ok(TestContext
->Bcb
!= NULL
, "Called in invalid context!\n");
282 ok(TestContext
->Buffer
!= NULL
, "Called in invalid context!\n");
283 ok(TestContext
->Length
!= 0, "Called in invalid context!\n");
286 Offset
.QuadPart
= 0x1000;
288 Ret
= CcPinRead(TestFileObject
, &Offset
, TestContext
->Length
, PIN_EXCLUSIVE
, &Bcb
, (PVOID
*)&Buffer
);
289 KmtEndSeh(STATUS_SUCCESS
);
290 ok(Ret
== FALSE
, "CcPinRead succeed\n");
298 Ret
= CcMapData(TestFileObject
, &Offset
, TestContext
->Length
, 0, &Bcb
, (PVOID
*)&Buffer
);
299 KmtEndSeh(STATUS_SUCCESS
);
301 if (!skip(Ret
== TRUE
, "CcMapData failed\n"))
303 ok(Bcb
!= TestContext
->Bcb
, "Returned same BCB!\n");
304 ok_eq_pointer(Buffer
, TestContext
->Buffer
);
309 Offset
.QuadPart
= 0x1500;
310 TestContext
->Length
-= 0x500;
313 Ret
= CcPinRead(TestFileObject
, &Offset
, TestContext
->Length
, PIN_IF_BCB
, &Bcb
, (PVOID
*)&Buffer
);
314 KmtEndSeh(STATUS_SUCCESS
);
315 ok(Ret
== FALSE
, "CcPinRead succeed\n");
323 Ret
= CcPinRead(TestFileObject
, &Offset
, TestContext
->Length
, 0, &Bcb
, (PVOID
*)&Buffer
);
324 KmtEndSeh(STATUS_SUCCESS
);
325 ok(Ret
== FALSE
, "CcPinRead succeed\n");
333 Ret
= CcMapData(TestFileObject
, &Offset
, TestContext
->Length
, 0, &Bcb
, (PVOID
*)&Buffer
);
334 KmtEndSeh(STATUS_SUCCESS
);
336 if (!skip(Ret
== TRUE
, "CcMapData failed\n"))
338 ok(Bcb
!= TestContext
->Bcb
, "Returned same BCB!\n");
339 ok_eq_pointer(Buffer
, (PVOID
)((ULONG_PTR
)TestContext
->Buffer
+ 0x500));
351 PDEVICE_OBJECT DeviceObject
)
357 LARGE_INTEGER Offset
;
359 ok_eq_pointer(TestFileObject
, NULL
);
360 ok_eq_pointer(TestDeviceObject
, NULL
);
361 ok_eq_ulong(TestTestId
, -1);
363 TestDeviceObject
= DeviceObject
;
365 TestFileObject
= IoCreateStreamFileObject(NULL
, DeviceObject
);
366 if (!skip(TestFileObject
!= NULL
, "Failed to allocate FO\n"))
368 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(TEST_FCB
));
369 if (!skip(Fcb
!= NULL
, "ExAllocatePool failed\n"))
371 BOOLEAN PinAccess
= (TestId
!= 4);
373 RtlZeroMemory(Fcb
, sizeof(TEST_FCB
));
374 ExInitializeFastMutex(&Fcb
->HeaderMutex
);
375 FsRtlSetupAdvancedHeader(&Fcb
->Header
, &Fcb
->HeaderMutex
);
377 TestFileObject
->FsContext
= Fcb
;
378 TestFileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
381 CcInitializeCacheMap(TestFileObject
, &FileSizes
, PinAccess
, &Callbacks
, NULL
);
382 KmtEndSeh(STATUS_SUCCESS
);
384 if (!skip(CcIsFileCached(TestFileObject
) == TRUE
, "CcInitializeCacheMap failed\n"))
389 Offset
.QuadPart
= TestId
* 0x1000;
391 Ret
= CcPinRead(TestFileObject
, &Offset
, FileSizes
.FileSize
.QuadPart
- Offset
.QuadPart
, PIN_WAIT
, &Bcb
, (PVOID
*)&Buffer
);
392 KmtEndSeh(STATUS_SUCCESS
);
394 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
396 ok(*(PUSHORT
)Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)Bcb
);
397 ok_eq_ulong(Buffer
[(0x3000 - TestId
* 0x1000) / sizeof(ULONG
)], 0xDEADBABE);
402 else if (TestId
== 3)
404 PTEST_CONTEXT TestContext
;
406 TestContext
= ExAllocatePool(NonPagedPool
, sizeof(TEST_CONTEXT
));
407 if (!skip(Fcb
!= NULL
, "ExAllocatePool failed\n"))
410 Offset
.QuadPart
= 0x1000;
412 /* Try enforce BCB first */
414 Ret
= CcPinRead(TestFileObject
, &Offset
, FileSizes
.FileSize
.QuadPart
- Offset
.QuadPart
, PIN_WAIT
| PIN_IF_BCB
, &Bcb
, (PVOID
*)&Buffer
);
415 KmtEndSeh(STATUS_SUCCESS
);
416 ok(Ret
== FALSE
, "CcPinRead succeed\n");
423 Ret
= CcPinRead(TestFileObject
, &Offset
, FileSizes
.FileSize
.QuadPart
- Offset
.QuadPart
, PIN_WAIT
, &TestContext
->Bcb
, &TestContext
->Buffer
);
424 KmtEndSeh(STATUS_SUCCESS
);
426 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
428 PKTHREAD ThreadHandle
;
430 ok(*(PUSHORT
)TestContext
->Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)TestContext
->Bcb
);
433 /* FIXME: Should be fixed, will fail under certains conditions */
434 ok(TestContext
->Buffer
> (PVOID
)0xC1000000 && TestContext
->Buffer
< (PVOID
)0xDCFFFFFF,
435 "Buffer %p not mapped in system space\n", TestContext
->Buffer
);
438 ok(TestContext
->Buffer
> (PVOID
)0xFFFFF98000000000 && TestContext
->Buffer
< (PVOID
)0xFFFFFA8000000000,
439 "Buffer %p not mapped in system space\n", TestContext
->Buffer
);
441 skip(FALSE
, "System space mapping not defined\n");
444 TestContext
->Length
= FileSizes
.FileSize
.QuadPart
- Offset
.QuadPart
;
445 ThreadHandle
= KmtStartThread(PinInAnotherThread
, TestContext
);
446 KmtFinishThread(ThreadHandle
, NULL
);
448 TestContext
->Length
= FileSizes
.FileSize
.QuadPart
- 2 * Offset
.QuadPart
;
449 ThreadHandle
= KmtStartThread(PinInAnotherThread
, TestContext
);
450 KmtFinishThread(ThreadHandle
, NULL
);
452 CcUnpinData(TestContext
->Bcb
);
456 Ret
= CcPinRead(TestFileObject
, &Offset
, FileSizes
.FileSize
.QuadPart
- Offset
.QuadPart
, PIN_WAIT
| PIN_EXCLUSIVE
, &TestContext
->Bcb
, &TestContext
->Buffer
);
457 KmtEndSeh(STATUS_SUCCESS
);
459 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
461 PKTHREAD ThreadHandle
;
463 ok(*(PUSHORT
)TestContext
->Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)TestContext
->Bcb
);
465 TestContext
->Length
= FileSizes
.FileSize
.QuadPart
- Offset
.QuadPart
;
466 ThreadHandle
= KmtStartThread(PinInAnotherThreadExclusive
, TestContext
);
467 KmtFinishThread(ThreadHandle
, NULL
);
469 CcUnpinData(TestContext
->Bcb
);
472 ExFreePool(TestContext
);
475 else if (TestId
== 4)
478 Offset
.QuadPart
= 0x1000;
480 Ret
= CcPinRead(TestFileObject
, &Offset
, FileSizes
.FileSize
.QuadPart
- Offset
.QuadPart
, PIN_WAIT
, &Bcb
, (PVOID
*)&Buffer
);
481 KmtEndSeh(STATUS_SUCCESS
);
483 if (!skip(Ret
== TRUE
, "CcPinRead failed\n"))
485 ok(*(PUSHORT
)Bcb
== 0x2FD, "Not a BCB: %x\n", *(PUSHORT
)Bcb
);
486 ok_eq_ulong(Buffer
[0x2000 / sizeof(ULONG
)], 0);
491 else if (TestId
== 5)
495 Offset
.QuadPart
= FileSizes
.FileSize
.QuadPart
+ 0x1000;
498 Ret
= CcPinRead(TestFileObject
, &Offset
, 0x1000, 0, &Bcb
, (PVOID
*)&Buffer
);
499 KmtEndSeh(STATUS_SUCCESS
);
500 ok(Ret
== FALSE
, "CcPinRead succeed\n");
507 /* Pin a VACB after EOF */
509 Offset
.QuadPart
= FileSizes
.FileSize
.QuadPart
+ 0x1000 + VACB_MAPPING_GRANULARITY
;
512 Ret
= CcPinRead(TestFileObject
, &Offset
, 0x1000, 0, &Bcb
, (PVOID
*)&Buffer
);
513 KmtEndSeh(STATUS_ACCESS_VIOLATION
);
514 ok(Ret
== FALSE
, "CcPinRead succeed\n");
521 /* Pin more than a VACB */
523 Offset
.QuadPart
= 0x0;
526 Ret
= CcPinRead(TestFileObject
, &Offset
, 0x1000 + VACB_MAPPING_GRANULARITY
, 0, &Bcb
, (PVOID
*)&Buffer
);
527 KmtEndSeh(STATUS_SUCCESS
);
528 ok(Ret
== FALSE
, "CcPinRead succeed\n");
545 PDEVICE_OBJECT DeviceObject
)
547 LARGE_INTEGER Zero
= RTL_CONSTANT_LARGE_INTEGER(0LL);
548 CACHE_UNINITIALIZE_EVENT CacheUninitEvent
;
550 ok_eq_pointer(TestDeviceObject
, DeviceObject
);
551 ok_eq_ulong(TestTestId
, TestId
);
553 if (!skip(TestFileObject
!= NULL
, "No test FO\n"))
555 if (CcIsFileCached(TestFileObject
))
557 KeInitializeEvent(&CacheUninitEvent
.Event
, NotificationEvent
, FALSE
);
558 CcUninitializeCacheMap(TestFileObject
, &Zero
, &CacheUninitEvent
);
559 KeWaitForSingleObject(&CacheUninitEvent
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
562 if (TestFileObject
->FsContext
!= NULL
)
564 ExFreePool(TestFileObject
->FsContext
);
565 TestFileObject
->FsContext
= NULL
;
566 TestFileObject
->SectionObjectPointer
= NULL
;
569 ObDereferenceObject(TestFileObject
);
572 TestFileObject
= NULL
;
573 TestDeviceObject
= NULL
;
581 _In_ PDEVICE_OBJECT DeviceObject
,
582 _In_ ULONG ControlCode
,
583 _In_opt_ PVOID Buffer
,
584 _In_ SIZE_T InLength
,
585 _Inout_ PSIZE_T OutLength
)
587 NTSTATUS Status
= STATUS_SUCCESS
;
589 FsRtlEnterFileSystem();
593 case IOCTL_START_TEST
:
594 ok_eq_ulong((ULONG
)InLength
, sizeof(ULONG
));
595 PerformTest(*(PULONG
)Buffer
, DeviceObject
);
598 case IOCTL_FINISH_TEST
:
599 ok_eq_ulong((ULONG
)InLength
, sizeof(ULONG
));
600 CleanupTest(*(PULONG
)Buffer
, DeviceObject
);
604 Status
= STATUS_NOT_IMPLEMENTED
;
608 FsRtlExitFileSystem();
616 _In_ PDEVICE_OBJECT DeviceObject
,
618 _In_ PIO_STACK_LOCATION IoStack
)
624 DPRINT("IRP %x/%x\n", IoStack
->MajorFunction
, IoStack
->MinorFunction
);
625 ASSERT(IoStack
->MajorFunction
== IRP_MJ_READ
);
627 FsRtlEnterFileSystem();
629 Status
= STATUS_NOT_SUPPORTED
;
630 Irp
->IoStatus
.Information
= 0;
632 if (IoStack
->MajorFunction
== IRP_MJ_READ
)
637 LARGE_INTEGER Offset
;
639 Offset
= IoStack
->Parameters
.Read
.ByteOffset
;
640 Length
= IoStack
->Parameters
.Read
.Length
;
642 ok_eq_pointer(DeviceObject
, TestDeviceObject
);
643 ok_eq_pointer(IoStack
->FileObject
, TestFileObject
);
645 ok(FlagOn(Irp
->Flags
, IRP_NOCACHE
), "Not coming from Cc\n");
648 ok((Offset
.QuadPart
% PAGE_SIZE
== 0 || Offset
.QuadPart
== 0), "Offset is not aligned: %I64i\n", Offset
.QuadPart
);
649 ok(Length
% PAGE_SIZE
== 0, "Length is not aligned: %I64i\n", Length
);
651 ok(Irp
->AssociatedIrp
.SystemBuffer
== NULL
, "A SystemBuffer was allocated!\n");
652 Buffer
= MapAndLockUserBuffer(Irp
, Length
);
653 ok(Buffer
!= NULL
, "Null pointer!\n");
654 RtlFillMemory(Buffer
, Length
, 0xBA);
656 Status
= STATUS_SUCCESS
;
657 if (Offset
.QuadPart
<= 0x3000 && Offset
.QuadPart
+ Length
> 0x3000)
659 *(PULONG
)((ULONG_PTR
)Buffer
+ (ULONG_PTR
)(0x3000 - Offset
.QuadPart
)) = 0xDEADBABE;
662 Mdl
= Irp
->MdlAddress
;
663 ok(Mdl
!= NULL
, "Null pointer for MDL!\n");
664 ok((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) != 0, "MDL not locked\n");
665 ok((Mdl
->MdlFlags
& MDL_SOURCE_IS_NONPAGED_POOL
) == 0, "MDL from non paged\n");
666 ok((Mdl
->MdlFlags
& MDL_IO_PAGE_READ
) != 0, "Non paging IO\n");
667 ok((Irp
->Flags
& IRP_PAGING_IO
) != 0, "Non paging IO\n");
669 Irp
->IoStatus
.Information
= Length
;
672 if (Status
== STATUS_PENDING
)
674 IoMarkIrpPending(Irp
);
675 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
676 Status
= STATUS_PENDING
;
680 Irp
->IoStatus
.Status
= Status
;
681 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
684 FsRtlExitFileSystem();