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 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;
35 static BOOLEAN TestWriteCalled = FALSE;
36 static ULONGLONG Memory = 0;
37 static BOOLEAN TS = FALSE;
38
39 LARGE_INTEGER WriteOffset;
40 ULONG WriteLength;
41
42 NTSTATUS
TestEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PCUNICODE_STRING RegistryPath,_Out_ PCWSTR * DeviceName,_Inout_ INT * Flags)43 TestEntry(
44 _In_ PDRIVER_OBJECT DriverObject,
45 _In_ PCUNICODE_STRING RegistryPath,
46 _Out_ PCWSTR *DeviceName,
47 _Inout_ INT *Flags)
48 {
49 ULONG Length;
50 SYSTEM_BASIC_INFORMATION SBI;
51 NTSTATUS Status = STATUS_SUCCESS;
52 RTL_OSVERSIONINFOEXW VersionInfo;
53
54 PAGED_CODE();
55
56 UNREFERENCED_PARAMETER(RegistryPath);
57
58 *DeviceName = L"CcPinRead";
59 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE |
60 TESTENTRY_BUFFERED_IO_DEVICE |
61 TESTENTRY_NO_READONLY_DEVICE;
62
63 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler);
64 KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler);
65 KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
66
67 Status = ZwQuerySystemInformation(SystemBasicInformation,
68 &SBI,
69 sizeof(SBI),
70 &Length);
71 if (NT_SUCCESS(Status))
72 {
73 Memory = (SBI.NumberOfPhysicalPages * SBI.PageSize) / 1024 / 1024;
74 }
75 else
76 {
77 Status = STATUS_SUCCESS;
78 }
79
80 VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
81 Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&VersionInfo);
82 if (NT_SUCCESS(Status))
83 {
84 TS = BooleanFlagOn(VersionInfo.wSuiteMask, VER_SUITE_TERMINAL) &&
85 !BooleanFlagOn(VersionInfo.wSuiteMask, VER_SUITE_SINGLEUSERTS);
86 }
87 else
88 {
89 Status = STATUS_SUCCESS;
90 }
91
92 trace("System with %I64dMb RAM and terminal services %S\n", Memory, (TS ? L"enabled" : L"disabled"));
93
94 return Status;
95 }
96
97 VOID
TestUnload(_In_ PDRIVER_OBJECT DriverObject)98 TestUnload(
99 _In_ PDRIVER_OBJECT DriverObject)
100 {
101 PAGED_CODE();
102 }
103
104 BOOLEAN
105 NTAPI
AcquireForLazyWrite(_In_ PVOID Context,_In_ BOOLEAN Wait)106 AcquireForLazyWrite(
107 _In_ PVOID Context,
108 _In_ BOOLEAN Wait)
109 {
110 return TRUE;
111 }
112
113 VOID
114 NTAPI
ReleaseFromLazyWrite(_In_ PVOID Context)115 ReleaseFromLazyWrite(
116 _In_ PVOID Context)
117 {
118 return;
119 }
120
121 BOOLEAN
122 NTAPI
AcquireForReadAhead(_In_ PVOID Context,_In_ BOOLEAN Wait)123 AcquireForReadAhead(
124 _In_ PVOID Context,
125 _In_ BOOLEAN Wait)
126 {
127 return TRUE;
128 }
129
130 VOID
131 NTAPI
ReleaseFromReadAhead(_In_ PVOID Context)132 ReleaseFromReadAhead(
133 _In_ PVOID Context)
134 {
135 return;
136 }
137
138 static CACHE_MANAGER_CALLBACKS Callbacks = {
139 AcquireForLazyWrite,
140 ReleaseFromLazyWrite,
141 AcquireForReadAhead,
142 ReleaseFromReadAhead,
143 };
144
145 static CC_FILE_SIZES FileSizes = {
146 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000), // .AllocationSize
147 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000), // .FileSize
148 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000) // .ValidDataLength
149 };
150
151 static CC_FILE_SIZES SmallFileSizes = {
152 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)512), // .AllocationSize
153 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)496), // .FileSize
154 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)496) // .ValidDataLength
155 };
156
157 static
158 PVOID
MapAndLockUserBuffer(_In_ _Out_ PIRP Irp,_In_ ULONG BufferLength)159 MapAndLockUserBuffer(
160 _In_ _Out_ PIRP Irp,
161 _In_ ULONG BufferLength)
162 {
163 PMDL Mdl;
164
165 if (Irp->MdlAddress == NULL)
166 {
167 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
168 if (Mdl == NULL)
169 {
170 return NULL;
171 }
172
173 _SEH2_TRY
174 {
175 MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoWriteAccess);
176 }
177 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
178 {
179 IoFreeMdl(Mdl);
180 Irp->MdlAddress = NULL;
181 _SEH2_YIELD(return NULL);
182 }
183 _SEH2_END;
184 }
185
186 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
187 }
188
189 #define ok_bcb(B, L, O) \
190 { \
191 PPUBLIC_BCB public_bcb = (B); \
192 ok(public_bcb->NodeTypeCode == 0x2FD, "Not a BCB: %04x\n", public_bcb->NodeTypeCode); \
193 ok(public_bcb->NodeByteSize == 0, "Invalid size: %d\n", public_bcb->NodeByteSize); \
194 ok_eq_ulong(public_bcb->MappedLength, (L)); \
195 ok_eq_longlong(public_bcb->MappedFileOffset.QuadPart, (O)); \
196 }
197
198 static
199 VOID
200 NTAPI
PinInAnotherThread(IN PVOID Context)201 PinInAnotherThread(IN PVOID Context)
202 {
203 BOOLEAN Ret;
204 PULONG Buffer;
205 PVOID Bcb;
206 LARGE_INTEGER Offset;
207 PTEST_CONTEXT TestContext;
208
209 ok(TestFileObject != NULL, "Called in invalid context!\n");
210 ok_eq_ulong(TestTestId, 3);
211
212 TestContext = Context;
213 ok(TestContext != NULL, "Called in invalid context!\n");
214 ok(TestContext->Bcb != NULL, "Called in invalid context!\n");
215 ok(TestContext->Buffer != NULL, "Called in invalid context!\n");
216 ok(TestContext->Length != 0, "Called in invalid context!\n");
217
218 Ret = FALSE;
219 Offset.QuadPart = 0x1000;
220 KmtStartSeh();
221 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
222 KmtEndSeh(STATUS_SUCCESS);
223
224 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
225 {
226 ok_bcb(Bcb, 12288, Offset.QuadPart);
227 ok_eq_pointer(Bcb, TestContext->Bcb);
228 ok_eq_pointer(Buffer, TestContext->Buffer);
229
230 CcUnpinData(Bcb);
231 }
232
233 KmtStartSeh();
234 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_WAIT | PIN_IF_BCB, &Bcb, (PVOID *)&Buffer);
235 KmtEndSeh(STATUS_SUCCESS);
236
237 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
238 {
239 ok_bcb(Bcb, 12288, Offset.QuadPart);
240 ok_eq_pointer(Bcb, TestContext->Bcb);
241 ok_eq_pointer(Buffer, TestContext->Buffer);
242
243 CcUnpinData(Bcb);
244 }
245
246 KmtStartSeh();
247 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_EXCLUSIVE, &Bcb, (PVOID *)&Buffer);
248 KmtEndSeh(STATUS_SUCCESS);
249
250 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
251 {
252 ok_bcb(Bcb, 12288, Offset.QuadPart);
253 ok_eq_pointer(Bcb, TestContext->Bcb);
254 ok_eq_pointer(Buffer, TestContext->Buffer);
255
256 CcUnpinData(Bcb);
257 }
258
259 KmtStartSeh();
260 Ret = CcMapData(TestFileObject, &Offset, TestContext->Length, MAP_WAIT, &Bcb, (PVOID *)&Buffer);
261 KmtEndSeh(STATUS_SUCCESS);
262
263 if (!skip(Ret == TRUE, "CcMapData failed\n"))
264 {
265 ok(Bcb != TestContext->Bcb, "Returned same BCB!\n");
266 ok_eq_pointer(Buffer, TestContext->Buffer);
267
268 CcUnpinData(Bcb);
269 }
270
271 Offset.QuadPart = 0x1500;
272 TestContext->Length -= 0x500;
273
274 KmtStartSeh();
275 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_WAIT | PIN_IF_BCB, &Bcb, (PVOID *)&Buffer);
276 KmtEndSeh(STATUS_SUCCESS);
277
278 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
279 {
280 ok_bcb(Bcb, 12288, 4096);
281 ok_eq_pointer(Bcb, TestContext->Bcb);
282 ok_eq_pointer(Buffer, (PVOID)((ULONG_PTR)TestContext->Buffer + 0x500));
283
284 CcUnpinData(Bcb);
285 }
286
287 KmtStartSeh();
288 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
289 KmtEndSeh(STATUS_SUCCESS);
290
291 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
292 {
293 ok_bcb(Bcb, 12288, 4096);
294 ok_eq_pointer(Bcb, TestContext->Bcb);
295 ok_eq_pointer(Buffer, (PVOID)((ULONG_PTR)TestContext->Buffer + 0x500));
296
297 CcUnpinData(Bcb);
298 }
299
300 KmtStartSeh();
301 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_EXCLUSIVE, &Bcb, (PVOID *)&Buffer);
302 KmtEndSeh(STATUS_SUCCESS);
303
304 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
305 {
306 ok_bcb(Bcb, 12288, 4096);
307 ok_eq_pointer(Bcb, TestContext->Bcb);
308 ok_eq_pointer(Buffer, (PVOID)((ULONG_PTR)TestContext->Buffer + 0x500));
309
310 CcUnpinData(Bcb);
311 }
312
313 return;
314 }
315
316 static
317 VOID
318 NTAPI
PinInAnotherThreadExclusive(IN PVOID Context)319 PinInAnotherThreadExclusive(IN PVOID Context)
320 {
321 BOOLEAN Ret;
322 PULONG Buffer;
323 PVOID Bcb;
324 LARGE_INTEGER Offset;
325 PTEST_CONTEXT TestContext;
326
327 ok(TestFileObject != NULL, "Called in invalid context!\n");
328 ok_eq_ulong(TestTestId, 3);
329
330 TestContext = Context;
331 ok(TestContext != NULL, "Called in invalid context!\n");
332 ok(TestContext->Bcb != NULL, "Called in invalid context!\n");
333 ok(TestContext->Buffer != NULL, "Called in invalid context!\n");
334 ok(TestContext->Length != 0, "Called in invalid context!\n");
335
336 Ret = FALSE;
337 Offset.QuadPart = 0x1000;
338 KmtStartSeh();
339 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_EXCLUSIVE, &Bcb, (PVOID *)&Buffer);
340 KmtEndSeh(STATUS_SUCCESS);
341 ok(Ret == FALSE, "CcPinRead succeed\n");
342
343 if (Ret)
344 {
345 CcUnpinData(Bcb);
346 }
347
348 KmtStartSeh();
349 Ret = CcMapData(TestFileObject, &Offset, TestContext->Length, 0, &Bcb, (PVOID *)&Buffer);
350 KmtEndSeh(STATUS_SUCCESS);
351
352 if (!skip(Ret == TRUE, "CcMapData failed\n"))
353 {
354 ok(Bcb != TestContext->Bcb, "Returned same BCB!\n");
355 ok_eq_pointer(Buffer, TestContext->Buffer);
356
357 CcUnpinData(Bcb);
358 }
359
360 Offset.QuadPart = 0x1500;
361 TestContext->Length -= 0x500;
362
363 KmtStartSeh();
364 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_IF_BCB, &Bcb, (PVOID *)&Buffer);
365 KmtEndSeh(STATUS_SUCCESS);
366 ok(Ret == FALSE, "CcPinRead succeed\n");
367
368 if (Ret)
369 {
370 CcUnpinData(Bcb);
371 }
372
373 KmtStartSeh();
374 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, 0, &Bcb, (PVOID *)&Buffer);
375 KmtEndSeh(STATUS_SUCCESS);
376 ok(Ret == FALSE, "CcPinRead succeed\n");
377
378 if (Ret)
379 {
380 CcUnpinData(Bcb);
381 }
382
383 KmtStartSeh();
384 Ret = CcMapData(TestFileObject, &Offset, TestContext->Length, 0, &Bcb, (PVOID *)&Buffer);
385 KmtEndSeh(STATUS_SUCCESS);
386
387 if (!skip(Ret == TRUE, "CcMapData failed\n"))
388 {
389 ok(Bcb != TestContext->Bcb, "Returned same BCB!\n");
390 ok_eq_pointer(Buffer, (PVOID)((ULONG_PTR)TestContext->Buffer + 0x500));
391
392 CcUnpinData(Bcb);
393 }
394
395 return;
396 }
397
398 static
399 VOID
PerformTest(ULONG TestId,PDEVICE_OBJECT DeviceObject)400 PerformTest(
401 ULONG TestId,
402 PDEVICE_OBJECT DeviceObject)
403 {
404 PVOID Bcb;
405 BOOLEAN Ret;
406 PULONG Buffer;
407 PTEST_FCB Fcb;
408 LARGE_INTEGER Offset;
409
410 ok_eq_pointer(TestFileObject, NULL);
411 ok_eq_pointer(TestDeviceObject, NULL);
412 ok_eq_ulong(TestTestId, -1);
413
414 TestDeviceObject = DeviceObject;
415 TestTestId = TestId;
416 TestFileObject = IoCreateStreamFileObject(NULL, DeviceObject);
417 if (!skip(TestFileObject != NULL, "Failed to allocate FO\n"))
418 {
419 Fcb = ExAllocatePool(NonPagedPool, sizeof(TEST_FCB));
420 if (!skip(Fcb != NULL, "ExAllocatePool failed\n"))
421 {
422 BOOLEAN PinAccess = (TestId != 4);
423
424 RtlZeroMemory(Fcb, sizeof(TEST_FCB));
425 ExInitializeFastMutex(&Fcb->HeaderMutex);
426 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
427
428 TestFileObject->FsContext = Fcb;
429 TestFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
430
431 KmtStartSeh();
432 if (TestId < 6)
433 {
434 CcInitializeCacheMap(TestFileObject, &FileSizes, PinAccess, &Callbacks, NULL);
435 }
436 else
437 {
438 CcInitializeCacheMap(TestFileObject, &SmallFileSizes, PinAccess, &Callbacks, NULL);
439 }
440 KmtEndSeh(STATUS_SUCCESS);
441
442 if (!skip(CcIsFileCached(TestFileObject) == TRUE, "CcInitializeCacheMap failed\n"))
443 {
444 if (TestId < 3)
445 {
446 Ret = FALSE;
447 Offset.QuadPart = TestId * 0x1000;
448 KmtStartSeh();
449 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
450 KmtEndSeh(STATUS_SUCCESS);
451
452 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
453 {
454 ok_bcb(Bcb, ((4 - TestId) * 4096), Offset.QuadPart);
455 ok_eq_ulong(Buffer[(0x3000 - TestId * 0x1000) / sizeof(ULONG)], 0xDEADBABE);
456
457 CcUnpinData(Bcb);
458 }
459 }
460 else if (TestId == 3)
461 {
462 PTEST_CONTEXT TestContext;
463
464 TestContext = ExAllocatePool(NonPagedPool, sizeof(TEST_CONTEXT));
465 if (!skip(TestContext != NULL, "ExAllocatePool failed\n"))
466 {
467 Ret = FALSE;
468 Offset.QuadPart = 0x1000;
469
470 /* Try enforce BCB first */
471 KmtStartSeh();
472 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT | PIN_IF_BCB, &Bcb, (PVOID *)&Buffer);
473 KmtEndSeh(STATUS_SUCCESS);
474 ok(Ret == FALSE, "CcPinRead succeed\n");
475 if (Ret)
476 {
477 CcUnpinData(Bcb);
478 }
479
480 KmtStartSeh();
481 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT, &TestContext->Bcb, &TestContext->Buffer);
482 KmtEndSeh(STATUS_SUCCESS);
483
484 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
485 {
486 PKTHREAD ThreadHandle;
487
488 ok_bcb(TestContext->Bcb, 12288, Offset.QuadPart);
489
490 /* That's a bit rough but should do the job */
491 #ifdef _X86_
492 if (Memory >= 2 * 1024)
493 {
494 ok((TestContext->Buffer >= (PVOID)0xC1000000 && TestContext->Buffer < (PVOID)0xE0FFFFFF) ||
495 (TestContext->Buffer >= (PVOID)0xA4000000 && TestContext->Buffer < (PVOID)0xBFFFFFFF),
496 "Buffer %p not mapped in system space\n", TestContext->Buffer);
497 }
498 else if (TS)
499 {
500 ok(TestContext->Buffer >= (PVOID)0xC1000000 && TestContext->Buffer < (PVOID)0xDCFFFFFF,
501 "Buffer %p not mapped in system space\n", TestContext->Buffer);
502 }
503 else
504 {
505 ok(TestContext->Buffer >= (PVOID)0xC1000000 && TestContext->Buffer < (PVOID)0xDBFFFFFF,
506 "Buffer %p not mapped in system space\n", TestContext->Buffer);
507 }
508 #elif defined(_M_AMD64)
509 ok(TestContext->Buffer >= (PVOID)0xFFFFF98000000000 && TestContext->Buffer < (PVOID)0xFFFFFA8000000000,
510 "Buffer %p not mapped in system space\n", TestContext->Buffer);
511 #else
512 skip(FALSE, "System space mapping not defined\n");
513 #endif
514
515 TestContext->Length = FileSizes.FileSize.QuadPart - Offset.QuadPart;
516 ThreadHandle = KmtStartThread(PinInAnotherThread, TestContext);
517 KmtFinishThread(ThreadHandle, NULL);
518
519 TestContext->Length = FileSizes.FileSize.QuadPart - 2 * Offset.QuadPart;
520 ThreadHandle = KmtStartThread(PinInAnotherThread, TestContext);
521 KmtFinishThread(ThreadHandle, NULL);
522
523 CcUnpinData(TestContext->Bcb);
524 }
525
526 KmtStartSeh();
527 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT | PIN_EXCLUSIVE, &TestContext->Bcb, &TestContext->Buffer);
528 KmtEndSeh(STATUS_SUCCESS);
529
530 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
531 {
532 PKTHREAD ThreadHandle;
533
534 ok_bcb(TestContext->Bcb, 12288, Offset.QuadPart);
535
536 TestContext->Length = FileSizes.FileSize.QuadPart - Offset.QuadPart;
537 ThreadHandle = KmtStartThread(PinInAnotherThreadExclusive, TestContext);
538 KmtFinishThread(ThreadHandle, NULL);
539
540 CcUnpinData(TestContext->Bcb);
541 }
542
543 ExFreePool(TestContext);
544 }
545 }
546 else if (TestId == 4)
547 {
548 Ret = FALSE;
549 Offset.QuadPart = 0x1000;
550 KmtStartSeh();
551 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
552 KmtEndSeh(STATUS_SUCCESS);
553
554 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
555 {
556 ok_bcb(Bcb, 12288, Offset.QuadPart);
557 ok_eq_ulong(Buffer[0x2000 / sizeof(ULONG)], 0);
558
559 CcUnpinData(Bcb);
560 }
561 }
562 else if (TestId == 5)
563 {
564 FileSizes.AllocationSize.QuadPart += VACB_MAPPING_GRANULARITY;
565 CcSetFileSizes(TestFileObject, &FileSizes);
566
567 /* Pin after EOF */
568 Ret = FALSE;
569 Offset.QuadPart = FileSizes.FileSize.QuadPart + 0x1000;
570
571 KmtStartSeh();
572 Ret = CcPinRead(TestFileObject, &Offset, 0x1000, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
573 KmtEndSeh(STATUS_SUCCESS);
574 ok(Ret == TRUE, "CcPinRead failed\n");
575 if (Ret)
576 {
577 CcUnpinData(Bcb);
578 }
579
580 /* Pin a VACB after EOF */
581 Ret = FALSE;
582 Offset.QuadPart = FileSizes.FileSize.QuadPart + 0x1000 + VACB_MAPPING_GRANULARITY;
583
584 KmtStartSeh();
585 Ret = CcPinRead(TestFileObject, &Offset, 0x1000, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
586 KmtEndSeh(STATUS_SUCCESS);
587 ok(Ret == TRUE, "CcPinRead failed\n");
588 if (Ret)
589 {
590 CcUnpinData(Bcb);
591 }
592
593 /* Pin after Allocation */
594 Ret = FALSE;
595 Offset.QuadPart = FileSizes.AllocationSize.QuadPart + 0x1000;
596
597 KmtStartSeh();
598 Ret = CcPinRead(TestFileObject, &Offset, 0x1000, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
599 KmtEndSeh(STATUS_SUCCESS);
600 ok(Ret == TRUE, "CcPinRead failed\n");
601 if (Ret)
602 {
603 /* Set this one dirty */
604 CcSetDirtyPinnedData(Bcb, NULL);
605
606 CcUnpinData(Bcb);
607
608 WriteOffset.QuadPart = -1LL;
609 WriteLength = MAXULONG;
610 /* Flush to trigger the write */
611 CcFlushCache(TestFileObject->SectionObjectPointer, &Offset, 0x1000, NULL);
612
613 ok_eq_longlong(WriteOffset.QuadPart, Offset.QuadPart);
614 ok_eq_ulong(WriteLength, 0x1000);
615 }
616
617 /* Pin a VACB after Allocation */
618 Ret = FALSE;
619 Offset.QuadPart = FileSizes.AllocationSize.QuadPart + 0x1000 + VACB_MAPPING_GRANULARITY;
620
621 KmtStartSeh();
622 Ret = CcPinRead(TestFileObject, &Offset, 0x1000, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
623 KmtEndSeh(STATUS_SUCCESS);
624 ok(Ret == TRUE, "CcPinRead failed\n");
625 if (Ret)
626 {
627 /* Set this one dirty */
628 CcSetDirtyPinnedData(Bcb, NULL);
629
630 CcUnpinData(Bcb);
631
632 WriteOffset.QuadPart = -1LL;
633 WriteLength = MAXULONG;
634 /* Flush to trigger the write */
635 CcFlushCache(TestFileObject->SectionObjectPointer, &Offset, 0x1000, NULL);
636
637 ok_eq_longlong(WriteOffset.QuadPart, Offset.QuadPart);
638 ok_eq_ulong(WriteLength, 0x1000);
639 }
640
641 /* Pin more than a VACB */
642 Ret = FALSE;
643 Offset.QuadPart = 0x0;
644
645 KmtStartSeh();
646 Ret = CcPinRead(TestFileObject, &Offset, 0x1000 + VACB_MAPPING_GRANULARITY, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
647 KmtEndSeh(STATUS_SUCCESS);
648 ok(Ret == TRUE, "CcPinRead failed\n");
649 if (Ret)
650 {
651 /* Set this one dirty */
652 CcSetDirtyPinnedData(Bcb, NULL);
653
654 CcUnpinData(Bcb);
655
656 /* The data is dirtified through the VACB */
657 WriteOffset.QuadPart = -1LL;
658 WriteLength = MAXULONG;
659 CcFlushCache(TestFileObject->SectionObjectPointer, &Offset, VACB_MAPPING_GRANULARITY + 0x1000, NULL);
660
661 ok_eq_longlong(WriteOffset.QuadPart, Offset.QuadPart);
662 ok_eq_ulong(WriteLength, VACB_MAPPING_GRANULARITY + 0x1000);
663 }
664 }
665 else if (TestId == 6)
666 {
667 Ret = FALSE;
668 Offset.QuadPart = 0;
669
670 KmtStartSeh();
671 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart, PIN_WAIT, &Bcb, (PVOID *)&Buffer);
672 KmtEndSeh(STATUS_SUCCESS);
673
674 if (!skip(Ret == TRUE, "CcPinRead failed\n"))
675 {
676 ok_bcb(Bcb, PAGE_SIZE * 4, Offset.QuadPart);
677 RtlFillMemory(Buffer, 0xbd, FileSizes.FileSize.LowPart);
678 CcSetDirtyPinnedData(Bcb, NULL);
679
680 CcUnpinData(Bcb);
681 }
682 }
683 }
684 }
685 }
686 }
687
688
689 static
690 VOID
CleanupTest(ULONG TestId,PDEVICE_OBJECT DeviceObject)691 CleanupTest(
692 ULONG TestId,
693 PDEVICE_OBJECT DeviceObject)
694 {
695 LARGE_INTEGER Zero = RTL_CONSTANT_LARGE_INTEGER(0LL);
696 CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
697
698 ok_eq_pointer(TestDeviceObject, DeviceObject);
699 ok_eq_ulong(TestTestId, TestId);
700
701 if (!skip(TestFileObject != NULL, "No test FO\n"))
702 {
703 if (CcIsFileCached(TestFileObject))
704 {
705 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
706 CcUninitializeCacheMap(TestFileObject, &Zero, &CacheUninitEvent);
707 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
708 }
709
710 if (TestFileObject->FsContext != NULL)
711 {
712 ExFreePool(TestFileObject->FsContext);
713 TestFileObject->FsContext = NULL;
714 TestFileObject->SectionObjectPointer = NULL;
715 }
716
717 if (TestTestId == 6)
718 {
719 ok_bool_true(TestWriteCalled, "Write was not called!\n");
720 }
721 else
722 {
723 ok_bool_false(TestWriteCalled, "Write was unexpectedly called\n");
724 }
725
726 ObDereferenceObject(TestFileObject);
727 }
728
729 TestFileObject = NULL;
730 TestDeviceObject = NULL;
731 TestTestId = -1;
732 TestWriteCalled = FALSE;
733 }
734
735
736 static
737 NTSTATUS
TestMessageHandler(_In_ PDEVICE_OBJECT DeviceObject,_In_ ULONG ControlCode,_In_opt_ PVOID Buffer,_In_ SIZE_T InLength,_Inout_ PSIZE_T OutLength)738 TestMessageHandler(
739 _In_ PDEVICE_OBJECT DeviceObject,
740 _In_ ULONG ControlCode,
741 _In_opt_ PVOID Buffer,
742 _In_ SIZE_T InLength,
743 _Inout_ PSIZE_T OutLength)
744 {
745 NTSTATUS Status = STATUS_SUCCESS;
746
747 FsRtlEnterFileSystem();
748
749 switch (ControlCode)
750 {
751 case IOCTL_START_TEST:
752 ok_eq_ulong((ULONG)InLength, sizeof(ULONG));
753 PerformTest(*(PULONG)Buffer, DeviceObject);
754 break;
755
756 case IOCTL_FINISH_TEST:
757 ok_eq_ulong((ULONG)InLength, sizeof(ULONG));
758 CleanupTest(*(PULONG)Buffer, DeviceObject);
759 break;
760
761 default:
762 Status = STATUS_NOT_IMPLEMENTED;
763 break;
764 }
765
766 FsRtlExitFileSystem();
767
768 return Status;
769 }
770
771 static
772 NTSTATUS
TestIrpHandler(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp,_In_ PIO_STACK_LOCATION IoStack)773 TestIrpHandler(
774 _In_ PDEVICE_OBJECT DeviceObject,
775 _In_ PIRP Irp,
776 _In_ PIO_STACK_LOCATION IoStack)
777 {
778 NTSTATUS Status;
779
780 PAGED_CODE();
781
782 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction);
783 ASSERT(IoStack->MajorFunction == IRP_MJ_READ ||
784 IoStack->MajorFunction == IRP_MJ_WRITE);
785
786 FsRtlEnterFileSystem();
787
788 Status = STATUS_NOT_SUPPORTED;
789 Irp->IoStatus.Information = 0;
790
791 if (IoStack->MajorFunction == IRP_MJ_READ)
792 {
793 PMDL Mdl;
794 ULONG Length;
795 PVOID Buffer;
796 LARGE_INTEGER Offset;
797
798 Offset = IoStack->Parameters.Read.ByteOffset;
799 Length = IoStack->Parameters.Read.Length;
800
801 ok_eq_pointer(DeviceObject, TestDeviceObject);
802 ok_eq_pointer(IoStack->FileObject, TestFileObject);
803
804 ok(FlagOn(Irp->Flags, IRP_NOCACHE), "Not coming from Cc\n");
805
806 ok_irql(APC_LEVEL);
807 ok((Offset.QuadPart % PAGE_SIZE == 0 || Offset.QuadPart == 0), "Offset is not aligned: %I64i\n", Offset.QuadPart);
808 ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length);
809
810 ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n");
811 Buffer = MapAndLockUserBuffer(Irp, Length);
812 ok(Buffer != NULL, "Null pointer!\n");
813 RtlFillMemory(Buffer, Length, 0xBA);
814
815 Status = STATUS_SUCCESS;
816 if (Offset.QuadPart <= 0x3000 && Offset.QuadPart + Length > 0x3000)
817 {
818 *(PULONG)((ULONG_PTR)Buffer + (ULONG_PTR)(0x3000 - Offset.QuadPart)) = 0xDEADBABE;
819 }
820
821 Mdl = Irp->MdlAddress;
822 ok(Mdl != NULL, "Null pointer for MDL!\n");
823 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n");
824 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n");
825 ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0, "Non paging IO\n");
826 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n");
827
828 Irp->IoStatus.Information = Length;
829 }
830 else if (IoStack->MajorFunction == IRP_MJ_WRITE)
831 {
832 PMDL Mdl;
833 ULONG Length;
834 PVOID Buffer;
835 LARGE_INTEGER Offset;
836
837 Offset = IoStack->Parameters.Write.ByteOffset;
838 Length = IoStack->Parameters.Write.Length;
839
840 ok((TestTestId == 5) || (TestTestId == 6), "Unexpected test id: %d\n", TestTestId);
841 ok_eq_pointer(DeviceObject, TestDeviceObject);
842 ok_eq_pointer(IoStack->FileObject, TestFileObject);
843
844 ok(FlagOn(Irp->Flags, IRP_NOCACHE), "Not coming from Cc\n");
845
846 ok_irql(PASSIVE_LEVEL);
847
848 if (TestTestId == 5)
849 {
850 /* This assumes continuous writes. */
851 if (WriteOffset.QuadPart != -1)
852 {
853 LONGLONG WriteEnd = WriteOffset.QuadPart + WriteLength;
854
855 if (WriteOffset.QuadPart > Offset.QuadPart)
856 WriteOffset = Offset;
857 if (WriteEnd < (Offset.QuadPart + Length))
858 WriteLength = (Offset.QuadPart + Length) - WriteOffset.QuadPart;
859 }
860 else
861 {
862 WriteOffset = Offset;
863 WriteLength = Length;
864 }
865 }
866 else
867 {
868 ok(Offset.QuadPart == 0, "Offset is not null: %I64i\n", Offset.QuadPart);
869 ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length);
870 ok(Length == PAGE_SIZE * 4, "Length is not MappedLength-sized: %I64i\n", Length);
871
872 Buffer = MapAndLockUserBuffer(Irp, Length);
873 ok(Buffer != NULL, "Null pointer!\n");
874
875 Mdl = Irp->MdlAddress;
876 ok(Mdl != NULL, "Null pointer for MDL!\n");
877 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n");
878 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n");
879 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n");
880
881 ok_bool_false(TestWriteCalled, "Write has been unexpectedly called twice!\n");
882 TestWriteCalled = TRUE;
883 }
884
885 Status = STATUS_SUCCESS;
886 Irp->IoStatus.Information = Length;
887 }
888
889 if (Status == STATUS_PENDING)
890 {
891 IoMarkIrpPending(Irp);
892 IoCompleteRequest(Irp, IO_NO_INCREMENT);
893 Status = STATUS_PENDING;
894 }
895 else
896 {
897 Irp->IoStatus.Status = Status;
898 IoCompleteRequest(Irp, IO_NO_INCREMENT);
899 }
900
901 FsRtlExitFileSystem();
902
903 return Status;
904 }
905