1 //////////////////////////////////////////////////////////////////// 2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine 3 // All rights reserved 4 // This file was released under the GPLv2 on June 2015. 5 //////////////////////////////////////////////////////////////////// 6 /************************************************************************* 7 * 8 * File: LockCtrl.cpp.cpp 9 * 10 * Module: UDF File System Driver (Kernel mode execution only) 11 * 12 * Description: 13 * Contains code to handle the "byte-range locking" dispatch entry point. 14 * 15 *************************************************************************/ 16 17 #include "udffs.h" 18 19 // define the file specific bug-check id 20 #define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN 21 22 23 /************************************************************************* 24 * 25 * Function: UDFLockControl() 26 * 27 * Description: 28 * 29 * Expected Interrupt Level (for execution) : 30 * 31 * IRQL_PASSIVE_LEVEL 32 * 33 * Return Value: Irrelevant. 34 * 35 *************************************************************************/ 36 NTSTATUS 37 NTAPI 38 UDFLockControl( 39 IN PDEVICE_OBJECT DeviceObject, // the logical volume device object 40 IN PIRP Irp) // I/O Request Packet 41 { 42 NTSTATUS RC = STATUS_SUCCESS; 43 PtrUDFIrpContext PtrIrpContext = NULL; 44 BOOLEAN AreWeTopLevel = FALSE; 45 46 UDFPrint(("UDFLockControl\n")); 47 // BrutePoint(); 48 49 FsRtlEnterFileSystem(); 50 ASSERT(DeviceObject); 51 ASSERT(Irp); 52 53 // set the top level context 54 AreWeTopLevel = UDFIsIrpTopLevel(Irp); 55 // Call the common Lock Control routine, with blocking allowed if 56 // synchronous 57 _SEH2_TRY { 58 59 // get an IRP context structure and issue the request 60 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); 61 if(PtrIrpContext) { 62 RC = UDFCommonLockControl(PtrIrpContext, Irp); 63 } else { 64 RC = STATUS_INSUFFICIENT_RESOURCES; 65 Irp->IoStatus.Status = RC; 66 Irp->IoStatus.Information = 0; 67 // complete the IRP 68 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 69 } 70 71 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { 72 73 RC = UDFExceptionHandler(PtrIrpContext, Irp); 74 75 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); 76 } _SEH2_END; 77 78 if (AreWeTopLevel) { 79 IoSetTopLevelIrp(NULL); 80 } 81 82 FsRtlExitFileSystem(); 83 84 return(RC); 85 } // end UDFLockControl() 86 87 88 /************************************************************************* 89 * 90 * Function: UDFCommonLockControl() 91 * 92 * Description: 93 * This is the common routine for doing Lock control operations called 94 * by both the fsd and fsp threads 95 * 96 * Expected Interrupt Level (for execution) : 97 * 98 * IRQL_PASSIVE_LEVEL 99 * 100 * Return Value: Irrelevant 101 * 102 *************************************************************************/ 103 NTSTATUS 104 NTAPI 105 UDFCommonLockControl( 106 IN PtrUDFIrpContext PtrIrpContext, 107 IN PIRP Irp) 108 { 109 NTSTATUS RC = STATUS_SUCCESS; 110 PIO_STACK_LOCATION IrpSp = NULL; 111 //IO_STATUS_BLOCK LocalIoStatus; 112 // BOOLEAN CompleteRequest = FALSE; 113 BOOLEAN PostRequest = FALSE; 114 BOOLEAN CanWait = FALSE; 115 PtrUDFNTRequiredFCB NtReqFcb = NULL; 116 BOOLEAN AcquiredFCB = FALSE; 117 PFILE_OBJECT FileObject = NULL; 118 PtrUDFFCB Fcb = NULL; 119 PtrUDFCCB Ccb = NULL; 120 121 UDFPrint(("UDFCommonLockControl\n")); 122 123 _SEH2_TRY { 124 // First, get a pointer to the current I/O stack location. 125 IrpSp = IoGetCurrentIrpStackLocation(Irp); 126 ASSERT(IrpSp); 127 128 FileObject = IrpSp->FileObject; 129 ASSERT(FileObject); 130 131 // Get the FCB and CCB pointers. 132 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 133 ASSERT(Ccb); 134 Fcb = Ccb->Fcb; 135 ASSERT(Fcb); 136 // Validate the sent-in FCB 137 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || 138 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { 139 140 // CompleteRequest = TRUE; 141 try_return(RC = STATUS_INVALID_PARAMETER); 142 } 143 144 NtReqFcb = Fcb->NTRequiredFCB; 145 CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); 146 147 // Acquire the FCB resource shared 148 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 149 if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { 150 PostRequest = TRUE; 151 try_return(RC = STATUS_PENDING); 152 } 153 AcquiredFCB = TRUE; 154 155 RC = FsRtlProcessFileLock(&(NtReqFcb->FileLock), Irp, NULL); 156 // CompleteRequest = TRUE; 157 158 try_exit: NOTHING; 159 160 } _SEH2_FINALLY { 161 162 // Release the FCB resources if acquired. 163 if (AcquiredFCB) { 164 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 165 UDFReleaseResource(&(NtReqFcb->MainResource)); 166 AcquiredFCB = FALSE; 167 } 168 if (PostRequest) { 169 // Perform appropriate post related processing here 170 RC = UDFPostRequest(PtrIrpContext, Irp); 171 } else 172 if(!_SEH2_AbnormalTermination()) { 173 // Simply free up the IrpContext since the IRP has been queued or 174 // Completed by FsRtlProcessFileLock 175 UDFReleaseIrpContext(PtrIrpContext); 176 } 177 } _SEH2_END; // end of "__finally" processing 178 179 return(RC); 180 } // end UDFCommonLockControl() 181 182 183 /* 184 Routine Description: 185 This is a call back routine for doing the fast lock call. 186 Arguments: 187 FileObject - Supplies the file object used in this operation 188 FileOffset - Supplies the file offset used in this operation 189 Length - Supplies the length used in this operation 190 ProcessId - Supplies the process ID used in this operation 191 Key - Supplies the key used in this operation 192 FailImmediately - Indicates if the request should fail immediately 193 if the lock cannot be granted. 194 ExclusiveLock - Indicates if this is a request for an exclusive or 195 shared lock 196 IoStatus - Receives the Status if this operation is successful 197 198 Return Value: 199 BOOLEAN - TRUE if this operation completed and FALSE if caller 200 needs to take the long route. 201 */ 202 203 BOOLEAN 204 NTAPI 205 UDFFastLock ( 206 IN PFILE_OBJECT FileObject, 207 IN PLARGE_INTEGER FileOffset, 208 IN PLARGE_INTEGER Length, 209 PEPROCESS ProcessId, 210 ULONG Key, 211 BOOLEAN FailImmediately, 212 BOOLEAN ExclusiveLock, 213 OUT PIO_STATUS_BLOCK IoStatus, 214 IN PDEVICE_OBJECT DeviceObject 215 ) 216 { 217 BOOLEAN Results = FALSE; 218 219 // BOOLEAN AcquiredFCB = FALSE; 220 PtrUDFFCB Fcb = NULL; 221 PtrUDFCCB Ccb = NULL; 222 223 UDFPrint(("UDFFastLock\n")); 224 // Decode the type of file object we're being asked to process and make 225 // sure it is only a user file open. 226 227 228 // Get the FCB and CCB pointers. 229 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 230 ASSERT(Ccb); 231 Fcb = Ccb->Fcb; 232 ASSERT(Fcb); 233 // Validate the sent-in FCB 234 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || 235 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { 236 237 IoStatus->Status = STATUS_INVALID_PARAMETER; 238 IoStatus->Information = 0; 239 return TRUE; 240 } 241 242 // Acquire exclusive access to the Fcb this operation can always wait 243 244 FsRtlEnterFileSystem(); 245 246 // BUGBUG: kenr 247 // (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE ); 248 249 _SEH2_TRY { 250 251 // We check whether we can proceed 252 // based on the state of the file oplocks. 253 254 // Now call the FsRtl routine to do the actual processing of the 255 // Lock request 256 if ((Results = FsRtlFastLock( &(Fcb->NTRequiredFCB->FileLock), 257 FileObject, 258 FileOffset, 259 Length, 260 ProcessId, 261 Key, 262 FailImmediately, 263 ExclusiveLock, 264 IoStatus, 265 NULL, 266 FALSE ))) { 267 268 // Set the flag indicating if Fast I/O is possible 269 Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); 270 } 271 272 //try_exit: NOTHING; 273 } _SEH2_FINALLY { 274 275 // Release the Fcb, and return to our caller 276 277 // BUGBUG: kenr 278 // UDFReleaseResource( (Fcb)->Header.Resource ); 279 280 FsRtlExitFileSystem(); 281 282 } _SEH2_END; 283 284 return Results; 285 } // end UDFFastLock() 286 287 288 /* 289 Routine Description: 290 291 This is a call back routine for doing the fast unlock single call. 292 293 Arguments: 294 295 FileObject - Supplies the file object used in this operation 296 FileOffset - Supplies the file offset used in this operation 297 Length - Supplies the length used in this operation 298 ProcessId - Supplies the process ID used in this operation 299 Key - Supplies the key used in this operation 300 Status - Receives the Status if this operation is successful 301 302 Return Value: 303 304 BOOLEAN - TRUE if this operation completed and FALSE if caller 305 needs to take the long route. 306 */ 307 BOOLEAN 308 NTAPI 309 UDFFastUnlockSingle( 310 IN PFILE_OBJECT FileObject, 311 IN PLARGE_INTEGER FileOffset, 312 IN PLARGE_INTEGER Length, 313 PEPROCESS ProcessId, 314 ULONG Key, 315 OUT PIO_STATUS_BLOCK IoStatus, 316 IN PDEVICE_OBJECT DeviceObject 317 ) 318 319 { 320 BOOLEAN Results = FALSE; 321 322 // BOOLEAN AcquiredFCB = FALSE; 323 PtrUDFFCB Fcb = NULL; 324 PtrUDFCCB Ccb = NULL; 325 326 UDFPrint(("UDFFastUnlockSingle\n")); 327 // Decode the type of file object we're being asked to process and make 328 // sure it is only a user file open. 329 330 IoStatus->Information = 0; 331 332 // Get the FCB and CCB pointers. 333 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 334 ASSERT(Ccb); 335 Fcb = Ccb->Fcb; 336 ASSERT(Fcb); 337 // Validate the sent-in FCB 338 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || 339 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { 340 341 IoStatus->Status = STATUS_INVALID_PARAMETER; 342 return TRUE; 343 } 344 345 // Acquire exclusive access to the Fcb this operation can always wait 346 347 FsRtlEnterFileSystem(); 348 349 // BUGBUG: kenr 350 // (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE ); 351 352 _SEH2_TRY { 353 354 // We check whether we can proceed 355 // based on the state of the file oplocks. 356 357 // Now call the FsRtl routine to do the actual processing of the 358 // Lock request 359 Results = TRUE; 360 IoStatus->Status = FsRtlFastUnlockSingle( &(Fcb->NTRequiredFCB->FileLock), 361 FileObject, 362 FileOffset, 363 Length, 364 ProcessId, 365 Key, 366 NULL, 367 FALSE ); 368 // Set the flag indicating if Fast I/O is possible 369 Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); 370 371 //try_exit: NOTHING; 372 } _SEH2_FINALLY { 373 374 // Release the Fcb, and return to our caller 375 376 // BUGBUG: kenr 377 // UDFReleaseResource( (Fcb)->Header.Resource ); 378 379 FsRtlExitFileSystem(); 380 381 } _SEH2_END; 382 383 return Results; 384 } // end UDFFastUnlockSingle() 385 386 387 /* 388 Routine Description: 389 390 This is a call back routine for doing the fast unlock all call. 391 392 Arguments: 393 FileObject - Supplies the file object used in this operation 394 ProcessId - Supplies the process ID used in this operation 395 Status - Receives the Status if this operation is successful 396 397 Return Value: 398 399 BOOLEAN - TRUE if this operation completed and FALSE if caller 400 needs to take the long route. 401 */ 402 BOOLEAN 403 NTAPI 404 UDFFastUnlockAll( 405 IN PFILE_OBJECT FileObject, 406 PEPROCESS ProcessId, 407 OUT PIO_STATUS_BLOCK IoStatus, 408 IN PDEVICE_OBJECT DeviceObject 409 ) 410 411 { 412 BOOLEAN Results = FALSE; 413 414 // BOOLEAN AcquiredFCB = FALSE; 415 PtrUDFFCB Fcb = NULL; 416 PtrUDFCCB Ccb = NULL; 417 418 UDFPrint(("UDFFastUnlockAll\n")); 419 420 IoStatus->Information = 0; 421 // Decode the type of file object we're being asked to process and make 422 // sure it is only a user file open. 423 424 // Get the FCB and CCB pointers. 425 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 426 ASSERT(Ccb); 427 Fcb = Ccb->Fcb; 428 ASSERT(Fcb); 429 // Validate the sent-in FCB 430 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || 431 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { 432 433 IoStatus->Status = STATUS_INVALID_PARAMETER; 434 return TRUE; 435 } 436 437 // Acquire shared access to the Fcb this operation can always wait 438 439 FsRtlEnterFileSystem(); 440 441 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); 442 UDFAcquireResourceShared( &(Fcb->NTRequiredFCB->MainResource),TRUE ); 443 444 _SEH2_TRY { 445 446 // We check whether we can proceed 447 // based on the state of the file oplocks. 448 449 // Now call the FsRtl routine to do the actual processing of the 450 // Lock request 451 Results = TRUE; 452 IoStatus->Status = FsRtlFastUnlockAll( &(Fcb->NTRequiredFCB->FileLock), 453 FileObject, 454 ProcessId, 455 NULL ); 456 457 // Set the flag indicating if Fast I/O is questionable 458 459 Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible( Fcb ); 460 461 //try_exit: NOTHING; 462 } _SEH2_FINALLY { 463 464 // Release the Fcb, and return to our caller 465 466 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); 467 UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource)); 468 FsRtlExitFileSystem(); 469 470 } _SEH2_END; 471 472 return Results; 473 } // end UDFFastUnlockAll() 474 475 476 /* 477 Routine Description: 478 479 This is a call back routine for doing the fast unlock all call. 480 481 Arguments: 482 FileObject - Supplies the file object used in this operation 483 ProcessId - Supplies the process ID used in this operation 484 Status - Receives the Status if this operation is successful 485 486 Return Value: 487 488 BOOLEAN - TRUE if this operation completed and FALSE if caller 489 needs to take the long route. 490 */ 491 492 BOOLEAN 493 NTAPI 494 UDFFastUnlockAllByKey( 495 IN PFILE_OBJECT FileObject, 496 PEPROCESS ProcessId, 497 ULONG Key, 498 OUT PIO_STATUS_BLOCK IoStatus, 499 IN PDEVICE_OBJECT DeviceObject 500 ) 501 502 { 503 BOOLEAN Results = FALSE; 504 505 // BOOLEAN AcquiredFCB = FALSE; 506 PtrUDFFCB Fcb = NULL; 507 PtrUDFCCB Ccb = NULL; 508 509 UDFPrint(("UDFFastUnlockAllByKey\n")); 510 511 IoStatus->Information = 0; 512 // Decode the type of file object we're being asked to process and make 513 // sure it is only a user file open. 514 515 // Get the FCB and CCB pointers. 516 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 517 ASSERT(Ccb); 518 Fcb = Ccb->Fcb; 519 ASSERT(Fcb); 520 // Validate the sent-in FCB 521 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || 522 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { 523 524 IoStatus->Status = STATUS_INVALID_PARAMETER; 525 return TRUE; 526 } 527 528 // Acquire shared access to the Fcb this operation can always wait 529 530 FsRtlEnterFileSystem(); 531 532 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); 533 UDFAcquireResourceShared( &(Fcb->NTRequiredFCB->MainResource),TRUE ); 534 535 _SEH2_TRY { 536 537 // We check whether we can proceed 538 // based on the state of the file oplocks. 539 540 // Now call the FsRtl routine to do the actual processing of the 541 // Lock request 542 Results = TRUE; 543 IoStatus->Status = FsRtlFastUnlockAllByKey( &(Fcb->NTRequiredFCB->FileLock), 544 FileObject, 545 ProcessId, 546 Key, 547 NULL ); 548 549 // Set the flag indicating if Fast I/O is possible 550 551 Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible( Fcb ); 552 553 //try_exit: NOTHING; 554 } _SEH2_FINALLY { 555 556 // Release the Fcb, and return to our caller 557 558 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); 559 UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource)); 560 FsRtlExitFileSystem(); 561 562 } _SEH2_END; 563 564 return Results; 565 } // end UDFFastUnlockAllByKey() 566