Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3738 lines
96 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Oplock.c
  5. Abstract:
  6. The OPLOCK routines provide support to filesystems which implement
  7. opporuntistics locks. The specific actions needed are based on
  8. the current oplocked state of the file (maintained in the OPLOCK
  9. structure) and the Irp the Io system provides to the file systems.
  10. Rather than define separate entry points for each oplock operation
  11. a single generic entry point is defined.
  12. The file systems will maintain a variable of type OPLOCK for
  13. each open file in the system. This variable is initialized
  14. when an unopened file is opened. It is uninitialized when the
  15. last reference to the file is cleared when the Io system calls
  16. the file system with a close call.
  17. The following routines are provided by this package:
  18. o FsRtlInitializeOplock - Initialize a new OPLOCK structure. There
  19. should be one OPLOCK for every opened file. Each OPLOCK structure
  20. must be initialized before it can be used by the system.
  21. o FsRtlUninitializeOplock - Uninitialize an OPLOCK structure. This
  22. call is used to cleanup any anciallary structures allocated and
  23. maintained by the OPLOCK. After being uninitialized the OPLOCK
  24. must again be initialized before it can be used by the system.
  25. Author:
  26. Brian Andrew [BrianAn] 10-Dec-1990
  27. Revision History:
  28. --*/
  29. #include "FsRtlP.h"
  30. //
  31. // Trace level for the module
  32. //
  33. #define Dbg (0x08000000)
  34. //
  35. // Define the compatible filter oplock desired access flags. We won't break
  36. // a filter oplock when these flags are the only flags specified.
  37. //
  38. #define FILTER_OPLOCK_VALID_FLAGS ( \
  39. FILE_READ_ATTRIBUTES | \
  40. FILE_WRITE_ATTRIBUTES | \
  41. FILE_READ_DATA | \
  42. FILE_READ_EA | \
  43. FILE_EXECUTE | \
  44. SYNCHRONIZE | \
  45. READ_CONTROL \
  46. )
  47. //
  48. // We encode the different bits so we can test without having to enumerate
  49. // all of the possible states.
  50. //
  51. // NOTE - The LEVEL_1, BATCH_OPLOCK and FILTER_OPLOCK must be in this order.
  52. // We assume later on that they are in this order.
  53. //
  54. #define NO_OPLOCK (0x00000001)
  55. #define LEVEL_I_OPLOCK (0x00000002)
  56. #define BATCH_OPLOCK (0x00000004)
  57. #define FILTER_OPLOCK (0x00000008)
  58. #define LEVEL_II_OPLOCK (0x00000010)
  59. #define OPLOCK_TYPE_MASK (0x0000001f)
  60. #define EXCLUSIVE (0x00000040)
  61. #define PENDING (0x00000080)
  62. #define OPLOCK_HELD_MASK (0x000000c0)
  63. #define BREAK_TO_II (0x00000100)
  64. #define BREAK_TO_NONE (0x00000200)
  65. #define BREAK_TO_II_TO_NONE (0x00000400)
  66. #define CLOSE_PENDING (0x00000800)
  67. #define OPLOCK_BREAK_MASK (0x00000f00)
  68. //
  69. // The oplock types consist of the appropriate flags.
  70. //
  71. #define NoOplocksHeld (NO_OPLOCK)
  72. #define OplockIGranted (LEVEL_I_OPLOCK | EXCLUSIVE)
  73. #define OpBatchGranted (BATCH_OPLOCK | EXCLUSIVE)
  74. #define OpFilterGranted (FILTER_OPLOCK | EXCLUSIVE)
  75. #define OpFilterReqPending (FILTER_OPLOCK | EXCLUSIVE | PENDING )
  76. #define OplockBreakItoII (LEVEL_I_OPLOCK | EXCLUSIVE | BREAK_TO_II)
  77. #define OpBatchBreaktoII (BATCH_OPLOCK | EXCLUSIVE | BREAK_TO_II)
  78. #define OpFilterBreaktoII (FILTER_OPLOCK | EXCLUSIVE | BREAK_TO_II)
  79. #define OplockBreakItoNone (LEVEL_I_OPLOCK | EXCLUSIVE | BREAK_TO_NONE)
  80. #define OpBatchBreaktoNone (BATCH_OPLOCK | EXCLUSIVE | BREAK_TO_NONE)
  81. #define OpFilterBreaktoNone (FILTER_OPLOCK | EXCLUSIVE | BREAK_TO_NONE)
  82. #define OplockBreakItoIItoNone (LEVEL_I_OPLOCK | EXCLUSIVE | BREAK_TO_II_NONE)
  83. #define OpBatchBreaktoIItoNone (BATCH_OPLOCK | EXCLUSIVE | BREAK_TO_II_NONE)
  84. #define OpFilterBreaktoIItoNone (FILTER_OPLOCK | EXCLUSIVE | BREAK_TO_II_NONE)
  85. #define OpBatchClosePending (BATCH_OPLOCK | EXCLUSIVE | CLOSE_PENDING)
  86. #define OpFilterClosePending (FILTER_OPLOCK | EXCLUSIVE | CLOSE_PENDING)
  87. #define OplockIIGranted (LEVEL_II_OPLOCK)
  88. //
  89. // The oplock state is now just a ULONG.
  90. //
  91. typedef ULONG OPLOCK_STATE;
  92. //
  93. // The non-opaque definition of an OPLOCK is a pointer to a privately
  94. // defined structure.
  95. //
  96. typedef struct _NONOPAQUE_OPLOCK {
  97. //
  98. // This is the Irp used to successfully request a level I oplock or
  99. // batch oplock. It is completed to initiate the Oplock I break
  100. // procedure.
  101. //
  102. PIRP IrpExclusiveOplock;
  103. //
  104. // This is a pointer to the original file object used when granting
  105. // an Oplock I or batch oplock.
  106. //
  107. PFILE_OBJECT FileObject;
  108. //
  109. // The start of a linked list of Irps used to successfully request
  110. // a level II oplock.
  111. //
  112. LIST_ENTRY IrpOplocksII;
  113. //
  114. // The following links the Irps waiting to be completed on a queue
  115. // of Irps.
  116. //
  117. LIST_ENTRY WaitingIrps;
  118. //
  119. // Oplock state. This indicates the current oplock state.
  120. //
  121. OPLOCK_STATE OplockState;
  122. //
  123. // This FastMutex is used to control access to this structure.
  124. //
  125. PFAST_MUTEX FastMutex;
  126. } NONOPAQUE_OPLOCK, *PNONOPAQUE_OPLOCK;
  127. //
  128. // Each Waiting Irp record corresponds to an Irp that is waiting for an
  129. // oplock break to be acknowledged and is maintained in a queue off of the
  130. // Oplock's WaitingIrps list.
  131. //
  132. typedef struct _WAITING_IRP {
  133. //
  134. // The link structures for the list of waiting irps.
  135. //
  136. LIST_ENTRY Links;
  137. //
  138. // This is the Irp attached to this structure.
  139. //
  140. PIRP Irp;
  141. //
  142. // This is the routine to call when we are done with an Irp we
  143. // held on a waiting queue. (We originally returned STATUS_PENDING).
  144. //
  145. POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine;
  146. //
  147. // The context field to use when we are done with the Irp.
  148. //
  149. PVOID Context;
  150. //
  151. // This points to an event object used when we do not want to
  152. // give up this thread.
  153. //
  154. PKEVENT Event;
  155. //
  156. // This field contains a copy of the Irp Iosb.Information field.
  157. // We copy it here so that we can store the Oplock address in the
  158. // Irp.
  159. //
  160. ULONG Information;
  161. } WAITING_IRP, *PWAITING_IRP;
  162. //
  163. // Define a tag for general pool allocations from this module
  164. //
  165. #undef MODULE_POOL_TAG
  166. #define MODULE_POOL_TAG ('orSF')
  167. //
  168. // Local support routines
  169. //
  170. PNONOPAQUE_OPLOCK
  171. FsRtlAllocateOplock (
  172. );
  173. NTSTATUS
  174. FsRtlRequestExclusiveOplock (
  175. IN OUT PNONOPAQUE_OPLOCK *Oplock,
  176. IN PIO_STACK_LOCATION IrpSp,
  177. IN PIRP Irp OPTIONAL,
  178. IN OPLOCK_STATE NextOplockState
  179. );
  180. NTSTATUS
  181. FsRtlRequestOplockII (
  182. IN OUT PNONOPAQUE_OPLOCK *Oplock,
  183. IN PIO_STACK_LOCATION IrpSp,
  184. IN PIRP Irp
  185. );
  186. NTSTATUS
  187. FsRtlAcknowledgeOplockBreak (
  188. IN OUT PNONOPAQUE_OPLOCK Oplock,
  189. IN PIO_STACK_LOCATION IrpSp,
  190. IN PIRP Irp,
  191. IN BOOLEAN GrantLevelII
  192. );
  193. NTSTATUS
  194. FsRtlOpBatchBreakClosePending (
  195. IN OUT PNONOPAQUE_OPLOCK Oplock,
  196. IN PIO_STACK_LOCATION IrpSp,
  197. IN PIRP Irp
  198. );
  199. NTSTATUS
  200. FsRtlOplockBreakNotify (
  201. IN OUT PNONOPAQUE_OPLOCK Oplock,
  202. IN PIO_STACK_LOCATION IrpSp,
  203. IN PIRP Irp
  204. );
  205. VOID
  206. FsRtlOplockCleanup (
  207. IN OUT PNONOPAQUE_OPLOCK Oplock,
  208. IN PIO_STACK_LOCATION IrpSp
  209. );
  210. NTSTATUS
  211. FsRtlOplockBreakToII (
  212. IN OUT PNONOPAQUE_OPLOCK Oplock,
  213. IN PIO_STACK_LOCATION IrpSp,
  214. IN PIRP Irp,
  215. IN PVOID Context,
  216. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  217. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL
  218. );
  219. NTSTATUS
  220. FsRtlOplockBreakToNone (
  221. IN OUT PNONOPAQUE_OPLOCK Oplock,
  222. IN PIO_STACK_LOCATION IrpSp,
  223. IN PIRP Irp,
  224. IN PVOID Context,
  225. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  226. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL
  227. );
  228. VOID
  229. FsRtlRemoveAndCompleteIrp (
  230. IN PLIST_ENTRY Link
  231. );
  232. NTSTATUS
  233. FsRtlWaitOnIrp (
  234. IN OUT PNONOPAQUE_OPLOCK Oplock,
  235. IN PIRP Irp,
  236. IN PVOID Context,
  237. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  238. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL,
  239. IN PKEVENT Event
  240. );
  241. VOID
  242. FsRtlCompletionRoutinePriv (
  243. IN PVOID Context,
  244. IN PIRP Irp
  245. );
  246. VOID
  247. FsRtlCancelWaitIrp (
  248. IN PDEVICE_OBJECT DeviceObject,
  249. IN PIRP Irp
  250. );
  251. VOID
  252. FsRtlCancelOplockIIIrp (
  253. IN PDEVICE_OBJECT DeviceObject,
  254. IN PIRP Irp
  255. );
  256. VOID
  257. FsRtlCancelExclusiveIrp (
  258. IN PDEVICE_OBJECT DeviceObject,
  259. IN PIRP Irp
  260. );
  261. VOID
  262. FsRtlRemoveAndCompleteWaitIrp (
  263. IN PWAITING_IRP WaitingIrp
  264. );
  265. VOID
  266. FsRtlNotifyCompletion (
  267. IN PVOID Context,
  268. IN PIRP Irp
  269. );
  270. #ifdef ALLOC_PRAGMA
  271. #pragma alloc_text(PAGE, FsRtlAllocateOplock)
  272. #pragma alloc_text(PAGE, FsRtlCompletionRoutinePriv)
  273. #pragma alloc_text(PAGE, FsRtlCurrentBatchOplock)
  274. #pragma alloc_text(PAGE, FsRtlInitializeOplock)
  275. #pragma alloc_text(PAGE, FsRtlNotifyCompletion)
  276. #pragma alloc_text(PAGE, FsRtlOpBatchBreakClosePending)
  277. #pragma alloc_text(PAGE, FsRtlOplockBreakNotify)
  278. #pragma alloc_text(PAGE, FsRtlOplockFsctrl)
  279. #pragma alloc_text(PAGE, FsRtlOplockIsFastIoPossible)
  280. #endif
  281. VOID
  282. FsRtlInitializeOplock (
  283. IN OUT POPLOCK Oplock
  284. )
  285. /*++
  286. Routine Description:
  287. This routine initializes a new OPLOCK structure. This call must
  288. precede any other call to this entry point with this OPLOCK
  289. structure. In addition, this routine will have exclusive access
  290. to the Oplock structure.
  291. Arguments:
  292. Oplock - Supplies the address of an opaque OPLOCK structure.
  293. Return Value:
  294. None.
  295. --*/
  296. {
  297. UNREFERENCED_PARAMETER( Oplock );
  298. PAGED_CODE();
  299. DebugTrace(+1, Dbg, "FsRtlInitializeOplock: Oplock -> %08lx\n", *Oplock );
  300. //
  301. // No action is taken at this time.
  302. //
  303. DebugTrace(-1, Dbg, "FsRtlInitializeOplock: Exit\n", 0);
  304. return;
  305. }
  306. VOID
  307. FsRtlUninitializeOplock (
  308. IN OUT POPLOCK Oplock
  309. )
  310. /*++
  311. Routine Description:
  312. This routine uninitializes an OPLOCK structure. After calling this
  313. routine, the OPLOCK structure must be reinitialized before being
  314. used again.
  315. Arguments:
  316. Oplock - Supplies the address of an opaque OPLOCK structure.
  317. Return Value:
  318. None.
  319. --*/
  320. {
  321. PNONOPAQUE_OPLOCK ThisOplock;
  322. DebugTrace(+1, Dbg, "FsRtlUninitializeOplock: Oplock -> %08lx\n", *Oplock );
  323. //
  324. // If the Oplock structure has not been allocated, there is no action
  325. // to take.
  326. //
  327. if (*Oplock != NULL) {
  328. //
  329. // Remove this from the user's structure.
  330. //
  331. ThisOplock = (PNONOPAQUE_OPLOCK) *Oplock;
  332. *Oplock = NULL;
  333. //
  334. // Grab the waiting lock queue mutex to exclude anyone from messing
  335. // with the queue while we're using it
  336. //
  337. ExAcquireFastMutexUnsafe( ThisOplock->FastMutex );
  338. try {
  339. PIRP Irp;
  340. //
  341. // Release any waiting Irps held.
  342. //
  343. while (!IsListEmpty( &ThisOplock->WaitingIrps )) {
  344. PWAITING_IRP WaitingIrp;
  345. PIRP ThisIrp;
  346. WaitingIrp = CONTAINING_RECORD( ThisOplock->WaitingIrps.Flink,
  347. WAITING_IRP,
  348. Links );
  349. RemoveHeadList( &ThisOplock->WaitingIrps );
  350. ThisIrp = WaitingIrp->Irp;
  351. IoAcquireCancelSpinLock( &ThisIrp->CancelIrql );
  352. IoSetCancelRoutine( ThisIrp, NULL );
  353. IoReleaseCancelSpinLock( ThisIrp->CancelIrql );
  354. ThisIrp->IoStatus.Information = 0;
  355. //
  356. // Call the completion routine in the Waiting Irp.
  357. //
  358. WaitingIrp->CompletionRoutine( WaitingIrp->Context,
  359. WaitingIrp->Irp );
  360. ExFreePool( WaitingIrp );
  361. }
  362. //
  363. // Release any oplock II irps held.
  364. //
  365. while (!IsListEmpty( &ThisOplock->IrpOplocksII )) {
  366. Irp = CONTAINING_RECORD( ThisOplock->IrpOplocksII.Flink,
  367. IRP,
  368. Tail.Overlay.ListEntry );
  369. RemoveHeadList( &ThisOplock->IrpOplocksII );
  370. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  371. IoSetCancelRoutine( Irp, NULL );
  372. IoReleaseCancelSpinLock( Irp->CancelIrql );
  373. //
  374. // Complete the oplock II Irp.
  375. //
  376. ObDereferenceObject( IoGetCurrentIrpStackLocation( Irp )->FileObject );
  377. Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  378. FsRtlCompleteRequest( Irp, STATUS_SUCCESS );
  379. }
  380. //
  381. // Release any exclusive oplock held.
  382. //
  383. if (ThisOplock->IrpExclusiveOplock != NULL) {
  384. Irp = ThisOplock->IrpExclusiveOplock;
  385. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  386. IoSetCancelRoutine( Irp, NULL );
  387. IoReleaseCancelSpinLock( Irp->CancelIrql );
  388. Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  389. FsRtlCompleteRequest( Irp, STATUS_SUCCESS );
  390. ThisOplock->IrpExclusiveOplock = NULL;
  391. if (ThisOplock->FileObject != NULL) {
  392. ObDereferenceObject( ThisOplock->FileObject );
  393. }
  394. }
  395. } finally {
  396. //
  397. // No matter how we complete the preceding statements we will
  398. // now release the waiting lock queue mutex
  399. //
  400. ExReleaseFastMutexUnsafe( ThisOplock->FastMutex );
  401. }
  402. //
  403. // Deallocate the mutex.
  404. //
  405. ExFreePool( ThisOplock->FastMutex );
  406. //
  407. // Deallocate the Oplock structure.
  408. //
  409. ExFreePool( ThisOplock );
  410. }
  411. DebugTrace( -1, Dbg, "FsRtlUninitializeOplock: Exit\n", 0 );
  412. return;
  413. }
  414. NTSTATUS
  415. FsRtlOplockFsctrl (
  416. IN POPLOCK Oplock,
  417. IN PIRP Irp,
  418. IN ULONG OpenCount
  419. )
  420. /*++
  421. Routine Description:
  422. This is the interface with the filesystems for Fsctl calls, it handles
  423. oplock requests, break acknowledgement and break notify.
  424. Arguments:
  425. Oplock - Supplies the address of the opaque OPLOCK structure.
  426. Irp - Supplies a pointer to the Irp which declares the requested
  427. operation.
  428. OpenCount - This is the number of user handles on the file if we are requsting
  429. an exclusive oplock. A non-zero value for a level II request indicates
  430. that there are locks on the file.
  431. Return Value:
  432. NTSTATUS - Returns the result of this operation. If this is an Oplock
  433. request which is granted, then STATUS_PENDING is returned.
  434. If the Oplock isn't granted then STATUS_OPLOCK_NOT_GRANTED
  435. is returned. If this is an Oplock I break to no oplock,
  436. then STATUS_SUCCESS. If this is an Oplock I break to
  437. Oplock II then STATUS_PENDING is returned. Other
  438. error codes returned depend on the nature of the error.
  439. STATUS_CANCELLED is returned if the Irp is cancelled during
  440. this operation.
  441. STATUS_SUCCESS is returned if this is a create asking for
  442. a filter oplock.
  443. --*/
  444. {
  445. NTSTATUS Status;
  446. PIO_STACK_LOCATION IrpSp;
  447. OPLOCK_STATE OplockState;
  448. PAGED_CODE();
  449. //
  450. // Get the current IRP stack location
  451. //
  452. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  453. DebugTrace(+1, Dbg, "FsRtlOplockFsctrl: Entered\n", 0);
  454. DebugTrace( 0, Dbg, "FsRtlOplockFsctrl: Oplock -> %08lx\n", *Oplock );
  455. DebugTrace( 0, Dbg, "FsRtlOplockFsctrl: Irp -> %08lx\n", Irp );
  456. //
  457. // Check if this is the create case where the user is requesting a pending
  458. // filter oplock.
  459. //
  460. if (IrpSp->MajorFunction == IRP_MJ_CREATE) {
  461. //
  462. // Check that all the conditions hold to grant this oplock.
  463. // The conditions that must hold are:
  464. //
  465. // - This is the only opener of the file.
  466. // - Desired Access must be exactly FILE_READ_ATTRIBUTES.
  467. // This will insure an asynch open since the SYNCHRONIZE
  468. // flag can't be set.
  469. // - Share access is precisely
  470. // (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
  471. //
  472. if ((OpenCount != 1) ||
  473. (FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
  474. ~(FILE_READ_ATTRIBUTES))) ||
  475. ((IrpSp->Parameters.Create.ShareAccess &
  476. (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)) !=
  477. (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE))) {
  478. Status = STATUS_OPLOCK_NOT_GRANTED;
  479. } else {
  480. Status = FsRtlRequestExclusiveOplock( (PNONOPAQUE_OPLOCK *) Oplock,
  481. IrpSp,
  482. NULL,
  483. OpFilterReqPending );
  484. }
  485. //
  486. // Case on the FsControlFile code control code.
  487. //
  488. } else {
  489. //
  490. // Assume this is an OplockLevel I.
  491. //
  492. // NOTE - This code depends on the defined bits for these oplock types.
  493. // FILTER_OPLOCK = 4 * LEVEL_I_OPLOCK
  494. // BATCH_OPLOCK = 2 * LEVEL_I_OPLOCK
  495. //
  496. OplockState = LEVEL_I_OPLOCK;
  497. switch (IrpSp->Parameters.FileSystemControl.FsControlCode) {
  498. case FSCTL_REQUEST_FILTER_OPLOCK :
  499. OplockState *= 2;
  500. case FSCTL_REQUEST_BATCH_OPLOCK :
  501. OplockState *= 2;
  502. case FSCTL_REQUEST_OPLOCK_LEVEL_1 :
  503. //
  504. // Set the other flags for an exclusive oplock.
  505. //
  506. SetFlag( OplockState, EXCLUSIVE );
  507. //
  508. // We short circuit the request if this request is treated
  509. // synchronously or the open count is not 1. Otherwise the Io system
  510. // will hold the return code until the Irp is completed.
  511. //
  512. // Also fail this if the flag is set which indicates that
  513. // the IO system should copy data back to a user's buffer.
  514. //
  515. // If cleanup has occurrred on this file, then we refuse
  516. // the oplock request.
  517. //
  518. if ((OpenCount != 1) ||
  519. IoIsOperationSynchronous( Irp ) ||
  520. FlagOn( Irp->Flags, IRP_INPUT_OPERATION ) ||
  521. FlagOn( IrpSp->FileObject->Flags, FO_CLEANUP_COMPLETE )) {
  522. FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED );
  523. Status = STATUS_OPLOCK_NOT_GRANTED;
  524. } else {
  525. Status = FsRtlRequestExclusiveOplock( (PNONOPAQUE_OPLOCK *) Oplock,
  526. IrpSp,
  527. Irp,
  528. OplockState );
  529. }
  530. break;
  531. case FSCTL_REQUEST_OPLOCK_LEVEL_2 :
  532. //
  533. // We short circuit the request if this request is treated
  534. // synchronously. Otherwise the Io system will hold the return
  535. // code until the Irp is completed.
  536. //
  537. // If cleanup has occurrred on this file, then we refuse
  538. // the oplock request.
  539. //
  540. // Also fail this if the flag is set which indicates that
  541. // the IO system should copy data back to a user's buffer.
  542. //
  543. // A non-zero open count in this case indicates that there are
  544. // file locks on the file. We will also fail the request in
  545. // this case.
  546. //
  547. if ((OpenCount != 0) ||
  548. IoIsOperationSynchronous( Irp ) ||
  549. FlagOn( Irp->Flags, IRP_INPUT_OPERATION ) ||
  550. FlagOn( IrpSp->FileObject->Flags, FO_CLEANUP_COMPLETE )) {
  551. FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED );
  552. Status = STATUS_OPLOCK_NOT_GRANTED;
  553. } else {
  554. Status = FsRtlRequestOplockII( (PNONOPAQUE_OPLOCK *) Oplock,
  555. IrpSp,
  556. Irp );
  557. }
  558. break;
  559. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE :
  560. Status = FsRtlAcknowledgeOplockBreak( (PNONOPAQUE_OPLOCK) *Oplock,
  561. IrpSp,
  562. Irp,
  563. TRUE );
  564. break;
  565. case FSCTL_OPLOCK_BREAK_ACK_NO_2 :
  566. Status = FsRtlAcknowledgeOplockBreak( (PNONOPAQUE_OPLOCK) *Oplock,
  567. IrpSp,
  568. Irp,
  569. FALSE );
  570. break;
  571. case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
  572. Status = FsRtlOpBatchBreakClosePending( (PNONOPAQUE_OPLOCK) *Oplock,
  573. IrpSp,
  574. Irp );
  575. break;
  576. case FSCTL_OPLOCK_BREAK_NOTIFY :
  577. Status = FsRtlOplockBreakNotify( (PNONOPAQUE_OPLOCK) *Oplock,
  578. IrpSp,
  579. Irp );
  580. break;
  581. default :
  582. DebugTrace( 0,
  583. Dbg,
  584. "Invalid Control Code\n",
  585. 0);
  586. FsRtlCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
  587. Status = STATUS_INVALID_PARAMETER;
  588. }
  589. }
  590. DebugTrace(-1, Dbg, "FsRtlOplockFsctrl: Exit -> %08lx\n", Status );
  591. return Status;
  592. }
  593. NTSTATUS
  594. FsRtlCheckOplock (
  595. IN POPLOCK Oplock,
  596. IN PIRP Irp,
  597. IN PVOID Context,
  598. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  599. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL
  600. )
  601. /*++
  602. Routine Description:
  603. This routine is called as a support routine from a file system.
  604. It is used to synchronize I/O requests with the current Oplock
  605. state of a file. If the I/O operation will cause the Oplock to
  606. break, that action is initiated. If the operation cannot continue
  607. until the Oplock break is complete, STATUS_PENDING is returned and
  608. the caller supplied routine is called.
  609. Arguments:
  610. Oplock - Supplies a pointer to the non-opaque oplock structure for
  611. this file.
  612. Irp - Supplies a pointer to the Irp which declares the requested
  613. operation.
  614. Context - This value is passed as a parameter to the completion routine.
  615. CompletionRoutine - This is the routine which is called if this
  616. Irp must wait for an Oplock to break. This
  617. is a synchronous operation if not specified
  618. and we block in this thread waiting on
  619. an event.
  620. PostIrpRoutine - This is the routine to call before we put anything
  621. on our waiting Irp queue.
  622. Return Value:
  623. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  624. STATUS_PENDING if we return here but hold the Irp.
  625. STATUS_CANCELLED if the Irp is cancelled before we return.
  626. --*/
  627. {
  628. NTSTATUS Status = STATUS_SUCCESS;
  629. PNONOPAQUE_OPLOCK ThisOplock = *Oplock;
  630. PIO_STACK_LOCATION IrpSp;
  631. DebugTrace( +1, Dbg, "FsRtlCheckOplock: Entered\n", 0 );
  632. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  633. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  634. //
  635. // If there is no oplock structure or this is system I/O, we allow
  636. // the operation to continue. Otherwise we check the major function code.
  637. //
  638. if ((ThisOplock != NULL) &&
  639. !FlagOn( Irp->Flags, IRP_PAGING_IO )) {
  640. OPLOCK_STATE OplockState;
  641. PFILE_OBJECT OplockFileObject;
  642. BOOLEAN BreakToII;
  643. BOOLEAN BreakToNone;
  644. ULONG CreateDisposition;
  645. //
  646. // Capture the file object first and then the oplock state to perform
  647. // the unsafe checks below. We capture the file object first in case
  648. // there is an exclusive oplock break in progress. Otherwise the oplock
  649. // state may indicate break in progress but it could complete by
  650. // the time we snap the file object.
  651. //
  652. OplockFileObject = ThisOplock->FileObject;
  653. OplockState = ThisOplock->OplockState;
  654. //
  655. // Examine the Irp for the appropriate action provided there are
  656. // current oplocks on the file.
  657. //
  658. if (OplockState != NoOplocksHeld) {
  659. BreakToII = FALSE;
  660. BreakToNone = FALSE;
  661. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  662. //
  663. // Determine whether we are going to BreakToII or BreakToNone.
  664. //
  665. switch (IrpSp->MajorFunction) {
  666. case IRP_MJ_CREATE :
  667. //
  668. // If we are opening for attribute access only, we
  669. // return status success. Always break the oplock if this caller
  670. // wants a filter oplock.
  671. //
  672. if (!FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
  673. ~(FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE) ) &&
  674. !FlagOn( IrpSp->Parameters.Create.Options, FILE_RESERVE_OPFILTER )) {
  675. break;
  676. }
  677. //
  678. // If there is a filter oplock granted and this create iS reading
  679. // the file then don't break the oplock as long as we share
  680. // for reads.
  681. //
  682. if (FlagOn( OplockState, FILTER_OPLOCK ) &&
  683. !FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
  684. ~FILTER_OPLOCK_VALID_FLAGS ) &&
  685. FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ )) {
  686. break;
  687. }
  688. //
  689. // We we are superseding or overwriting, then break to none.
  690. //
  691. CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
  692. if ((CreateDisposition == FILE_SUPERSEDE) ||
  693. (CreateDisposition == FILE_OVERWRITE) ||
  694. (CreateDisposition == FILE_OVERWRITE_IF) ||
  695. FlagOn( IrpSp->Parameters.Create.Options, FILE_RESERVE_OPFILTER )) {
  696. BreakToNone = TRUE;
  697. } else {
  698. BreakToII = TRUE;
  699. }
  700. break;
  701. case IRP_MJ_READ :
  702. //
  703. // If a filter oplock has been granted then do nothing.
  704. // We will assume the oplock will have been broken
  705. // if this create needed to do that.
  706. //
  707. if (!FlagOn( OplockState, FILTER_OPLOCK )) {
  708. BreakToII = TRUE;
  709. }
  710. break;
  711. case IRP_MJ_FLUSH_BUFFERS :
  712. BreakToII = TRUE;
  713. break;
  714. case IRP_MJ_CLEANUP :
  715. FsRtlOplockCleanup( (PNONOPAQUE_OPLOCK) *Oplock,
  716. IrpSp );
  717. break;
  718. case IRP_MJ_LOCK_CONTROL :
  719. //
  720. // If a filter oplock has been granted then do nothing.
  721. // We will assume the oplock will have been broken
  722. // if this create needed to do that.
  723. //
  724. if (FlagOn( OplockState, FILTER_OPLOCK )) {
  725. break;
  726. }
  727. case IRP_MJ_WRITE :
  728. BreakToNone = TRUE;
  729. break;
  730. case IRP_MJ_SET_INFORMATION :
  731. //
  732. // We are only interested in calls that shrink the file size
  733. // or breaking batch oplocks for the rename case.
  734. //
  735. switch (IrpSp->Parameters.SetFile.FileInformationClass) {
  736. case FileEndOfFileInformation :
  737. //
  738. // Break immediately if this is the lazy writer callback.
  739. //
  740. if (IrpSp->Parameters.SetFile.AdvanceOnly) {
  741. break;
  742. }
  743. case FileAllocationInformation :
  744. BreakToNone = TRUE;
  745. break;
  746. case FileRenameInformation :
  747. case FileLinkInformation :
  748. case FileShortNameInformation :
  749. if (FlagOn( OplockState, BATCH_OPLOCK | FILTER_OPLOCK )) {
  750. BreakToNone = TRUE;
  751. }
  752. break;
  753. }
  754. case IRP_MJ_FILE_SYSTEM_CONTROL :
  755. //
  756. // We need to break to none if this is a zeroing operation.
  757. //
  758. if (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_SET_ZERO_DATA) {
  759. BreakToNone = TRUE;
  760. }
  761. }
  762. if (BreakToII) {
  763. //
  764. // If there are no outstanding oplocks or level II oplocks are held,
  765. // we can return immediately. If the first two tests fail then there
  766. // is an exclusive oplock. If the file objects match we allow the
  767. // operation to continue.
  768. //
  769. if ((OplockState != OplockIIGranted) &&
  770. (OplockFileObject != IrpSp->FileObject)) {
  771. Status = FsRtlOplockBreakToII( (PNONOPAQUE_OPLOCK) *Oplock,
  772. IrpSp,
  773. Irp,
  774. Context,
  775. CompletionRoutine,
  776. PostIrpRoutine );
  777. }
  778. } else if (BreakToNone) {
  779. //
  780. // If there are no oplocks, we can return immediately.
  781. // Otherwise if there is no level 2 oplock and this file
  782. // object matches the owning file object then this write is
  783. // on behalf of the owner of the oplock.
  784. //
  785. if ((OplockState == OplockIIGranted) ||
  786. (OplockFileObject != IrpSp->FileObject)) {
  787. Status = FsRtlOplockBreakToNone( (PNONOPAQUE_OPLOCK) *Oplock,
  788. IrpSp,
  789. Irp,
  790. Context,
  791. CompletionRoutine,
  792. PostIrpRoutine );
  793. }
  794. }
  795. }
  796. }
  797. DebugTrace( -1, Dbg, "FsRtlCheckOplock: Exit -> %08lx\n", Status );
  798. return Status;
  799. }
  800. BOOLEAN
  801. FsRtlOplockIsFastIoPossible (
  802. IN POPLOCK Oplock
  803. )
  804. /*++
  805. Routine Description:
  806. This routine indicates to the caller where there are any outstanding
  807. oplocks which prevent fast Io from happening.
  808. Arguments:
  809. OpLock - Supplies the oplock being queried
  810. Return Value:
  811. BOOLEAN - TRUE if there are outstanding oplocks and FALSE otherwise
  812. --*/
  813. {
  814. BOOLEAN FastIoPossible = TRUE;
  815. PAGED_CODE();
  816. DebugTrace(+1, Dbg, "FsRtlOplockIsFastIoPossible: Oplock -> %08lx\n", *Oplock);
  817. //
  818. // There are not any current oplocks if the variable is null or
  819. // the state is no oplocks held. If an exclusive oplock was granted
  820. // but no break is in progress then allow the Fast IO.
  821. //
  822. if (*Oplock != NULL) {
  823. OPLOCK_STATE OplockState;
  824. OplockState = ((PNONOPAQUE_OPLOCK) *Oplock)->OplockState;
  825. if (FlagOn( OplockState, LEVEL_II_OPLOCK | OPLOCK_BREAK_MASK )) {
  826. FastIoPossible = FALSE;
  827. }
  828. }
  829. DebugTrace(-1, Dbg, "FsRtlOplockIsFastIoPossible: Exit -> %08lx\n", FastIoPossible);
  830. return FastIoPossible;
  831. }
  832. BOOLEAN
  833. FsRtlCurrentBatchOplock (
  834. IN POPLOCK Oplock
  835. )
  836. /*++
  837. Routine Description:
  838. This routines indicates whether there are current outstanding
  839. batch oplocks.
  840. Arguments:
  841. OpLock - Supplies the oplock being queried
  842. Return Value:
  843. BOOLEAN - TRUE if there are outstanding batch oplocks and FALSE otherwise
  844. --*/
  845. {
  846. BOOLEAN BatchOplocks = FALSE;
  847. PAGED_CODE();
  848. DebugTrace(+1, Dbg, "FsRtlCurrentBatchOplock: Oplock -> %08lx\n", *Oplock);
  849. //
  850. // There are not any current oplocks if the variable is null or
  851. // the state is no oplocks held. We check whether there are batch
  852. // oplocks or filter oplocks which have not been broken.
  853. //
  854. if ((*Oplock != NULL) &&
  855. FlagOn( ((PNONOPAQUE_OPLOCK) *Oplock)->OplockState,
  856. BATCH_OPLOCK | FILTER_OPLOCK )) {
  857. BatchOplocks = TRUE;
  858. }
  859. DebugTrace(-1, Dbg, "FsRtlCurrentBatchOplock: Exit -> %08lx\n", BatchOplocks);
  860. return BatchOplocks;
  861. }
  862. //
  863. // Local support routine.
  864. //
  865. PNONOPAQUE_OPLOCK
  866. FsRtlAllocateOplock (
  867. )
  868. /*++
  869. Routine Description:
  870. This routine is called to initialize and allocate an opaque oplock
  871. structure. After allocation, the two events are set to the signalled
  872. state. The oplock state is set to NoOplocksHeld and the other
  873. fields are filled with zeroes.
  874. If the allocation fails, the appropriate status is raised.
  875. Arguments:
  876. None.
  877. Return Value:
  878. PNONOPAQUE_OPLOCK - A pointer to the allocated structure.
  879. --*/
  880. {
  881. PNONOPAQUE_OPLOCK NewOplock = NULL;
  882. PAGED_CODE();
  883. DebugTrace( +1, Dbg, "FsRtlAllocateOplock: Entered\n", 0);
  884. //
  885. // Use a try-finally to facilitate cleanup.
  886. //
  887. try {
  888. //
  889. // Raise an error status if the allocation is unsuccessful.
  890. // The structure is allocated out of non-paged pool.
  891. //
  892. NewOplock = FsRtlpAllocatePool( PagedPool|POOL_COLD_ALLOCATION, sizeof( NONOPAQUE_OPLOCK ));
  893. RtlZeroMemory( NewOplock, sizeof( NONOPAQUE_OPLOCK ));
  894. NewOplock->FastMutex = FsRtlpAllocatePool( NonPagedPool, sizeof( FAST_MUTEX ));
  895. ExInitializeFastMutex( NewOplock->FastMutex );
  896. InitializeListHead( &NewOplock->IrpOplocksII );
  897. InitializeListHead( &NewOplock->WaitingIrps );
  898. NewOplock->OplockState = NoOplocksHeld;
  899. } finally {
  900. //
  901. // Cleanup the oplock if abnormal termination.
  902. //
  903. if (AbnormalTermination() && NewOplock != NULL) {
  904. ExFreePool( NewOplock );
  905. }
  906. DebugTrace(-1, Dbg, "GetOplockStructure: Exit -> %08lx\n", NewOplock);
  907. }
  908. return NewOplock;
  909. }
  910. //
  911. // Local support routine.
  912. //
  913. NTSTATUS
  914. FsRtlRequestExclusiveOplock (
  915. IN OUT PNONOPAQUE_OPLOCK *Oplock,
  916. IN PIO_STACK_LOCATION IrpSp,
  917. IN PIRP Irp OPTIONAL,
  918. IN OPLOCK_STATE NextOplockState
  919. )
  920. /*++
  921. Routine Description:
  922. This routine is called whenever a user is requesting either a batch/filter
  923. oplock or a level I oplock. The request is granted if there are currently
  924. no oplocks on the file or we are completing the filter oplock request.
  925. NOTE - We already know that the open count on this file is exactly one.
  926. If the caller is requesting a PendingFilter Oplock then the state
  927. must be NoOplockHeld.
  928. Arguments:
  929. Oplock - Supplies a pointer to the non-opaque oplock structure for
  930. this file.
  931. IrpSp - This is the Irp stack location for the current Irp.
  932. Irp - Supplies a pointer to the Irp which declares the requested
  933. operation. This is not specified if we are granting a pending
  934. filter oplock (during a create).
  935. NextOplockState - Indicates the type of oplock being requested.
  936. Return Value:
  937. STATUS_PENDING if the oplock is granted (although it may be immediately cancelled).
  938. STATUS_SUCCESS if a pending filter oplock is requested and tentatively granted.
  939. STATUS_OPLOCK_NOT_GRANTED if the request is denied.
  940. --*/
  941. {
  942. NTSTATUS Status;
  943. PNONOPAQUE_OPLOCK ThisOplock;
  944. BOOLEAN AcquiredMutex;
  945. BOOLEAN BreakOpFilter = FALSE;
  946. PLIST_ENTRY Link;
  947. DebugTrace( +1, Dbg, "FsRtlRequestExclusiveOplock: Entered\n", 0 );
  948. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  949. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  950. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  951. DebugTrace( 0, Dbg, "BatchOplock -> %01x\n", BatchOplock );
  952. //
  953. // We can grant the oplock if no one else owns a level I or level II
  954. // oplock on this file. If the oplock pointer is NULL then there
  955. // are no oplocks on the file. Otherwise we need to check the
  956. // oplock state in an existing oplock structure.
  957. //
  958. if (*Oplock == NULL) {
  959. DebugTrace( 0,
  960. Dbg,
  961. "Oplock currently not allocated\n",
  962. 0);
  963. ThisOplock = FsRtlAllocateOplock();
  964. *Oplock = ThisOplock;
  965. } else {
  966. ThisOplock = *Oplock;
  967. }
  968. //
  969. // Grab the synchronization object for the oplock.
  970. //
  971. ExAcquireFastMutexUnsafe( ThisOplock->FastMutex );
  972. AcquiredMutex = TRUE;
  973. //
  974. // Use a try-finally to facilitate cleanup.
  975. //
  976. try {
  977. //
  978. // If we are requesting a PendingFilter Oplock then it must be
  979. // safe to grant. There is only one open handle and we are in
  980. // the process of opening it.
  981. //
  982. if (NextOplockState == OpFilterReqPending) {
  983. ASSERT( FlagOn( ThisOplock->OplockState, NO_OPLOCK | PENDING ));
  984. ThisOplock->IrpExclusiveOplock = Irp;
  985. ThisOplock->FileObject = IrpSp->FileObject;
  986. ThisOplock->OplockState = OpFilterReqPending;
  987. Status = STATUS_SUCCESS;
  988. //
  989. // If the current oplock state is no oplocks held then we
  990. // will grant the oplock to this requestor. If the state is
  991. // either of the OpFilter states then also grant the request.
  992. // We won't check for a matching file object because there can
  993. // only be one file object. Grant the request anyway.
  994. //
  995. // If the current state is OplockII granted then it must
  996. // be owned by this request. Break the oplock II and grant
  997. // the exclusive lock.
  998. //
  999. } else if (FlagOn( ThisOplock->OplockState,
  1000. LEVEL_II_OPLOCK | NO_OPLOCK | PENDING )) {
  1001. PFAST_MUTEX OplockFastMutex;
  1002. if (ThisOplock->OplockState == OplockIIGranted) {
  1003. ASSERT( ThisOplock->IrpOplocksII.Flink == ThisOplock->IrpOplocksII.Blink );
  1004. FsRtlRemoveAndCompleteIrp( ThisOplock->IrpOplocksII.Flink );
  1005. }
  1006. //
  1007. // Put the address of the fast mutex on the stack.
  1008. //
  1009. OplockFastMutex = ThisOplock->FastMutex;
  1010. //
  1011. // We store this Irp in the Oplocks structure.
  1012. // We set the oplock state to the correct exclusive oplock.
  1013. //
  1014. ThisOplock->IrpExclusiveOplock = Irp;
  1015. ThisOplock->FileObject = IrpSp->FileObject;
  1016. ThisOplock->OplockState = NextOplockState;
  1017. IoMarkIrpPending( Irp );
  1018. ObReferenceObject( IrpSp->FileObject );
  1019. Irp->IoStatus.Information = (ULONG_PTR) ThisOplock;
  1020. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  1021. //
  1022. // Now if the irp is cancelled then we'll call the cancel
  1023. // routine right now to do away with the irp, otherwise
  1024. // we set the cancel routine
  1025. //
  1026. if (Irp->Cancel) {
  1027. AcquiredMutex = FALSE;
  1028. ExReleaseFastMutexUnsafe( OplockFastMutex );
  1029. FsRtlCancelExclusiveIrp( NULL, Irp );
  1030. } else {
  1031. IoSetCancelRoutine( Irp, FsRtlCancelExclusiveIrp );
  1032. IoReleaseCancelSpinLock( Irp->CancelIrql );
  1033. }
  1034. Status = STATUS_PENDING;
  1035. } else {
  1036. //
  1037. // We'll complete the Irp with the Oplock not granted message
  1038. // and return that value as a status.
  1039. //
  1040. if (ARGUMENT_PRESENT( Irp )) {
  1041. FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED );
  1042. }
  1043. Status = STATUS_OPLOCK_NOT_GRANTED;
  1044. }
  1045. } finally {
  1046. //
  1047. // Give up the oplock synchronization object.
  1048. //
  1049. if (AcquiredMutex) {
  1050. ExReleaseFastMutexUnsafe( ThisOplock->FastMutex );
  1051. }
  1052. DebugTrace( +1, Dbg, "FsRtlRequestExclusiveOplock: Exit\n", 0 );
  1053. }
  1054. return Status;
  1055. }
  1056. //
  1057. // Local support routine.
  1058. //
  1059. NTSTATUS
  1060. FsRtlRequestOplockII (
  1061. IN OUT PNONOPAQUE_OPLOCK *Oplock,
  1062. IN PIO_STACK_LOCATION IrpSp,
  1063. IN PIRP Irp
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. This routine is called when a user is requesting an Oplock II on an
  1068. open file. The request is granted if there are currently no
  1069. level 1 oplocks on the file and an oplock break is not in progress.
  1070. Arguments:
  1071. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1072. this file.
  1073. IrpSp - This is the Irp stack location for the current Irp.
  1074. Irp - Supplies a pointer to the Irp which declares the requested
  1075. operation.
  1076. Return Value:
  1077. STATUS_PENDING if the oplock is granted.
  1078. STATUS_OPLOCK_NOT_GRANTED if the request is denied.
  1079. --*/
  1080. {
  1081. NTSTATUS Status;
  1082. PNONOPAQUE_OPLOCK ThisOplock;
  1083. BOOLEAN AcquiredMutex;
  1084. DebugTrace( +1, Dbg, "FsRtlRequestOplockII: Entered\n", 0 );
  1085. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1086. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1087. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1088. //
  1089. // We can grant the oplock if no one else owns a level I
  1090. // oplock on this file. If the oplock pointer is NULL then there
  1091. // are no oplocks on the file. Otherwise we need to check the
  1092. // oplock state in an existing oplock structure.
  1093. //
  1094. if (*Oplock == NULL) {
  1095. DebugTrace( 0,
  1096. Dbg,
  1097. "Oplock currently not allocated\n",
  1098. 0);
  1099. ThisOplock = FsRtlAllocateOplock();
  1100. *Oplock = ThisOplock;
  1101. } else {
  1102. ThisOplock = *Oplock;
  1103. }
  1104. //
  1105. // Grab the synchronization object for the oplock.
  1106. //
  1107. ExAcquireFastMutexUnsafe( ThisOplock->FastMutex );
  1108. AcquiredMutex = TRUE;
  1109. //
  1110. // Use a try-finally to facilitate cleanup.
  1111. //
  1112. try {
  1113. //
  1114. // If the current oplock state is no oplocks held or OplockIIGranted
  1115. // then we will grant the oplock to this requestor.
  1116. //
  1117. if (FlagOn( ThisOplock->OplockState, NO_OPLOCK | LEVEL_II_OPLOCK )) {
  1118. PFAST_MUTEX OplockFastMutex = ThisOplock->FastMutex;
  1119. //
  1120. // We store this Irp in the Oplocks structure.
  1121. // We set the oplock state to 'OplockIIGranted'.
  1122. //
  1123. IoMarkIrpPending( Irp );
  1124. Irp->IoStatus.Status = STATUS_SUCCESS;
  1125. InsertHeadList( &ThisOplock->IrpOplocksII,
  1126. &Irp->Tail.Overlay.ListEntry );
  1127. Irp->IoStatus.Information = (ULONG_PTR) ThisOplock;
  1128. ThisOplock->OplockState = OplockIIGranted;
  1129. ObReferenceObject( IrpSp->FileObject );
  1130. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  1131. //
  1132. // Now if the irp is cancelled then we'll call the cancel
  1133. // routine right now to do away with the irp, otherwise
  1134. // we set the cancel routine
  1135. //
  1136. if (Irp->Cancel) {
  1137. AcquiredMutex = FALSE;
  1138. ExReleaseFastMutexUnsafe( OplockFastMutex );
  1139. FsRtlCancelOplockIIIrp( NULL, Irp );
  1140. } else {
  1141. IoSetCancelRoutine( Irp, FsRtlCancelOplockIIIrp );
  1142. IoReleaseCancelSpinLock( Irp->CancelIrql );
  1143. }
  1144. Status = STATUS_PENDING;
  1145. } else {
  1146. //
  1147. // We'll complete the Irp with the Oplock not granted message
  1148. // and return that value as a status.
  1149. //
  1150. FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED );
  1151. Status = STATUS_OPLOCK_NOT_GRANTED;
  1152. }
  1153. } finally {
  1154. //
  1155. // Give up the oplock synchronization object.
  1156. //
  1157. if (AcquiredMutex) {
  1158. ExReleaseFastMutexUnsafe( ThisOplock->FastMutex );
  1159. }
  1160. DebugTrace( +1, Dbg, "FsRtlRequestOplockII: Exit\n", 0 );
  1161. }
  1162. return Status;
  1163. }
  1164. //
  1165. // Local support routine.
  1166. //
  1167. NTSTATUS
  1168. FsRtlAcknowledgeOplockBreak (
  1169. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1170. IN PIO_STACK_LOCATION IrpSp,
  1171. IN PIRP Irp,
  1172. IN BOOLEAN GrantLevelII
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. This routine is called when a user is acknowledging an Oplock I
  1177. break. If the level 1 oplock was being broken to level 2, then
  1178. a check is made to insure that the level 2 has not been broken
  1179. in the meantime.
  1180. If an oplock 1 break is not in progress then this will be treated
  1181. as an asynchronous break request. If this is an asynchronous break
  1182. request and the file object owns an outstanding level 1 oplock, then
  1183. the oplock will be broken at this point.
  1184. A spurious break request via a file object which does not (or did not)
  1185. own the level 1 oplock will generate a warning but will not affect
  1186. the oplock state.
  1187. At the end of an Oplock I break, all of the waiting irps are completed.
  1188. Arguments:
  1189. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1190. this file.
  1191. IrpSp - This is the Irp stack location for the current Irp.
  1192. Irp - Supplies a pointer to the Irp which declares the requested
  1193. operation.
  1194. GrantLevelII - Indicates that this caller wants a level II oplock left
  1195. on the file.
  1196. Return Value:
  1197. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1198. STATUS_CANCELLED if the Irp is cancelled before we return.
  1199. --*/
  1200. {
  1201. NTSTATUS Status;
  1202. BOOLEAN AcquiredMutex;
  1203. DebugTrace( +1, Dbg, "FsRtlAcknowledgeOplockBreak: Entered\n", 0 );
  1204. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1205. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1206. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1207. //
  1208. // If there is no oplock structure, we complete this with invalid
  1209. // oplock protocol.
  1210. //
  1211. if (Oplock == NULL) {
  1212. FsRtlCompleteRequest( Irp, STATUS_INVALID_OPLOCK_PROTOCOL );
  1213. DebugTrace( -1, Dbg, "FsRtlAcknowledgeOplockBreak: Exit -> %08lx\n", STATUS_INVALID_OPLOCK_PROTOCOL );
  1214. return STATUS_INVALID_OPLOCK_PROTOCOL;
  1215. }
  1216. //
  1217. // Grab the synchronization object for the oplock.
  1218. //
  1219. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1220. AcquiredMutex = TRUE;
  1221. //
  1222. // Use a try-finally to facilitate cleanup.
  1223. //
  1224. try {
  1225. BOOLEAN DereferenceFileObject = TRUE;
  1226. //
  1227. // If a break is underway but this is not the owner of the
  1228. // level 1 oplock, we complete the request and return a
  1229. // warning.
  1230. //
  1231. if (Oplock->FileObject != IrpSp->FileObject) {
  1232. Status = STATUS_INVALID_OPLOCK_PROTOCOL;
  1233. DebugTrace(0,
  1234. Dbg,
  1235. "Not oplock owner -> %08lx\n",
  1236. Status);
  1237. FsRtlCompleteRequest( Irp, Status );
  1238. try_return( Status );
  1239. }
  1240. //
  1241. // If the user would like a level II and we are breaking to level II
  1242. // then grant the oplock.
  1243. //
  1244. if (GrantLevelII &&
  1245. FlagOn( Oplock->OplockState, BREAK_TO_II )) {
  1246. PFAST_MUTEX OplockFastMutex = Oplock->FastMutex;
  1247. DebugTrace(0, Dbg, "OplockItoII\n", 0);
  1248. //
  1249. // The acknowledgement should never be synchronous.
  1250. //
  1251. ASSERT( !IoIsOperationSynchronous( Irp ));
  1252. //
  1253. // We need to add this Irp to the oplock II queue, change
  1254. // the oplock state to Oplock II granted and set the
  1255. // return value to STATUS_PENDING.
  1256. //
  1257. IoMarkIrpPending( Irp );
  1258. Irp->IoStatus.Status = STATUS_SUCCESS;
  1259. InsertHeadList( &Oplock->IrpOplocksII,
  1260. &Irp->Tail.Overlay.ListEntry );
  1261. DereferenceFileObject = FALSE;
  1262. Oplock->OplockState = OplockIIGranted;
  1263. Irp->IoStatus.Information = (ULONG_PTR) Oplock;
  1264. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  1265. //
  1266. // Now if the irp is cancelled then we'll call the cancel
  1267. // routine right now to do away with the irp, otherwise
  1268. // we set the cancel routine
  1269. //
  1270. if (Irp->Cancel) {
  1271. AcquiredMutex = FALSE;
  1272. ExReleaseFastMutexUnsafe( OplockFastMutex );
  1273. FsRtlCancelOplockIIIrp( NULL, Irp );
  1274. } else {
  1275. IoSetCancelRoutine( Irp, FsRtlCancelOplockIIIrp );
  1276. IoReleaseCancelSpinLock( Irp->CancelIrql );
  1277. }
  1278. Status = STATUS_PENDING;
  1279. //
  1280. // We will break to none since this is the expected case for these
  1281. // cases.
  1282. //
  1283. } else if (FlagOn( Oplock->OplockState, BREAK_TO_II | BREAK_TO_NONE )) {
  1284. //
  1285. // We need to complete this Irp and return STATUS_SUCCESS.
  1286. // We also set the oplock state to no oplocks held.
  1287. //
  1288. DebugTrace(0, Dbg, "OplockItoNone\n", 0);
  1289. Status = STATUS_SUCCESS;
  1290. FsRtlCompleteRequest( Irp, Status );
  1291. Oplock->OplockState = NoOplocksHeld;
  1292. //
  1293. // In this case the user expects to be at level II. He is
  1294. // expecting this Irp to be completed when the LevelII Oplock
  1295. // is broken.
  1296. //
  1297. } else if (FlagOn( Oplock->OplockState, BREAK_TO_II_TO_NONE )) {
  1298. DebugTrace(0, Dbg, "AcknowledgeOplockBreak: OplockItoIItoNone\n", 0);
  1299. Status = STATUS_SUCCESS;
  1300. Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1301. FsRtlCompleteRequest( Irp, Status );
  1302. Oplock->OplockState = NoOplocksHeld;
  1303. } else {
  1304. Status = STATUS_INVALID_OPLOCK_PROTOCOL;
  1305. DebugTrace(0,
  1306. Dbg,
  1307. "No break underway -> %08lx\n",
  1308. Status);
  1309. FsRtlCompleteRequest( Irp, Status );
  1310. try_return( Status );
  1311. }
  1312. //
  1313. // Complete the waiting Irps and cleanup the oplock structure.
  1314. //
  1315. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1316. PWAITING_IRP WaitingIrp;
  1317. //
  1318. // Remove the entry found and complete the Irp.
  1319. //
  1320. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1321. WAITING_IRP,
  1322. Links );
  1323. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1324. }
  1325. if (DereferenceFileObject) {
  1326. ObDereferenceObject( Oplock->FileObject );
  1327. }
  1328. Oplock->FileObject = NULL;
  1329. try_exit: NOTHING;
  1330. } finally {
  1331. //
  1332. // Give up the oplock synchronization object.
  1333. //
  1334. if (AcquiredMutex) {
  1335. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1336. }
  1337. DebugTrace( -1, Dbg, "FsRtlAcknowledgeOplockBreak: Exit -> %08x\n", Status );
  1338. }
  1339. return Status;
  1340. }
  1341. //
  1342. // Local support routine.
  1343. //
  1344. NTSTATUS
  1345. FsRtlOpBatchBreakClosePending (
  1346. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1347. IN PIO_STACK_LOCATION IrpSp,
  1348. IN PIRP Irp
  1349. )
  1350. /*++
  1351. Routine Description:
  1352. This routine is called when a user is acknowledging a batch oplock
  1353. break or Level I oplock break. In this case the user is planning
  1354. to close the file as well and doesn't need a level II oplock.
  1355. Arguments:
  1356. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1357. this file.
  1358. IrpSp - This is the Irp stack location for the current Irp.
  1359. Irp - Supplies a pointer to the Irp which declares the requested
  1360. operation.
  1361. Return Value:
  1362. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1363. STATUS_CANCELLED if the Irp is cancelled before we return.
  1364. --*/
  1365. {
  1366. NTSTATUS Status = STATUS_SUCCESS;
  1367. BOOLEAN AcquiredMutex;
  1368. PAGED_CODE();
  1369. DebugTrace( +1, Dbg, "FsRtlOpBatchBreakClosePending: Entered\n", 0 );
  1370. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1371. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1372. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1373. //
  1374. // If there is no oplock structure, we complete this with invalid
  1375. // oplock protocol.
  1376. //
  1377. if (Oplock == NULL) {
  1378. FsRtlCompleteRequest( Irp, STATUS_INVALID_OPLOCK_PROTOCOL );
  1379. DebugTrace( -1, Dbg, "FsRtlOpBatchClosePending: Exit -> %08lx\n", STATUS_INVALID_OPLOCK_PROTOCOL );
  1380. return STATUS_INVALID_OPLOCK_PROTOCOL;
  1381. }
  1382. //
  1383. // Grab the synchronization object for the oplock.
  1384. //
  1385. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1386. AcquiredMutex = TRUE;
  1387. //
  1388. // Use a try_finally to facilitate cleanup.
  1389. //
  1390. try {
  1391. //
  1392. // If a break is underway but this is not the owner of the
  1393. // level 1 oplock, we complete the request and return a
  1394. // warning.
  1395. //
  1396. if (Oplock->FileObject != IrpSp->FileObject) {
  1397. Status = STATUS_INVALID_OPLOCK_PROTOCOL;
  1398. DebugTrace(0,
  1399. Dbg,
  1400. "Not oplock owner -> %08lx\n",
  1401. Status);
  1402. } else {
  1403. //
  1404. // If this is an opbatch operation we want to note that a
  1405. // close is pending. For an exclusive oplock we set the state to
  1406. // no oplocsk held. There must be a break in progress to
  1407. // process however.
  1408. //
  1409. if (FlagOn( Oplock->OplockState,
  1410. BREAK_TO_II | BREAK_TO_NONE | BREAK_TO_II_TO_NONE )) {
  1411. //
  1412. // Break all oplocks for an exclusive oplock.
  1413. //
  1414. if (FlagOn( Oplock->OplockState, LEVEL_I_OPLOCK | PENDING )) {
  1415. //
  1416. // Clean up the oplock structure and complete all waiting Irps.
  1417. //
  1418. if (FlagOn( Oplock->OplockState, LEVEL_I_OPLOCK )) {
  1419. ObDereferenceObject( Oplock->FileObject );
  1420. }
  1421. Oplock->OplockState = NoOplocksHeld;
  1422. Oplock->FileObject = NULL;
  1423. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1424. PWAITING_IRP WaitingIrp;
  1425. //
  1426. // Remove the entry found and complete the Irp.
  1427. //
  1428. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1429. WAITING_IRP,
  1430. Links );
  1431. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1432. }
  1433. //
  1434. // Set the state to close pending for batch and filter
  1435. // oplocks.
  1436. //
  1437. } else {
  1438. ClearFlag( Oplock->OplockState, OPLOCK_BREAK_MASK );
  1439. SetFlag( Oplock->OplockState, CLOSE_PENDING );
  1440. }
  1441. } else {
  1442. Status = STATUS_INVALID_OPLOCK_PROTOCOL;
  1443. DebugTrace(0,
  1444. Dbg,
  1445. "No break underway -> %08lx\n",
  1446. Status);
  1447. }
  1448. }
  1449. //
  1450. // We simply complete this request.
  1451. //
  1452. FsRtlCompleteRequest( Irp, Status );
  1453. } finally {
  1454. //
  1455. // Release the synchronization object.
  1456. //
  1457. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1458. DebugTrace(-1, Dbg, "FsRtlOpBatchBreakClosePending: Exit -> %08lx\n", Status);
  1459. }
  1460. return Status;
  1461. }
  1462. //
  1463. // Local support routine
  1464. //
  1465. NTSTATUS
  1466. FsRtlOplockBreakNotify (
  1467. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1468. IN PIO_STACK_LOCATION IrpSp,
  1469. IN PIRP Irp
  1470. )
  1471. /*++
  1472. Routine Description:
  1473. This routine is called when the Irp refers the user request to
  1474. be notified when there is no level 1 oplock break in progress.
  1475. Under any other condition this routine completes immediately with
  1476. STATUS_SUCCESS. Otherwise we simply add this Irp to the list
  1477. of Irp's waiting for the break to complete.
  1478. Arguments:
  1479. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1480. this file.
  1481. IrpSp - This is the Irp stack location for the current Irp.
  1482. Irp - Supplies a pointer to the Irp which declares the requested
  1483. operation.
  1484. Return Value:
  1485. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1486. STATUS_PENDING if we return here but hold the Irp.
  1487. STATUS_CANCELLED if the Irp is cancelled before we return.
  1488. --*/
  1489. {
  1490. NTSTATUS Status;
  1491. BOOLEAN AcquiredMutex;
  1492. PAGED_CODE();
  1493. DebugTrace( +1, Dbg, "FsRtlOplockBreakNotify: Entered\n", 0 );
  1494. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1495. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1496. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1497. //
  1498. // If there is no oplock structure, we complete this with status success.
  1499. //
  1500. if (Oplock == NULL) {
  1501. FsRtlCompleteRequest( Irp, STATUS_SUCCESS );
  1502. DebugTrace( -1, Dbg, "FsRtlOpBatchClosePending: Exit -> %08lx\n", STATUS_SUCCESS );
  1503. return STATUS_SUCCESS;
  1504. }
  1505. //
  1506. // Grap the synchronization object.
  1507. //
  1508. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1509. AcquiredMutex = TRUE;
  1510. //
  1511. // Use a try-finally to facilitate cleanup.
  1512. //
  1513. try {
  1514. //
  1515. // If there are no outstanding level 1 oplocks breaks underway
  1516. // or batch oplock breaks underway we complete immediately.
  1517. //
  1518. if (!FlagOn( Oplock->OplockState, OPLOCK_BREAK_MASK )) {
  1519. DebugTrace(0,
  1520. Dbg,
  1521. "No exclusive oplock break underway\n",
  1522. 0);
  1523. FsRtlCompleteRequest( Irp, STATUS_SUCCESS );
  1524. try_return( Status = STATUS_SUCCESS );
  1525. } else if (FlagOn( Oplock->OplockState, PENDING )) {
  1526. Oplock->OplockState = NoOplocksHeld;
  1527. Oplock->FileObject = NULL;
  1528. FsRtlCompleteRequest( Irp, STATUS_SUCCESS );
  1529. try_return( Status = STATUS_SUCCESS );
  1530. }
  1531. //
  1532. // Otherwise we need to add this Irp to the list of Irp's waiting
  1533. // for the oplock break to complete.
  1534. //
  1535. AcquiredMutex = FALSE;
  1536. //
  1537. // Initialize the return value to status success.
  1538. //
  1539. Irp->IoStatus.Status = STATUS_SUCCESS;
  1540. Status = FsRtlWaitOnIrp( Oplock,
  1541. Irp,
  1542. NULL,
  1543. FsRtlNotifyCompletion,
  1544. NULL,
  1545. NULL );
  1546. try_exit: NOTHING;
  1547. } finally {
  1548. //
  1549. // Give up the synchronization event if we haven't done so.
  1550. //
  1551. if (AcquiredMutex) {
  1552. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1553. }
  1554. DebugTrace( -1, Dbg, "FsRtlOplockBreakNotify: Exit -> %08lx\n", Status );
  1555. }
  1556. return Status;
  1557. }
  1558. //
  1559. // Local support routine
  1560. //
  1561. VOID
  1562. FsRtlOplockCleanup (
  1563. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1564. IN PIO_STACK_LOCATION IrpSp
  1565. )
  1566. /*++
  1567. Routine Description:
  1568. This routine is called to coordinate a cleanup operation with the
  1569. oplock state for a file. If there is no level 1 oplock for the
  1570. file, then there is no action to take. If the file object in this
  1571. Irp matches the file object used in granting the level 1 oplock,
  1572. then the close operation will terminate the oplock. If this
  1573. cleanup refers to a file object which has a level II oplock, then
  1574. that Irp is completed and removed from the list of level II
  1575. oplocked Irps.
  1576. Arguments:
  1577. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1578. this file.
  1579. IrpSp - This is the Irp stack location for the current Irp.
  1580. Return Value:
  1581. None.
  1582. --*/
  1583. {
  1584. DebugTrace( +1, Dbg, "FsRtlOplockCleanup: Entered\n", 0 );
  1585. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1586. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1587. //
  1588. // Grab the synchronization object for the oplock.
  1589. //
  1590. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1591. //
  1592. // Use a try-finally to facilitate cleanup.
  1593. //
  1594. try {
  1595. //
  1596. // If the oplock has no oplock held we return immediately.
  1597. //
  1598. if (Oplock->OplockState == NoOplocksHeld) {
  1599. DebugTrace(0,
  1600. Dbg,
  1601. "No oplocks on file\n",
  1602. 0);
  1603. try_return( NOTHING );
  1604. }
  1605. //
  1606. // If level II oplocks are held, check if this matches any of them.
  1607. //
  1608. if (Oplock->OplockState == OplockIIGranted) {
  1609. PLIST_ENTRY Link;
  1610. PIRP Irp;
  1611. PIO_STACK_LOCATION NextIrpSp;
  1612. DebugTrace(0,
  1613. Dbg,
  1614. "File has level 2 oplocks\n",
  1615. 0);
  1616. for (Link = Oplock->IrpOplocksII.Flink;
  1617. Link != &Oplock->IrpOplocksII;
  1618. Link = Link->Flink) {
  1619. Irp = CONTAINING_RECORD( Link, IRP, Tail.Overlay.ListEntry );
  1620. NextIrpSp = IoGetCurrentIrpStackLocation( Irp );
  1621. //
  1622. // If the file objects match, then emove the entry found and complete the Irp.
  1623. //
  1624. if (IrpSp->FileObject == NextIrpSp->FileObject) {
  1625. //
  1626. // Back up to remember this link.
  1627. //
  1628. Link = Link->Blink;
  1629. //
  1630. //
  1631. FsRtlRemoveAndCompleteIrp( Link->Flink );
  1632. }
  1633. }
  1634. //
  1635. // If all the level II oplocks are gone, then the state is
  1636. // no oplocks held.
  1637. //
  1638. if (IsListEmpty( &Oplock->IrpOplocksII )) {
  1639. Oplock->OplockState = NoOplocksHeld;
  1640. }
  1641. try_return( NOTHING );
  1642. }
  1643. //
  1644. // If this file object matches that used to request an exclusive
  1645. // oplock, we completely close the oplock break.
  1646. //
  1647. if (IrpSp->FileObject == Oplock->FileObject) {
  1648. DebugTrace(0,
  1649. Dbg,
  1650. "Handle owns level 1 oplock\n",
  1651. 0);
  1652. //
  1653. // If an oplock break is not in progress, we initiate one and
  1654. // complete the exclusive Irp immediately.
  1655. //
  1656. if (!FlagOn( Oplock->OplockState, OPLOCK_BREAK_MASK | PENDING )) {
  1657. PIRP ExclusiveIrp = Oplock->IrpExclusiveOplock;
  1658. DebugTrace(0,
  1659. Dbg,
  1660. "Initiate oplock break\n",
  1661. 0);
  1662. IoAcquireCancelSpinLock( &ExclusiveIrp->CancelIrql );
  1663. IoSetCancelRoutine( ExclusiveIrp, NULL );
  1664. IoReleaseCancelSpinLock( ExclusiveIrp->CancelIrql );
  1665. ExclusiveIrp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1666. FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_SUCCESS );
  1667. Oplock->IrpExclusiveOplock = NULL;
  1668. }
  1669. //
  1670. // Clean up the oplock structure and complete all waiting Irps.
  1671. // Don't do this if this is a pending opfilter request.
  1672. //
  1673. if (!FlagOn( Oplock->OplockState, PENDING )) {
  1674. ObDereferenceObject( IrpSp->FileObject );
  1675. }
  1676. Oplock->FileObject = NULL;
  1677. Oplock->OplockState = NoOplocksHeld;
  1678. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1679. PWAITING_IRP WaitingIrp;
  1680. //
  1681. // Remove the entry found and complete the Irp.
  1682. //
  1683. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1684. WAITING_IRP,
  1685. Links );
  1686. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1687. }
  1688. }
  1689. try_exit: NOTHING;
  1690. } finally {
  1691. //
  1692. // Give up the oplock synchronization object.
  1693. //
  1694. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1695. DebugTrace( +1, Dbg, "FsRtlOplockCleanup: Exit\n", 0 );
  1696. }
  1697. return;
  1698. }
  1699. //
  1700. // Local support routine
  1701. //
  1702. NTSTATUS
  1703. FsRtlOplockBreakToII (
  1704. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1705. IN PIO_STACK_LOCATION IrpSp,
  1706. IN PIRP Irp,
  1707. IN PVOID Context,
  1708. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  1709. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine
  1710. )
  1711. /*++
  1712. Routine Description:
  1713. This routine is a generic worker routine which is called when an
  1714. operation will cause all oplocks to be broken to level II before the
  1715. operation can proceed.
  1716. Arguments:
  1717. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1718. this file.
  1719. IrpSp - This is the Irp stack location for the current Irp.
  1720. Irp - Supplies a pointer to the Irp which declares the requested
  1721. operation.
  1722. Context - This value is passed as a parameter to the completion routine.
  1723. CompletionRoutine - This is the routine which is called if this
  1724. Irp must wait for an Oplock to break. This
  1725. is a synchronous operation if not specified
  1726. and we block in this thread waiting on
  1727. an event.
  1728. PostIrpRoutine - This is the routine to call before we put anything
  1729. on our waiting Irp queue.
  1730. Return Value:
  1731. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1732. STATUS_PENDING if we return here but hold the Irp.
  1733. STATUS_CANCELLED if the Irp is cancelled before we return.
  1734. --*/
  1735. {
  1736. KEVENT Event;
  1737. NTSTATUS Status;
  1738. BOOLEAN AcquiredMutex;
  1739. DebugTrace( +1, Dbg, "CheckOplockBreakToII: Entered\n", 0 );
  1740. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1741. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1742. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1743. //
  1744. // Grap the synchronization object.
  1745. //
  1746. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1747. AcquiredMutex = TRUE;
  1748. //
  1749. // Use a try-finally to facilitate cleanup.
  1750. //
  1751. try {
  1752. //
  1753. // If there are no outstanding oplocks or level II oplocks are held,
  1754. // we can return immediately.
  1755. //
  1756. if (!FlagOn( Oplock->OplockState, EXCLUSIVE )) {
  1757. DebugTrace(0,
  1758. Dbg,
  1759. "No oplocks or level II oplocks on file\n",
  1760. 0);
  1761. try_return( Status = STATUS_SUCCESS );
  1762. }
  1763. //
  1764. // At this point there is an exclusive oplock break in progress.
  1765. // If this file object owns that oplock, we allow the operation
  1766. // to continue.
  1767. //
  1768. if (Oplock->FileObject == IrpSp->FileObject) {
  1769. DebugTrace(0,
  1770. Dbg,
  1771. "Handle owns level 1 oplock\n",
  1772. 0);
  1773. try_return( Status = STATUS_SUCCESS );
  1774. }
  1775. //
  1776. // If there is currently an exclusive oplock held then complete
  1777. // the exclusive irp.
  1778. //
  1779. if (!FlagOn( Oplock->OplockState, PENDING | OPLOCK_BREAK_MASK )) {
  1780. PIRP IrpExclusive = Oplock->IrpExclusiveOplock;
  1781. DebugTrace(0,
  1782. Dbg,
  1783. "Breaking exclusive oplock\n",
  1784. 0);
  1785. IoAcquireCancelSpinLock( &IrpExclusive->CancelIrql );
  1786. IoSetCancelRoutine( IrpExclusive, NULL );
  1787. IoReleaseCancelSpinLock( IrpExclusive->CancelIrql );
  1788. //
  1789. // If the Irp has been cancelled, we complete the Irp with
  1790. // status cancelled and break the oplock completely.
  1791. //
  1792. if (IrpExclusive->Cancel) {
  1793. IrpExclusive->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1794. FsRtlCompleteRequest( IrpExclusive, STATUS_CANCELLED );
  1795. Oplock->OplockState = NoOplocksHeld;
  1796. Oplock->IrpExclusiveOplock = NULL;
  1797. ObDereferenceObject( Oplock->FileObject );
  1798. Oplock->FileObject = NULL;
  1799. //
  1800. // Release any waiting irps.
  1801. //
  1802. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1803. PWAITING_IRP WaitingIrp;
  1804. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1805. WAITING_IRP,
  1806. Links );
  1807. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1808. }
  1809. try_return( Status = STATUS_SUCCESS );
  1810. } else {
  1811. NTSTATUS CompletionStatus;
  1812. if (FlagOn( Oplock->OplockState, LEVEL_I_OPLOCK | BATCH_OPLOCK )) {
  1813. SetFlag( Oplock->OplockState, BREAK_TO_II );
  1814. CompletionStatus = FILE_OPLOCK_BROKEN_TO_LEVEL_2;
  1815. } else {
  1816. SetFlag( Oplock->OplockState, BREAK_TO_NONE );
  1817. CompletionStatus = FILE_OPLOCK_BROKEN_TO_NONE;
  1818. }
  1819. Oplock->IrpExclusiveOplock->IoStatus.Information = CompletionStatus;
  1820. FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_SUCCESS );
  1821. Oplock->IrpExclusiveOplock = NULL;
  1822. }
  1823. //
  1824. // If there is a pending opfilter request then clear the request.
  1825. //
  1826. } else if (FlagOn( Oplock->OplockState, PENDING )) {
  1827. Oplock->OplockState = NoOplocksHeld;
  1828. Oplock->FileObject = NULL;
  1829. try_return( Status = STATUS_SUCCESS );
  1830. }
  1831. //
  1832. // If this is an open operation and the user doesn't want to
  1833. // block, we will complete the operation now.
  1834. //
  1835. if ((IrpSp->MajorFunction == IRP_MJ_CREATE) &&
  1836. FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) {
  1837. DebugTrace( 0, Dbg, "Don't block open\n", 0 );
  1838. try_return( Status = STATUS_OPLOCK_BREAK_IN_PROGRESS );
  1839. }
  1840. //
  1841. // If we get here that means that this operation can't continue
  1842. // until the oplock break is complete.
  1843. //
  1844. // FsRtlWaitOnIrp will release the mutex.
  1845. //
  1846. AcquiredMutex = FALSE;
  1847. Status = FsRtlWaitOnIrp( Oplock,
  1848. Irp,
  1849. Context,
  1850. CompletionRoutine,
  1851. PostIrpRoutine,
  1852. &Event );
  1853. try_exit: NOTHING;
  1854. } finally {
  1855. //
  1856. // Give up the synchronization event if we haven't done so.
  1857. //
  1858. if (AcquiredMutex) {
  1859. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1860. }
  1861. DebugTrace( -1, Dbg, "FsRtlOplockBreakToII: Exit -> %08lx\n", Status );
  1862. }
  1863. return Status;
  1864. }
  1865. //
  1866. // Local support routine.
  1867. //
  1868. NTSTATUS
  1869. FsRtlOplockBreakToNone (
  1870. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1871. IN PIO_STACK_LOCATION IrpSp,
  1872. IN PIRP Irp,
  1873. IN PVOID Context,
  1874. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  1875. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL
  1876. )
  1877. /*++
  1878. Routine Description:
  1879. This routine is a generic worker routine which is called when an
  1880. operation will cause all oplocks to be broken before the operation can
  1881. proceed.
  1882. Arguments:
  1883. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1884. this file.
  1885. IrpSp - This is the Irp stack location for the current Irp.
  1886. Irp - Supplies a pointer to the Irp which declares the requested
  1887. operation.
  1888. Context - This value is passed as a parameter to the completion routine.
  1889. CompletionRoutine - This is the routine which is called if this
  1890. Irp must wait for an Oplock to break. This
  1891. is a synchronous operation if not specified
  1892. and we block in this thread waiting on
  1893. an event.
  1894. PostIrpRoutine - This is the routine to call before we put anything
  1895. on our waiting Irp queue.
  1896. Return Value:
  1897. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1898. STATUS_PENDING if we return here but hold the Irp.
  1899. STATUS_CANCELLED if the Irp is cancelled before we return.
  1900. --*/
  1901. {
  1902. KEVENT Event;
  1903. NTSTATUS Status;
  1904. BOOLEAN AcquiredMutex;
  1905. DebugTrace( +1, Dbg, "CheckOplockBreakToNone: Entered\n", 0 );
  1906. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1907. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1908. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1909. //
  1910. // Grap the synchronization object.
  1911. //
  1912. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1913. AcquiredMutex = TRUE;
  1914. //
  1915. // Use a try-finally to facilitate cleanup.
  1916. //
  1917. try {
  1918. //
  1919. // If there are no outstanding oplocks, we can return immediately.
  1920. //
  1921. if (Oplock->OplockState == NoOplocksHeld) {
  1922. DebugTrace(0,
  1923. Dbg,
  1924. "No oplocks on file\n",
  1925. 0);
  1926. try_return( Status = STATUS_SUCCESS );
  1927. }
  1928. //
  1929. // If there is an exclusive oplock held, we begin the break to none.
  1930. //
  1931. if (!FlagOn( Oplock->OplockState,
  1932. LEVEL_II_OPLOCK | PENDING | OPLOCK_BREAK_MASK )) {
  1933. PIRP IrpExclusive = Oplock->IrpExclusiveOplock;
  1934. DebugTrace(0,
  1935. Dbg,
  1936. "Breaking exclusive oplock\n",
  1937. 0);
  1938. IoAcquireCancelSpinLock( &IrpExclusive->CancelIrql );
  1939. IoSetCancelRoutine( IrpExclusive, NULL );
  1940. IoReleaseCancelSpinLock( IrpExclusive->CancelIrql );
  1941. //
  1942. // If the Irp has been cancelled, we complete the Irp with
  1943. // status cancelled and break the oplock completely.
  1944. //
  1945. if (IrpExclusive->Cancel) {
  1946. IrpExclusive->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1947. FsRtlCompleteRequest( IrpExclusive, STATUS_CANCELLED );
  1948. Oplock->OplockState = NoOplocksHeld;
  1949. Oplock->IrpExclusiveOplock = NULL;
  1950. ObDereferenceObject( Oplock->FileObject );
  1951. Oplock->FileObject = NULL;
  1952. //
  1953. // Release any waiting irps.
  1954. //
  1955. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1956. PWAITING_IRP WaitingIrp;
  1957. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1958. WAITING_IRP,
  1959. Links );
  1960. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1961. }
  1962. try_return( Status = STATUS_SUCCESS );
  1963. } else {
  1964. Oplock->IrpExclusiveOplock->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1965. FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_SUCCESS );
  1966. Oplock->IrpExclusiveOplock = NULL;
  1967. SetFlag( Oplock->OplockState, BREAK_TO_NONE );
  1968. }
  1969. //
  1970. // If there are level II oplocks, this will break all of them.
  1971. //
  1972. } else if (Oplock->OplockState == OplockIIGranted) {
  1973. DebugTrace(0,
  1974. Dbg,
  1975. "Breaking all level 2 oplocks\n",
  1976. 0);
  1977. while (!IsListEmpty( &Oplock->IrpOplocksII )) {
  1978. //
  1979. // Remove and complete this Irp with STATUS_SUCCESS.
  1980. //
  1981. FsRtlRemoveAndCompleteIrp( Oplock->IrpOplocksII.Flink );
  1982. }
  1983. //
  1984. // Set the oplock state to no oplocks held.
  1985. //
  1986. Oplock->OplockState = NoOplocksHeld;
  1987. try_return( Status = STATUS_SUCCESS );
  1988. //
  1989. // If we are currently breaking to level II then change that
  1990. // to BreakToIIToNone.
  1991. //
  1992. } else if (FlagOn( Oplock->OplockState, BREAK_TO_II )) {
  1993. ClearFlag( Oplock->OplockState, BREAK_TO_II );
  1994. SetFlag( Oplock->OplockState, BREAK_TO_II_TO_NONE );
  1995. //
  1996. // If there is a pending opfilter request then clear that request.
  1997. //
  1998. } else if (FlagOn( Oplock->OplockState, PENDING )) {
  1999. Oplock->OplockState = NoOplocksHeld;
  2000. Oplock->FileObject = NULL;
  2001. try_return( Status = STATUS_SUCCESS );
  2002. }
  2003. //
  2004. // At this point there is already an exclusive oplock break in progress.
  2005. // If this file object owns that oplock, we allow the operation
  2006. // to continue.
  2007. //
  2008. if (Oplock->FileObject == IrpSp->FileObject) {
  2009. DebugTrace(0,
  2010. Dbg,
  2011. "Handle owns level 1 oplock\n",
  2012. 0);
  2013. try_return( Status = STATUS_SUCCESS );
  2014. }
  2015. //
  2016. // If this is an open operation and the user doesn't want to
  2017. // block, we will complete the operation now.
  2018. //
  2019. if ((IrpSp->MajorFunction == IRP_MJ_CREATE) &&
  2020. FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) {
  2021. DebugTrace( 0, Dbg, "Don't block open\n", 0 );
  2022. try_return( Status = STATUS_OPLOCK_BREAK_IN_PROGRESS );
  2023. }
  2024. //
  2025. // If we get here that means that this operation can't continue
  2026. // until the oplock break is complete.
  2027. //
  2028. // FsRtlWaitOnIrp will release the mutex.
  2029. //
  2030. AcquiredMutex = FALSE;
  2031. Status = FsRtlWaitOnIrp( Oplock,
  2032. Irp,
  2033. Context,
  2034. CompletionRoutine,
  2035. PostIrpRoutine,
  2036. &Event );
  2037. try_exit: NOTHING;
  2038. } finally {
  2039. //
  2040. // Give up the synchronization event if we haven't done so.
  2041. //
  2042. if (AcquiredMutex) {
  2043. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  2044. }
  2045. DebugTrace( -1, Dbg, "CheckOplockBreakToNone: Exit -> %08lx\n", Status );
  2046. }
  2047. return Status;
  2048. }
  2049. //
  2050. // Local support routine.
  2051. //
  2052. VOID
  2053. FsRtlRemoveAndCompleteIrp (
  2054. IN PLIST_ENTRY Link
  2055. )
  2056. /*++
  2057. Routine Description:
  2058. This routine is called to remove an Irp from a list of Irps linked
  2059. with the Tail.ListEntry field and complete them with STATUS_CANCELLED
  2060. if the Irp has been cancelled, STATUS_SUCCESS otherwise.
  2061. Arguments:
  2062. Link - Supplies the entry to remove from the list.
  2063. Return Value:
  2064. None.
  2065. --*/
  2066. {
  2067. PIRP Irp;
  2068. PIO_STACK_LOCATION OplockIIIrpSp;
  2069. DebugTrace( +1, Dbg, "FsRtlRemoveAndCompleteIrp: Entered\n", 0 );
  2070. //
  2071. // Reference the Irp.
  2072. //
  2073. Irp = CONTAINING_RECORD( Link, IRP, Tail.Overlay.ListEntry );
  2074. //
  2075. // Get the stack location and dereference the file object.
  2076. //
  2077. OplockIIIrpSp = IoGetCurrentIrpStackLocation( Irp );
  2078. ObDereferenceObject( OplockIIIrpSp->FileObject );
  2079. //
  2080. // Clear the cancel routine in the irp.
  2081. //
  2082. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  2083. IoSetCancelRoutine( Irp, NULL );
  2084. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2085. //
  2086. // Remove this from the list.
  2087. //
  2088. RemoveEntryList( Link );
  2089. //
  2090. // Complete the oplock Irp.
  2091. //
  2092. Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  2093. FsRtlCompleteRequest( Irp, Irp->Cancel ? STATUS_CANCELLED : STATUS_SUCCESS );
  2094. DebugTrace( -1, Dbg, "FsRtlRemoveAndCompleteIrp: Exit\n", 0 );
  2095. }
  2096. //
  2097. // Local support routine.
  2098. //
  2099. NTSTATUS
  2100. FsRtlWaitOnIrp (
  2101. IN OUT PNONOPAQUE_OPLOCK Oplock,
  2102. IN PIRP Irp,
  2103. IN PVOID Context,
  2104. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  2105. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL,
  2106. IN PKEVENT Event
  2107. )
  2108. /*++
  2109. Routine Description:
  2110. This routine is called to create a Wait Irp structure and attach it
  2111. to the current Irp. The Irp is then added to the list of Irps waiting
  2112. for an oplock break. We check if the Irp has been cancelled and if
  2113. so we call our cancel routine to perform the work.
  2114. This routine is holding the Mutex for the oplock on entry and
  2115. must give it up on exit.
  2116. Arguments:
  2117. Oplock - Supplies a pointer to the non-opaque oplock structure for
  2118. this file.
  2119. Irp - Supplies a pointer to the Irp which declares the requested
  2120. operation.
  2121. Context - This value is passed as a parameter to the completion routine.
  2122. CompletionRoutine - This is the routine which is called if this
  2123. Irp must wait for an Oplock to break. This
  2124. is a synchronous operation if not specified
  2125. and we block in this thread waiting on
  2126. an event.
  2127. PostIrpRoutine - This is the routine to call before we put anything
  2128. on our waiting Irp queue.
  2129. Event - If there is no user completion routine, this thread will
  2130. block using this event.
  2131. Return Value:
  2132. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  2133. STATUS_PENDING if we return here but hold the Irp.
  2134. STATUS_CANCELLED if the Irp is cancelled before we return.
  2135. --*/
  2136. {
  2137. BOOLEAN AcquiredMutex;
  2138. NTSTATUS Status;
  2139. PWAITING_IRP WaitingIrp;
  2140. DebugTrace( +1, Dbg, "FsRtlWaitOnIrp: Entered\n", 0 );
  2141. //
  2142. // Remember that we have the mutex.
  2143. //
  2144. AcquiredMutex = TRUE;
  2145. //
  2146. // Use a try-finally to facilitate cleanup.
  2147. //
  2148. try {
  2149. PFAST_MUTEX OplockFastMutex = Oplock->FastMutex;
  2150. //
  2151. // Allocate and initialize the Wait Irp structure.
  2152. //
  2153. WaitingIrp = FsRtlpAllocatePool( PagedPool, sizeof( WAITING_IRP ));
  2154. WaitingIrp->Irp = Irp;
  2155. WaitingIrp->Context = Context;
  2156. WaitingIrp->Information = (ULONG) Irp->IoStatus.Information;
  2157. //
  2158. // Take appropriate action if depending on the value of the
  2159. // completion routine.
  2160. //
  2161. if (ARGUMENT_PRESENT( CompletionRoutine )) {
  2162. WaitingIrp->CompletionRoutine = CompletionRoutine;
  2163. WaitingIrp->Context = Context;
  2164. } else {
  2165. WaitingIrp->CompletionRoutine = FsRtlCompletionRoutinePriv;
  2166. WaitingIrp->Context = Event;
  2167. KeInitializeEvent( Event, NotificationEvent, FALSE );
  2168. }
  2169. //
  2170. // Call the file system's post Irp code.
  2171. //
  2172. if (ARGUMENT_PRESENT( PostIrpRoutine )) {
  2173. PostIrpRoutine( Context, Irp );
  2174. }
  2175. //
  2176. // Initialize the return value to status success.
  2177. //
  2178. Irp->IoStatus.Status = STATUS_SUCCESS;
  2179. //
  2180. // We put this into the Waiting Irp queue.
  2181. //
  2182. InsertTailList( &Oplock->WaitingIrps, &WaitingIrp->Links );
  2183. //
  2184. // We grab the cancel spinlock and store the address of the oplock.
  2185. //
  2186. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  2187. Irp->IoStatus.Information = (ULONG_PTR) Oplock;
  2188. //
  2189. // If the Irp is cancelled then we'll call the cancel routine
  2190. // right now to do away with the Waiting Irp structure.
  2191. //
  2192. if (Irp->Cancel) {
  2193. ExReleaseFastMutexUnsafe( OplockFastMutex );
  2194. AcquiredMutex = FALSE;
  2195. if (ARGUMENT_PRESENT( CompletionRoutine )) {
  2196. IoMarkIrpPending( Irp );
  2197. Status = STATUS_PENDING;
  2198. } else {
  2199. Status = STATUS_CANCELLED;
  2200. }
  2201. FsRtlCancelWaitIrp( NULL, Irp );
  2202. //
  2203. // Otherwise, we set the cancel routine and decide whether we
  2204. // are going to wait on our local event.
  2205. //
  2206. } else {
  2207. IoSetCancelRoutine( Irp, FsRtlCancelWaitIrp );
  2208. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2209. //
  2210. // If we wait on the event, we pull the return code out of
  2211. // the Irp.
  2212. //
  2213. if (!ARGUMENT_PRESENT( CompletionRoutine )) {
  2214. AcquiredMutex = FALSE;
  2215. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  2216. KeWaitForSingleObject( Event,
  2217. Executive,
  2218. KernelMode,
  2219. FALSE,
  2220. NULL );
  2221. Status = Irp->IoStatus.Status;
  2222. //
  2223. // Otherwise, we return STATUS_PENDING.
  2224. //
  2225. } else {
  2226. IoMarkIrpPending( Irp );
  2227. Status = STATUS_PENDING;
  2228. }
  2229. }
  2230. } finally {
  2231. //
  2232. // Release the Mutex if we have not done so.
  2233. //
  2234. if (AcquiredMutex) {
  2235. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  2236. }
  2237. DebugTrace( -1, Dbg, "FsRtlWaitOnIrp: Exit\n", 0 );
  2238. }
  2239. return Status;
  2240. }
  2241. //
  2242. // Local support routine.
  2243. //
  2244. VOID
  2245. FsRtlCompletionRoutinePriv (
  2246. IN PVOID Context,
  2247. IN PIRP Irp
  2248. )
  2249. /*++
  2250. Routine Description:
  2251. This routine is called when an operation must be synchronous with
  2252. respect to the oplock package. This routine will simply set the
  2253. event in the Signalled state, allowing some other thread to resume
  2254. execution.
  2255. Arguments:
  2256. Context - This is the event to signal.
  2257. Irp - Supplies a pointer to the Irp which declares the requested
  2258. operation.
  2259. Return Value:
  2260. None.
  2261. --*/
  2262. {
  2263. PAGED_CODE();
  2264. DebugTrace( +1, Dbg, "FsRtlCompletionRoutinePriv: Entered\n", 0 );
  2265. KeSetEvent( (PKEVENT)Context, 0, FALSE );
  2266. DebugTrace( -1, Dbg, "FsRtlCompletionRoutinePriv: Exit\n", 0 );
  2267. return;
  2268. UNREFERENCED_PARAMETER( Irp );
  2269. }
  2270. //
  2271. // Local support routine.
  2272. //
  2273. VOID
  2274. FsRtlCancelWaitIrp (
  2275. IN PDEVICE_OBJECT DeviceObject,
  2276. IN PIRP Irp
  2277. )
  2278. /*++
  2279. Routine Description:
  2280. This routine is called for an Irp that is placed on the waiting
  2281. Irp queue. We remove the Cancel routine from the specified Irp and
  2282. then call the completion routines for all the cancelled Irps on the
  2283. queue.
  2284. Arguments:
  2285. DeviceObject - Ignored.
  2286. Irp - Supplies the Irp being cancelled. A pointer to the
  2287. Oplock structure for the Irp is stored in the information
  2288. field of the Irp's Iosb.
  2289. Return Value:
  2290. None.
  2291. --*/
  2292. {
  2293. PNONOPAQUE_OPLOCK Oplock;
  2294. PLIST_ENTRY Links;
  2295. DebugTrace( +1, Dbg, "FsRtlCancelWaitIrp: Entered\n", 0 );
  2296. Oplock = (PNONOPAQUE_OPLOCK) Irp->IoStatus.Information;
  2297. //
  2298. // We now need to void the cancel routine and release the spinlock
  2299. //
  2300. IoSetCancelRoutine( Irp, NULL );
  2301. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2302. //
  2303. // Iterate through all of the waiting locks looking for a canceled one
  2304. // We do this under the protection of the oplock mutex.
  2305. //
  2306. ExAcquireFastMutex( Oplock->FastMutex );
  2307. try {
  2308. for (Links = Oplock->WaitingIrps.Flink;
  2309. Links != &Oplock->WaitingIrps;
  2310. Links = Links->Flink ) {
  2311. PWAITING_IRP WaitingIrp;
  2312. //
  2313. // Get a pointer to the waiting Irp record
  2314. //
  2315. WaitingIrp = CONTAINING_RECORD( Links, WAITING_IRP, Links );
  2316. DebugTrace(0, Dbg, "FsRtlCancelWaitIrp, Loop top, WaitingIrp = %08lx\n", WaitingIrp);
  2317. //
  2318. // Check if the irp has been cancelled
  2319. //
  2320. if (WaitingIrp->Irp->Cancel) {
  2321. //
  2322. // Now we need to remove this waiter and call the
  2323. // completion routine. But we must not mess up our link
  2324. // iteration so we need to back up link one step and
  2325. // then the next iteration will go to our current flink.
  2326. //
  2327. Links = Links->Blink;
  2328. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  2329. }
  2330. }
  2331. } finally {
  2332. //
  2333. // No matter how we exit we release the mutex
  2334. //
  2335. ExReleaseFastMutex( Oplock->FastMutex );
  2336. DebugTrace( -1, Dbg, "FsRtlCancelWaitIrp: Exit\n", 0 );
  2337. }
  2338. return;
  2339. UNREFERENCED_PARAMETER( DeviceObject );
  2340. }
  2341. //
  2342. // Local support routine.
  2343. //
  2344. VOID
  2345. FsRtlCancelOplockIIIrp (
  2346. IN PDEVICE_OBJECT DeviceObject,
  2347. IN PIRP Irp
  2348. )
  2349. /*++
  2350. Routine Description:
  2351. This routine is called for an Irp that is placed in the Oplock II
  2352. Irp queue. We remove the Cancel routine from the specified Irp and
  2353. then call the completion routines for all the cancelled Irps on the
  2354. queue.
  2355. Arguments:
  2356. DeviceObject - Ignored.
  2357. Irp - Supplies the Irp being cancelled. A pointer to the
  2358. Oplock structure for the Irp is stored in the information
  2359. field of the Irp's Iosb.
  2360. Return Value:
  2361. None.
  2362. --*/
  2363. {
  2364. PNONOPAQUE_OPLOCK Oplock;
  2365. BOOLEAN LevelIIIrps;
  2366. PLIST_ENTRY Links;
  2367. DebugTrace( +1, Dbg, "FsRtlCancelOplockIIIrp: Entered\n", 0 );
  2368. Oplock = (PNONOPAQUE_OPLOCK) Irp->IoStatus.Information;
  2369. //
  2370. // We now need to void the cancel routine and release the spinlock
  2371. //
  2372. IoSetCancelRoutine( Irp, NULL );
  2373. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2374. LevelIIIrps = FALSE;
  2375. //
  2376. // Iterate through all of the level II oplocks looking for a canceled one
  2377. // We do this under the protection of the oplock mutex.
  2378. //
  2379. ExAcquireFastMutex( Oplock->FastMutex );
  2380. try {
  2381. for (Links = Oplock->IrpOplocksII.Flink;
  2382. Links != &Oplock->IrpOplocksII;
  2383. Links = Links->Flink ) {
  2384. PIRP OplockIIIrp;
  2385. //
  2386. // Get a pointer to the Irp record
  2387. //
  2388. OplockIIIrp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
  2389. DebugTrace(0, Dbg, "FsRtlCancelOplockIIIrp, Loop top, Irp = %08lx\n", OplockIIIrp);
  2390. //
  2391. // Check if the irp has been cancelled
  2392. //
  2393. if (OplockIIIrp->Cancel) {
  2394. //
  2395. // Now we need to remove this waiter and call the
  2396. // completion routine. But we must not mess up our link
  2397. // iteration so we need to back up link one step and
  2398. // then the next iteration will go to our current flink.
  2399. //
  2400. Links = Links->Blink;
  2401. FsRtlRemoveAndCompleteIrp( Links->Flink );
  2402. LevelIIIrps = TRUE;
  2403. }
  2404. }
  2405. //
  2406. // If the list is now empty, change the oplock status to
  2407. // no oplocks held.
  2408. //
  2409. if (LevelIIIrps && IsListEmpty( &Oplock->IrpOplocksII )) {
  2410. Oplock->OplockState = NoOplocksHeld;
  2411. }
  2412. } finally {
  2413. //
  2414. // No matter how we exit we release the mutex
  2415. //
  2416. ExReleaseFastMutex( Oplock->FastMutex );
  2417. DebugTrace( -1, Dbg, "FsRtlCancelOplockIIIrp: Exit\n", 0 );
  2418. }
  2419. return;
  2420. UNREFERENCED_PARAMETER( DeviceObject );
  2421. }
  2422. //
  2423. // Local support routine.
  2424. //
  2425. VOID
  2426. FsRtlCancelExclusiveIrp (
  2427. IN PDEVICE_OBJECT DeviceObject,
  2428. IN PIRP Irp
  2429. )
  2430. /*++
  2431. Routine Description:
  2432. This routine is called for either an exclusive or oplock I Irp.
  2433. Arguments:
  2434. DeviceObject - Ignored.
  2435. Irp - Supplies the Irp being cancelled. A pointer to the
  2436. Oplock structure for the Irp is stored in the information
  2437. field of the Irp's Iosb.
  2438. Return Value:
  2439. None.
  2440. --*/
  2441. {
  2442. PNONOPAQUE_OPLOCK Oplock;
  2443. DebugTrace( +1, Dbg, "FsRtlCancelExclusiveIrp: Entered\n", 0 );
  2444. Oplock = (PNONOPAQUE_OPLOCK) Irp->IoStatus.Information;
  2445. //
  2446. // We now need to void the cancel routine and release the spinlock
  2447. //
  2448. IoSetCancelRoutine( Irp, NULL );
  2449. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2450. //
  2451. // Grab the synchronization object for this oplock.
  2452. //
  2453. ExAcquireFastMutex( Oplock->FastMutex );
  2454. try {
  2455. //
  2456. // We look for the exclusive Irp, if present and cancelled
  2457. // we complete it.
  2458. //
  2459. if ((Oplock->IrpExclusiveOplock != NULL) &&
  2460. (Oplock->IrpExclusiveOplock->Cancel)) {
  2461. FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_CANCELLED );
  2462. Oplock->IrpExclusiveOplock = NULL;
  2463. ObDereferenceObject( Oplock->FileObject );
  2464. Oplock->FileObject = NULL;
  2465. Oplock->OplockState = NoOplocksHeld;
  2466. //
  2467. // Complete the waiting Irps.
  2468. //
  2469. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  2470. PWAITING_IRP WaitingIrp;
  2471. //
  2472. // Remove the entry found and complete the Irp.
  2473. //
  2474. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  2475. WAITING_IRP,
  2476. Links );
  2477. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  2478. }
  2479. }
  2480. } finally {
  2481. //
  2482. // No matter how we exit we release the mutex
  2483. //
  2484. ExReleaseFastMutex( Oplock->FastMutex );
  2485. DebugTrace( -1, Dbg, "FsRtlCancelExclusiveIrp: Exit\n", 0 );
  2486. }
  2487. return;
  2488. UNREFERENCED_PARAMETER( DeviceObject );
  2489. }
  2490. //
  2491. // Local support routine.
  2492. //
  2493. VOID
  2494. FsRtlRemoveAndCompleteWaitIrp (
  2495. IN PWAITING_IRP WaitingIrp
  2496. )
  2497. /*++
  2498. Routine Description:
  2499. This routine is called to remove and perform any neccessary cleanup
  2500. for an Irp stored on the waiting Irp list in an oplock structure.
  2501. Arguments:
  2502. WaitingIrp - This is the auxilary structure attached to the Irp
  2503. being completed.
  2504. Return Value:
  2505. None.
  2506. --*/
  2507. {
  2508. PIRP Irp;
  2509. PAGED_CODE();
  2510. DebugTrace( +1, Dbg, "FsRtlRemoveAndCompleteWaitIrp: Entered\n", 0 );
  2511. //
  2512. // Remove the Irp from the queue.
  2513. //
  2514. RemoveEntryList( &WaitingIrp->Links );
  2515. Irp = WaitingIrp->Irp;
  2516. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  2517. IoSetCancelRoutine( Irp, NULL );
  2518. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2519. //
  2520. // Restore the information field.
  2521. //
  2522. Irp->IoStatus.Information = WaitingIrp->Information;
  2523. Irp->IoStatus.Status = (Irp->Cancel
  2524. ? STATUS_CANCELLED
  2525. : STATUS_SUCCESS);
  2526. //
  2527. // Call the completion routine in the Waiting Irp.
  2528. //
  2529. WaitingIrp->CompletionRoutine( WaitingIrp->Context, Irp );
  2530. //
  2531. // And free up pool
  2532. //
  2533. ExFreePool( WaitingIrp );
  2534. DebugTrace( -1, Dbg, "FsRtlRemoveAndCompleteWaitIrp: Exit\n", 0 );
  2535. return;
  2536. }
  2537. //
  2538. // Local support routine.
  2539. //
  2540. VOID
  2541. FsRtlNotifyCompletion (
  2542. IN PVOID Context,
  2543. IN PIRP Irp
  2544. )
  2545. /*++
  2546. Routine Description:
  2547. This is the completion routine called when a break notify Irp is to
  2548. be completed. We simply call FsRtlComplete request to dispose of the
  2549. Irp.
  2550. Arguments:
  2551. Context - Ignored.
  2552. Irp - Irp used to request break notify.
  2553. Return Value:
  2554. None.
  2555. --*/
  2556. {
  2557. PAGED_CODE();
  2558. DebugTrace( +1, Dbg, "FsRtlNotifyCompletion: Entered\n", 0 );
  2559. //
  2560. // Call FsRtlCompleteRequest using the value in the Irp.
  2561. //
  2562. FsRtlCompleteRequest( Irp, Irp->IoStatus.Status );
  2563. DebugTrace( -1, Dbg, "FsRtlNotifyCompletion: Exit\n", 0 );
  2564. return;
  2565. }