Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

oplock.c

Go to the documentation of this file.
00001 /*++ 00002 00003 00004 Copyright (c) 1989 Microsoft Corporation 00005 00006 Module Name: 00007 00008 Oplock.c 00009 00010 Abstract: 00011 00012 The OPLOCK routines provide support to filesystems which implement 00013 opporuntistics locks. The specific actions needed are based on 00014 the current oplocked state of the file (maintained in the OPLOCK 00015 structure) and the Irp the Io system provides to the file systems. 00016 Rather than define separate entry points for each oplock operation 00017 a single generic entry point is defined. 00018 00019 The file systems will maintain a variable of type OPLOCK for 00020 each open file in the system. This variable is initialized 00021 when an unopened file is opened. It is uninitialized when the 00022 last reference to the file is cleared when the Io system calls 00023 the file system with a close call. 00024 00025 The following routines are provided by this package: 00026 00027 o FsRtlInitializeOplock - Initialize a new OPLOCK structure. There 00028 should be one OPLOCK for every opened file. Each OPLOCK structure 00029 must be initialized before it can be used by the system. 00030 00031 o FsRtlUninitializeOplock - Uninitialize an OPLOCK structure. This 00032 call is used to cleanup any anciallary structures allocated and 00033 maintained by the OPLOCK. After being uninitialized the OPLOCK 00034 must again be initialized before it can be used by the system. 00035 00036 Author: 00037 00038 Brian Andrew [BrianAn] 10-Dec-1990 00039 00040 Revision History: 00041 00042 --*/ 00043 00044 #include "FsRtlP.h" 00045 00046 // 00047 // Trace level for the module 00048 // 00049 00050 #define Dbg (0x08000000) 00051 00052 // 00053 // Define the compatible filter oplock desired access flags. We won't break 00054 // a filter oplock when these flags are the only flags specified. 00055 // 00056 00057 #define FILTER_OPLOCK_VALID_FLAGS ( \ 00058 FILE_READ_ATTRIBUTES | \ 00059 FILE_WRITE_ATTRIBUTES | \ 00060 FILE_READ_DATA | \ 00061 FILE_READ_EA | \ 00062 FILE_EXECUTE | \ 00063 SYNCHRONIZE | \ 00064 READ_CONTROL \ 00065 ) 00066 00067 00068 // 00069 // We encode the different bits so we can test without having to enumerate 00070 // all of the possible states. 00071 // 00072 // NOTE - The LEVEL_1, BATCH_OPLOCK and FILTER_OPLOCK must be in this order. 00073 // We assume later on that they are in this order. 00074 // 00075 00076 #define NO_OPLOCK (0x00000001) 00077 #define LEVEL_I_OPLOCK (0x00000002) 00078 #define BATCH_OPLOCK (0x00000004) 00079 #define FILTER_OPLOCK (0x00000008) 00080 #define LEVEL_II_OPLOCK (0x00000010) 00081 00082 #define OPLOCK_TYPE_MASK (0x0000001f) 00083 00084 #define EXCLUSIVE (0x00000040) 00085 #define PENDING (0x00000080) 00086 00087 #define OPLOCK_HELD_MASK (0x000000c0) 00088 00089 #define BREAK_TO_II (0x00000100) 00090 #define BREAK_TO_NONE (0x00000200) 00091 #define BREAK_TO_II_TO_NONE (0x00000400) 00092 #define CLOSE_PENDING (0x00000800) 00093 00094 #define OPLOCK_BREAK_MASK (0x00000f00) 00095 00096 // 00097 // The oplock types consist of the appropriate flags. 00098 // 00099 00100 #define NoOplocksHeld (NO_OPLOCK) 00101 00102 #define OplockIGranted (LEVEL_I_OPLOCK | EXCLUSIVE) 00103 #define OpBatchGranted (BATCH_OPLOCK | EXCLUSIVE) 00104 #define OpFilterGranted (FILTER_OPLOCK | EXCLUSIVE) 00105 #define OpFilterReqPending (FILTER_OPLOCK | EXCLUSIVE | PENDING ) 00106 00107 #define OplockBreakItoII (LEVEL_I_OPLOCK | EXCLUSIVE | BREAK_TO_II) 00108 #define OpBatchBreaktoII (BATCH_OPLOCK | EXCLUSIVE | BREAK_TO_II) 00109 #define OpFilterBreaktoII (FILTER_OPLOCK | EXCLUSIVE | BREAK_TO_II) 00110 00111 #define OplockBreakItoNone (LEVEL_I_OPLOCK | EXCLUSIVE | BREAK_TO_NONE) 00112 #define OpBatchBreaktoNone (BATCH_OPLOCK | EXCLUSIVE | BREAK_TO_NONE) 00113 #define OpFilterBreaktoNone (FILTER_OPLOCK | EXCLUSIVE | BREAK_TO_NONE) 00114 00115 #define OplockBreakItoIItoNone (LEVEL_I_OPLOCK | EXCLUSIVE | BREAK_TO_II_NONE) 00116 #define OpBatchBreaktoIItoNone (BATCH_OPLOCK | EXCLUSIVE | BREAK_TO_II_NONE) 00117 #define OpFilterBreaktoIItoNone (FILTER_OPLOCK | EXCLUSIVE | BREAK_TO_II_NONE) 00118 00119 #define OpBatchClosePending (BATCH_OPLOCK | EXCLUSIVE | CLOSE_PENDING) 00120 #define OpFilterClosePending (FILTER_OPLOCK | EXCLUSIVE | CLOSE_PENDING) 00121 00122 #define OplockIIGranted (LEVEL_II_OPLOCK) 00123 00124 // 00125 // The oplock state is now just a ULONG. 00126 // 00127 00128 typedef ULONG OPLOCK_STATE; 00129 00130 // 00131 // The non-opaque definition of an OPLOCK is a pointer to a privately 00132 // defined structure. 00133 // 00134 00135 typedef struct _NONOPAQUE_OPLOCK { 00136 00137 // 00138 // This is the Irp used to successfully request a level I oplock or 00139 // batch oplock. It is completed to initiate the Oplock I break 00140 // procedure. 00141 // 00142 00143 PIRP IrpExclusiveOplock; 00144 00145 // 00146 // This is a pointer to the original file object used when granting 00147 // an Oplock I or batch oplock. 00148 // 00149 00150 PFILE_OBJECT FileObject; 00151 00152 // 00153 // The start of a linked list of Irps used to successfully request 00154 // a level II oplock. 00155 // 00156 00157 LIST_ENTRY IrpOplocksII; 00158 00159 // 00160 // The following links the Irps waiting to be completed on a queue 00161 // of Irps. 00162 // 00163 00164 LIST_ENTRY WaitingIrps; 00165 00166 // 00167 // Oplock state. This indicates the current oplock state. 00168 // 00169 00170 OPLOCK_STATE OplockState; 00171 00172 // 00173 // This FastMutex is used to control access to this structure. 00174 // 00175 00176 PFAST_MUTEX FastMutex; 00177 00178 } NONOPAQUE_OPLOCK, *PNONOPAQUE_OPLOCK; 00179 00180 // 00181 // Each Waiting Irp record corresponds to an Irp that is waiting for an 00182 // oplock break to be acknowledged and is maintained in a queue off of the 00183 // Oplock's WaitingIrps list. 00184 // 00185 00186 typedef struct _WAITING_IRP { 00187 00188 // 00189 // The link structures for the list of waiting irps. 00190 // 00191 00192 LIST_ENTRY Links; 00193 00194 // 00195 // This is the Irp attached to this structure. 00196 // 00197 00198 PIRP Irp; 00199 00200 // 00201 // This is the routine to call when we are done with an Irp we 00202 // held on a waiting queue. (We originally returned STATUS_PENDING). 00203 // 00204 00205 POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine; 00206 00207 // 00208 // The context field to use when we are done with the Irp. 00209 // 00210 00211 PVOID Context; 00212 00213 // 00214 // This points to an event object used when we do not want to 00215 // give up this thread. 00216 // 00217 00218 PKEVENT Event; 00219 00220 // 00221 // This field contains a copy of the Irp Iosb.Information field. 00222 // We copy it here so that we can store the Oplock address in the 00223 // Irp. 00224 // 00225 00226 ULONG Information; 00227 00228 } WAITING_IRP, *PWAITING_IRP; 00229 00230 // 00231 // Define a tag for general pool allocations from this module 00232 // 00233 00234 #undef MODULE_POOL_TAG 00235 #define MODULE_POOL_TAG ('orSF') 00236 00237 00238 // 00239 // Local support routines 00240 // 00241 00242 PNONOPAQUE_OPLOCK 00243 FsRtlAllocateOplock ( 00244 ); 00245 00246 NTSTATUS 00247 FsRtlRequestExclusiveOplock ( 00248 IN OUT PNONOPAQUE_OPLOCK *Oplock, 00249 IN PIO_STACK_LOCATION IrpSp, 00250 IN PIRP Irp OPTIONAL, 00251 IN OPLOCK_STATE NextOplockState 00252 ); 00253 00254 NTSTATUS 00255 FsRtlRequestOplockII ( 00256 IN OUT PNONOPAQUE_OPLOCK *Oplock, 00257 IN PIO_STACK_LOCATION IrpSp, 00258 IN PIRP Irp 00259 ); 00260 00261 NTSTATUS 00262 FsRtlAcknowledgeOplockBreak ( 00263 IN OUT PNONOPAQUE_OPLOCK Oplock, 00264 IN PIO_STACK_LOCATION IrpSp, 00265 IN PIRP Irp, 00266 IN BOOLEAN GrantLevelII 00267 ); 00268 00269 NTSTATUS 00270 FsRtlOpBatchBreakClosePending ( 00271 IN OUT PNONOPAQUE_OPLOCK Oplock, 00272 IN PIO_STACK_LOCATION IrpSp, 00273 IN PIRP Irp 00274 ); 00275 00276 NTSTATUS 00277 FsRtlOplockBreakNotify ( 00278 IN OUT PNONOPAQUE_OPLOCK Oplock, 00279 IN PIO_STACK_LOCATION IrpSp, 00280 IN PIRP Irp 00281 ); 00282 00283 VOID 00284 FsRtlOplockCleanup ( 00285 IN OUT PNONOPAQUE_OPLOCK Oplock, 00286 IN PIO_STACK_LOCATION IrpSp 00287 ); 00288 00289 NTSTATUS 00290 FsRtlOplockBreakToII ( 00291 IN OUT PNONOPAQUE_OPLOCK Oplock, 00292 IN PIO_STACK_LOCATION IrpSp, 00293 IN PIRP Irp, 00294 IN PVOID Context, 00295 IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, 00296 IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL 00297 ); 00298 00299 NTSTATUS 00300 FsRtlOplockBreakToNone ( 00301 IN OUT PNONOPAQUE_OPLOCK Oplock, 00302 IN PIO_STACK_LOCATION IrpSp, 00303 IN PIRP Irp, 00304 IN PVOID Context, 00305 IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, 00306 IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL 00307 ); 00308 00309 VOID 00310 FsRtlRemoveAndCompleteIrp ( 00311 IN PLIST_ENTRY Link 00312 ); 00313 00314 NTSTATUS 00315 FsRtlWaitOnIrp ( 00316 IN OUT PNONOPAQUE_OPLOCK Oplock, 00317 IN PIRP Irp, 00318 IN PVOID Context, 00319 IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, 00320 IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL, 00321 IN PKEVENT Event 00322 ); 00323 00324 VOID 00325 FsRtlCompletionRoutinePriv ( 00326 IN PVOID Context, 00327 IN PIRP Irp 00328 ); 00329 00330 VOID 00331 FsRtlCancelWaitIrp ( 00332 IN PDEVICE_OBJECT DeviceObject, 00333 IN PIRP Irp 00334 ); 00335 00336 VOID 00337 FsRtlCancelOplockIIIrp ( 00338 IN PDEVICE_OBJECT DeviceObject, 00339 IN PIRP Irp 00340 ); 00341 00342 VOID 00343 FsRtlCancelExclusiveIrp ( 00344 IN PDEVICE_OBJECT DeviceObject, 00345 IN PIRP Irp 00346 ); 00347 00348 VOID 00349 FsRtlRemoveAndCompleteWaitIrp ( 00350 IN PWAITING_IRP WaitingIrp 00351 ); 00352 00353 VOID 00354 FsRtlNotifyCompletion ( 00355 IN PVOID Context, 00356 IN PIRP Irp 00357 ); 00358 00359 #ifdef ALLOC_PRAGMA 00360 #pragma alloc_text(PAGE, FsRtlAllocateOplock) 00361 #pragma alloc_text(PAGE, FsRtlCompletionRoutinePriv) 00362 #pragma alloc_text(PAGE, FsRtlCurrentBatchOplock) 00363 #pragma alloc_text(PAGE, FsRtlInitializeOplock) 00364 #pragma alloc_text(PAGE, FsRtlNotifyCompletion) 00365 #pragma alloc_text(PAGE, FsRtlOpBatchBreakClosePending) 00366 #pragma alloc_text(PAGE, FsRtlOplockBreakNotify) 00367 #pragma alloc_text(PAGE, FsRtlOplockFsctrl) 00368 #pragma alloc_text(PAGE, FsRtlOplockIsFastIoPossible) 00369 #endif 00370 00371 00372 VOID 00373 FsRtlInitializeOplock ( 00374 IN OUT POPLOCK Oplock 00375 ) 00376 00377 /*++ 00378 00379 Routine Description: 00380 00381 This routine initializes a new OPLOCK structure. This call must 00382 precede any other call to this entry point with this OPLOCK 00383 structure. In addition, this routine will have exclusive access 00384 to the Oplock structure. 00385 00386 Arguments: 00387 00388 Oplock - Supplies the address of an opaque OPLOCK structure. 00389 00390 Return Value: 00391 00392 None. 00393 00394 --*/ 00395 00396 { 00397 UNREFERENCED_PARAMETER( Oplock ); 00398 00399 PAGED_CODE(); 00400 00401 DebugTrace(+1, Dbg, "FsRtlInitializeOplock: Oplock -> %08lx\n", *Oplock ); 00402 00403 // 00404 // No action is taken at this time. 00405 // 00406 00407 DebugTrace(-1, Dbg, "FsRtlInitializeOplock: Exit\n", 0); 00408 return; 00409 } 00410 00411 00412 VOID 00413 FsRtlUninitializeOplock ( 00414 IN OUT POPLOCK Oplock 00415 ) 00416 00417 /*++ 00418 00419 Routine Description: 00420 00421 This routine uninitializes an OPLOCK structure. After calling this 00422 routine, the OPLOCK structure must be reinitialized before being 00423 used again. 00424 00425 Arguments: 00426 00427 Oplock - Supplies the address of an opaque OPLOCK structure. 00428 00429 Return Value: 00430 00431 None. 00432 00433 --*/ 00434 00435 00436 { 00437 PNONOPAQUE_OPLOCK ThisOplock; 00438 00439 DebugTrace(+1, Dbg, "FsRtlUninitializeOplock: Oplock -> %08lx\n", *Oplock ); 00440 00441 // 00442 // If the Oplock structure has not been allocated, there is no action 00443 // to take. 00444 // 00445 00446 if (*Oplock != NULL) { 00447 00448 // 00449 // Remove this from the user's structure. 00450 // 00451 00452 ThisOplock = (PNONOPAQUE_OPLOCK) *Oplock; 00453 00454 *Oplock = NULL; 00455 00456 // 00457 // Grab the waiting lock queue mutex to exclude anyone from messing 00458 // with the queue while we're using it 00459 // 00460 00461 ExAcquireFastMutexUnsafe( ThisOplock->FastMutex ); 00462 00463 try { 00464 00465 PIRP Irp; 00466 00467 // 00468 // Release any waiting Irps held. 00469 // 00470 00471 while (!IsListEmpty( &ThisOplock->WaitingIrps )) { 00472 00473 PWAITING_IRP WaitingIrp; 00474 PIRP ThisIrp; 00475 00476 WaitingIrp = CONTAINING_RECORD( ThisOplock->WaitingIrps.Flink, 00477 WAITING_IRP, 00478 Links ); 00479 00480 RemoveHeadList( &ThisOplock->WaitingIrps ); 00481 00482 ThisIrp = WaitingIrp->Irp; 00483 00484 IoAcquireCancelSpinLock( &ThisIrp->CancelIrql ); 00485 00486 IoSetCancelRoutine( ThisIrp, NULL ); 00487 IoReleaseCancelSpinLock( ThisIrp->CancelIrql ); 00488 00489 ThisIrp->IoStatus.Information = 0; 00490 00491 // 00492 // Call the completion routine in the Waiting Irp. 00493 // 00494 00495 WaitingIrp->CompletionRoutine( WaitingIrp->Context, 00496 WaitingIrp->Irp ); 00497 00498 ExFreePool( WaitingIrp ); 00499 } 00500 00501 // 00502 // Release any oplock II irps held. 00503 // 00504 00505 while (!IsListEmpty( &ThisOplock->IrpOplocksII )) { 00506 00507 Irp = CONTAINING_RECORD( ThisOplock->IrpOplocksII.Flink, 00508 IRP, 00509 Tail.Overlay.ListEntry ); 00510 00511 RemoveHeadList( &ThisOplock->IrpOplocksII ); 00512 00513 IoAcquireCancelSpinLock( &Irp->CancelIrql ); 00514 00515 IoSetCancelRoutine( Irp, NULL ); 00516 IoReleaseCancelSpinLock( Irp->CancelIrql ); 00517 00518 // 00519 // Complete the oplock II Irp. 00520 // 00521 00522 ObDereferenceObject( IoGetCurrentIrpStackLocation( Irp )->FileObject ); 00523 00524 Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE; 00525 FsRtlCompleteRequest( Irp, STATUS_SUCCESS ); 00526 } 00527 00528 // 00529 // Release any exclusive oplock held. 00530 // 00531 00532 if (ThisOplock->IrpExclusiveOplock != NULL) { 00533 00534 Irp = ThisOplock->IrpExclusiveOplock; 00535 00536 IoAcquireCancelSpinLock( &Irp->CancelIrql ); 00537 00538 IoSetCancelRoutine( Irp, NULL ); 00539 IoReleaseCancelSpinLock( Irp->CancelIrql ); 00540 00541 Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE; 00542 FsRtlCompleteRequest( Irp, STATUS_SUCCESS ); 00543 00544 ThisOplock->IrpExclusiveOplock = NULL; 00545 00546 if (ThisOplock->FileObject != NULL) { 00547 00548 ObDereferenceObject( ThisOplock->FileObject ); 00549 } 00550 } 00551 00552 } finally { 00553 00554 // 00555 // No matter how we complete the preceding statements we will 00556 // now release the waiting lock queue mutex 00557 // 00558 00559 ExReleaseFastMutexUnsafe( ThisOplock->FastMutex ); 00560 } 00561 00562 // 00563 // Deallocate the mutex. 00564 // 00565 00566 ExFreePool( ThisOplock->FastMutex ); 00567 00568 // 00569 // Deallocate the Oplock structure. 00570 // 00571 00572 ExFreePool( ThisOplock ); 00573 } 00574 00575 DebugTrace( -1, Dbg, "FsRtlUninitializeOplock: Exit\n", 0 ); 00576 return; 00577 } 00578 00579 00580 NTSTATUS 00581 FsRtlOplockFsctrl ( 00582 IN POPLOCK Oplock, 00583 IN PIRP Irp, 00584 IN ULONG OpenCount 00585 ) 00586 00587 /*++ 00588 00589 Routine Description: 00590 00591 This is the interface with the filesystems for Fsctl calls, it handles 00592 oplock requests, break acknowledgement and break notify. 00593 00594 Arguments: 00595 00596 Oplock - Supplies the address of the opaque OPLOCK structure. 00597 00598 Irp - Supplies a pointer to the Irp which declares the requested 00599 operation. 00600 00601 OpenCount - This is the number of user handles on the file if we are requsting 00602 an exclusive oplock. A non-zero value for a level II request indicates 00603 that there are locks on the file. 00604 00605 Return Value: 00606 00607 NTSTATUS - Returns the result of this operation. If this is an Oplock 00608 request which is granted, then STATUS_PENDING is returned. 00609 If the Oplock isn't granted then STATUS_OPLOCK_NOT_GRANTED 00610 is returned. If this is an Oplock I break to no oplock, 00611 then STATUS_SUCCESS. If this is an Oplock I break to 00612 Oplock II then STATUS_PENDING is returned. Other 00613 error codes returned depend on the nature of the error. 00614 00615 STATUS_CANCELLED is returned if the Irp is cancelled during 00616 this operation. 00617 00618 STATUS_SUCCESS is returned if this is a create asking for 00619 a filter oplock. 00620 00621 --*/ 00622 00623 { 00624 NTSTATUS Status; 00625 PIO_STACK_LOCATION IrpSp; 00626 OPLOCK_STATE OplockState; 00627 00628 PAGED_CODE(); 00629 00630 // 00631 // Get the current IRP stack location 00632 // 00633 00634 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00635 00636 DebugTrace(+1, Dbg, "FsRtlOplockFsctrl: Entered\n", 0); 00637 DebugTrace( 0, Dbg, "FsRtlOplockFsctrl: Oplock -> %08lx\n", *Oplock ); 00638 DebugTrace( 0, Dbg, "FsRtlOplockFsctrl: Irp -> %08lx\n", Irp ); 00639 00640 // 00641 // Check if this is the create case where the user is requesting a pending 00642 // filter oplock. 00643 // 00644 00645 if (IrpSp->MajorFunction == IRP_MJ_CREATE) { 00646 00647 // 00648 // Check that all the conditions hold to grant this oplock. 00649 // The conditions that must hold are: 00650 // 00651 // - This is the only opener of the file. 00652 // - Desired Access must be exactly FILE_READ_ATTRIBUTES. 00653 // This will insure an asynch open since the SYNCHRONIZE 00654 // flag can't be set. 00655 // - Share access is precisely 00656 // (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) 00657 // 00658 00659 if ((OpenCount != 1) || 00660 (FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 00661 ~(FILE_READ_ATTRIBUTES))) || 00662 ((IrpSp->Parameters.Create.ShareAccess & 00663 (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)) != 00664 (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE))) { 00665 00666 Status = STATUS_OPLOCK_NOT_GRANTED; 00667 00668 } else { 00669 00670 Status = FsRtlRequestExclusiveOplock( (PNONOPAQUE_OPLOCK *) Oplock, 00671 IrpSp, 00672 NULL, 00673 OpFilterReqPending ); 00674 } 00675 00676 // 00677 // Case on the FsControlFile code control code. 00678 // 00679 00680 } else { 00681 00682 // 00683 // Assume this is an OplockLevel I. 00684 // 00685 // NOTE - This code depends on the defined bits for these oplock types. 00686 // FILTER_OPLOCK = 4 * LEVEL_I_OPLOCK 00687 // BATCH_OPLOCK = 2 * LEVEL_I_OPLOCK 00688 // 00689 00690 OplockState = LEVEL_I_OPLOCK; 00691 00692 switch (IrpSp->Parameters.FileSystemControl.FsControlCode) { 00693 00694 case FSCTL_REQUEST_FILTER_OPLOCK : 00695 00696 OplockState *= 2; 00697 00698 case FSCTL_REQUEST_BATCH_OPLOCK : 00699 00700 OplockState *= 2; 00701 00702 case FSCTL_REQUEST_OPLOCK_LEVEL_1 : 00703 00704 // 00705 // Set the other flags for an exclusive oplock. 00706 // 00707 00708 SetFlag( OplockState, EXCLUSIVE ); 00709 00710 // 00711 // We short circuit the request if this request is treated 00712 // synchronously or the open count is not 1. Otherwise the Io system 00713 // will hold the return code until the Irp is completed. 00714 // 00715 // Also fail this if the flag is set which indicates that 00716 // the IO system should copy data back to a user's buffer. 00717 // 00718 // If cleanup has occurrred on this file, then we refuse 00719 // the oplock request. 00720 // 00721 00722 if ((OpenCount != 1) || 00723 IoIsOperationSynchronous( Irp ) || 00724 FlagOn( Irp->Flags, IRP_INPUT_OPERATION ) || 00725 FlagOn( IrpSp->FileObject->Flags, FO_CLEANUP_COMPLETE )) { 00726 00727 FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED ); 00728 Status = STATUS_OPLOCK_NOT_GRANTED; 00729 00730 } else { 00731 00732 Status = FsRtlRequestExclusiveOplock( (PNONOPAQUE_OPLOCK *) Oplock, 00733 IrpSp, 00734 Irp, 00735 OplockState ); 00736 } 00737 00738 break; 00739 00740 case FSCTL_REQUEST_OPLOCK_LEVEL_2 : 00741 00742 // 00743 // We short circuit the request if this request is treated 00744 // synchronously. Otherwise the Io system will hold the return 00745 // code until the Irp is completed. 00746 // 00747 // If cleanup has occurrred on this file, then we refuse 00748 // the oplock request. 00749 // 00750 // Also fail this if the flag is set which indicates that 00751 // the IO system should copy data back to a user's buffer. 00752 // 00753 // A non-zero open count in this case indicates that there are 00754 // file locks on the file. We will also fail the request in 00755 // this case. 00756 // 00757 00758 if ((OpenCount != 0) || 00759 IoIsOperationSynchronous( Irp ) || 00760 FlagOn( Irp->Flags, IRP_INPUT_OPERATION ) || 00761 FlagOn( IrpSp->FileObject->Flags, FO_CLEANUP_COMPLETE )) { 00762 00763 FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED ); 00764 Status = STATUS_OPLOCK_NOT_GRANTED; 00765 00766 } else { 00767 00768 Status = FsRtlRequestOplockII( (PNONOPAQUE_OPLOCK *) Oplock, 00769 IrpSp, 00770 Irp ); 00771 } 00772 00773 break; 00774 00775 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE : 00776 00777 Status = FsRtlAcknowledgeOplockBreak( (PNONOPAQUE_OPLOCK) *Oplock, 00778 IrpSp, 00779 Irp, 00780 TRUE ); 00781 break; 00782 00783 case FSCTL_OPLOCK_BREAK_ACK_NO_2 : 00784 00785 Status = FsRtlAcknowledgeOplockBreak( (PNONOPAQUE_OPLOCK) *Oplock, 00786 IrpSp, 00787 Irp, 00788 FALSE ); 00789 break; 00790 00791 case FSCTL_OPBATCH_ACK_CLOSE_PENDING : 00792 00793 Status = FsRtlOpBatchBreakClosePending( (PNONOPAQUE_OPLOCK) *Oplock, 00794 IrpSp, 00795 Irp ); 00796 break; 00797 00798 case FSCTL_OPLOCK_BREAK_NOTIFY : 00799 00800 Status = FsRtlOplockBreakNotify( (PNONOPAQUE_OPLOCK) *Oplock, 00801 IrpSp, 00802 Irp ); 00803 break; 00804 00805 default : 00806 00807 DebugTrace( 0, 00808 Dbg, 00809 "Invalid Control Code\n", 00810 0); 00811 00812 FsRtlCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); 00813 Status = STATUS_INVALID_PARAMETER; 00814 } 00815 } 00816 00817 DebugTrace(-1, Dbg, "FsRtlOplockFsctrl: Exit -> %08lx\n", Status ); 00818 return Status; 00819 } 00820 00821 00822 NTSTATUS 00823 FsRtlCheckOplock ( 00824 IN POPLOCK Oplock, 00825 IN PIRP Irp, 00826 IN PVOID Context, 00827 IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, 00828 IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL 00829 ) 00830 00831 /*++ 00832 00833 Routine Description: 00834 00835 This routine is called as a support routine from a file system. 00836 It is used to synchronize I/O requests with the current Oplock 00837 state of a file. If the I/O operation will cause the Oplock to 00838 break, that action is initiated. If the operation cannot continue 00839 until the Oplock break is complete, STATUS_PENDING is returned and 00840 the caller supplied routine is called. 00841 00842 Arguments: 00843 00844 Oplock - Supplies a pointer to the non-opaque oplock structure for 00845 this file. 00846 00847 Irp - Supplies a pointer to the Irp which declares the requested 00848 operation. 00849 00850 Context - This value is passed as a parameter to the completion routine. 00851 00852 CompletionRoutine - This is the routine which is called if this 00853 Irp must wait for an Oplock to break. This 00854 is a synchronous operation if not specified 00855 and we block in this thread waiting on 00856 an event. 00857 00858 PostIrpRoutine - This is the routine to call before we put anything 00859 on our waiting Irp queue. 00860 00861 Return Value: 00862 00863 STATUS_SUCCESS if we can complete the operation on exiting this thread. 00864 STATUS_PENDING if we return here but hold the Irp. 00865 STATUS_CANCELLED if the Irp is cancelled before we return. 00866 00867 --*/ 00868 00869 { 00870 NTSTATUS Status = STATUS_SUCCESS; 00871 PNONOPAQUE_OPLOCK ThisOplock = *Oplock; 00872 00873 PIO_STACK_LOCATION IrpSp; 00874 00875 DebugTrace( +1, Dbg, "FsRtlCheckOplock: Entered\n", 0 ); 00876 DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock ); 00877 DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp ); 00878 00879 // 00880 // If there is no oplock structure or this is system I/O, we allow 00881 // the operation to continue. Otherwise we check the major function code. 00882 // 00883 00884 if ((ThisOplock != NULL) && 00885 !FlagOn( Irp->Flags, IRP_PAGING_IO )) { 00886 00887 OPLOCK_STATE OplockState; 00888 PFILE_OBJECT OplockFileObject; 00889 00890 BOOLEAN BreakToII; 00891 BOOLEAN BreakToNone; 00892 00893 ULONG CreateDisposition; 00894 00895 // 00896 // Capture the file object first and then the oplock state to perform 00897 // the unsafe checks below. We capture the file object first in case 00898 // there is an exclusive oplock break in progress. Otherwise the oplock 00899 // state may indicate break in progress but it could complete by 00900 // the time we snap the file object. 00901 // 00902 00903 OplockFileObject = ThisOplock->FileObject; 00904 OplockState = ThisOplock->OplockState; 00905 00906 // 00907 // Examine the Irp for the appropriate action provided there are 00908 // current oplocks on the file. 00909 // 00910 00911 if (OplockState != NoOplocksHeld) { 00912 00913 BreakToII = FALSE; 00914 BreakToNone = FALSE; 00915 00916 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00917 00918 // 00919 // Determine whether we are going to BreakToII or BreakToNone. 00920 // 00921 00922 switch (IrpSp->MajorFunction) { 00923 00924 case IRP_MJ_CREATE : 00925 00926 // 00927 // If we are opening for attribute access only, we 00928 // return status success. Always break the oplock if this caller 00929 // wants a filter oplock. 00930 // 00931 00932 if (!FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 00933 ~(FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE) ) && 00934 !FlagOn( IrpSp->Parameters.Create.Options, FILE_RESERVE_OPFILTER )) { 00935 00936 break; 00937 } 00938 00939 // 00940 // If there is a filter oplock granted and this create iS reading 00941 // the file then don't break the oplock as long as we share 00942 // for reads. 00943 // 00944 00945 if (FlagOn( OplockState, FILTER_OPLOCK ) && 00946 !FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 00947 ~FILTER_OPLOCK_VALID_FLAGS ) && 00948 FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ )) { 00949 00950 break; 00951 } 00952 00953 // 00954 // We we are superseding or overwriting, then break to none. 00955 // 00956 00957 CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff; 00958 00959 if ((CreateDisposition == FILE_SUPERSEDE) || 00960 (CreateDisposition == FILE_OVERWRITE) || 00961 (CreateDisposition == FILE_OVERWRITE_IF) || 00962 FlagOn( IrpSp->Parameters.Create.Options, FILE_RESERVE_OPFILTER )) { 00963 00964 BreakToNone = TRUE; 00965 00966 } else { 00967 00968 BreakToII = TRUE; 00969 } 00970 00971 break; 00972 00973 case IRP_MJ_READ : 00974 00975 // 00976 // If a filter oplock has been granted then do nothing. 00977 // We will assume the oplock will have been broken 00978 // if this create needed to do that. 00979 // 00980 00981 if (!FlagOn( OplockState, FILTER_OPLOCK )) { 00982 00983 BreakToII = TRUE; 00984 } 00985 00986 break; 00987 00988 case IRP_MJ_FLUSH_BUFFERS : 00989 00990 BreakToII = TRUE; 00991 break; 00992 00993 case IRP_MJ_CLEANUP : 00994 00995 FsRtlOplockCleanup( (PNONOPAQUE_OPLOCK) *Oplock, 00996 IrpSp ); 00997 00998 break; 00999 01000 case IRP_MJ_LOCK_CONTROL : 01001 01002 // 01003 // If a filter oplock has been granted then do nothing. 01004 // We will assume the oplock will have been broken 01005 // if this create needed to do that. 01006 // 01007 01008 if (FlagOn( OplockState, FILTER_OPLOCK )) { 01009 01010 break; 01011 } 01012 01013 case IRP_MJ_WRITE : 01014 01015 BreakToNone = TRUE; 01016 break; 01017 01018 case IRP_MJ_SET_INFORMATION : 01019 01020 // 01021 // We are only interested in calls that shrink the file size 01022 // or breaking batch oplocks for the rename case. 01023 // 01024 01025 switch (IrpSp->Parameters.SetFile.FileInformationClass) { 01026 01027 case FileEndOfFileInformation : 01028 01029 // 01030 // Break immediately if this is the lazy writer callback. 01031 // 01032 01033 if (IrpSp->Parameters.SetFile.AdvanceOnly) { 01034 01035 break; 01036 } 01037 01038 case FileAllocationInformation : 01039 01040 BreakToNone = TRUE; 01041 break; 01042 01043 case FileRenameInformation : 01044 case FileLinkInformation : 01045 01046 if (FlagOn( OplockState, BATCH_OPLOCK | FILTER_OPLOCK )) { 01047 01048 BreakToNone = TRUE; 01049 } 01050 01051 break; 01052 } 01053 01054 case IRP_MJ_FILE_SYSTEM_CONTROL : 01055 01056 // 01057 // We need to break to none if this is a zeroing operation. 01058 // 01059 01060 if (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_SET_ZERO_DATA) { 01061 01062 BreakToNone = TRUE; 01063 } 01064 } 01065 01066 if (BreakToII) { 01067 01068 // 01069 // If there are no outstanding oplocks or level II oplocks are held, 01070 // we can return immediately. If the first two tests fail then there 01071 // is an exclusive oplock. If the file objects match we allow the 01072 // operation to continue. 01073 // 01074 01075 if ((OplockState != OplockIIGranted) && 01076 (OplockFileObject != IrpSp->FileObject)) { 01077 01078 Status = FsRtlOplockBreakToII( (PNONOPAQUE_OPLOCK) *Oplock, 01079 IrpSp, 01080 Irp, 01081 Context, 01082 CompletionRoutine, 01083 PostIrpRoutine ); 01084 } 01085 01086 } else if (BreakToNone) { 01087 01088 // 01089 // If there are no oplocks, we can return immediately. 01090 // Otherwise if there is no level 2 oplock and this file 01091 // object matches the owning file object then this write is 01092 // on behalf of the owner of the oplock. 01093 // 01094 01095 if ((OplockState == OplockIIGranted) || 01096 (OplockFileObject != IrpSp->FileObject)) { 01097 01098 Status = FsRtlOplockBreakToNone( (PNONOPAQUE_OPLOCK) *Oplock, 01099 IrpSp, 01100 Irp, 01101 Context, 01102 CompletionRoutine, 01103 PostIrpRoutine ); 01104 } 01105 } 01106 } 01107 } 01108 01109 DebugTrace( -1, Dbg, "FsRtlCheckOplock: Exit -> %08lx\n", Status ); 01110 01111 return Status; 01112 } 01113 01114 01115 BOOLEAN 01116 FsRtlOplockIsFastIoPossible ( 01117 IN POPLOCK Oplock 01118 ) 01119 01120 /*++ 01121 01122 Routine Description: 01123 01124 This routine indicates to the caller where there are any outstanding 01125 oplocks which prevent fast Io from happening. 01126 01127 Arguments: 01128 01129 OpLock - Supplies the oplock being queried 01130 01131 Return Value: 01132 01133 BOOLEAN - TRUE if there are outstanding oplocks and FALSE otherwise 01134 01135 --*/ 01136 01137 { 01138 BOOLEAN FastIoPossible = TRUE; 01139 01140 PAGED_CODE(); 01141 01142 DebugTrace(+1, Dbg, "FsRtlOplockIsFastIoPossible: Oplock -> %08lx\n", *Oplock); 01143 01144 // 01145 // There are not any current oplocks if the variable is null or 01146 // the state is no oplocks held. If an exclusive oplock was granted 01147 // but no break is in progress then allow the Fast IO. 01148 // 01149 01150 if (*Oplock != NULL) { 01151 01152 OPLOCK_STATE OplockState; 01153 01154 OplockState = ((PNONOPAQUE_OPLOCK) *Oplock)->OplockState; 01155 01156 if (FlagOn( OplockState, LEVEL_II_OPLOCK | OPLOCK_BREAK_MASK )) { 01157 01158 FastIoPossible = FALSE; 01159 } 01160 } 01161 01162 DebugTrace(-1, Dbg, "FsRtlOplockIsFastIoPossible: Exit -> %08lx\n", FastIoPossible); 01163 01164 return FastIoPossible; 01165 } 01166 01167 01168 BOOLEAN 01169 FsRtlCurrentBatchOplock ( 01170 IN POPLOCK Oplock 01171 ) 01172 01173 /*++ 01174 01175 Routine Description: 01176 01177 This routines indicates whether there are current outstanding 01178 batch oplocks. 01179 01180 Arguments: 01181 01182 OpLock - Supplies the oplock being queried 01183 01184 Return Value: 01185 01186 BOOLEAN - TRUE if there are outstanding batch oplocks and FALSE otherwise 01187 01188 --*/ 01189 01190 { 01191 BOOLEAN BatchOplocks = FALSE; 01192 01193 PAGED_CODE(); 01194 01195 DebugTrace(+1, Dbg, "FsRtlCurrentBatchOplock: Oplock -> %08lx\n", *Oplock); 01196 01197 // 01198 // There are not any current oplocks if the variable is null or 01199 // the state is no oplocks held. We check whether there are batch 01200 // oplocks or filter oplocks which have not been broken. 01201 // 01202 01203 if ((*Oplock != NULL) && 01204 FlagOn( ((PNONOPAQUE_OPLOCK) *Oplock)->OplockState, 01205 BATCH_OPLOCK | FILTER_OPLOCK )) { 01206 01207 BatchOplocks = TRUE; 01208 } 01209 01210 DebugTrace(-1, Dbg, "FsRtlCurrentBatchOplock: Exit -> %08lx\n", BatchOplocks); 01211 01212 return BatchOplocks; 01213 } 01214 01215 01216 // 01217 // Local support routine. 01218 // 01219 01220 PNONOPAQUE_OPLOCK 01221 FsRtlAllocateOplock ( 01222 ) 01223 01224 /*++ 01225 01226 Routine Description: 01227 01228 This routine is called to initialize and allocate an opaque oplock 01229 structure. After allocation, the two events are set to the signalled 01230 state. The oplock state is set to NoOplocksHeld and the other 01231 fields are filled with zeroes. 01232 01233 If the allocation fails, the appropriate status is raised. 01234 01235 Arguments: 01236 01237 None. 01238 01239 Return Value: 01240 01241 PNONOPAQUE_OPLOCK - A pointer to the allocated structure. 01242 01243 --*/ 01244 01245 { 01246 PNONOPAQUE_OPLOCK NewOplock = NULL; 01247 01248 PAGED_CODE(); 01249 01250 DebugTrace( +1, Dbg, "FsRtlAllocateOplock: Entered\n", 0); 01251 01252 // 01253 // Use a try-finally to facilitate cleanup. 01254 // 01255 01256 try { 01257 01258 // 01259 // Raise an error status if the allocation is unsuccessful. 01260 // The structure is allocated out of non-paged pool. 01261 // 01262 01263 NewOplock = FsRtlpAllocatePool( PagedPool, sizeof( NONOPAQUE_OPLOCK )); 01264 01265 RtlZeroMemory( NewOplock, sizeof( NONOPAQUE_OPLOCK )); 01266 01267 NewOplock->FastMutex = FsRtlpAllocatePool( NonPagedPool, sizeof( FAST_MUTEX )); 01268 01269 ExInitializeFastMutex( NewOplock->FastMutex ); 01270 01271 InitializeListHead( &NewOplock->IrpOplocksII ); 01272 InitializeListHead( &NewOplock->WaitingIrps ); 01273 01274 NewOplock->OplockState = NoOplocksHeld; 01275 01276 } finally { 01277 01278 // 01279 // Cleanup the oplock if abnormal termination. 01280 // 01281 01282 if (AbnormalTermination() && NewOplock != NULL) { 01283 01284 ExFreePool( NewOplock ); 01285 } 01286 01287 DebugTrace(-1, Dbg, "GetOplockStructure: Exit -> %08lx\n", NewOplock); 01288 } 01289 01290 return NewOplock; 01291 } 01292 01293 01294 // 01295 // Local support routine. 01296 // 01297 01298 NTSTATUS 01299 FsRtlRequestExclusiveOplock ( 01300 IN OUT PNONOPAQUE_OPLOCK *Oplock, 01301 IN PIO_STACK_LOCATION IrpSp, 01302 IN PIRP Irp OPTIONAL, 01303 IN OPLOCK_STATE NextOplockState 01304 ) 01305 01306 /*++ 01307 01308 Routine Description: 01309 01310 This routine is called whenever a user is requesting either a batch/filter 01311 oplock or a level I oplock. The request is granted if there are currently 01312 no oplocks on the file or we are completing the filter oplock request. 01313 01314 NOTE - We already know that the open count on this file is exactly one. 01315 If the caller is requesting a PendingFilter Oplock then the state 01316 must be NoOplockHeld. 01317 01318 Arguments: 01319 01320 Oplock - Supplies a pointer to the non-opaque oplock structure for 01321 this file. 01322 01323 IrpSp - This is the Irp stack location for the current Irp. 01324 01325 Irp - Supplies a pointer to the Irp which declares the requested 01326 operation. This is not specified if we are granting a pending 01327 filter oplock (during a create). 01328 01329 NextOplockState - Indicates the type of oplock being requested. 01330 01331 Return Value: 01332 01333 STATUS_PENDING if the oplock is granted (although it may be immediately cancelled). 01334 STATUS_SUCCESS if a pending filter oplock is requested and tentatively granted. 01335 STATUS_OPLOCK_NOT_GRANTED if the request is denied. 01336 01337 --*/ 01338 01339 { 01340 NTSTATUS Status; 01341 01342 PNONOPAQUE_OPLOCK ThisOplock; 01343 01344 BOOLEAN AcquiredMutex; 01345 BOOLEAN BreakOpFilter = FALSE; 01346 01347 PLIST_ENTRY Link; 01348 01349 DebugTrace( +1, Dbg, "FsRtlRequestExclusiveOplock: Entered\n", 0 ); 01350 DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock ); 01351 DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp ); 01352 DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp ); 01353 DebugTrace( 0, Dbg, "BatchOplock -> %01x\n", BatchOplock ); 01354 01355 // 01356 // We can grant the oplock if no one else owns a level I or level II 01357 // oplock on this file. If the oplock pointer is NULL then there 01358 // are no oplocks on the file. Otherwise we need to check the 01359 // oplock state in an existing oplock structure. 01360 // 01361 01362 if (*Oplock == NULL) { 01363 01364 DebugTrace( 0, 01365 Dbg, 01366 "Oplock currently not allocated\n", 01367 0); 01368 01369 ThisOplock = FsRtlAllocateOplock(); 01370 *Oplock = ThisOplock; 01371 01372 } else { 01373 01374 ThisOplock = *Oplock; 01375 } 01376 01377 // 01378 // Grab the synchronization object for the oplock. 01379 // 01380 01381 ExAcquireFastMutexUnsafe( ThisOplock->FastMutex ); 01382 01383 AcquiredMutex = TRUE; 01384 01385 // 01386 // Use a try-finally to facilitate cleanup. 01387 // 01388 01389 try { 01390 01391 // 01392 // If we are requesting a PendingFilter Oplock then it must be 01393 // safe to grant. There is only one open handle and we are in 01394 // the process of opening it. 01395 // 01396 01397 if (NextOplockState == OpFilterReqPending) { 01398 01399 ASSERT( FlagOn( ThisOplock->OplockState, NO_OPLOCK | PENDING )); 01400 01401 ThisOplock->IrpExclusiveOplock = Irp; 01402 ThisOplock->FileObject = IrpSp->FileObject; 01403 01404 ThisOplock->OplockState = OpFilterReqPending; 01405 Status = STATUS_SUCCESS; 01406 01407 // 01408 // If the current oplock state is no oplocks held then we 01409 // will grant the oplock to this requestor. If the state is 01410 // either of the OpFilter states then also grant the request. 01411 // We won't check for a matching file object because there can 01412 // only be one file object. Grant the request anyway. 01413 // 01414 // If the current state is OplockII granted then it must 01415 // be owned by this request. Break the oplock II and grant 01416 // the exclusive lock. 01417 // 01418 01419 } else if (FlagOn( ThisOplock->OplockState, 01420 LEVEL_II_OPLOCK | NO_OPLOCK | PENDING )) { 01421 01422 PFAST_MUTEX OplockFastMutex; 01423 01424 if (ThisOplock->OplockState == OplockIIGranted) { 01425 01426 ASSERT( ThisOplock->IrpOplocksII.Flink == ThisOplock->IrpOplocksII.Blink ); 01427 01428 FsRtlRemoveAndCompleteIrp( ThisOplock->IrpOplocksII.Flink ); 01429 } 01430 01431 // 01432 // Put the address of the fast mutex on the stack. 01433 // 01434 01435 OplockFastMutex = ThisOplock->FastMutex; 01436 01437 // 01438 // We store this Irp in the Oplocks structure. 01439 // We set the oplock state to the correct exclusive oplock. 01440 // 01441 01442 ThisOplock->IrpExclusiveOplock = Irp; 01443 ThisOplock->FileObject = IrpSp->FileObject; 01444 ThisOplock->OplockState = NextOplockState; 01445 01446 IoMarkIrpPending( Irp ); 01447 01448 ObReferenceObject( IrpSp->FileObject ); 01449 01450 Irp->IoStatus.Information = (ULONG_PTR) ThisOplock; 01451 01452 IoAcquireCancelSpinLock( &Irp->CancelIrql ); 01453 01454 // 01455 // Now if the irp is cancelled then we'll call the cancel 01456 // routine right now to do away with the irp, otherwise 01457 // we set the cancel routine 01458 // 01459 01460 if (Irp->Cancel) { 01461 01462 AcquiredMutex = FALSE; 01463 01464 ExReleaseFastMutexUnsafe( OplockFastMutex ); 01465 01466 FsRtlCancelExclusiveIrp( NULL, Irp ); 01467 01468 } else { 01469 01470 IoSetCancelRoutine( Irp, FsRtlCancelExclusiveIrp ); 01471 IoReleaseCancelSpinLock( Irp->CancelIrql ); 01472 } 01473 01474 Status = STATUS_PENDING; 01475 01476 } else { 01477 01478 // 01479 // We'll complete the Irp with the Oplock not granted message 01480 // and return that value as a status. 01481 // 01482 01483 if (ARGUMENT_PRESENT( Irp )) { 01484 01485 FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED ); 01486 } 01487 01488 Status = STATUS_OPLOCK_NOT_GRANTED; 01489 } 01490 01491 } finally { 01492 01493 // 01494 // Give up the oplock synchronization object. 01495 // 01496 01497 if (AcquiredMutex) { 01498 01499 ExReleaseFastMutexUnsafe( ThisOplock->FastMutex ); 01500 } 01501 01502 DebugTrace( +1, Dbg, "FsRtlRequestExclusiveOplock: Exit\n", 0 ); 01503 } 01504 01505 return Status; 01506 } 01507 01508 01509 // 01510 // Local support routine. 01511 // 01512 01513 NTSTATUS 01514 FsRtlRequestOplockII ( 01515 IN OUT PNONOPAQUE_OPLOCK *Oplock, 01516 IN PIO_STACK_LOCATION IrpSp, 01517 IN PIRP Irp 01518 ) 01519 01520 /*++ 01521 01522 Routine Description: 01523 01524 This routine is called when a user is requesting an Oplock II on an 01525 open file. The request is granted if there are currently no 01526 level 1 oplocks on the file and an oplock break is not in progress. 01527 01528 Arguments: 01529 01530 Oplock - Supplies a pointer to the non-opaque oplock structure for 01531 this file. 01532 01533 IrpSp - This is the Irp stack location for the current Irp. 01534 01535 Irp - Supplies a pointer to the Irp which declares the requested 01536 operation. 01537 01538 Return Value: 01539 01540 STATUS_PENDING if the oplock is granted. 01541 STATUS_OPLOCK_NOT_GRANTED if the request is denied. 01542 01543 --*/ 01544 01545 { 01546 NTSTATUS Status; 01547 01548 PNONOPAQUE_OPLOCK ThisOplock; 01549 01550 BOOLEAN AcquiredMutex; 01551 01552 DebugTrace( +1, Dbg, "FsRtlRequestOplockII: Entered\n", 0 ); 01553 DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock ); 01554 DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp ); 01555 DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp ); 01556 01557 // 01558 // We can grant the oplock if no one else owns a level I 01559 // oplock on this file. If the oplock pointer is NULL then there 01560 // are no oplocks on the file. Otherwise we need to check the 01561 // oplock state in an existing oplock structure. 01562 // 01563 01564 if (*Oplock == NULL) { 01565 01566 DebugTrace( 0, 01567 Dbg, 01568 "Oplock currently not allocated\n", 01569 0); 01570 01571 ThisOplock = FsRtlAllocateOplock(); 01572 *Oplock = ThisOplock; 01573 01574 } else { 01575 01576 ThisOplock = *Oplock; 01577 } 01578 01579 // 01580 // Grab the synchronization object for the oplock. 01581 // 01582 01583 ExAcquireFastMutexUnsafe( ThisOplock->FastMutex ); 01584 01585 AcquiredMutex = TRUE; 01586 01587 // 01588 // Use a try-finally to facilitate cleanup. 01589 // 01590 01591 try { 01592 01593 // 01594 // If the current oplock state is no oplocks held or OplockIIGranted 01595 // then we will grant the oplock to this requestor. 01596 // 01597 01598 if (FlagOn( ThisOplock->OplockState, NO_OPLOCK | LEVEL_II_OPLOCK )) { 01599 01600 PFAST_MUTEX OplockFastMutex = ThisOplock->FastMutex; 01601 01602 // 01603 // We store this Irp in the Oplocks structure. 01604 // We set the oplock state to 'OplockIIGranted'. 01605 // 01606 01607 IoMarkIrpPending( Irp ); 01608 01609 Irp->IoStatus.Status = STATUS_SUCCESS; 01610 01611 InsertHeadList( &ThisOplock->IrpOplocksII, 01612 &Irp->Tail.Overlay.ListEntry ); 01613 01614 Irp->IoStatus.Information = (ULONG_PTR) ThisOplock; 01615 01616 ThisOplock->OplockState = OplockIIGranted; 01617 01618 ObReferenceObject( IrpSp->FileObject ); 01619 01620 IoAcquireCancelSpinLock( &Irp->CancelIrql ); 01621 01622 // 01623 // Now if the irp is cancelled then we'll call the cancel 01624 // routine right now to do away with the irp, otherwise 01625 // we set the cancel routine 01626 // 01627 01628 if (Irp->Cancel) { 01629 01630 AcquiredMutex = FALSE; 01631 01632 ExReleaseFastMutexUnsafe( OplockFastMutex ); 01633 01634 FsRtlCancelOplockIIIrp( NULL, Irp ); 01635 01636 } else { 01637 01638 IoSetCancelRoutine( Irp, FsRtlCancelOplockIIIrp ); 01639 IoReleaseCancelSpinLock( Irp->CancelIrql ); 01640 } 01641 01642 Status = STATUS_PENDING; 01643 01644 } else { 01645 01646 // 01647 // We'll complete the Irp with the Oplock not granted message 01648 // and return that value as a status. 01649 // 01650 01651 FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED ); 01652 Status = STATUS_OPLOCK_NOT_GRANTED; 01653 } 01654 01655 } finally { 01656 01657 // 01658 // Give up the oplock synchronization object. 01659 // 01660 01661 if (AcquiredMutex) { 01662 01663 ExReleaseFastMutexUnsafe( ThisOplock->FastMutex ); 01664 } 01665 01666 DebugTrace( +1, Dbg, "FsRtlRequestOplockII: Exit\n", 0 ); 01667 } 01668 01669 return Status; 01670 } 01671 01672 01673 // 01674 // Local support routine. 01675 // 01676 01677 NTSTATUS 01678 FsRtlAcknowledgeOplockBreak ( 01679 IN OUT PNONOPAQUE_OPLOCK Oplock, 01680 IN PIO_STACK_LOCATION IrpSp, 01681 IN PIRP Irp, 01682 IN BOOLEAN GrantLevelII 01683 ) 01684 01685 /*++ 01686 01687 Routine Description: 01688 01689 This routine is called when a user is acknowledging an Oplock I 01690 break. If the level 1 oplock was being broken to level 2, then 01691 a check is made to insure that the level 2 has not been broken 01692 in the meantime. 01693 01694 If an oplock 1 break is not in progress then this will be treated 01695 as an asynchronous break request. If this is an asynchronous break 01696 request and the file object owns an outstanding level 1 oplock, then 01697 the oplock will be broken at this point. 01698 01699 A spurious break request via a file object which does not (or did not) 01700 own the level 1 oplock will generate a warning but will not affect 01701 the oplock state. 01702 01703 At the end of an Oplock I break, all of the waiting irps are completed. 01704 01705 Arguments: 01706 01707 Oplock - Supplies a pointer to the non-opaque oplock structure for 01708 this file. 01709 01710 IrpSp - This is the Irp stack location for the current Irp. 01711 01712 Irp - Supplies a pointer to the Irp which declares the requested 01713 operation. 01714 01715 GrantLevelII - Indicates that this caller wants a level II oplock left 01716 on the file. 01717 01718 Return Value: 01719 01720 STATUS_SUCCESS if we can complete the operation on exiting this thread. 01721 STATUS_CANCELLED if the Irp is cancelled before we return. 01722 01723 --*/ 01724 01725 { 01726 NTSTATUS Status; 01727 01728 BOOLEAN AcquiredMutex; 01729 01730 DebugTrace( +1, Dbg, "FsRtlAcknowledgeOplockBreak: Entered\n", 0 ); 01731 DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock ); 01732 DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp ); 01733 DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp ); 01734 01735 // 01736 // If there is no oplock structure, we complete this with invalid 01737 // oplock protocol. 01738 // 01739 01740 if (Oplock == NULL) { 01741 01742 FsRtlCompleteRequest( Irp, STATUS_INVALID_OPLOCK_PROTOCOL ); 01743 DebugTrace( -1, Dbg, "FsRtlAcknowledgeOplockBreak: Exit -> %08lx\n", STATUS_INVALID_OPLOCK_PROTOCOL ); 01744 return STATUS_INVALID_OPLOCK_PROTOCOL; 01745 } 01746 01747 // 01748 // Grab the synchronization object for the oplock. 01749 // 01750 01751 ExAcquireFastMutexUnsafe( Oplock->FastMutex ); 01752 AcquiredMutex = TRUE; 01753 01754 // 01755 // Use a try-finally to facilitate cleanup. 01756 // 01757 01758 try { 01759 01760 BOOLEAN DereferenceFileObject = TRUE; 01761 01762 // 01763 // If a break is underway but this is not the owner of the 01764 // level 1 oplock, we complete the request and return a 01765 // warning. 01766 // 01767 01768 if (Oplock->FileObject != IrpSp->FileObject) { 01769 01770 Status = STATUS_INVALID_OPLOCK_PROTOCOL; 01771 DebugTrace(0, 01772 Dbg, 01773 "Not oplock owner -> %08lx\n", 01774 Status); 01775 01776 FsRtlCompleteRequest( Irp, Status ); 01777 try_return( Status ); 01778 } 01779 01780 // 01781 // If the user would like a level II and we are breaking to level II 01782 // then grant the oplock. 01783 // 01784 01785 if (GrantLevelII && 01786 FlagOn( Oplock->OplockState, BREAK_TO_II )) { 01787 01788 PFAST_MUTEX OplockFastMutex = Oplock->FastMutex; 01789 01790 DebugTrace(0, Dbg, "OplockItoII\n", 0); 01791 01792 // 01793 // The acknowledgement should never be synchronous. 01794 // 01795 01796 ASSERT( !IoIsOperationSynchronous( Irp )); 01797 01798 // 01799 // We need to add this Irp to the oplock II queue, change 01800 // the oplock state to Oplock II granted and set the 01801 // return value to STATUS_PENDING. 01802 // 01803 01804 01805 IoMarkIrpPending( Irp ); 01806 01807 Irp->IoStatus.Status = STATUS_SUCCESS; 01808 01809 InsertHeadList( &Oplock->IrpOplocksII, 01810 &Irp->Tail.Overlay.ListEntry ); 01811 01812 DereferenceFileObject = FALSE; 01813 01814 Oplock->OplockState = OplockIIGranted; 01815 01816 Irp->IoStatus.Information = (ULONG_PTR) Oplock; 01817 01818 IoAcquireCancelSpinLock( &Irp->CancelIrql ); 01819 01820 // 01821 // Now if the irp is cancelled then we'll call the cancel 01822 // routine right now to do away with the irp, otherwise 01823 // we set the cancel routine 01824 // 01825 01826 if (Irp->Cancel) { 01827 01828 AcquiredMutex = FALSE; 01829 01830 ExReleaseFastMutexUnsafe( OplockFastMutex ); 01831 01832 FsRtlCancelOplockIIIrp( NULL, Irp ); 01833 01834 } else { 01835 01836 IoSetCancelRoutine( Irp, FsRtlCancelOplockIIIrp ); 01837 IoReleaseCancelSpinLock( Irp->CancelIrql ); 01838 } 01839 01840 Status = STATUS_PENDING; 01841 01842 // 01843 // We will break to none since this is the expected case for these 01844 // cases. 01845 // 01846 01847 } else if (FlagOn( Oplock->OplockState, BREAK_TO_II | BREAK_TO_NONE )) { 01848 01849 // 01850 // We need to complete this Irp and return STATUS_SUCCESS. 01851 // We also set the oplock state to no oplocks held. 01852 // 01853 01854 DebugTrace(0, Dbg, "OplockItoNone\n", 0); 01855 01856 Status = STATUS_SUCCESS; 01857 FsRtlCompleteRequest( Irp, Status ); 01858 Oplock->OplockState = NoOplocksHeld; 01859 01860 // 01861 // In this case the user expects to be at level II. He is 01862 // expecting this Irp to be completed when the LevelII Oplock 01863 // is broken. 01864 // 01865 01866 } else if (FlagOn( Oplock->OplockState, BREAK_TO_II_TO_NONE )) { 01867 01868 DebugTrace(0, Dbg, "AcknowledgeOplockBreak: OplockItoIItoNone\n", 0); 01869 01870 Status = STATUS_SUCCESS; 01871 Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE; 01872 FsRtlCompleteRequest( Irp, Status ); 01873 Oplock->OplockState = NoOplocksHeld; 01874 01875 } else { 01876 01877 Status = STATUS_INVALID_OPLOCK_PROTOCOL; 01878 DebugTrace(0, 01879 Dbg, 01880 "No break underway -> %08lx\n", 01881 Status); 01882 01883 FsRtlCompleteRequest( Irp, Status ); 01884 try_return( Status ); 01885 } 01886 01887 // 01888 // Complete the waiting Irps and cleanup the oplock structure. 01889 // 01890 01891 while (!IsListEmpty( &Oplock->WaitingIrps )) { 01892 01893 PWAITING_IRP WaitingIrp; 01894 01895 // 01896 // Remove the entry found and complete the Irp. 01897 // 01898 01899 WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink, 01900 WAITING_IRP, 01901 Links ); 01902 01903 FsRtlRemoveAndCompleteWaitIrp( WaitingIrp ); 01904 } 01905 01906 if (DereferenceFileObject) { 01907 01908 ObDereferenceObject( Oplock->FileObject ); 01909 } 01910 01911 Oplock->FileObject = NULL; 01912 01913 try_exit: NOTHING; 01914 } finally { 01915 01916 // 01917 // Give up the oplock synchronization object. 01918 // 01919 01920 if (AcquiredMutex) { 01921 01922 ExReleaseFastMutexUnsafe( Oplock->FastMutex ); 01923 } 01924 01925 DebugTrace( -1, Dbg, "FsRtlAcknowledgeOplockBreak: Exit -> %08x\n", Status ); 01926 } 01927 01928 return Status; 01929 } 01930 01931 01932 // 01933 // Local support routine. 01934 // 01935 01936 NTSTATUS 01937 FsRtlOpBatchBreakClosePending ( 01938 IN OUT PNONOPAQUE_OPLOCK Oplock, 01939 IN PIO_STACK_LOCATION IrpSp, 01940 IN PIRP Irp 01941 ) 01942 01943 /*++ 01944 01945 Routine Description: 01946 01947 This routine is called when a user is acknowledging a batch oplock 01948 break or Level I oplock break. In this case the user is planning 01949 to close the file as well and doesn't need a level II oplock. 01950 01951 Arguments: 01952 01953 Oplock - Supplies a pointer to the non-opaque oplock structure for 01954 this file. 01955 01956 IrpSp - This is the Irp stack location for the current Irp. 01957 01958 Irp - Supplies a pointer to the Irp which declares the requested 01959 operation. 01960 01961 Return Value: 01962 01963 STATUS_SUCCESS if we can complete the operation on exiting this thread. 01964 STATUS_CANCELLED if the Irp is cancelled before we return. 01965 01966 --*/ 01967 01968 { 01969 NTSTATUS Status = STATUS_SUCCESS; 01970 01971 BOOLEAN AcquiredMutex; 01972 01973 PAGED_CODE(); 01974 01975 DebugTrace( +1, Dbg, "FsRtlOpBatchBreakClosePending: Entered\n", 0 ); 01976 DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock ); 01977 DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp ); 01978 DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp ); 01979 01980 // 01981 // If there is no oplock structure, we complete this with invalid 01982 // oplock protocol. 01983 // 01984 01985 if (Oplock == NULL) { 01986 01987 FsRtlCompleteRequest( Irp, STATUS_INVALID_OPLOCK_PROTOCOL ); 01988 DebugTrace( -1, Dbg, "FsRtlOpBatchClosePending: Exit -> %08lx\n", STATUS_INVALID_OPLOCK_PROTOCOL ); 01989 return STATUS_INVALID_OPLOCK_PROTOCOL; 01990 } 01991 01992 // 01993 // Grab the synchronization object for the oplock. 01994 // 01995 01996 ExAcquireFastMutexUnsafe( Oplock->FastMutex ); 01997 AcquiredMutex = TRUE; 01998 01999 // 02000 // Use a try_finally to facilitate cleanup. 02001 // 02002 02003 try { 02004 02005 // 02006 // If a break is underway but this is not the owner of the 02007 // level 1 oplock, we complete the request and return a 02008 // warning. 02009 // 02010 02011 if (Oplock->FileObject != IrpSp->FileObject) { 02012 02013 Status = STATUS_INVALID_OPLOCK_PROTOCOL; 02014 DebugTrace(0, 02015 Dbg, 02016 "Not oplock owner -> %08lx\n", 02017 Status); 02018 02019 } else { 02020 02021 // 02022 // If this is an opbatch operation we want to note that a 02023 // close is pending. For an exclusive oplock we set the state to 02024 // no oplocsk held. There must be a break in progress to 02025 // process however. 02026 // 02027 02028 if (FlagOn( Oplock->OplockState, 02029 BREAK_TO_II | BREAK_TO_NONE | BREAK_TO_II_TO_NONE )) { 02030 02031 // 02032 // Break all oplocks for an exclusive oplock. 02033 // 02034 02035 if (FlagOn( Oplock->OplockState, LEVEL_I_OPLOCK | PENDING )) { 02036 02037 // 02038 // Clean up the oplock structure and complete all waiting Irps. 02039 // 02040 02041 if (FlagOn( Oplock->OplockState, LEVEL_I_OPLOCK )) { 02042 02043 ObDereferenceObject( Oplock->FileObject ); 02044 } 02045 02046 Oplock->OplockState = NoOplocksHeld; 02047 Oplock->FileObject = NULL; 02048 02049 while (!IsListEmpty( &Oplock->WaitingIrps )) { 02050 02051 PWAITING_IRP WaitingIrp; 02052 02053 // 02054 // Remove the entry found and complete the Irp. 02055 // 02056 02057 WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink, 02058 WAITING_IRP, 02059 Links ); 02060 02061 FsRtlRemoveAndCompleteWaitIrp( WaitingIrp ); 02062 } 02063 02064 // 02065 // Set the state to close pending for batch and filter 02066 // oplocks. 02067 // 02068 02069 } else { 02070 02071 ClearFlag( Oplock->OplockState, OPLOCK_BREAK_MASK ); 02072 SetFlag( Oplock->OplockState, CLOSE_PENDING ); 02073 } 02074 02075 } else { 02076 02077 Status = STATUS_INVALID_OPLOCK_PROTOCOL; 02078 DebugTrace(0, 02079 Dbg, 02080 "No break underway -> %08lx\n", 02081 Status); 02082 } 02083 } 02084 02085 // 02086 // We simply complete this request. 02087 // 02088 02089 FsRtlCompleteRequest( Irp, Status ); 02090 02091 } finally { 02092 02093 // 02094 // Release the synchronization object. 02095 // 02096 02097 ExReleaseFastMutexUnsafe( Oplock->FastMutex ); 02098 02099 DebugTrace(-1, Dbg, "FsRtlOpBatchBreakClosePending: Exit -> %08lx\n", Status); 02100 } 02101 02102 return Status; 02103 } 02104 02105 02106 // 02107 // Local support routine 02108 // 02109 02110 NTSTATUS 02111 FsRtlOplockBreakNotify ( 02112 IN OUT PNONOPAQUE_OPLOCK Oplock, 02113 IN PIO_STACK_LOCATION IrpSp, 02114 IN PIRP Irp 02115 ) 02116 02117 /*++ 02118 02119 Routine Description: 02120 02121 This routine is called when the Irp refers the user request to 02122 be notified when there is no level 1 oplock break in progress. 02123 Under any other condition this routine completes immediately with 02124 STATUS_SUCCESS. Otherwise we simply add this Irp to the list 02125 of Irp's waiting for the break to complete. 02126 02127 Arguments: 02128 02129 Oplock - Supplies a pointer to the non-opaque oplock structure for 02130 this file. 02131 02132 IrpSp - This is the Irp stack location for the current Irp. 02133 02134 Irp - Supplies a pointer to the Irp which declares the requested 02135 operation. 02136 02137 Return Value: 02138 02139 STATUS_SUCCESS if we can complete the operation on exiting this thread. 02140 STATUS_PENDING if we return here but hold the Irp. 02141 STATUS_CANCELLED if the Irp is cancelled before we return. 02142 02143 --*/ 02144 02145 { 02146 NTSTATUS Status; 02147 02148 BOOLEAN AcquiredMutex; 02149 02150 PAGED_CODE(); 02151 02152 DebugTrace( +1, Dbg, "FsRtlOplockBreakNotify: Entered\n", 0 ); 02153 DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock ); 02154 DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp ); 02155 DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp ); 02156 02157 // 02158 // If there is no oplock structure, we complete this with status success. 02159 // 02160 02161 if (Oplock == NULL) { 02162 02163 FsRtlCompleteRequest( Irp, STATUS_SUCCESS ); 02164 DebugTrace( -1, Dbg, "FsRtlOpBatchClosePending: Exit -> %08lx\n", STATUS_SUCCESS ); 02165 return STATUS_SUCCESS; 02166 } 02167 02168 // 02169 // Grap the synchronization object. 02170 // 02171 02172 ExAcquireFastMutexUnsafe( Oplock->FastMutex ); 02173 AcquiredMutex = TRUE; 02174 02175 // 02176 // Use a try-finally to facilitate cleanup. 02177 // 02178 02179 try { 02180 02181 // 02182 // If there are no outstanding level 1 oplocks breaks underway 02183 // or batch oplock breaks underway we complete immediately. 02184 // 02185 02186 if (!FlagOn( Oplock->OplockState, OPLOCK_BREAK_MASK )) { 02187 02188 DebugTrace(0, 02189 Dbg, 02190 "No exclusive oplock break underway\n", 02191 0); 02192 02193 FsRtlCompleteRequest( Irp, STATUS_SUCCESS ); 02194 try_return( Status = STATUS_SUCCESS ); 02195 02196 } else if (FlagOn( Oplock->OplockState, PENDING )) { 02197 02198 Oplock->OplockState = NoOplocksHeld; 02199 Oplock->FileObject = NULL; 02200 02201 FsRtlCompleteRequest( Irp, STATUS_SUCCESS ); 02202 try_return( Status = STATUS_SUCCESS ); 02203 } 02204 02205 // 02206 // Otherwise we need to add this Irp to the list of Irp's waiting 02207 // for the oplock break to complete. 02208 // 02209 02210 AcquiredMutex = FALSE; 02211 02212 // 02213 // Initialize the return value to status success. 02214 // 02215 02216 Irp->IoStatus.Status = STATUS_SUCCESS; 02217 02218 Status = FsRtlWaitOnIrp( Oplock, 02219 Irp, 02220 NULL, 02221 FsRtlNotifyCompletion, 02222 NULL, 02223 NULL ); 02224 02225 try_exit: NOTHING; 02226 } finally { 02227 02228 // 02229 // Give up the synchronization event if we haven't done so. 02230 // 02231 02232 if (AcquiredMutex) { 02233 02234 ExReleaseFastMutexUnsafe( Oplock->FastMutex ); 02235 } 02236 02237 DebugTrace( -1, Dbg, "FsRtlOplockBreakNotify: Exit -> %08lx\n", Status ); 02238 } 02239 02240 return Status; 02241 } 02242 02243 02244 // 02245 // Local support routine 02246 // 02247 02248 VOID 02249 FsRtlOplockCleanup ( 02250 IN OUT PNONOPAQUE_OPLOCK Oplock, 02251 IN PIO_STACK_LOCATION IrpSp 02252 ) 02253 02254 /*++ 02255 02256 Routine Description: 02257 02258 This routine is called to coordinate a cleanup operation with the 02259 oplock state for a file. If there is no level 1 oplock for the 02260 file, then there is no action to take. If the file object in this 02261 Irp matches the file object used in granting the level 1 oplock, 02262 then the close operation will terminate the oplock. If this 02263 cleanup refers to a file object which has a level II oplock, then 02264 that Irp is completed and removed from the list of level II 02265 oplocked Irps. 02266 02267 02268 Arguments: 02269 02270 Oplock - Supplies a pointer to the non-opaque oplock structure for 02271 this file. 02272 02273 IrpSp - This is the Irp stack location for the current Irp. 02274 02275 Return Value: 02276 02277 None. 02278 02279 --*/ 02280 02281 { 02282 DebugTrace( +1, Dbg, "FsRtlOplockCleanup: Entered\n", 0 ); 02283 DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock ); 02284 DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp ); 02285 02286 // 02287 // Grab the synchronization object for the oplock. 02288 // 02289 02290 ExAcquireFastMutexUnsafe( Oplock->FastMutex ); 02291 02292 // 02293 // Use a try-finally to facilitate cleanup. 02294 // 02295 02296 try { 02297 02298 // 02299 // If the oplock has no oplock held we return immediately. 02300 // 02301 02302 if (Oplock->OplockState == NoOplocksHeld) { 02303 02304 DebugTrace(0, 02305 Dbg, 02306 "No oplocks on file\n", 02307 0); 02308 02309 try_return( NOTHING ); 02310 } 02311 02312 // 02313 // If level II oplocks are held, check if this matches any of them. 02314 // 02315 02316 if (Oplock->OplockState == OplockIIGranted) { 02317 02318 PLIST_ENTRY Link; 02319 PIRP Irp; 02320 PIO_STACK_LOCATION NextIrpSp; 02321 02322 DebugTrace(0, 02323 Dbg, 02324 "File has level 2 oplocks\n", 02325 0); 02326 02327 for (Link = Oplock->IrpOplocksII.Flink; 02328 Link != &Oplock->IrpOplocksII; 02329 Link = Link->Flink) { 02330 02331 Irp = CONTAINING_RECORD( Link, IRP, Tail.Overlay.ListEntry ); 02332 02333 NextIrpSp = IoGetCurrentIrpStackLocation( Irp ); 02334 02335 // 02336 // If the file objects match, then emove the entry found and complete the Irp. 02337 // 02338 02339 if (IrpSp->FileObject == NextIrpSp->FileObject) { 02340 02341 // 02342 // Back up to remember this link. 02343 // 02344 02345 Link = Link->Blink; 02346 02347 // 02348 // 02349 02350 FsRtlRemoveAndCompleteIrp( Link->Flink ); 02351 } 02352 } 02353 02354 // 02355 // If all the level II oplocks are gone, then the state is 02356 // no oplocks held. 02357 // 02358 02359 if (IsListEmpty( &Oplock->IrpOplocksII )) { 02360 02361 Oplock->OplockState = NoOplocksHeld; 02362 } 02363 02364 try_return( NOTHING ); 02365 } 02366 02367 // 02368 // If this file object matches that used to request an exclusive 02369 // oplock, we completely close the oplock break. 02370 // 02371 02372 if (IrpSp->FileObject == Oplock->FileObject) { 02373 02374 DebugTrace(0, 02375 Dbg, 02376 "Handle owns level 1 oplock\n", 02377 0); 02378 02379 // 02380 // If an oplock break is not in progress, we initiate one and 02381 // complete the exclusive Irp immediately. 02382 // 02383 02384 if (!FlagOn( Oplock->OplockState, OPLOCK_BREAK_MASK | PENDING )) { 02385 02386 PIRP ExclusiveIrp = Oplock->IrpExclusiveOplock; 02387 02388 DebugTrace(0, 02389 Dbg, 02390 "Initiate oplock break\n", 02391 0); 02392 02393 IoAcquireCancelSpinLock( &ExclusiveIrp->CancelIrql ); 02394 02395 IoSetCancelRoutine( ExclusiveIrp, NULL ); 02396 IoReleaseCancelSpinLock( ExclusiveIrp->CancelIrql ); 02397 02398 ExclusiveIrp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE; 02399 02400 FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_SUCCESS ); 02401 02402 Oplock->IrpExclusiveOplock = NULL; 02403 } 02404 02405 // 02406 // Clean up the oplock structure and complete all waiting Irps. 02407 // Don't do this if this is a pending opfilter request. 02408 // 02409 02410 if (!FlagOn( Oplock->OplockState, PENDING )) { 02411 02412 ObDereferenceObject( IrpSp->FileObject ); 02413 } 02414 02415 Oplock->FileObject = NULL; 02416 Oplock->OplockState = NoOplocksHeld; 02417 02418 while (!IsListEmpty( &Oplock->WaitingIrps )) { 02419 02420 PWAITING_IRP WaitingIrp; 02421 02422 // 02423 // Remove the entry found and complete the Irp. 02424 // 02425 02426 WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink, 02427 WAITING_IRP, 02428 Links ); 02429 02430 FsRtlRemoveAndCompleteWaitIrp( WaitingIrp ); 02431 } 02432 } 02433 02434 try_exit: NOTHING; 02435 } finally { 02436 02437 // 02438 // Give up the oplock synchronization object. 02439 // 02440 02441 ExReleaseFastMutexUnsafe( Oplock->FastMutex ); 02442 DebugTrace( +1, Dbg, "FsRtlOplockCleanup: Exit\n", 0 ); 02443 } 02444 02445 return; 02446 } 02447 02448 02449 // 02450 // Local support routine 02451 // 02452 02453 NTSTATUS 02454 FsRtlOplockBreakToII ( 02455 IN OUT PNONOPAQUE_OPLOCK Oplock, 02456 IN PIO_STACK_LOCATION IrpSp, 02457 IN PIRP Irp, 02458 IN PVOID Context, 02459 IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, 02460 IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine 02461 ) 02462 02463 /*++ 02464 02465 Routine Description: 02466 02467 This routine is a generic worker routine which is called when an 02468 operation will cause all oplocks to be broken to level II before the 02469 operation can proceed. 02470 02471 Arguments: 02472 02473 Oplock - Supplies a pointer to the non-opaque oplock structure for 02474 this file. 02475 02476 IrpSp - This is the Irp stack location for the current Irp. 02477 02478 Irp - Supplies a pointer to the Irp which declares the requested 02479 operation. 02480 02481 Context - This value is passed as a parameter to the completion routine. 02482 02483 CompletionRoutine - This is the routine which is called if this 02484 Irp must wait for an Oplock to break. This 02485 is a synchronous operation if not specified 02486 and we block in this thread waiting on 02487 an event. 02488 02489 PostIrpRoutine - This is the routine to call before we put anything 02490 on our waiting Irp queue. 02491 02492 Return Value: 02493 02494 STATUS_SUCCESS if we can complete the operation on exiting this thread. 02495 STATUS_PENDING if we return here but hold the Irp. 02496 STATUS_CANCELLED if the Irp is cancelled before we return. 02497 02498 --*/ 02499 02500 { 02501 KEVENT Event; 02502 NTSTATUS Status; 02503 02504 BOOLEAN AcquiredMutex; 02505 02506 DebugTrace( +1, Dbg, "CheckOplockBreakToII: Entered\n", 0 ); 02507 DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock ); 02508 DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp ); 02509 DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp ); 02510 02511 // 02512 // Grap the synchronization object. 02513 // 02514 02515 ExAcquireFastMutexUnsafe( Oplock->FastMutex ); 02516 AcquiredMutex = TRUE; 02517 02518 // 02519 // Use a try-finally to facilitate cleanup. 02520 // 02521 02522 try { 02523 02524 // 02525 // If there are no outstanding oplocks or level II oplocks are held, 02526 // we can return immediately. 02527 // 02528 02529 if (!FlagOn( Oplock->OplockState, EXCLUSIVE )) { 02530 02531 DebugTrace(0, 02532 Dbg, 02533 "No oplocks or level II oplocks on file\n", 02534 0); 02535 02536 try_return( Status = STATUS_SUCCESS ); 02537 } 02538 02539 // 02540 // At this point there is an exclusive oplock break in progress. 02541 // If this file object owns that oplock, we allow the operation 02542 // to continue. 02543 // 02544 02545 if (Oplock->FileObject == IrpSp->FileObject) { 02546 02547 DebugTrace(0, 02548 Dbg, 02549 "Handle owns level 1 oplock\n", 02550 0); 02551 02552 try_return( Status = STATUS_SUCCESS ); 02553 } 02554 02555 // 02556 // If there is currently an exclusive oplock held then complete 02557 // the exclusive irp. 02558 // 02559 02560 if (!FlagOn( Oplock->OplockState, PENDING | OPLOCK_BREAK_MASK )) { 02561 02562 PIRP IrpExclusive = Oplock->IrpExclusiveOplock; 02563 02564 DebugTrace(0, 02565 Dbg, 02566 "Breaking exclusive oplock\n", 02567 0); 02568 02569 IoAcquireCancelSpinLock( &IrpExclusive->CancelIrql ); 02570 IoSetCancelRoutine( IrpExclusive, NULL ); 02571 IoReleaseCancelSpinLock( IrpExclusive->CancelIrql ); 02572 02573 // 02574 // If the Irp has been cancelled, we complete the Irp with 02575 // status cancelled and break the oplock completely. 02576 // 02577 02578 if (IrpExclusive->Cancel) { 02579 02580 IrpExclusive->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE; 02581 FsRtlCompleteRequest( IrpExclusive, STATUS_CANCELLED ); 02582 Oplock->OplockState = NoOplocksHeld; 02583 Oplock->IrpExclusiveOplock = NULL; 02584 02585 ObDereferenceObject( Oplock->FileObject ); 02586 Oplock->FileObject = NULL; 02587 02588 // 02589 // Release any waiting irps. 02590 // 02591 02592 while (!IsListEmpty( &Oplock->WaitingIrps )) { 02593 02594 PWAITING_IRP WaitingIrp; 02595 02596 WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink, 02597 WAITING_IRP, 02598 Links ); 02599 02600 FsRtlRemoveAndCompleteWaitIrp( WaitingIrp ); 02601 } 02602 02603 try_return( Status = STATUS_SUCCESS ); 02604 02605 } else { 02606 02607 NTSTATUS CompletionStatus; 02608 02609 if (FlagOn( Oplock->OplockState, LEVEL_I_OPLOCK | BATCH_OPLOCK )) { 02610 02611 SetFlag( Oplock->OplockState, BREAK_TO_II ); 02612 CompletionStatus = FILE_OPLOCK_BROKEN_TO_LEVEL_2; 02613 02614 } else { 02615 02616 SetFlag( Oplock->OplockState, BREAK_TO_NONE ); 02617 CompletionStatus = FILE_OPLOCK_BROKEN_TO_NONE; 02618 } 02619 02620 Oplock->IrpExclusiveOplock->IoStatus.Information = CompletionStatus; 02621 FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_SUCCESS ); 02622 Oplock->IrpExclusiveOplock = NULL; 02623 } 02624 02625 // 02626 // If there is a pending opfilter request then clear the request. 02627 // 02628 02629 } else if (FlagOn( Oplock->OplockState, PENDING )) { 02630 02631 Oplock->OplockState = NoOplocksHeld; 02632 Oplock->FileObject = NULL; 02633 02634 try_return( Status = STATUS_SUCCESS ); 02635 } 02636 02637 // 02638 // If this is an open operation and the user doesn't want to 02639 // block, we will complete the operation now. 02640 // 02641 02642 if ((IrpSp->MajorFunction == IRP_MJ_CREATE) && 02643 FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) { 02644 02645 DebugTrace( 0, Dbg, "Don't block open\n", 0 ); 02646 02647 try_return( Status = STATUS_OPLOCK_BREAK_IN_PROGRESS ); 02648 } 02649 02650 // 02651 // If we get here that means that this operation can't continue 02652 // until the oplock break is complete. 02653 // 02654 // FsRtlWaitOnIrp will release the mutex. 02655 // 02656 02657 AcquiredMutex = FALSE; 02658 02659 Status = FsRtlWaitOnIrp( Oplock, 02660 Irp, 02661 Context, 02662 CompletionRoutine, 02663 PostIrpRoutine, 02664 &Event ); 02665 02666 try_exit: NOTHING; 02667 } finally { 02668 02669 // 02670 // Give up the synchronization event if we haven't done so. 02671 // 02672 02673 if (AcquiredMutex) { 02674 02675 ExReleaseFastMutexUnsafe( Oplock->FastMutex ); 02676 } 02677 02678 DebugTrace( -1, Dbg, "FsRtlOplockBreakToII: Exit -> %08lx\n", Status ); 02679 } 02680 02681 return Status; 02682 } 02683 02684 02685 // 02686 // Local support routine. 02687 // 02688 02689 NTSTATUS 02690 FsRtlOplockBreakToNone ( 02691 IN OUT PNONOPAQUE_OPLOCK Oplock, 02692 IN PIO_STACK_LOCATION IrpSp, 02693 IN PIRP Irp, 02694 IN PVOID Context, 02695 IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, 02696 IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL 02697 ) 02698 02699 /*++ 02700 02701 Routine Description: 02702 02703 This routine is a generic worker routine which is called when an 02704 operation will cause all oplocks to be broken before the operation can 02705 proceed. 02706 02707 Arguments: 02708 02709 Oplock - Supplies a pointer to the non-opaque oplock structure for 02710 this file. 02711 02712 IrpSp - This is the Irp stack location for the current Irp. 02713 02714 Irp - Supplies a pointer to the Irp which declares the requested 02715 operation. 02716 02717 Context - This value is passed as a parameter to the completion routine. 02718 02719 CompletionRoutine - This is the routine which is called if this 02720 Irp must wait for an Oplock to break. This 02721 is a synchronous operation if not specified 02722 and we block in this thread waiting on 02723 an event. 02724 02725 PostIrpRoutine - This is the routine to call before we put anything 02726 on our waiting Irp queue. 02727 02728 Return Value: 02729 02730 STATUS_SUCCESS if we can complete the operation on exiting this thread. 02731 STATUS_PENDING if we return here but hold the Irp. 02732 STATUS_CANCELLED if the Irp is cancelled before we return. 02733 02734 --*/ 02735 02736 { 02737 KEVENT Event; 02738 NTSTATUS Status; 02739 02740 BOOLEAN AcquiredMutex; 02741 02742 DebugTrace( +1, Dbg, "CheckOplockBreakToNone: Entered\n", 0 ); 02743 DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock ); 02744 DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp ); 02745 DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp ); 02746 02747 // 02748 // Grap the synchronization object. 02749 // 02750 02751 ExAcquireFastMutexUnsafe( Oplock->FastMutex ); 02752 AcquiredMutex = TRUE; 02753 02754 // 02755 // Use a try-finally to facilitate cleanup. 02756 // 02757 02758 try { 02759 02760 // 02761 // If there are no outstanding oplocks, we can return immediately. 02762 // 02763 02764 if (Oplock->OplockState == NoOplocksHeld) { 02765 02766 DebugTrace(0, 02767 Dbg, 02768 "No oplocks on file\n", 02769 0); 02770 02771 try_return( Status = STATUS_SUCCESS ); 02772 } 02773 02774 // 02775 // If there is an exclusive oplock held, we begin the break to none. 02776 // 02777 02778 if (!FlagOn( Oplock->OplockState, 02779 LEVEL_II_OPLOCK | PENDING | OPLOCK_BREAK_MASK )) { 02780 02781 PIRP IrpExclusive = Oplock->IrpExclusiveOplock; 02782 02783 DebugTrace(0, 02784 Dbg, 02785 "Breaking exclusive oplock\n", 02786 0); 02787 02788 IoAcquireCancelSpinLock( &IrpExclusive->CancelIrql ); 02789 IoSetCancelRoutine( IrpExclusive, NULL ); 02790 IoReleaseCancelSpinLock( IrpExclusive->CancelIrql ); 02791 02792 // 02793 // If the Irp has been cancelled, we complete the Irp with 02794 // status cancelled and break the oplock completely. 02795 // 02796 02797 if (IrpExclusive->Cancel) { 02798 02799 IrpExclusive->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE; 02800 FsRtlCompleteRequest( IrpExclusive, STATUS_CANCELLED ); 02801 Oplock->OplockState = NoOplocksHeld; 02802 Oplock->IrpExclusiveOplock = NULL; 02803 02804 ObDereferenceObject( Oplock->FileObject ); 02805 Oplock->FileObject = NULL; 02806 02807 // 02808 // Release any waiting irps. 02809 // 02810 02811 while (!IsListEmpty( &Oplock->WaitingIrps )) { 02812 02813 PWAITING_IRP WaitingIrp; 02814 02815 WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink, 02816 WAITING_IRP, 02817 Links ); 02818 02819 FsRtlRemoveAndCompleteWaitIrp( WaitingIrp ); 02820 } 02821 02822 try_return( Status = STATUS_SUCCESS ); 02823 02824 } else { 02825 02826 Oplock->IrpExclusiveOplock->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE; 02827 FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_SUCCESS ); 02828 Oplock->IrpExclusiveOplock = NULL; 02829 02830 SetFlag( Oplock->OplockState, BREAK_TO_NONE ); 02831 } 02832 02833 // 02834 // If there are level II oplocks, this will break all of them. 02835 // 02836 02837 } else if (Oplock->OplockState == OplockIIGranted) { 02838 02839 DebugTrace(0, 02840 Dbg, 02841 "Breaking all level 2 oplocks\n", 02842 0); 02843 02844 while (!IsListEmpty( &Oplock->IrpOplocksII )) { 02845 02846 // 02847 // Remove and complete this Irp with STATUS_SUCCESS. 02848 // 02849 02850 FsRtlRemoveAndCompleteIrp( Oplock->IrpOplocksII.Flink ); 02851 } 02852 02853 // 02854 // Set the oplock state to no oplocks held. 02855 // 02856 02857 Oplock->OplockState = NoOplocksHeld; 02858 02859 try_return( Status = STATUS_SUCCESS ); 02860 02861 // 02862 // If we are currently breaking to level II then change that 02863 // to BreakToIIToNone. 02864 // 02865 02866 } else if (FlagOn( Oplock->OplockState, BREAK_TO_II )) { 02867 02868 ClearFlag( Oplock->OplockState, BREAK_TO_II ); 02869 SetFlag( Oplock->OplockState, BREAK_TO_II_TO_NONE ); 02870 02871 // 02872 // If there is a pending opfilter request then clear that request. 02873 // 02874 02875 } else if (FlagOn( Oplock->OplockState, PENDING )) { 02876 02877 Oplock->OplockState = NoOplocksHeld; 02878 Oplock->FileObject = NULL; 02879 02880 try_return( Status = STATUS_SUCCESS ); 02881 } 02882 02883 // 02884 // At this point there is already an exclusive oplock break in progress. 02885 // If this file object owns that oplock, we allow the operation 02886 // to continue. 02887 // 02888 02889 if (Oplock->FileObject == IrpSp->FileObject) { 02890 02891 DebugTrace(0, 02892 Dbg, 02893 "Handle owns level 1 oplock\n", 02894 0); 02895 02896 try_return( Status = STATUS_SUCCESS ); 02897 } 02898 02899 // 02900 // If this is an open operation and the user doesn't want to 02901 // block, we will complete the operation now. 02902 // 02903 02904 if ((IrpSp->MajorFunction == IRP_MJ_CREATE) && 02905 FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) { 02906 02907 DebugTrace( 0, Dbg, "Don't block open\n", 0 ); 02908 02909 try_return( Status = STATUS_OPLOCK_BREAK_IN_PROGRESS ); 02910 } 02911 02912 // 02913 // If we get here that means that this operation can't continue 02914 // until the oplock break is complete. 02915 // 02916 // FsRtlWaitOnIrp will release the mutex. 02917 // 02918 02919 AcquiredMutex = FALSE; 02920 02921 Status = FsRtlWaitOnIrp( Oplock, 02922 Irp, 02923 Context, 02924 CompletionRoutine, 02925 PostIrpRoutine, 02926 &Event ); 02927 02928 try_exit: NOTHING; 02929 } finally { 02930 02931 // 02932 // Give up the synchronization event if we haven't done so. 02933 // 02934 02935 if (AcquiredMutex) { 02936 02937 ExReleaseFastMutexUnsafe( Oplock->FastMutex ); 02938 } 02939 02940 DebugTrace( -1, Dbg, "CheckOplockBreakToNone: Exit -> %08lx\n", Status ); 02941 } 02942 02943 return Status; 02944 } 02945 02946 02947 // 02948 // Local support routine. 02949 // 02950 02951 VOID 02952 FsRtlRemoveAndCompleteIrp ( 02953 IN PLIST_ENTRY Link 02954 ) 02955 02956 /*++ 02957 02958 Routine Description: 02959 02960 This routine is called to remove an Irp from a list of Irps linked 02961 with the Tail.ListEntry field and complete them with STATUS_CANCELLED 02962 if the Irp has been cancelled, STATUS_SUCCESS otherwise. 02963 02964 Arguments: 02965 02966 Link - Supplies the entry to remove from the list. 02967 02968 Return Value: 02969 02970 None. 02971 02972 --*/ 02973 02974 { 02975 PIRP Irp; 02976 PIO_STACK_LOCATION OplockIIIrpSp; 02977 02978 DebugTrace( +1, Dbg, "FsRtlRemoveAndCompleteIrp: Entered\n", 0 ); 02979 02980 // 02981 // Reference the Irp. 02982 // 02983 02984 Irp = CONTAINING_RECORD( Link, IRP, Tail.Overlay.ListEntry ); 02985 02986 // 02987 // Get the stack location and dereference the file object. 02988 // 02989 02990 OplockIIIrpSp = IoGetCurrentIrpStackLocation( Irp ); 02991 ObDereferenceObject( OplockIIIrpSp->FileObject ); 02992 02993 // 02994 // Clear the cancel routine in the irp. 02995 // 02996 02997 IoAcquireCancelSpinLock( &Irp->CancelIrql ); 02998 02999 IoSetCancelRoutine( Irp, NULL ); 03000 IoReleaseCancelSpinLock( Irp->CancelIrql ); 03001 03002 // 03003 // Remove this from the list. 03004 // 03005 03006 RemoveEntryList( Link ); 03007 03008 // 03009 // Complete the oplock Irp. 03010 // 03011 03012 Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE; 03013 03014 FsRtlCompleteRequest( Irp, Irp->Cancel ? STATUS_CANCELLED : STATUS_SUCCESS ); 03015 03016 DebugTrace( -1, Dbg, "FsRtlRemoveAndCompleteIrp: Exit\n", 0 ); 03017 } 03018 03019 03020 // 03021 // Local support routine. 03022 // 03023 03024 NTSTATUS 03025 FsRtlWaitOnIrp ( 03026 IN OUT PNONOPAQUE_OPLOCK Oplock, 03027 IN PIRP Irp, 03028 IN PVOID Context, 03029 IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, 03030 IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL, 03031 IN PKEVENT Event 03032 ) 03033 03034 /*++ 03035 03036 Routine Description: 03037 03038 This routine is called to create a Wait Irp structure and attach it 03039 to the current Irp. The Irp is then added to the list of Irps waiting 03040 for an oplock break. We check if the Irp has been cancelled and if 03041 so we call our cancel routine to perform the work. 03042 03043 This routine is holding the Mutex for the oplock on entry and 03044 must give it up on exit. 03045 03046 Arguments: 03047 03048 Oplock - Supplies a pointer to the non-opaque oplock structure for 03049 this file. 03050 03051 Irp - Supplies a pointer to the Irp which declares the requested 03052 operation. 03053 03054 Context - This value is passed as a parameter to the completion routine. 03055 03056 CompletionRoutine - This is the routine which is called if this 03057 Irp must wait for an Oplock to break. This 03058 is a synchronous operation if not specified 03059 and we block in this thread waiting on 03060 an event. 03061 03062 PostIrpRoutine - This is the routine to call before we put anything 03063 on our waiting Irp queue. 03064 03065 Event - If there is no user completion routine, this thread will 03066 block using this event. 03067 03068 Return Value: 03069 03070 STATUS_SUCCESS if we can complete the operation on exiting this thread. 03071 STATUS_PENDING if we return here but hold the Irp. 03072 STATUS_CANCELLED if the Irp is cancelled before we return. 03073 03074 --*/ 03075 03076 { 03077 BOOLEAN AcquiredMutex; 03078 NTSTATUS Status; 03079 03080 PWAITING_IRP WaitingIrp; 03081 03082 DebugTrace( +1, Dbg, "FsRtlWaitOnIrp: Entered\n", 0 ); 03083 03084 // 03085 // Remember that we have the mutex. 03086 // 03087 03088 AcquiredMutex = TRUE; 03089 03090 // 03091 // Use a try-finally to facilitate cleanup. 03092 // 03093 03094 try { 03095 03096 PFAST_MUTEX OplockFastMutex = Oplock->FastMutex; 03097 03098 // 03099 // Allocate and initialize the Wait Irp structure. 03100 // 03101 03102 WaitingIrp = FsRtlpAllocatePool( PagedPool, sizeof( WAITING_IRP )); 03103 03104 WaitingIrp->Irp = Irp; 03105 03106 WaitingIrp->Context = Context; 03107 WaitingIrp->Information = (ULONG) Irp->IoStatus.Information; 03108 03109 // 03110 // Take appropriate action if depending on the value of the 03111 // completion routine. 03112 // 03113 03114 if (ARGUMENT_PRESENT( CompletionRoutine )) { 03115 03116 WaitingIrp->CompletionRoutine = CompletionRoutine; 03117 WaitingIrp->Context = Context; 03118 03119 } else { 03120 03121 WaitingIrp->CompletionRoutine = FsRtlCompletionRoutinePriv; 03122 WaitingIrp->Context = Event; 03123 03124 KeInitializeEvent( Event, NotificationEvent, FALSE ); 03125 } 03126 03127 // 03128 // Call the file system's post Irp code. 03129 // 03130 03131 if (ARGUMENT_PRESENT( PostIrpRoutine )) { 03132 03133 PostIrpRoutine( Context, Irp ); 03134 } 03135 03136 // 03137 // Initialize the return value to status success. 03138 // 03139 03140 Irp->IoStatus.Status = STATUS_SUCCESS; 03141 03142 // 03143 // We put this into the Waiting Irp queue. 03144 // 03145 03146 InsertTailList( &Oplock->WaitingIrps, &WaitingIrp->Links ); 03147 03148 // 03149 // We grab the cancel spinlock and store the address of the oplock. 03150 // 03151 03152 IoAcquireCancelSpinLock( &Irp->CancelIrql ); 03153 Irp->IoStatus.Information = (ULONG_PTR) Oplock; 03154 03155 // 03156 // If the Irp is cancelled then we'll call the cancel routine 03157 // right now to do away with the Waiting Irp structure. 03158 // 03159 03160 if (Irp->Cancel) { 03161 03162 ExReleaseFastMutexUnsafe( OplockFastMutex ); 03163 AcquiredMutex = FALSE; 03164 03165 if (ARGUMENT_PRESENT( CompletionRoutine )) { 03166 03167 IoMarkIrpPending( Irp ); 03168 Status = STATUS_PENDING; 03169 03170 } else { 03171 03172 Status = STATUS_CANCELLED; 03173 } 03174 03175 FsRtlCancelWaitIrp( NULL, Irp ); 03176 03177 // 03178 // Otherwise, we set the cancel routine and decide whether we 03179 // are going to wait on our local event. 03180 // 03181 03182 } else { 03183 03184 IoSetCancelRoutine( Irp, FsRtlCancelWaitIrp ); 03185 IoReleaseCancelSpinLock( Irp->CancelIrql ); 03186 03187 // 03188 // If we wait on the event, we pull the return code out of 03189 // the Irp. 03190 // 03191 03192 if (!ARGUMENT_PRESENT( CompletionRoutine )) { 03193 03194 AcquiredMutex = FALSE; 03195 03196 ExReleaseFastMutexUnsafe( Oplock->FastMutex ); 03197 03198 KeWaitForSingleObject( Event, 03199 Executive, 03200 KernelMode, 03201 FALSE, 03202 NULL ); 03203 03204 Status = Irp->IoStatus.Status; 03205 03206 // 03207 // Otherwise, we return STATUS_PENDING. 03208 // 03209 03210 } else { 03211 03212 IoMarkIrpPending( Irp ); 03213 03214 Status = STATUS_PENDING; 03215 } 03216 } 03217 03218 } finally { 03219 03220 // 03221 // Release the Mutex if we have not done so. 03222 // 03223 03224 if (AcquiredMutex) { 03225 03226 ExReleaseFastMutexUnsafe( Oplock->FastMutex ); 03227 } 03228 03229 DebugTrace( -1, Dbg, "FsRtlWaitOnIrp: Exit\n", 0 ); 03230 } 03231 03232 return Status; 03233 } 03234 03235 03236 // 03237 // Local support routine. 03238 // 03239 03240 VOID 03241 FsRtlCompletionRoutinePriv ( 03242 IN PVOID Context, 03243 IN PIRP Irp 03244 ) 03245 03246 /*++ 03247 03248 Routine Description: 03249 03250 This routine is called when an operation must be synchronous with 03251 respect to the oplock package. This routine will simply set the 03252 event in the Signalled state, allowing some other thread to resume 03253 execution. 03254 03255 Arguments: 03256 03257 Context - This is the event to signal. 03258 03259 Irp - Supplies a pointer to the Irp which declares the requested 03260 operation. 03261 03262 Return Value: 03263 03264 None. 03265 03266 --*/ 03267 03268 { 03269 PAGED_CODE(); 03270 03271 DebugTrace( +1, Dbg, "FsRtlCompletionRoutinePriv: Entered\n", 0 ); 03272 03273 KeSetEvent( (PKEVENT)Context, 0, FALSE ); 03274 03275 DebugTrace( -1, Dbg, "FsRtlCompletionRoutinePriv: Exit\n", 0 ); 03276 03277 return; 03278 03279 UNREFERENCED_PARAMETER( Irp ); 03280 } 03281 03282 03283 // 03284 // Local support routine. 03285 // 03286 03287 VOID 03288 FsRtlCancelWaitIrp ( 03289 IN PDEVICE_OBJECT DeviceObject, 03290 IN PIRP Irp 03291 ) 03292 03293 /*++ 03294 03295 Routine Description: 03296 03297 This routine is called for an Irp that is placed on the waiting 03298 Irp queue. We remove the Cancel routine from the specified Irp and 03299 then call the completion routines for all the cancelled Irps on the 03300 queue. 03301 03302 Arguments: 03303 03304 DeviceObject - Ignored. 03305 03306 Irp - Supplies the Irp being cancelled. A pointer to the 03307 Oplock structure for the Irp is stored in the information 03308 field of the Irp's Iosb. 03309 03310 Return Value: 03311 03312 None. 03313 03314 --*/ 03315 03316 { 03317 PNONOPAQUE_OPLOCK Oplock; 03318 03319 PLIST_ENTRY Links; 03320 03321 DebugTrace( +1, Dbg, "FsRtlCancelWaitIrp: Entered\n", 0 ); 03322 03323 Oplock = (PNONOPAQUE_OPLOCK) Irp->IoStatus.Information; 03324 03325 // 03326 // We now need to void the cancel routine and release the spinlock 03327 // 03328 03329 IoSetCancelRoutine( Irp, NULL ); 03330 IoReleaseCancelSpinLock( Irp->CancelIrql ); 03331 03332 // 03333 // Iterate through all of the waiting locks looking for a canceled one 03334 // We do this under the protection of the oplock mutex. 03335 // 03336 03337 ExAcquireFastMutex( Oplock->FastMutex ); 03338 03339 try { 03340 03341 for (Links = Oplock->WaitingIrps.Flink; 03342 Links != &Oplock->WaitingIrps; 03343 Links = Links->Flink ) { 03344 03345 PWAITING_IRP WaitingIrp; 03346 03347 // 03348 // Get a pointer to the waiting Irp record 03349 // 03350 03351 WaitingIrp = CONTAINING_RECORD( Links, WAITING_IRP, Links ); 03352 03353 DebugTrace(0, Dbg, "FsRtlCancelWaitIrp, Loop top, WaitingIrp = %08lx\n", WaitingIrp); 03354 03355 // 03356 // Check if the irp has been cancelled 03357 // 03358 03359 if (WaitingIrp->Irp->Cancel) { 03360 03361 // 03362 // Now we need to remove this waiter and call the 03363 // completion routine. But we must not mess up our link 03364 // iteration so we need to back up link one step and 03365 // then the next iteration will go to our current flink. 03366 // 03367 03368 Links = Links->Blink; 03369 03370 FsRtlRemoveAndCompleteWaitIrp( WaitingIrp ); 03371 } 03372 } 03373 03374 } finally { 03375 03376 // 03377 // No matter how we exit we release the mutex 03378 // 03379 03380 ExReleaseFastMutex( Oplock->FastMutex ); 03381 03382 DebugTrace( -1, Dbg, "FsRtlCancelWaitIrp: Exit\n", 0 ); 03383 } 03384 03385 return; 03386 03387 UNREFERENCED_PARAMETER( DeviceObject ); 03388 } 03389 03390 03391 // 03392 // Local support routine. 03393 // 03394 03395 VOID 03396 FsRtlCancelOplockIIIrp ( 03397 IN PDEVICE_OBJECT DeviceObject, 03398 IN PIRP Irp 03399 ) 03400 03401 /*++ 03402 03403 Routine Description: 03404 03405 This routine is called for an Irp that is placed in the Oplock II 03406 Irp queue. We remove the Cancel routine from the specified Irp and 03407 then call the completion routines for all the cancelled Irps on the 03408 queue. 03409 03410 Arguments: 03411 03412 DeviceObject - Ignored. 03413 03414 Irp - Supplies the Irp being cancelled. A pointer to the 03415 Oplock structure for the Irp is stored in the information 03416 field of the Irp's Iosb. 03417 03418 Return Value: 03419 03420 None. 03421 03422 --*/ 03423 03424 { 03425 PNONOPAQUE_OPLOCK Oplock; 03426 BOOLEAN LevelIIIrps; 03427 03428 PLIST_ENTRY Links; 03429 03430 DebugTrace( +1, Dbg, "FsRtlCancelOplockIIIrp: Entered\n", 0 ); 03431 03432 Oplock = (PNONOPAQUE_OPLOCK) Irp->IoStatus.Information; 03433 03434 // 03435 // We now need to void the cancel routine and release the spinlock 03436 // 03437 03438 IoSetCancelRoutine( Irp, NULL ); 03439 IoReleaseCancelSpinLock( Irp->CancelIrql ); 03440 03441 LevelIIIrps = FALSE; 03442 03443 // 03444 // Iterate through all of the level II oplocks looking for a canceled one 03445 // We do this under the protection of the oplock mutex. 03446 // 03447 03448 ExAcquireFastMutex( Oplock->FastMutex ); 03449 03450 try { 03451 03452 for (Links = Oplock->IrpOplocksII.Flink; 03453 Links != &Oplock->IrpOplocksII; 03454 Links = Links->Flink ) { 03455 03456 PIRP OplockIIIrp; 03457 03458 // 03459 // Get a pointer to the Irp record 03460 // 03461 03462 OplockIIIrp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry ); 03463 03464 DebugTrace(0, Dbg, "FsRtlCancelOplockIIIrp, Loop top, Irp = %08lx\n", OplockIIIrp); 03465 03466 // 03467 // Check if the irp has been cancelled 03468 // 03469 03470 if (OplockIIIrp->Cancel) { 03471 03472 // 03473 // Now we need to remove this waiter and call the 03474 // completion routine. But we must not mess up our link 03475 // iteration so we need to back up link one step and 03476 // then the next iteration will go to our current flink. 03477 // 03478 03479 Links = Links->Blink; 03480 03481 FsRtlRemoveAndCompleteIrp( Links->Flink ); 03482 03483 LevelIIIrps = TRUE; 03484 } 03485 } 03486 03487 // 03488 // If the list is now empty, change the oplock status to 03489 // no oplocks held. 03490 // 03491 03492 if (LevelIIIrps && IsListEmpty( &Oplock->IrpOplocksII )) { 03493 03494 Oplock->OplockState = NoOplocksHeld; 03495 } 03496 03497 } finally { 03498 03499 // 03500 // No matter how we exit we release the mutex 03501 // 03502 03503 ExReleaseFastMutex( Oplock->FastMutex ); 03504 03505 DebugTrace( -1, Dbg, "FsRtlCancelOplockIIIrp: Exit\n", 0 ); 03506 } 03507 03508 return; 03509 03510 UNREFERENCED_PARAMETER( DeviceObject ); 03511 } 03512 03513 03514 // 03515 // Local support routine. 03516 // 03517 03518 VOID 03519 FsRtlCancelExclusiveIrp ( 03520 IN PDEVICE_OBJECT DeviceObject, 03521 IN PIRP Irp 03522 ) 03523 03524 /*++ 03525 03526 Routine Description: 03527 03528 This routine is called for either an exclusive or oplock I Irp. 03529 03530 Arguments: 03531 03532 DeviceObject - Ignored. 03533 03534 Irp - Supplies the Irp being cancelled. A pointer to the 03535 Oplock structure for the Irp is stored in the information 03536 field of the Irp's Iosb. 03537 03538 Return Value: 03539 03540 None. 03541 03542 --*/ 03543 03544 { 03545 PNONOPAQUE_OPLOCK Oplock; 03546 03547 DebugTrace( +1, Dbg, "FsRtlCancelExclusiveIrp: Entered\n", 0 ); 03548 03549 Oplock = (PNONOPAQUE_OPLOCK) Irp->IoStatus.Information; 03550 03551 // 03552 // We now need to void the cancel routine and release the spinlock 03553 // 03554 03555 IoSetCancelRoutine( Irp, NULL ); 03556 IoReleaseCancelSpinLock( Irp->CancelIrql ); 03557 03558 // 03559 // Grab the synchronization object for this oplock. 03560 // 03561 03562 ExAcquireFastMutex( Oplock->FastMutex ); 03563 03564 try { 03565 03566 // 03567 // We look for the exclusive Irp, if present and cancelled 03568 // we complete it. 03569 // 03570 03571 if ((Oplock->IrpExclusiveOplock != NULL) && 03572 (Oplock->IrpExclusiveOplock->Cancel)) { 03573 03574 FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_CANCELLED ); 03575 Oplock->IrpExclusiveOplock = NULL; 03576 03577 ObDereferenceObject( Oplock->FileObject ); 03578 Oplock->FileObject = NULL; 03579 Oplock->OplockState = NoOplocksHeld; 03580 03581 // 03582 // Complete the waiting Irps. 03583 // 03584 03585 while (!IsListEmpty( &Oplock->WaitingIrps )) { 03586 03587 PWAITING_IRP WaitingIrp; 03588 03589 // 03590 // Remove the entry found and complete the Irp. 03591 // 03592 03593 WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink, 03594 WAITING_IRP, 03595 Links ); 03596 03597 FsRtlRemoveAndCompleteWaitIrp( WaitingIrp ); 03598 } 03599 } 03600 03601 } finally { 03602 03603 // 03604 // No matter how we exit we release the mutex 03605 // 03606 03607 ExReleaseFastMutex( Oplock->FastMutex ); 03608 03609 DebugTrace( -1, Dbg, "FsRtlCancelExclusiveIrp: Exit\n", 0 ); 03610 } 03611 03612 return; 03613 03614 UNREFERENCED_PARAMETER( DeviceObject ); 03615 } 03616 03617 03618 // 03619 // Local support routine. 03620 // 03621 03622 VOID 03623 FsRtlRemoveAndCompleteWaitIrp ( 03624 IN PWAITING_IRP WaitingIrp 03625 ) 03626 03627 /*++ 03628 03629 Routine Description: 03630 03631 This routine is called to remove and perform any neccessary cleanup 03632 for an Irp stored on the waiting Irp list in an oplock structure. 03633 03634 Arguments: 03635 03636 WaitingIrp - This is the auxilary structure attached to the Irp 03637 being completed. 03638 03639 Return Value: 03640 03641 None. 03642 03643 --*/ 03644 03645 { 03646 PIRP Irp; 03647 03648 PAGED_CODE(); 03649 03650 DebugTrace( +1, Dbg, "FsRtlRemoveAndCompleteWaitIrp: Entered\n", 0 ); 03651 03652 // 03653 // Remove the Irp from the queue. 03654 // 03655 03656 RemoveEntryList( &WaitingIrp->Links ); 03657 03658 Irp = WaitingIrp->Irp; 03659 03660 IoAcquireCancelSpinLock( &Irp->CancelIrql ); 03661 03662 IoSetCancelRoutine( Irp, NULL ); 03663 IoReleaseCancelSpinLock( Irp->CancelIrql ); 03664 03665 // 03666 // Restore the information field. 03667 // 03668 03669 Irp->IoStatus.Information = WaitingIrp->Information; 03670 03671 Irp->IoStatus.Status = (Irp->Cancel 03672 ? STATUS_CANCELLED 03673 : STATUS_SUCCESS); 03674 03675 // 03676 // Call the completion routine in the Waiting Irp. 03677 // 03678 03679 WaitingIrp->CompletionRoutine( WaitingIrp->Context, Irp ); 03680 03681 // 03682 // And free up pool 03683 // 03684 03685 ExFreePool( WaitingIrp ); 03686 03687 DebugTrace( -1, Dbg, "FsRtlRemoveAndCompleteWaitIrp: Exit\n", 0 ); 03688 03689 return; 03690 } 03691 03692 03693 // 03694 // Local support routine. 03695 // 03696 03697 VOID 03698 FsRtlNotifyCompletion ( 03699 IN PVOID Context, 03700 IN PIRP Irp 03701 ) 03702 03703 /*++ 03704 03705 Routine Description: 03706 03707 This is the completion routine called when a break notify Irp is to 03708 be completed. We simply call FsRtlComplete request to dispose of the 03709 Irp. 03710 03711 Arguments: 03712 03713 Context - Ignored. 03714 03715 Irp - Irp used to request break notify. 03716 03717 Return Value: 03718 03719 None. 03720 03721 --*/ 03722 03723 { 03724 PAGED_CODE(); 03725 03726 DebugTrace( +1, Dbg, "FsRtlNotifyCompletion: Entered\n", 0 ); 03727 03728 // 03729 // Call FsRtlCompleteRequest using the value in the Irp. 03730 // 03731 03732 FsRtlCompleteRequest( Irp, Irp->IoStatus.Status ); 03733 03734 DebugTrace( -1, Dbg, "FsRtlNotifyCompletion: Exit\n", 0 ); 03735 03736 return; 03737 }

Generated on Sat May 15 19:41:06 2004 for test by doxygen 1.3.7