1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 LockCtrl.c 8 9 Abstract: 10 11 This module implements the Lock Control routines for Fat called 12 by the dispatch driver. 13 14 15 --*/ 16 17 #include "fatprocs.h" 18 19 // 20 // The local debug trace level 21 // 22 23 #define Dbg (DEBUG_TRACE_LOCKCTRL) 24 25 #ifdef ALLOC_PRAGMA 26 #pragma alloc_text(PAGE, FatCommonLockControl) 27 #pragma alloc_text(PAGE, FatFastLock) 28 #pragma alloc_text(PAGE, FatFastUnlockAll) 29 #pragma alloc_text(PAGE, FatFastUnlockAllByKey) 30 #pragma alloc_text(PAGE, FatFastUnlockSingle) 31 #pragma alloc_text(PAGE, FatFsdLockControl) 32 #endif 33 34 35 _Function_class_(IRP_MJ_LOCK_CONTROL) 36 _Function_class_(DRIVER_DISPATCH) 37 NTSTATUS 38 NTAPI 39 FatFsdLockControl ( 40 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, 41 _Inout_ PIRP Irp 42 ) 43 44 /*++ 45 46 Routine Description: 47 48 This routine implements the FSD part of Lock control operations 49 50 Arguments: 51 52 VolumeDeviceObject - Supplies the volume device object where the 53 file exists 54 55 Irp - Supplies the Irp being processed 56 57 Return Value: 58 59 NTSTATUS - The FSD status for the IRP 60 61 --*/ 62 63 { 64 NTSTATUS Status; 65 PIRP_CONTEXT IrpContext = NULL; 66 67 BOOLEAN TopLevel; 68 69 PAGED_CODE(); 70 71 DebugTrace(+1, Dbg, "FatFsdLockControl\n", 0); 72 73 // 74 // Call the common Lock Control routine, with blocking allowed if 75 // synchronous 76 // 77 78 FsRtlEnterFileSystem(); 79 80 TopLevel = FatIsIrpTopLevel( Irp ); 81 82 _SEH2_TRY { 83 84 IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) ); 85 86 Status = FatCommonLockControl( IrpContext, Irp ); 87 88 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 89 90 // 91 // We had some trouble trying to perform the requested 92 // operation, so we'll abort the I/O request with 93 // the error status that we get back from the 94 // execption code 95 // 96 97 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); 98 } _SEH2_END; 99 100 if (TopLevel) { IoSetTopLevelIrp( NULL ); } 101 102 FsRtlExitFileSystem(); 103 104 // 105 // And return to our caller 106 // 107 108 DebugTrace(-1, Dbg, "FatFsdLockControl -> %08lx\n", Status); 109 110 UNREFERENCED_PARAMETER( VolumeDeviceObject ); 111 112 return Status; 113 } 114 115 116 _Function_class_(FAST_IO_LOCK) 117 BOOLEAN 118 NTAPI 119 FatFastLock ( 120 IN PFILE_OBJECT FileObject, 121 IN PLARGE_INTEGER FileOffset, 122 IN PLARGE_INTEGER Length, 123 PEPROCESS ProcessId, 124 ULONG Key, 125 BOOLEAN FailImmediately, 126 BOOLEAN ExclusiveLock, 127 OUT PIO_STATUS_BLOCK IoStatus, 128 IN PDEVICE_OBJECT DeviceObject 129 ) 130 131 /*++ 132 133 Routine Description: 134 135 This is a call back routine for doing the fast lock call. 136 137 Arguments: 138 139 FileObject - Supplies the file object used in this operation 140 141 FileOffset - Supplies the file offset used in this operation 142 143 Length - Supplies the length used in this operation 144 145 ProcessId - Supplies the process ID used in this operation 146 147 Key - Supplies the key used in this operation 148 149 FailImmediately - Indicates if the request should fail immediately 150 if the lock cannot be granted. 151 152 ExclusiveLock - Indicates if this is a request for an exclusive or 153 shared lock 154 155 IoStatus - Receives the Status if this operation is successful 156 157 Return Value: 158 159 BOOLEAN - TRUE if this operation completed and FALSE if caller 160 needs to take the long route. 161 162 --*/ 163 164 { 165 BOOLEAN Results = FALSE; 166 PVCB Vcb; 167 PFCB Fcb; 168 PCCB Ccb; 169 170 PAGED_CODE(); 171 UNREFERENCED_PARAMETER( DeviceObject ); 172 173 DebugTrace(+1, Dbg, "FatFastLock\n", 0); 174 175 // 176 // Decode the type of file object we're being asked to process and make 177 // sure it is only a user file open. 178 // 179 180 if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) { 181 182 IoStatus->Status = STATUS_INVALID_PARAMETER; 183 IoStatus->Information = 0; 184 185 DebugTrace(-1, Dbg, "FatFastLock -> TRUE (STATUS_INVALID_PARAMETER)\n", 0); 186 return TRUE; 187 } 188 189 // 190 // Acquire shared access to the Fcb 191 // 192 193 FsRtlEnterFileSystem(); 194 ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE ); 195 196 _SEH2_TRY { 197 198 // 199 // We check whether we can proceed 200 // based on the state of the file oplocks. 201 // 202 203 if (!FsRtlOplockIsFastIoPossible( FatGetFcbOplock(Fcb) )) { 204 205 try_return( Results = FALSE ); 206 } 207 208 // 209 // Now call the FsRtl routine to do the actual processing of the 210 // Lock request 211 // 212 213 #ifdef _MSC_VER 214 #pragma prefast( suppress:28159, "prefast indicates this API is obsolete but it is ok for fastfat to continue using it" ) 215 #endif 216 Results = FsRtlFastLock( &Fcb->Specific.Fcb.FileLock, 217 FileObject, 218 FileOffset, 219 Length, 220 ProcessId, 221 Key, 222 FailImmediately, 223 ExclusiveLock, 224 IoStatus, 225 NULL, 226 FALSE ); 227 228 if (Results) { 229 230 // 231 // Set the flag indicating if Fast I/O is possible 232 // 233 234 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); 235 } 236 237 try_exit: NOTHING; 238 } _SEH2_FINALLY { 239 240 DebugUnwind( FatFastLock ); 241 242 // 243 // Release the Fcb, and return to our caller 244 // 245 246 ExReleaseResourceLite( Fcb->Header.Resource ); 247 FsRtlExitFileSystem(); 248 249 DebugTrace(-1, Dbg, "FatFastLock -> %08lx\n", Results); 250 } _SEH2_END; 251 252 return Results; 253 } 254 255 256 _Function_class_(FAST_IO_UNLOCK_SINGLE) 257 BOOLEAN 258 NTAPI 259 FatFastUnlockSingle ( 260 IN PFILE_OBJECT FileObject, 261 IN PLARGE_INTEGER FileOffset, 262 IN PLARGE_INTEGER Length, 263 PEPROCESS ProcessId, 264 ULONG Key, 265 OUT PIO_STATUS_BLOCK IoStatus, 266 IN PDEVICE_OBJECT DeviceObject 267 ) 268 269 /*++ 270 271 Routine Description: 272 273 This is a call back routine for doing the fast unlock single call. 274 275 Arguments: 276 277 FileObject - Supplies the file object used in this operation 278 279 FileOffset - Supplies the file offset used in this operation 280 281 Length - Supplies the length used in this operation 282 283 ProcessId - Supplies the process ID used in this operation 284 285 Key - Supplies the key used in this operation 286 287 Status - Receives the Status if this operation is successful 288 289 Return Value: 290 291 BOOLEAN - TRUE if this operation completed and FALSE if caller 292 needs to take the long route. 293 294 --*/ 295 296 { 297 BOOLEAN Results = FALSE; 298 PVCB Vcb; 299 PFCB Fcb; 300 PCCB Ccb; 301 302 PAGED_CODE(); 303 UNREFERENCED_PARAMETER( DeviceObject ); 304 305 DebugTrace(+1, Dbg, "FatFastUnlockSingle\n", 0); 306 307 IoStatus->Information = 0; 308 309 // 310 // Decode the type of file object we're being asked to process and make sure 311 // it is only a user file open 312 // 313 314 if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) { 315 316 IoStatus->Status = STATUS_INVALID_PARAMETER; 317 318 DebugTrace(-1, Dbg, "FatFastUnlockSingle -> TRUE (STATUS_INVALID_PARAMETER)\n", 0); 319 return TRUE; 320 } 321 322 // 323 // Acquire exclusive access to the Fcb this operation can always wait 324 // 325 326 FsRtlEnterFileSystem(); 327 328 _SEH2_TRY { 329 330 // 331 // We check whether we can proceed based on the state of the file oplocks. 332 // 333 334 if (!FsRtlOplockIsFastIoPossible( FatGetFcbOplock(Fcb) )) { 335 336 try_return( Results = FALSE ); 337 } 338 339 // 340 // Now call the FsRtl routine to do the actual processing of the 341 // Lock request. The call will always succeed. 342 // 343 344 Results = TRUE; 345 IoStatus->Status = FsRtlFastUnlockSingle( &Fcb->Specific.Fcb.FileLock, 346 FileObject, 347 FileOffset, 348 Length, 349 ProcessId, 350 Key, 351 NULL, 352 FALSE ); 353 354 // 355 // Set the flag indicating if Fast I/O is possible 356 // 357 358 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); 359 360 try_exit: NOTHING; 361 } _SEH2_FINALLY { 362 363 DebugUnwind( FatFastUnlockSingle ); 364 365 // 366 // Release the Fcb, and return to our caller 367 // 368 369 FsRtlExitFileSystem(); 370 371 DebugTrace(-1, Dbg, "FatFastUnlockSingle -> %08lx\n", Results); 372 } _SEH2_END; 373 374 return Results; 375 } 376 377 378 _Function_class_(FAST_IO_UNLOCK_ALL) 379 BOOLEAN 380 NTAPI 381 FatFastUnlockAll ( 382 IN PFILE_OBJECT FileObject, 383 PEPROCESS ProcessId, 384 OUT PIO_STATUS_BLOCK IoStatus, 385 IN PDEVICE_OBJECT DeviceObject 386 ) 387 388 /*++ 389 390 Routine Description: 391 392 This is a call back routine for doing the fast unlock all call. 393 394 Arguments: 395 396 FileObject - Supplies the file object used in this operation 397 398 ProcessId - Supplies the process ID used in this operation 399 400 Status - Receives the Status if this operation is successful 401 402 Return Value: 403 404 BOOLEAN - TRUE if this operation completed and FALSE if caller 405 needs to take the long route. 406 407 --*/ 408 409 { 410 BOOLEAN Results = FALSE; 411 PVCB Vcb; 412 PFCB Fcb; 413 PCCB Ccb; 414 415 PAGED_CODE(); 416 UNREFERENCED_PARAMETER( DeviceObject ); 417 418 DebugTrace(+1, Dbg, "FatFastUnlockAll\n", 0); 419 420 IoStatus->Information = 0; 421 422 // 423 // Decode the type of file object we're being asked to process and make sure 424 // it is only a user file open. 425 // 426 427 if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) { 428 429 IoStatus->Status = STATUS_INVALID_PARAMETER; 430 431 DebugTrace(-1, Dbg, "FatFastUnlockAll -> TRUE (STATUS_INVALID_PARAMETER)\n", 0); 432 return TRUE; 433 } 434 435 // 436 // Acquire exclusive access to the Fcb this operation can always wait 437 // 438 439 FsRtlEnterFileSystem(); 440 441 (VOID) ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE ); 442 443 _SEH2_TRY { 444 445 // 446 // We check whether we can proceed based on the state of the file oplocks. 447 // 448 449 if (!FsRtlOplockIsFastIoPossible( FatGetFcbOplock(Fcb) )) { 450 451 try_return( Results = FALSE ); 452 } 453 454 // 455 // Now call the FsRtl routine to do the actual processing of the 456 // Lock request. The call will always succeed. 457 // 458 459 Results = TRUE; 460 IoStatus->Status = FsRtlFastUnlockAll( &Fcb->Specific.Fcb.FileLock, 461 FileObject, 462 ProcessId, 463 NULL ); 464 465 // 466 // Set the flag indicating if Fast I/O is possible 467 // 468 469 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); 470 471 try_exit: NOTHING; 472 } _SEH2_FINALLY { 473 474 DebugUnwind( FatFastUnlockAll ); 475 476 // 477 // Release the Fcb, and return to our caller 478 // 479 480 ExReleaseResourceLite( (Fcb)->Header.Resource ); 481 482 FsRtlExitFileSystem(); 483 484 DebugTrace(-1, Dbg, "FatFastUnlockAll -> %08lx\n", Results); 485 } _SEH2_END; 486 487 return Results; 488 } 489 490 491 _Function_class_(FAST_IO_UNLOCK_ALL_BY_KEY) 492 BOOLEAN 493 NTAPI 494 FatFastUnlockAllByKey ( 495 IN PFILE_OBJECT FileObject, 496 PVOID ProcessId, 497 ULONG Key, 498 OUT PIO_STATUS_BLOCK IoStatus, 499 IN PDEVICE_OBJECT DeviceObject 500 ) 501 502 /*++ 503 504 Routine Description: 505 506 This is a call back routine for doing the fast unlock all by key call. 507 508 Arguments: 509 510 FileObject - Supplies the file object used in this operation 511 512 ProcessId - Supplies the process ID used in this operation 513 514 Key - Supplies the key used in this operation 515 516 Status - Receives the Status if this operation is successful 517 518 Return Value: 519 520 BOOLEAN - TRUE if this operation completed and FALSE if caller 521 needs to take the long route. 522 523 --*/ 524 525 { 526 BOOLEAN Results = FALSE; 527 PVCB Vcb; 528 PFCB Fcb; 529 PCCB Ccb; 530 531 PAGED_CODE(); 532 UNREFERENCED_PARAMETER( DeviceObject ); 533 534 DebugTrace(+1, Dbg, "FatFastUnlockAllByKey\n", 0); 535 536 IoStatus->Information = 0; 537 538 // 539 // Decode the type of file object we're being asked to process and make sure 540 // it is only a user file open. 541 // 542 543 if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) { 544 545 IoStatus->Status = STATUS_INVALID_PARAMETER; 546 547 DebugTrace(-1, Dbg, "FatFastUnlockAll -> TRUE (STATUS_INVALID_PARAMETER)\n", 0); 548 return TRUE; 549 } 550 551 // 552 // Acquire exclusive access to the Fcb this operation can always wait 553 // 554 555 FsRtlEnterFileSystem(); 556 557 (VOID) ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE ); 558 559 _SEH2_TRY { 560 561 // 562 // We check whether we can proceed based on the state of the file oplocks. 563 // 564 565 if (!FsRtlOplockIsFastIoPossible( FatGetFcbOplock(Fcb) )) { 566 567 try_return( Results = FALSE ); 568 } 569 570 // 571 // Now call the FsRtl routine to do the actual processing of the 572 // Lock request. The call will always succeed. 573 // 574 575 Results = TRUE; 576 IoStatus->Status = FsRtlFastUnlockAllByKey( &Fcb->Specific.Fcb.FileLock, 577 FileObject, 578 ProcessId, 579 Key, 580 NULL ); 581 582 // 583 // Set the flag indicating if Fast I/O is possible 584 // 585 586 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); 587 588 try_exit: NOTHING; 589 } _SEH2_FINALLY { 590 591 DebugUnwind( FatFastUnlockAllByKey ); 592 593 // 594 // Release the Fcb, and return to our caller 595 // 596 597 ExReleaseResourceLite( (Fcb)->Header.Resource ); 598 599 FsRtlExitFileSystem(); 600 601 DebugTrace(-1, Dbg, "FatFastUnlockAllByKey -> %08lx\n", Results); 602 } _SEH2_END; 603 604 return Results; 605 } 606 607 608 _Requires_lock_held_(_Global_critical_region_) 609 NTSTATUS 610 FatCommonLockControl ( 611 IN PIRP_CONTEXT IrpContext, 612 IN PIRP Irp 613 ) 614 615 /*++ 616 617 Routine Description: 618 619 This is the common routine for doing Lock control operations called 620 by both the fsd and fsp threads 621 622 Arguments: 623 624 Irp - Supplies the Irp to process 625 626 Return Value: 627 628 NTSTATUS - The return status for the operation 629 630 --*/ 631 632 { 633 NTSTATUS Status = STATUS_SUCCESS; 634 PIO_STACK_LOCATION IrpSp; 635 636 TYPE_OF_OPEN TypeOfOpen; 637 638 PVCB Vcb; 639 PFCB Fcb; 640 PCCB Ccb; 641 642 BOOLEAN OplockPostIrp = FALSE; 643 644 PAGED_CODE(); 645 646 // 647 // Get a pointer to the current Irp stack location 648 // 649 650 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 651 652 DebugTrace(+1, Dbg, "FatCommonLockControl\n", 0); 653 DebugTrace( 0, Dbg, "Irp = %p\n", Irp); 654 DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction); 655 656 // 657 // Decode the type of file object we're being asked to process 658 // 659 660 TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ); 661 662 // 663 // If the file is not a user file open then we reject the request 664 // as an invalid parameter 665 // 666 667 if (TypeOfOpen != UserFileOpen) { 668 669 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 670 671 DebugTrace(-1, Dbg, "FatCommonLockControl -> STATUS_INVALID_PARAMETER\n", 0); 672 return STATUS_INVALID_PARAMETER; 673 } 674 675 // 676 // Acquire exclusive access to the Fcb and enqueue the Irp if we didn't 677 // get access 678 // 679 680 if (!FatAcquireSharedFcb( IrpContext, Fcb )) { 681 682 Status = FatFsdPostRequest( IrpContext, Irp ); 683 684 DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status); 685 return Status; 686 } 687 688 _SEH2_TRY { 689 690 // 691 // We check whether we can proceed 692 // based on the state of the file oplocks. 693 // 694 695 #if (NTDDI_VERSION >= NTDDI_WIN8) 696 697 if (((IRP_MN_LOCK == IrpSp->MinorFunction) && 698 ((ULONGLONG)IrpSp->Parameters.LockControl.ByteOffset.QuadPart < 699 (ULONGLONG)Fcb->Header.AllocationSize.QuadPart)) || 700 ((IRP_MN_LOCK != IrpSp->MinorFunction) && 701 FsRtlAreThereWaitingFileLocks( &Fcb->Specific.Fcb.FileLock ))) { 702 703 // 704 // Check whether we can proceed based on the state of file oplocks if doing 705 // an operation that interferes with oplocks. Those operations are: 706 // 707 // 1. Lock a range within the file's AllocationSize. 708 // 2. Unlock a range when there are waiting locks on the file. This one 709 // is not guaranteed to interfere with oplocks, but it could, as 710 // unlocking this range might cause a waiting lock to be granted 711 // within AllocationSize! 712 // 713 714 #endif 715 Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb), 716 Irp, 717 IrpContext, 718 FatOplockComplete, 719 NULL ); 720 721 #if (NTDDI_VERSION >= NTDDI_WIN8) 722 } 723 #endif 724 725 if (Status != STATUS_SUCCESS) { 726 727 OplockPostIrp = TRUE; 728 try_return( NOTHING ); 729 } 730 731 // 732 // Now call the FsRtl routine to do the actual processing of the 733 // Lock request 734 // 735 736 Status = FsRtlProcessFileLock( &Fcb->Specific.Fcb.FileLock, Irp, NULL ); 737 738 // 739 // Set the flag indicating if Fast I/O is possible 740 // 741 742 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); 743 744 try_exit: NOTHING; 745 } _SEH2_FINALLY { 746 747 DebugUnwind( FatCommonLockControl ); 748 749 // 750 // Only if this is not an abnormal termination do we delete the 751 // irp context 752 // 753 754 if (!_SEH2_AbnormalTermination() && !OplockPostIrp) { 755 756 FatCompleteRequest( IrpContext, FatNull, 0 ); 757 } 758 759 // 760 // Release the Fcb, and return to our caller 761 // 762 763 FatReleaseFcb( IrpContext, Fcb ); 764 765 DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status); 766 } _SEH2_END; 767 768 return Status; 769 } 770 771