[KMTESTS:CC] That wasn't meant to be committed
[reactos.git] / modules / rostests / kmtests / ntos_cc / CcPinRead_drv.c
1 /*
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>
6 */
7
8 #include <kmt_test.h>
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define IOCTL_START_TEST 1
14 #define IOCTL_FINISH_TEST 2
15
16 typedef struct _TEST_FCB
17 {
18 FSRTL_ADVANCED_FCB_HEADER Header;
19 SECTION_OBJECT_POINTERS SectionObjectPointers;
20 FAST_MUTEX HeaderMutex;
21 } TEST_FCB, *PTEST_FCB;
22
23 typedef struct _TEST_CONTEXT
24 {
25 PVOID Bcb;
26 PVOID Buffer;
27 ULONG Length;
28 } TEST_CONTEXT, *PTEST_CONTEXT;
29
30 static BOOLEAN TestMap = FALSE;
31 static ULONG TestTestId = -1;
32 static PFILE_OBJECT TestFileObject;
33 static PDEVICE_OBJECT TestDeviceObject;
34 static KMT_IRP_HANDLER TestIrpHandler;
35 static KMT_MESSAGE_HANDLER TestMessageHandler;
36
37 NTSTATUS
38 TestEntry(
39 _In_ PDRIVER_OBJECT DriverObject,
40 _In_ PCUNICODE_STRING RegistryPath,
41 _Out_ PCWSTR *DeviceName,
42 _Inout_ INT *Flags)
43 {
44 NTSTATUS Status = STATUS_SUCCESS;
45
46 PAGED_CODE();
47
48 UNREFERENCED_PARAMETER(RegistryPath);
49
50 *DeviceName = L"CcMapData";
51 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE |
52 TESTENTRY_BUFFERED_IO_DEVICE |
53 TESTENTRY_NO_READONLY_DEVICE;
54
55 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler);
56 KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
57
58
59 return Status;
60 }
61
62 VOID
63 TestUnload(
64 _In_ PDRIVER_OBJECT DriverObject)
65 {
66 PAGED_CODE();
67 }
68
69 BOOLEAN
70 NTAPI
71 AcquireForLazyWrite(
72 _In_ PVOID Context,
73 _In_ BOOLEAN Wait)
74 {
75 return TRUE;
76 }
77
78 VOID
79 NTAPI
80 ReleaseFromLazyWrite(
81 _In_ PVOID Context)
82 {
83 return;
84 }
85
86 BOOLEAN
87 NTAPI
88 AcquireForReadAhead(
89 _In_ PVOID Context,
90 _In_ BOOLEAN Wait)
91 {
92 return TRUE;
93 }
94
95 VOID
96 NTAPI
97 ReleaseFromReadAhead(
98 _In_ PVOID Context)
99 {
100 return;
101 }
102
103 static CACHE_MANAGER_CALLBACKS Callbacks = {
104 AcquireForLazyWrite,
105 ReleaseFromLazyWrite,
106 AcquireForReadAhead,
107 ReleaseFromReadAhead,
108 };
109
110 static CC_FILE_SIZES FileSizes = {
111 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000), // .AllocationSize
112 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000), // .FileSize
113 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000) // .ValidDataLength
114 };
115
116 static
117 PVOID
118 MapAndLockUserBuffer(
119 _In_ _Out_ PIRP Irp,
120 _In_ ULONG BufferLength)
121 {
122 PMDL Mdl;
123
124 if (Irp->MdlAddress == NULL)
125 {
126 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
127 if (Mdl == NULL)
128 {
129 return NULL;
130 }
131
132 _SEH2_TRY
133 {
134 MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoWriteAccess);
135 }
136 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
137 {
138 IoFreeMdl(Mdl);
139 Irp->MdlAddress = NULL;
140 _SEH2_YIELD(return NULL);
141 }
142 _SEH2_END;
143 }
144
145 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
146 }
147
148 static
149 VOID
150 NTAPI
151 MapInAnotherThread(IN PVOID Context)
152 {
153 BOOLEAN Ret;
154 PULONG Buffer;
155 PVOID Bcb;
156 LARGE_INTEGER Offset;
157 PTEST_CONTEXT TestContext;
158
159 ok(TestFileObject != NULL, "Called in invalid context!\n");
160 ok_eq_ulong(TestTestId, 3);
161
162 TestContext = Context;
163 ok(TestContext != NULL, "Called in invalid context!\n");
164 ok(TestContext->Bcb != NULL, "Called in invalid context!\n");
165 ok(TestContext->Buffer != NULL, "Called in invalid context!\n");
166 ok(TestContext->Length != 0, "Called in invalid context!\n");
167
168 Ret = FALSE;
169 Offset.QuadPart = 0x1000;
170 KmtStartSeh();
171 TestMap = TRUE;
172 Ret = CcMapData(TestFileObject, &Offset, TestContext->Length, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
173 TestMap = FALSE;
174 KmtEndSeh(STATUS_SUCCESS);
175
176 if (!skip(Ret == TRUE, "CcMapData failed\n"))
177 {
178 ok_eq_pointer(Bcb, TestContext->Bcb);
179 ok_eq_pointer(Buffer, TestContext->Buffer);
180
181 CcUnpinData(Bcb);
182 }
183
184 return;
185 }
186
187 static
188 VOID
189 PerformTest(
190 ULONG TestId,
191 PDEVICE_OBJECT DeviceObject)
192 {
193 PVOID Bcb;
194 BOOLEAN Ret;
195 PULONG Buffer;
196 PTEST_FCB Fcb;
197 LARGE_INTEGER Offset;
198
199 ok_eq_pointer(TestFileObject, NULL);
200 ok_eq_pointer(TestDeviceObject, NULL);
201 ok_eq_ulong(TestTestId, -1);
202
203 TestDeviceObject = DeviceObject;
204 TestTestId = TestId;
205 TestFileObject = IoCreateStreamFileObject(NULL, DeviceObject);
206 if (!skip(TestFileObject != NULL, "Failed to allocate FO\n"))
207 {
208 Fcb = ExAllocatePool(NonPagedPool, sizeof(TEST_FCB));
209 if (!skip(Fcb != NULL, "ExAllocatePool failed\n"))
210 {
211 RtlZeroMemory(Fcb, sizeof(TEST_FCB));
212 ExInitializeFastMutex(&Fcb->HeaderMutex);
213 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
214
215 TestFileObject->FsContext = Fcb;
216 TestFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
217
218 KmtStartSeh();
219 CcInitializeCacheMap(TestFileObject, &FileSizes, FALSE, &Callbacks, NULL);
220 KmtEndSeh(STATUS_SUCCESS);
221
222 if (!skip(CcIsFileCached(TestFileObject) == TRUE, "CcInitializeCacheMap failed\n"))
223 {
224 if (TestId < 3)
225 {
226 Ret = FALSE;
227 Offset.QuadPart = TestId * 0x1000;
228 KmtStartSeh();
229 Ret = CcMapData(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
230 KmtEndSeh(STATUS_SUCCESS);
231
232 if (!skip(Ret == TRUE, "CcMapData failed\n"))
233 {
234 ok_eq_ulong(Buffer[(0x3000 - TestId * 0x1000) / sizeof(ULONG)], 0xDEADBABE);
235
236 CcUnpinData(Bcb);
237 }
238 }
239 else if (TestId == 3)
240 {
241 PTEST_CONTEXT TestContext;
242
243 TestContext = ExAllocatePool(NonPagedPool, sizeof(TEST_CONTEXT));
244 if (!skip(Fcb != NULL, "ExAllocatePool failed\n"))
245 {
246 Ret = FALSE;
247 Offset.QuadPart = 0x1000;
248 KmtStartSeh();
249 TestMap = TRUE;
250 Ret = CcMapData(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, MAP_WAIT, &TestContext->Bcb, &TestContext->Buffer);
251 TestMap = FALSE;
252 KmtEndSeh(STATUS_SUCCESS);
253
254 if (!skip(Ret == TRUE, "CcMapData failed\n"))
255 {
256 PKTHREAD ThreadHandle;
257
258 #ifdef _X86_
259 /* FIXME: Should be fixed, will fail under certains conditions */
260 ok(TestContext->Buffer > (PVOID)0xC1000000 && TestContext->Buffer < (PVOID)0xDCFFFFFF,
261 "Buffer %p not mapped in system space\n", TestContext->Buffer);
262 #else
263 #ifdef _M_AMD64
264 ok(TestContext->Buffer > (PVOID)0xFFFFF98000000000 && TestContext->Buffer < (PVOID)0xFFFFFA8000000000,
265 "Buffer %p not mapped in system space\n", TestContext->Buffer);
266 #else
267 skip(FALSE, "System space mapping not defined\n");
268 #endif
269 #endif
270
271 TestContext->Length = FileSizes.FileSize.QuadPart - Offset.QuadPart;
272 ThreadHandle = KmtStartThread(MapInAnotherThread, TestContext);
273 KmtFinishThread(ThreadHandle, NULL);
274
275 TestContext->Length = FileSizes.FileSize.QuadPart - 2 * Offset.QuadPart;
276 ThreadHandle = KmtStartThread(MapInAnotherThread, TestContext);
277 KmtFinishThread(ThreadHandle, NULL);
278
279 CcUnpinData(TestContext->Bcb);
280 }
281
282 ExFreePool(TestContext);
283 }
284 }
285 }
286 }
287 }
288 }
289
290
291 static
292 VOID
293 CleanupTest(
294 ULONG TestId,
295 PDEVICE_OBJECT DeviceObject)
296 {
297 LARGE_INTEGER Zero = RTL_CONSTANT_LARGE_INTEGER(0LL);
298 CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
299
300 ok_eq_pointer(TestDeviceObject, DeviceObject);
301 ok_eq_ulong(TestTestId, TestId);
302
303 if (!skip(TestFileObject != NULL, "No test FO\n"))
304 {
305 if (CcIsFileCached(TestFileObject))
306 {
307 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
308 CcUninitializeCacheMap(TestFileObject, &Zero, &CacheUninitEvent);
309 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
310 }
311
312 if (TestFileObject->FsContext != NULL)
313 {
314 ExFreePool(TestFileObject->FsContext);
315 TestFileObject->FsContext = NULL;
316 TestFileObject->SectionObjectPointer = NULL;
317 }
318
319 ObDereferenceObject(TestFileObject);
320 }
321
322 TestFileObject = NULL;
323 TestDeviceObject = NULL;
324 TestTestId = -1;
325 }
326
327
328 static
329 NTSTATUS
330 TestMessageHandler(
331 _In_ PDEVICE_OBJECT DeviceObject,
332 _In_ ULONG ControlCode,
333 _In_opt_ PVOID Buffer,
334 _In_ SIZE_T InLength,
335 _Inout_ PSIZE_T OutLength)
336 {
337 NTSTATUS Status = STATUS_SUCCESS;
338
339 switch (ControlCode)
340 {
341 case IOCTL_START_TEST:
342 ok_eq_ulong((ULONG)InLength, sizeof(ULONG));
343 PerformTest(*(PULONG)Buffer, DeviceObject);
344 break;
345
346 case IOCTL_FINISH_TEST:
347 ok_eq_ulong((ULONG)InLength, sizeof(ULONG));
348 CleanupTest(*(PULONG)Buffer, DeviceObject);
349 break;
350
351 default:
352 Status = STATUS_NOT_IMPLEMENTED;
353 break;
354 }
355
356 return Status;
357 }
358
359 static
360 NTSTATUS
361 TestIrpHandler(
362 _In_ PDEVICE_OBJECT DeviceObject,
363 _In_ PIRP Irp,
364 _In_ PIO_STACK_LOCATION IoStack)
365 {
366 NTSTATUS Status;
367
368 PAGED_CODE();
369
370 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction);
371 ASSERT(IoStack->MajorFunction == IRP_MJ_READ);
372
373 Status = STATUS_NOT_SUPPORTED;
374 Irp->IoStatus.Information = 0;
375
376 if (IoStack->MajorFunction == IRP_MJ_READ)
377 {
378 PMDL Mdl;
379 ULONG Length;
380 PVOID Buffer;
381 LARGE_INTEGER Offset;
382
383 Offset = IoStack->Parameters.Read.ByteOffset;
384 Length = IoStack->Parameters.Read.Length;
385
386 ok_eq_pointer(DeviceObject, TestDeviceObject);
387 ok_eq_pointer(IoStack->FileObject, TestFileObject);
388
389 ok(FlagOn(Irp->Flags, IRP_NOCACHE), "Not coming from Cc\n");
390
391 ok_irql(APC_LEVEL);
392 ok((Offset.QuadPart % PAGE_SIZE == 0 || Offset.QuadPart == 0), "Offset is not aligned: %I64i\n", Offset.QuadPart);
393 ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length);
394
395 ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n");
396 Buffer = MapAndLockUserBuffer(Irp, Length);
397 ok(Buffer != NULL, "Null pointer!\n");
398 RtlFillMemory(Buffer, Length, 0xBA);
399
400 Status = STATUS_SUCCESS;
401 if (Offset.QuadPart <= 0x3000 && Offset.QuadPart + Length > 0x3000)
402 {
403 *(PULONG)((ULONG_PTR)Buffer + (ULONG_PTR)(0x3000 - Offset.QuadPart)) = 0xDEADBABE;
404 }
405
406 Mdl = Irp->MdlAddress;
407 ok(Mdl != NULL, "Null pointer for MDL!\n");
408 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n");
409 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n");
410 ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0, "Non paging IO\n");
411 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n");
412
413 Irp->IoStatus.Information = Length;
414 }
415
416 if (Status == STATUS_PENDING)
417 {
418 IoMarkIrpPending(Irp);
419 IoCompleteRequest(Irp, IO_NO_INCREMENT);
420 Status = STATUS_PENDING;
421 }
422 else
423 {
424 Irp->IoStatus.Status = Status;
425 IoCompleteRequest(Irp, IO_NO_INCREMENT);
426 }
427
428 return Status;
429 }