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 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 98 TestUnload( 99 _In_ PDRIVER_OBJECT DriverObject) 100 { 101 PAGED_CODE(); 102 } 103 104 BOOLEAN 105 NTAPI 106 AcquireForLazyWrite( 107 _In_ PVOID Context, 108 _In_ BOOLEAN Wait) 109 { 110 return TRUE; 111 } 112 113 VOID 114 NTAPI 115 ReleaseFromLazyWrite( 116 _In_ PVOID Context) 117 { 118 return; 119 } 120 121 BOOLEAN 122 NTAPI 123 AcquireForReadAhead( 124 _In_ PVOID Context, 125 _In_ BOOLEAN Wait) 126 { 127 return TRUE; 128 } 129 130 VOID 131 NTAPI 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 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 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 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 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 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 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 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