Leaked source code of windows server 2003
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.

3737 lines
99 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. LOGICAL AcquiredMutex;
  945. DebugTrace( +1, Dbg, "FsRtlRequestExclusiveOplock: Entered\n", 0 );
  946. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  947. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  948. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  949. DebugTrace( 0, Dbg, "BatchOplock -> %01x\n", BatchOplock );
  950. //
  951. // We can grant the oplock if no one else owns a level I or level II
  952. // oplock on this file. If the oplock pointer is NULL then there
  953. // are no oplocks on the file. Otherwise we need to check the
  954. // oplock state in an existing oplock structure.
  955. //
  956. if (*Oplock == NULL) {
  957. DebugTrace( 0,
  958. Dbg,
  959. "Oplock currently not allocated\n",
  960. 0);
  961. ThisOplock = FsRtlAllocateOplock();
  962. *Oplock = ThisOplock;
  963. } else {
  964. ThisOplock = *Oplock;
  965. }
  966. //
  967. // Grab the synchronization object for the oplock.
  968. //
  969. Status = STATUS_SUCCESS;
  970. AcquiredMutex = TRUE;
  971. ExAcquireFastMutexUnsafe( ThisOplock->FastMutex );
  972. //
  973. // Use a try-finally to facilitate cleanup.
  974. //
  975. try {
  976. //
  977. // If we are requesting a PendingFilter Oplock then it must be
  978. // safe to grant. There is only one open handle and we are in
  979. // the process of opening it.
  980. //
  981. if (NextOplockState == OpFilterReqPending) {
  982. ASSERT( FlagOn( ThisOplock->OplockState, NO_OPLOCK | PENDING ));
  983. ThisOplock->IrpExclusiveOplock = Irp;
  984. ThisOplock->FileObject = IrpSp->FileObject;
  985. ThisOplock->OplockState = OpFilterReqPending;
  986. //
  987. // If the current oplock state is no oplocks held then we
  988. // will grant the oplock to this requestor. If the state is
  989. // either of the OpFilter states then also grant the request.
  990. // We won't check for a matching file object because there can
  991. // only be one file object. Grant the request anyway.
  992. //
  993. // If the current state is OplockII granted then it must
  994. // be owned by this request. Break the oplock II and grant
  995. // the exclusive lock.
  996. //
  997. } else if (FlagOn( ThisOplock->OplockState,
  998. LEVEL_II_OPLOCK | NO_OPLOCK | PENDING )) {
  999. PFAST_MUTEX OplockFastMutex;
  1000. if (ThisOplock->OplockState == OplockIIGranted) {
  1001. ASSERT( ThisOplock->IrpOplocksII.Flink == ThisOplock->IrpOplocksII.Blink );
  1002. FsRtlRemoveAndCompleteIrp( ThisOplock->IrpOplocksII.Flink );
  1003. }
  1004. //
  1005. // Put the address of the fast mutex on the stack.
  1006. //
  1007. OplockFastMutex = ThisOplock->FastMutex;
  1008. //
  1009. // We store this Irp in the Oplocks structure.
  1010. // We set the oplock state to the correct exclusive oplock.
  1011. //
  1012. ThisOplock->IrpExclusiveOplock = Irp;
  1013. ThisOplock->FileObject = IrpSp->FileObject;
  1014. ThisOplock->OplockState = NextOplockState;
  1015. IoMarkIrpPending( Irp );
  1016. ObReferenceObject( IrpSp->FileObject );
  1017. Irp->IoStatus.Information = (ULONG_PTR) ThisOplock;
  1018. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  1019. //
  1020. // Now if the irp is cancelled then we'll call the cancel
  1021. // routine right now to do away with the irp, otherwise
  1022. // we set the cancel routine
  1023. //
  1024. if (Irp->Cancel) {
  1025. AcquiredMutex = FALSE;
  1026. ExReleaseFastMutexUnsafe( OplockFastMutex );
  1027. FsRtlCancelExclusiveIrp( NULL, Irp );
  1028. } else {
  1029. IoSetCancelRoutine( Irp, FsRtlCancelExclusiveIrp );
  1030. IoReleaseCancelSpinLock( Irp->CancelIrql );
  1031. }
  1032. Status = STATUS_PENDING;
  1033. } else {
  1034. //
  1035. // We'll complete the Irp with the Oplock not granted message
  1036. // and return that value as a status.
  1037. //
  1038. if (ARGUMENT_PRESENT( Irp )) {
  1039. FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED );
  1040. }
  1041. Status = STATUS_OPLOCK_NOT_GRANTED;
  1042. }
  1043. } finally {
  1044. //
  1045. // Give up the oplock synchronization object.
  1046. //
  1047. if (AcquiredMutex) {
  1048. ExReleaseFastMutexUnsafe( ThisOplock->FastMutex );
  1049. }
  1050. DebugTrace( +1, Dbg, "FsRtlRequestExclusiveOplock: Exit\n", 0 );
  1051. }
  1052. return Status;
  1053. }
  1054. //
  1055. // Local support routine.
  1056. //
  1057. NTSTATUS
  1058. FsRtlRequestOplockII (
  1059. IN OUT PNONOPAQUE_OPLOCK *Oplock,
  1060. IN PIO_STACK_LOCATION IrpSp,
  1061. IN PIRP Irp
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine is called when a user is requesting an Oplock II on an
  1066. open file. The request is granted if there are currently no
  1067. level 1 oplocks on the file and an oplock break is not in progress.
  1068. Arguments:
  1069. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1070. this file.
  1071. IrpSp - This is the Irp stack location for the current Irp.
  1072. Irp - Supplies a pointer to the Irp which declares the requested
  1073. operation.
  1074. Return Value:
  1075. STATUS_PENDING if the oplock is granted.
  1076. STATUS_OPLOCK_NOT_GRANTED if the request is denied.
  1077. --*/
  1078. {
  1079. NTSTATUS Status;
  1080. PNONOPAQUE_OPLOCK ThisOplock;
  1081. LOGICAL AcquiredMutex;
  1082. DebugTrace( +1, Dbg, "FsRtlRequestOplockII: Entered\n", 0 );
  1083. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1084. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1085. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1086. //
  1087. // We can grant the oplock if no one else owns a level I
  1088. // oplock on this file. If the oplock pointer is NULL then there
  1089. // are no oplocks on the file. Otherwise we need to check the
  1090. // oplock state in an existing oplock structure.
  1091. //
  1092. if (*Oplock == NULL) {
  1093. DebugTrace( 0,
  1094. Dbg,
  1095. "Oplock currently not allocated\n",
  1096. 0);
  1097. ThisOplock = FsRtlAllocateOplock();
  1098. *Oplock = ThisOplock;
  1099. } else {
  1100. ThisOplock = *Oplock;
  1101. }
  1102. //
  1103. // Grab the synchronization object for the oplock.
  1104. //
  1105. Status = STATUS_PENDING;
  1106. AcquiredMutex = TRUE;
  1107. ExAcquireFastMutexUnsafe( ThisOplock->FastMutex );
  1108. //
  1109. // Use a try-finally to facilitate cleanup.
  1110. //
  1111. try {
  1112. //
  1113. // If the current oplock state is no oplocks held or OplockIIGranted
  1114. // then we will grant the oplock to this requestor.
  1115. //
  1116. if (FlagOn( ThisOplock->OplockState, NO_OPLOCK | LEVEL_II_OPLOCK )) {
  1117. PFAST_MUTEX OplockFastMutex = ThisOplock->FastMutex;
  1118. //
  1119. // We store this Irp in the Oplocks structure.
  1120. // We set the oplock state to 'OplockIIGranted'.
  1121. //
  1122. IoMarkIrpPending( Irp );
  1123. Irp->IoStatus.Status = STATUS_SUCCESS;
  1124. InsertHeadList( &ThisOplock->IrpOplocksII,
  1125. &Irp->Tail.Overlay.ListEntry );
  1126. Irp->IoStatus.Information = (ULONG_PTR) ThisOplock;
  1127. ThisOplock->OplockState = OplockIIGranted;
  1128. ObReferenceObject( IrpSp->FileObject );
  1129. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  1130. //
  1131. // Now if the irp is cancelled then we'll call the cancel
  1132. // routine right now to do away with the irp, otherwise
  1133. // we set the cancel routine
  1134. //
  1135. if (Irp->Cancel) {
  1136. AcquiredMutex = FALSE;
  1137. ExReleaseFastMutexUnsafe( OplockFastMutex );
  1138. FsRtlCancelOplockIIIrp( NULL, Irp );
  1139. } else {
  1140. IoSetCancelRoutine( Irp, FsRtlCancelOplockIIIrp );
  1141. IoReleaseCancelSpinLock( Irp->CancelIrql );
  1142. }
  1143. } else {
  1144. //
  1145. // We'll complete the Irp with the Oplock not granted message
  1146. // and return that value as a status.
  1147. //
  1148. FsRtlCompleteRequest( Irp, STATUS_OPLOCK_NOT_GRANTED );
  1149. Status = STATUS_OPLOCK_NOT_GRANTED;
  1150. }
  1151. } finally {
  1152. //
  1153. // Give up the oplock synchronization object.
  1154. //
  1155. if (AcquiredMutex) {
  1156. ExReleaseFastMutexUnsafe( ThisOplock->FastMutex );
  1157. }
  1158. DebugTrace( +1, Dbg, "FsRtlRequestOplockII: Exit\n", 0 );
  1159. }
  1160. return Status;
  1161. }
  1162. //
  1163. // Local support routine.
  1164. //
  1165. NTSTATUS
  1166. FsRtlAcknowledgeOplockBreak (
  1167. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1168. IN PIO_STACK_LOCATION IrpSp,
  1169. IN PIRP Irp,
  1170. IN BOOLEAN GrantLevelII
  1171. )
  1172. /*++
  1173. Routine Description:
  1174. This routine is called when a user is acknowledging an Oplock I
  1175. break. If the level 1 oplock was being broken to level 2, then
  1176. a check is made to insure that the level 2 has not been broken
  1177. in the meantime.
  1178. If an oplock 1 break is not in progress then this will be treated
  1179. as an asynchronous break request. If this is an asynchronous break
  1180. request and the file object owns an outstanding level 1 oplock, then
  1181. the oplock will be broken at this point.
  1182. A spurious break request via a file object which does not (or did not)
  1183. own the level 1 oplock will generate a warning but will not affect
  1184. the oplock state.
  1185. At the end of an Oplock I break, all of the waiting irps are completed.
  1186. Arguments:
  1187. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1188. this file.
  1189. IrpSp - This is the Irp stack location for the current Irp.
  1190. Irp - Supplies a pointer to the Irp which declares the requested
  1191. operation.
  1192. GrantLevelII - Indicates that this caller wants a level II oplock left
  1193. on the file.
  1194. Return Value:
  1195. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1196. STATUS_CANCELLED if the Irp is cancelled before we return.
  1197. --*/
  1198. {
  1199. NTSTATUS Status = STATUS_INVALID_OPLOCK_PROTOCOL;
  1200. LOGICAL AcquiredMutex;
  1201. DebugTrace( +1, Dbg, "FsRtlAcknowledgeOplockBreak: Entered\n", 0 );
  1202. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1203. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1204. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1205. //
  1206. // If there is no oplock structure, we complete this with invalid
  1207. // oplock protocol.
  1208. //
  1209. if (Oplock == NULL) {
  1210. FsRtlCompleteRequest( Irp, STATUS_INVALID_OPLOCK_PROTOCOL );
  1211. DebugTrace( -1, Dbg, "FsRtlAcknowledgeOplockBreak: Exit -> %08lx\n", STATUS_INVALID_OPLOCK_PROTOCOL );
  1212. return STATUS_INVALID_OPLOCK_PROTOCOL;
  1213. }
  1214. //
  1215. // Grab the synchronization object for the oplock.
  1216. //
  1217. AcquiredMutex = TRUE;
  1218. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1219. //
  1220. // Use a try-finally to facilitate cleanup.
  1221. //
  1222. try {
  1223. BOOLEAN DereferenceFileObject = TRUE;
  1224. //
  1225. // If a break is underway but this is not the owner of the
  1226. // level 1 oplock, we complete the request and return a
  1227. // warning.
  1228. //
  1229. if (Oplock->FileObject != IrpSp->FileObject) {
  1230. Status = STATUS_INVALID_OPLOCK_PROTOCOL;
  1231. DebugTrace(0,
  1232. Dbg,
  1233. "Not oplock owner -> %08lx\n",
  1234. Status);
  1235. FsRtlCompleteRequest( Irp, Status );
  1236. try_return( Status );
  1237. }
  1238. //
  1239. // If the user would like a level II and we are breaking to level II
  1240. // then grant the oplock.
  1241. //
  1242. if (GrantLevelII &&
  1243. FlagOn( Oplock->OplockState, BREAK_TO_II )) {
  1244. PFAST_MUTEX OplockFastMutex = Oplock->FastMutex;
  1245. DebugTrace(0, Dbg, "OplockItoII\n", 0);
  1246. //
  1247. // The acknowledgement should never be synchronous.
  1248. //
  1249. ASSERT( !IoIsOperationSynchronous( Irp ));
  1250. //
  1251. // We need to add this Irp to the oplock II queue, change
  1252. // the oplock state to Oplock II granted and set the
  1253. // return value to STATUS_PENDING.
  1254. //
  1255. IoMarkIrpPending( Irp );
  1256. Irp->IoStatus.Status = STATUS_SUCCESS;
  1257. InsertHeadList( &Oplock->IrpOplocksII,
  1258. &Irp->Tail.Overlay.ListEntry );
  1259. DereferenceFileObject = FALSE;
  1260. Oplock->OplockState = OplockIIGranted;
  1261. Irp->IoStatus.Information = (ULONG_PTR) Oplock;
  1262. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  1263. //
  1264. // Now if the irp is cancelled then we'll call the cancel
  1265. // routine right now to do away with the irp, otherwise
  1266. // we set the cancel routine
  1267. //
  1268. if (Irp->Cancel) {
  1269. ExReleaseFastMutexUnsafe( OplockFastMutex );
  1270. AcquiredMutex = FALSE;
  1271. FsRtlCancelOplockIIIrp( NULL, Irp );
  1272. } else {
  1273. IoSetCancelRoutine( Irp, FsRtlCancelOplockIIIrp );
  1274. IoReleaseCancelSpinLock( Irp->CancelIrql );
  1275. }
  1276. Status = STATUS_PENDING;
  1277. //
  1278. // We will break to none since this is the expected case for these
  1279. // cases.
  1280. //
  1281. } else if (FlagOn( Oplock->OplockState, BREAK_TO_II | BREAK_TO_NONE )) {
  1282. //
  1283. // We need to complete this Irp and return STATUS_SUCCESS.
  1284. // We also set the oplock state to no oplocks held.
  1285. //
  1286. DebugTrace(0, Dbg, "OplockItoNone\n", 0);
  1287. Status = STATUS_SUCCESS;
  1288. FsRtlCompleteRequest( Irp, Status );
  1289. Oplock->OplockState = NoOplocksHeld;
  1290. //
  1291. // In this case the user expects to be at level II. He is
  1292. // expecting this Irp to be completed when the LevelII Oplock
  1293. // is broken.
  1294. //
  1295. } else if (FlagOn( Oplock->OplockState, BREAK_TO_II_TO_NONE )) {
  1296. DebugTrace(0, Dbg, "AcknowledgeOplockBreak: OplockItoIItoNone\n", 0);
  1297. Status = STATUS_SUCCESS;
  1298. Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1299. FsRtlCompleteRequest( Irp, Status );
  1300. Oplock->OplockState = NoOplocksHeld;
  1301. } else {
  1302. Status = STATUS_INVALID_OPLOCK_PROTOCOL;
  1303. DebugTrace(0,
  1304. Dbg,
  1305. "No break underway -> %08lx\n",
  1306. Status);
  1307. FsRtlCompleteRequest( Irp, Status );
  1308. try_return( Status );
  1309. }
  1310. //
  1311. // Complete the waiting Irps and cleanup the oplock structure.
  1312. //
  1313. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1314. PWAITING_IRP WaitingIrp;
  1315. //
  1316. // Remove the entry found and complete the Irp.
  1317. //
  1318. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1319. WAITING_IRP,
  1320. Links );
  1321. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1322. }
  1323. if (DereferenceFileObject) {
  1324. ObDereferenceObject( Oplock->FileObject );
  1325. }
  1326. Oplock->FileObject = NULL;
  1327. try_exit: NOTHING;
  1328. } finally {
  1329. //
  1330. // Give up the oplock synchronization object.
  1331. //
  1332. if (AcquiredMutex) {
  1333. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1334. }
  1335. DebugTrace( -1, Dbg, "FsRtlAcknowledgeOplockBreak: Exit -> %08x\n", Status );
  1336. }
  1337. return Status;
  1338. }
  1339. //
  1340. // Local support routine.
  1341. //
  1342. NTSTATUS
  1343. FsRtlOpBatchBreakClosePending (
  1344. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1345. IN PIO_STACK_LOCATION IrpSp,
  1346. IN PIRP Irp
  1347. )
  1348. /*++
  1349. Routine Description:
  1350. This routine is called when a user is acknowledging a batch oplock
  1351. break or Level I oplock break. In this case the user is planning
  1352. to close the file as well and doesn't need a level II oplock.
  1353. Arguments:
  1354. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1355. this file.
  1356. IrpSp - This is the Irp stack location for the current Irp.
  1357. Irp - Supplies a pointer to the Irp which declares the requested
  1358. operation.
  1359. Return Value:
  1360. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1361. STATUS_CANCELLED if the Irp is cancelled before we return.
  1362. --*/
  1363. {
  1364. NTSTATUS Status = STATUS_SUCCESS;
  1365. PAGED_CODE();
  1366. DebugTrace( +1, Dbg, "FsRtlOpBatchBreakClosePending: Entered\n", 0 );
  1367. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1368. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1369. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1370. //
  1371. // If there is no oplock structure, we complete this with invalid
  1372. // oplock protocol.
  1373. //
  1374. if (Oplock == NULL) {
  1375. FsRtlCompleteRequest( Irp, STATUS_INVALID_OPLOCK_PROTOCOL );
  1376. DebugTrace( -1, Dbg, "FsRtlOpBatchClosePending: Exit -> %08lx\n", STATUS_INVALID_OPLOCK_PROTOCOL );
  1377. return STATUS_INVALID_OPLOCK_PROTOCOL;
  1378. }
  1379. //
  1380. // Grab the synchronization object for the oplock.
  1381. //
  1382. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1383. //
  1384. // Use a try_finally to facilitate cleanup.
  1385. //
  1386. try {
  1387. //
  1388. // If a break is underway but this is not the owner of the
  1389. // level 1 oplock, we complete the request and return a
  1390. // warning.
  1391. //
  1392. if (Oplock->FileObject != IrpSp->FileObject) {
  1393. Status = STATUS_INVALID_OPLOCK_PROTOCOL;
  1394. DebugTrace(0,
  1395. Dbg,
  1396. "Not oplock owner -> %08lx\n",
  1397. Status);
  1398. } else {
  1399. //
  1400. // If this is an opbatch operation we want to note that a
  1401. // close is pending. For an exclusive oplock we set the state to
  1402. // no oplocsk held. There must be a break in progress to
  1403. // process however.
  1404. //
  1405. if (FlagOn( Oplock->OplockState,
  1406. BREAK_TO_II | BREAK_TO_NONE | BREAK_TO_II_TO_NONE )) {
  1407. //
  1408. // Break all oplocks for an exclusive oplock.
  1409. //
  1410. if (FlagOn( Oplock->OplockState, LEVEL_I_OPLOCK | PENDING )) {
  1411. //
  1412. // Clean up the oplock structure and complete all waiting Irps.
  1413. //
  1414. if (FlagOn( Oplock->OplockState, LEVEL_I_OPLOCK )) {
  1415. ObDereferenceObject( Oplock->FileObject );
  1416. }
  1417. Oplock->OplockState = NoOplocksHeld;
  1418. Oplock->FileObject = NULL;
  1419. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1420. PWAITING_IRP WaitingIrp;
  1421. //
  1422. // Remove the entry found and complete the Irp.
  1423. //
  1424. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1425. WAITING_IRP,
  1426. Links );
  1427. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1428. }
  1429. //
  1430. // Set the state to close pending for batch and filter
  1431. // oplocks.
  1432. //
  1433. } else {
  1434. ClearFlag( Oplock->OplockState, OPLOCK_BREAK_MASK );
  1435. SetFlag( Oplock->OplockState, CLOSE_PENDING );
  1436. }
  1437. } else {
  1438. Status = STATUS_INVALID_OPLOCK_PROTOCOL;
  1439. DebugTrace(0,
  1440. Dbg,
  1441. "No break underway -> %08lx\n",
  1442. Status);
  1443. }
  1444. }
  1445. //
  1446. // We simply complete this request.
  1447. //
  1448. FsRtlCompleteRequest( Irp, Status );
  1449. } finally {
  1450. //
  1451. // Release the synchronization object.
  1452. //
  1453. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1454. DebugTrace(-1, Dbg, "FsRtlOpBatchBreakClosePending: Exit -> %08lx\n", Status);
  1455. }
  1456. return Status;
  1457. }
  1458. //
  1459. // Local support routine
  1460. //
  1461. NTSTATUS
  1462. FsRtlOplockBreakNotify (
  1463. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1464. IN PIO_STACK_LOCATION IrpSp,
  1465. IN PIRP Irp
  1466. )
  1467. /*++
  1468. Routine Description:
  1469. This routine is called when the Irp refers the user request to
  1470. be notified when there is no level 1 oplock break in progress.
  1471. Under any other condition this routine completes immediately with
  1472. STATUS_SUCCESS. Otherwise we simply add this Irp to the list
  1473. of Irp's waiting for the break to complete.
  1474. Arguments:
  1475. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1476. this file.
  1477. IrpSp - This is the Irp stack location for the current Irp.
  1478. Irp - Supplies a pointer to the Irp which declares the requested
  1479. operation.
  1480. Return Value:
  1481. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1482. STATUS_PENDING if we return here but hold the Irp.
  1483. STATUS_CANCELLED if the Irp is cancelled before we return.
  1484. --*/
  1485. {
  1486. NTSTATUS Status = STATUS_SUCCESS;
  1487. LOGICAL AcquiredMutex;
  1488. UNREFERENCED_PARAMETER (IrpSp);
  1489. PAGED_CODE();
  1490. DebugTrace( +1, Dbg, "FsRtlOplockBreakNotify: Entered\n", 0 );
  1491. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1492. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1493. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1494. //
  1495. // If there is no oplock structure, we complete this with status success.
  1496. //
  1497. if (Oplock == NULL) {
  1498. FsRtlCompleteRequest( Irp, STATUS_SUCCESS );
  1499. DebugTrace( -1, Dbg, "FsRtlOpBatchClosePending: Exit -> %08lx\n", STATUS_SUCCESS );
  1500. return STATUS_SUCCESS;
  1501. }
  1502. //
  1503. // Grap the synchronization object.
  1504. //
  1505. AcquiredMutex = TRUE;
  1506. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1507. //
  1508. // Use a try-finally to facilitate cleanup.
  1509. //
  1510. try {
  1511. //
  1512. // If there are no outstanding level 1 oplocks breaks underway
  1513. // or batch oplock breaks underway we complete immediately.
  1514. //
  1515. if (!FlagOn( Oplock->OplockState, OPLOCK_BREAK_MASK )) {
  1516. DebugTrace(0,
  1517. Dbg,
  1518. "No exclusive oplock break underway\n",
  1519. 0);
  1520. FsRtlCompleteRequest( Irp, STATUS_SUCCESS );
  1521. try_return( Status = STATUS_SUCCESS );
  1522. } else if (FlagOn( Oplock->OplockState, PENDING )) {
  1523. Oplock->OplockState = NoOplocksHeld;
  1524. Oplock->FileObject = NULL;
  1525. FsRtlCompleteRequest( Irp, STATUS_SUCCESS );
  1526. try_return( Status = STATUS_SUCCESS );
  1527. }
  1528. //
  1529. // Otherwise we need to add this Irp to the list of Irp's waiting
  1530. // for the oplock break to complete.
  1531. //
  1532. AcquiredMutex = FALSE;
  1533. //
  1534. // Initialize the return value to status success.
  1535. //
  1536. Irp->IoStatus.Status = STATUS_SUCCESS;
  1537. Status = FsRtlWaitOnIrp( Oplock,
  1538. Irp,
  1539. NULL,
  1540. FsRtlNotifyCompletion,
  1541. NULL,
  1542. NULL );
  1543. try_exit: NOTHING;
  1544. } finally {
  1545. //
  1546. // Give up the synchronization event if we haven't done so.
  1547. //
  1548. if (AcquiredMutex) {
  1549. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1550. }
  1551. DebugTrace( -1, Dbg, "FsRtlOplockBreakNotify: Exit -> %08lx\n", Status );
  1552. }
  1553. return Status;
  1554. }
  1555. //
  1556. // Local support routine
  1557. //
  1558. VOID
  1559. FsRtlOplockCleanup (
  1560. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1561. IN PIO_STACK_LOCATION IrpSp
  1562. )
  1563. /*++
  1564. Routine Description:
  1565. This routine is called to coordinate a cleanup operation with the
  1566. oplock state for a file. If there is no level 1 oplock for the
  1567. file, then there is no action to take. If the file object in this
  1568. Irp matches the file object used in granting the level 1 oplock,
  1569. then the close operation will terminate the oplock. If this
  1570. cleanup refers to a file object which has a level II oplock, then
  1571. that Irp is completed and removed from the list of level II
  1572. oplocked Irps.
  1573. Arguments:
  1574. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1575. this file.
  1576. IrpSp - This is the Irp stack location for the current Irp.
  1577. Return Value:
  1578. None.
  1579. --*/
  1580. {
  1581. DebugTrace( +1, Dbg, "FsRtlOplockCleanup: Entered\n", 0 );
  1582. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1583. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1584. //
  1585. // Grab the synchronization object for the oplock.
  1586. //
  1587. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1588. //
  1589. // Use a try-finally to facilitate cleanup.
  1590. //
  1591. try {
  1592. //
  1593. // If the oplock has no oplock held we return immediately.
  1594. //
  1595. if (Oplock->OplockState == NoOplocksHeld) {
  1596. DebugTrace(0,
  1597. Dbg,
  1598. "No oplocks on file\n",
  1599. 0);
  1600. try_return( NOTHING );
  1601. }
  1602. //
  1603. // If level II oplocks are held, check if this matches any of them.
  1604. //
  1605. if (Oplock->OplockState == OplockIIGranted) {
  1606. PLIST_ENTRY Link;
  1607. PIRP Irp;
  1608. PIO_STACK_LOCATION NextIrpSp;
  1609. DebugTrace(0,
  1610. Dbg,
  1611. "File has level 2 oplocks\n",
  1612. 0);
  1613. for (Link = Oplock->IrpOplocksII.Flink;
  1614. Link != &Oplock->IrpOplocksII;
  1615. Link = Link->Flink) {
  1616. Irp = CONTAINING_RECORD( Link, IRP, Tail.Overlay.ListEntry );
  1617. NextIrpSp = IoGetCurrentIrpStackLocation( Irp );
  1618. //
  1619. // If the file objects match, then emove the entry found and complete the Irp.
  1620. //
  1621. if (IrpSp->FileObject == NextIrpSp->FileObject) {
  1622. //
  1623. // Back up to remember this link.
  1624. //
  1625. Link = Link->Blink;
  1626. //
  1627. //
  1628. FsRtlRemoveAndCompleteIrp( Link->Flink );
  1629. }
  1630. }
  1631. //
  1632. // If all the level II oplocks are gone, then the state is
  1633. // no oplocks held.
  1634. //
  1635. if (IsListEmpty( &Oplock->IrpOplocksII )) {
  1636. Oplock->OplockState = NoOplocksHeld;
  1637. }
  1638. try_return( NOTHING );
  1639. }
  1640. //
  1641. // If this file object matches that used to request an exclusive
  1642. // oplock, we completely close the oplock break.
  1643. //
  1644. if (IrpSp->FileObject == Oplock->FileObject) {
  1645. DebugTrace(0,
  1646. Dbg,
  1647. "Handle owns level 1 oplock\n",
  1648. 0);
  1649. //
  1650. // If an oplock break is not in progress, we initiate one and
  1651. // complete the exclusive Irp immediately.
  1652. //
  1653. if (!FlagOn( Oplock->OplockState, OPLOCK_BREAK_MASK | PENDING )) {
  1654. PIRP ExclusiveIrp = Oplock->IrpExclusiveOplock;
  1655. DebugTrace(0,
  1656. Dbg,
  1657. "Initiate oplock break\n",
  1658. 0);
  1659. IoAcquireCancelSpinLock( &ExclusiveIrp->CancelIrql );
  1660. IoSetCancelRoutine( ExclusiveIrp, NULL );
  1661. IoReleaseCancelSpinLock( ExclusiveIrp->CancelIrql );
  1662. ExclusiveIrp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1663. FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_SUCCESS );
  1664. Oplock->IrpExclusiveOplock = NULL;
  1665. }
  1666. //
  1667. // Clean up the oplock structure and complete all waiting Irps.
  1668. // Don't do this if this is a pending opfilter request.
  1669. //
  1670. if (!FlagOn( Oplock->OplockState, PENDING )) {
  1671. ObDereferenceObject( IrpSp->FileObject );
  1672. }
  1673. Oplock->FileObject = NULL;
  1674. Oplock->OplockState = NoOplocksHeld;
  1675. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1676. PWAITING_IRP WaitingIrp;
  1677. //
  1678. // Remove the entry found and complete the Irp.
  1679. //
  1680. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1681. WAITING_IRP,
  1682. Links );
  1683. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1684. }
  1685. }
  1686. try_exit: NOTHING;
  1687. } finally {
  1688. //
  1689. // Give up the oplock synchronization object.
  1690. //
  1691. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1692. DebugTrace( +1, Dbg, "FsRtlOplockCleanup: Exit\n", 0 );
  1693. }
  1694. return;
  1695. }
  1696. //
  1697. // Local support routine
  1698. //
  1699. NTSTATUS
  1700. FsRtlOplockBreakToII (
  1701. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1702. IN PIO_STACK_LOCATION IrpSp,
  1703. IN PIRP Irp,
  1704. IN PVOID Context,
  1705. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  1706. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine
  1707. )
  1708. /*++
  1709. Routine Description:
  1710. This routine is a generic worker routine which is called when an
  1711. operation will cause all oplocks to be broken to level II before the
  1712. operation can proceed.
  1713. Arguments:
  1714. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1715. this file.
  1716. IrpSp - This is the Irp stack location for the current Irp.
  1717. Irp - Supplies a pointer to the Irp which declares the requested
  1718. operation.
  1719. Context - This value is passed as a parameter to the completion routine.
  1720. CompletionRoutine - This is the routine which is called if this
  1721. Irp must wait for an Oplock to break. This
  1722. is a synchronous operation if not specified
  1723. and we block in this thread waiting on
  1724. an event.
  1725. PostIrpRoutine - This is the routine to call before we put anything
  1726. on our waiting Irp queue.
  1727. Return Value:
  1728. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1729. STATUS_PENDING if we return here but hold the Irp.
  1730. STATUS_CANCELLED if the Irp is cancelled before we return.
  1731. --*/
  1732. {
  1733. KEVENT Event;
  1734. NTSTATUS Status;
  1735. LOGICAL AcquiredMutex;
  1736. DebugTrace( +1, Dbg, "CheckOplockBreakToII: Entered\n", 0 );
  1737. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1738. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1739. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1740. //
  1741. // Grap the synchronization object.
  1742. //
  1743. Status = STATUS_SUCCESS;
  1744. AcquiredMutex = TRUE;
  1745. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1746. //
  1747. // Use a try-finally to facilitate cleanup.
  1748. //
  1749. try {
  1750. //
  1751. // If there are no outstanding oplocks or level II oplocks are held,
  1752. // we can return immediately.
  1753. //
  1754. if (!FlagOn( Oplock->OplockState, EXCLUSIVE )) {
  1755. DebugTrace(0,
  1756. Dbg,
  1757. "No oplocks or level II oplocks on file\n",
  1758. 0);
  1759. try_return( Status = STATUS_SUCCESS );
  1760. }
  1761. //
  1762. // At this point there is an exclusive oplock break in progress.
  1763. // If this file object owns that oplock, we allow the operation
  1764. // to continue.
  1765. //
  1766. if (Oplock->FileObject == IrpSp->FileObject) {
  1767. DebugTrace(0,
  1768. Dbg,
  1769. "Handle owns level 1 oplock\n",
  1770. 0);
  1771. try_return( Status = STATUS_SUCCESS );
  1772. }
  1773. //
  1774. // If there is currently an exclusive oplock held then complete
  1775. // the exclusive irp.
  1776. //
  1777. if (!FlagOn( Oplock->OplockState, PENDING | OPLOCK_BREAK_MASK )) {
  1778. PIRP IrpExclusive = Oplock->IrpExclusiveOplock;
  1779. DebugTrace(0,
  1780. Dbg,
  1781. "Breaking exclusive oplock\n",
  1782. 0);
  1783. IoAcquireCancelSpinLock( &IrpExclusive->CancelIrql );
  1784. IoSetCancelRoutine( IrpExclusive, NULL );
  1785. IoReleaseCancelSpinLock( IrpExclusive->CancelIrql );
  1786. //
  1787. // If the Irp has been cancelled, we complete the Irp with
  1788. // status cancelled and break the oplock completely.
  1789. //
  1790. if (IrpExclusive->Cancel) {
  1791. IrpExclusive->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1792. FsRtlCompleteRequest( IrpExclusive, STATUS_CANCELLED );
  1793. Oplock->OplockState = NoOplocksHeld;
  1794. Oplock->IrpExclusiveOplock = NULL;
  1795. ObDereferenceObject( Oplock->FileObject );
  1796. Oplock->FileObject = NULL;
  1797. //
  1798. // Release any waiting irps.
  1799. //
  1800. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1801. PWAITING_IRP WaitingIrp;
  1802. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1803. WAITING_IRP,
  1804. Links );
  1805. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1806. }
  1807. try_return( Status = STATUS_SUCCESS );
  1808. } else {
  1809. NTSTATUS CompletionStatus;
  1810. if (FlagOn( Oplock->OplockState, LEVEL_I_OPLOCK | BATCH_OPLOCK )) {
  1811. SetFlag( Oplock->OplockState, BREAK_TO_II );
  1812. CompletionStatus = FILE_OPLOCK_BROKEN_TO_LEVEL_2;
  1813. } else {
  1814. SetFlag( Oplock->OplockState, BREAK_TO_NONE );
  1815. CompletionStatus = FILE_OPLOCK_BROKEN_TO_NONE;
  1816. }
  1817. Oplock->IrpExclusiveOplock->IoStatus.Information = CompletionStatus;
  1818. FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_SUCCESS );
  1819. Oplock->IrpExclusiveOplock = NULL;
  1820. }
  1821. //
  1822. // If there is a pending opfilter request then clear the request.
  1823. //
  1824. } else if (FlagOn( Oplock->OplockState, PENDING )) {
  1825. Oplock->OplockState = NoOplocksHeld;
  1826. Oplock->FileObject = NULL;
  1827. try_return( Status = STATUS_SUCCESS );
  1828. }
  1829. //
  1830. // If this is an open operation and the user doesn't want to
  1831. // block, we will complete the operation now.
  1832. //
  1833. if ((IrpSp->MajorFunction == IRP_MJ_CREATE) &&
  1834. FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) {
  1835. DebugTrace( 0, Dbg, "Don't block open\n", 0 );
  1836. try_return( Status = STATUS_OPLOCK_BREAK_IN_PROGRESS );
  1837. }
  1838. //
  1839. // If we get here that means that this operation can't continue
  1840. // until the oplock break is complete.
  1841. //
  1842. // FsRtlWaitOnIrp will release the mutex.
  1843. //
  1844. AcquiredMutex = FALSE;
  1845. Status = FsRtlWaitOnIrp( Oplock,
  1846. Irp,
  1847. Context,
  1848. CompletionRoutine,
  1849. PostIrpRoutine,
  1850. &Event );
  1851. try_exit: NOTHING;
  1852. } finally {
  1853. //
  1854. // Give up the synchronization event if we haven't done so.
  1855. //
  1856. if (AcquiredMutex) {
  1857. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  1858. }
  1859. DebugTrace( -1, Dbg, "FsRtlOplockBreakToII: Exit -> %08lx\n", Status );
  1860. }
  1861. return Status;
  1862. }
  1863. //
  1864. // Local support routine.
  1865. //
  1866. NTSTATUS
  1867. FsRtlOplockBreakToNone (
  1868. IN OUT PNONOPAQUE_OPLOCK Oplock,
  1869. IN PIO_STACK_LOCATION IrpSp,
  1870. IN PIRP Irp,
  1871. IN PVOID Context,
  1872. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  1873. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. This routine is a generic worker routine which is called when an
  1878. operation will cause all oplocks to be broken before the operation can
  1879. proceed.
  1880. Arguments:
  1881. Oplock - Supplies a pointer to the non-opaque oplock structure for
  1882. this file.
  1883. IrpSp - This is the Irp stack location for the current Irp.
  1884. Irp - Supplies a pointer to the Irp which declares the requested
  1885. operation.
  1886. Context - This value is passed as a parameter to the completion routine.
  1887. CompletionRoutine - This is the routine which is called if this
  1888. Irp must wait for an Oplock to break. This
  1889. is a synchronous operation if not specified
  1890. and we block in this thread waiting on
  1891. an event.
  1892. PostIrpRoutine - This is the routine to call before we put anything
  1893. on our waiting Irp queue.
  1894. Return Value:
  1895. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  1896. STATUS_PENDING if we return here but hold the Irp.
  1897. STATUS_CANCELLED if the Irp is cancelled before we return.
  1898. --*/
  1899. {
  1900. KEVENT Event;
  1901. NTSTATUS Status = STATUS_SUCCESS;
  1902. LOGICAL AcquiredMutex;
  1903. DebugTrace( +1, Dbg, "CheckOplockBreakToNone: Entered\n", 0 );
  1904. DebugTrace( 0, Dbg, "Oplock -> %08lx\n", Oplock );
  1905. DebugTrace( 0, Dbg, "IrpSp -> %08lx\n", IrpSp );
  1906. DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp );
  1907. //
  1908. // Grap the synchronization object.
  1909. //
  1910. AcquiredMutex = TRUE;
  1911. ExAcquireFastMutexUnsafe( Oplock->FastMutex );
  1912. //
  1913. // Use a try-finally to facilitate cleanup.
  1914. //
  1915. try {
  1916. //
  1917. // If there are no outstanding oplocks, we can return immediately.
  1918. //
  1919. if (Oplock->OplockState == NoOplocksHeld) {
  1920. DebugTrace(0,
  1921. Dbg,
  1922. "No oplocks on file\n",
  1923. 0);
  1924. try_return( Status = STATUS_SUCCESS );
  1925. }
  1926. //
  1927. // If there is an exclusive oplock held, we begin the break to none.
  1928. //
  1929. if (!FlagOn( Oplock->OplockState,
  1930. LEVEL_II_OPLOCK | PENDING | OPLOCK_BREAK_MASK )) {
  1931. PIRP IrpExclusive = Oplock->IrpExclusiveOplock;
  1932. DebugTrace(0,
  1933. Dbg,
  1934. "Breaking exclusive oplock\n",
  1935. 0);
  1936. IoAcquireCancelSpinLock( &IrpExclusive->CancelIrql );
  1937. IoSetCancelRoutine( IrpExclusive, NULL );
  1938. IoReleaseCancelSpinLock( IrpExclusive->CancelIrql );
  1939. //
  1940. // If the Irp has been cancelled, we complete the Irp with
  1941. // status cancelled and break the oplock completely.
  1942. //
  1943. if (IrpExclusive->Cancel) {
  1944. IrpExclusive->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1945. FsRtlCompleteRequest( IrpExclusive, STATUS_CANCELLED );
  1946. Oplock->OplockState = NoOplocksHeld;
  1947. Oplock->IrpExclusiveOplock = NULL;
  1948. ObDereferenceObject( Oplock->FileObject );
  1949. Oplock->FileObject = NULL;
  1950. //
  1951. // Release any waiting irps.
  1952. //
  1953. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  1954. PWAITING_IRP WaitingIrp;
  1955. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  1956. WAITING_IRP,
  1957. Links );
  1958. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  1959. }
  1960. try_return( Status = STATUS_SUCCESS );
  1961. } else {
  1962. Oplock->IrpExclusiveOplock->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  1963. FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_SUCCESS );
  1964. Oplock->IrpExclusiveOplock = NULL;
  1965. SetFlag( Oplock->OplockState, BREAK_TO_NONE );
  1966. }
  1967. //
  1968. // If there are level II oplocks, this will break all of them.
  1969. //
  1970. } else if (Oplock->OplockState == OplockIIGranted) {
  1971. DebugTrace(0,
  1972. Dbg,
  1973. "Breaking all level 2 oplocks\n",
  1974. 0);
  1975. while (!IsListEmpty( &Oplock->IrpOplocksII )) {
  1976. //
  1977. // Remove and complete this Irp with STATUS_SUCCESS.
  1978. //
  1979. FsRtlRemoveAndCompleteIrp( Oplock->IrpOplocksII.Flink );
  1980. }
  1981. //
  1982. // Set the oplock state to no oplocks held.
  1983. //
  1984. Oplock->OplockState = NoOplocksHeld;
  1985. try_return( Status = STATUS_SUCCESS );
  1986. //
  1987. // If we are currently breaking to level II then change that
  1988. // to BreakToIIToNone.
  1989. //
  1990. } else if (FlagOn( Oplock->OplockState, BREAK_TO_II )) {
  1991. ClearFlag( Oplock->OplockState, BREAK_TO_II );
  1992. SetFlag( Oplock->OplockState, BREAK_TO_II_TO_NONE );
  1993. //
  1994. // If there is a pending opfilter request then clear that request.
  1995. //
  1996. } else if (FlagOn( Oplock->OplockState, PENDING )) {
  1997. Oplock->OplockState = NoOplocksHeld;
  1998. Oplock->FileObject = NULL;
  1999. try_return( Status = STATUS_SUCCESS );
  2000. }
  2001. //
  2002. // At this point there is already an exclusive oplock break in progress.
  2003. // If this file object owns that oplock, we allow the operation
  2004. // to continue.
  2005. //
  2006. if (Oplock->FileObject == IrpSp->FileObject) {
  2007. DebugTrace(0,
  2008. Dbg,
  2009. "Handle owns level 1 oplock\n",
  2010. 0);
  2011. try_return( Status = STATUS_SUCCESS );
  2012. }
  2013. //
  2014. // If this is an open operation and the user doesn't want to
  2015. // block, we will complete the operation now.
  2016. //
  2017. if ((IrpSp->MajorFunction == IRP_MJ_CREATE) &&
  2018. FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) {
  2019. DebugTrace( 0, Dbg, "Don't block open\n", 0 );
  2020. try_return( Status = STATUS_OPLOCK_BREAK_IN_PROGRESS );
  2021. }
  2022. //
  2023. // If we get here that means that this operation can't continue
  2024. // until the oplock break is complete.
  2025. //
  2026. // FsRtlWaitOnIrp will release the mutex.
  2027. //
  2028. AcquiredMutex = FALSE;
  2029. Status = FsRtlWaitOnIrp( Oplock,
  2030. Irp,
  2031. Context,
  2032. CompletionRoutine,
  2033. PostIrpRoutine,
  2034. &Event );
  2035. try_exit: NOTHING;
  2036. } finally {
  2037. //
  2038. // Give up the synchronization event if we haven't done so.
  2039. //
  2040. if (AcquiredMutex) {
  2041. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  2042. }
  2043. DebugTrace( -1, Dbg, "CheckOplockBreakToNone: Exit -> %08lx\n", Status );
  2044. }
  2045. return Status;
  2046. }
  2047. //
  2048. // Local support routine.
  2049. //
  2050. VOID
  2051. FsRtlRemoveAndCompleteIrp (
  2052. IN PLIST_ENTRY Link
  2053. )
  2054. /*++
  2055. Routine Description:
  2056. This routine is called to remove an Irp from a list of Irps linked
  2057. with the Tail.ListEntry field and complete them with STATUS_CANCELLED
  2058. if the Irp has been cancelled, STATUS_SUCCESS otherwise.
  2059. Arguments:
  2060. Link - Supplies the entry to remove from the list.
  2061. Return Value:
  2062. None.
  2063. --*/
  2064. {
  2065. PIRP Irp;
  2066. PIO_STACK_LOCATION OplockIIIrpSp;
  2067. DebugTrace( +1, Dbg, "FsRtlRemoveAndCompleteIrp: Entered\n", 0 );
  2068. //
  2069. // Reference the Irp.
  2070. //
  2071. Irp = CONTAINING_RECORD( Link, IRP, Tail.Overlay.ListEntry );
  2072. //
  2073. // Get the stack location and dereference the file object.
  2074. //
  2075. OplockIIIrpSp = IoGetCurrentIrpStackLocation( Irp );
  2076. ObDereferenceObject( OplockIIIrpSp->FileObject );
  2077. //
  2078. // Clear the cancel routine in the irp.
  2079. //
  2080. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  2081. IoSetCancelRoutine( Irp, NULL );
  2082. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2083. //
  2084. // Remove this from the list.
  2085. //
  2086. RemoveEntryList( Link );
  2087. //
  2088. // Complete the oplock Irp.
  2089. //
  2090. Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
  2091. FsRtlCompleteRequest( Irp, Irp->Cancel ? STATUS_CANCELLED : STATUS_SUCCESS );
  2092. DebugTrace( -1, Dbg, "FsRtlRemoveAndCompleteIrp: Exit\n", 0 );
  2093. }
  2094. //
  2095. // Local support routine.
  2096. //
  2097. NTSTATUS
  2098. FsRtlWaitOnIrp (
  2099. IN OUT PNONOPAQUE_OPLOCK Oplock,
  2100. IN PIRP Irp,
  2101. IN PVOID Context,
  2102. IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL,
  2103. IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL,
  2104. IN PKEVENT Event
  2105. )
  2106. /*++
  2107. Routine Description:
  2108. This routine is called to create a Wait Irp structure and attach it
  2109. to the current Irp. The Irp is then added to the list of Irps waiting
  2110. for an oplock break. We check if the Irp has been cancelled and if
  2111. so we call our cancel routine to perform the work.
  2112. This routine is holding the Mutex for the oplock on entry and
  2113. must give it up on exit.
  2114. Arguments:
  2115. Oplock - Supplies a pointer to the non-opaque oplock structure for
  2116. this file.
  2117. Irp - Supplies a pointer to the Irp which declares the requested
  2118. operation.
  2119. Context - This value is passed as a parameter to the completion routine.
  2120. CompletionRoutine - This is the routine which is called if this
  2121. Irp must wait for an Oplock to break. This
  2122. is a synchronous operation if not specified
  2123. and we block in this thread waiting on
  2124. an event.
  2125. PostIrpRoutine - This is the routine to call before we put anything
  2126. on our waiting Irp queue.
  2127. Event - If there is no user completion routine, this thread will
  2128. block using this event.
  2129. Return Value:
  2130. STATUS_SUCCESS if we can complete the operation on exiting this thread.
  2131. STATUS_PENDING if we return here but hold the Irp.
  2132. STATUS_CANCELLED if the Irp is cancelled before we return.
  2133. --*/
  2134. {
  2135. LOGICAL AcquiredMutex;
  2136. NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
  2137. PWAITING_IRP WaitingIrp;
  2138. DebugTrace( +1, Dbg, "FsRtlWaitOnIrp: Entered\n", 0 );
  2139. //
  2140. // Remember that we have the mutex.
  2141. //
  2142. AcquiredMutex = TRUE;
  2143. //
  2144. // Use a try-finally to facilitate cleanup.
  2145. //
  2146. try {
  2147. PFAST_MUTEX OplockFastMutex = Oplock->FastMutex;
  2148. //
  2149. // Allocate and initialize the Wait Irp structure.
  2150. //
  2151. WaitingIrp = FsRtlpAllocatePool( PagedPool, sizeof( WAITING_IRP ));
  2152. WaitingIrp->Irp = Irp;
  2153. WaitingIrp->Context = Context;
  2154. WaitingIrp->Information = (ULONG) Irp->IoStatus.Information;
  2155. //
  2156. // Take appropriate action if depending on the value of the
  2157. // completion routine.
  2158. //
  2159. if (ARGUMENT_PRESENT( CompletionRoutine )) {
  2160. WaitingIrp->CompletionRoutine = CompletionRoutine;
  2161. WaitingIrp->Context = Context;
  2162. } else {
  2163. WaitingIrp->CompletionRoutine = FsRtlCompletionRoutinePriv;
  2164. WaitingIrp->Context = Event;
  2165. KeInitializeEvent( Event, NotificationEvent, FALSE );
  2166. }
  2167. //
  2168. // Call the file system's post Irp code.
  2169. //
  2170. if (ARGUMENT_PRESENT( PostIrpRoutine )) {
  2171. PostIrpRoutine( Context, Irp );
  2172. }
  2173. //
  2174. // Initialize the return value to status success.
  2175. //
  2176. Irp->IoStatus.Status = STATUS_SUCCESS;
  2177. //
  2178. // We put this into the Waiting Irp queue.
  2179. //
  2180. InsertTailList( &Oplock->WaitingIrps, &WaitingIrp->Links );
  2181. //
  2182. // We grab the cancel spinlock and store the address of the oplock.
  2183. //
  2184. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  2185. Irp->IoStatus.Information = (ULONG_PTR) Oplock;
  2186. //
  2187. // If the Irp is cancelled then we'll call the cancel routine
  2188. // right now to do away with the Waiting Irp structure.
  2189. //
  2190. if (Irp->Cancel) {
  2191. ExReleaseFastMutexUnsafe( OplockFastMutex );
  2192. AcquiredMutex = FALSE;
  2193. if (ARGUMENT_PRESENT( CompletionRoutine )) {
  2194. IoMarkIrpPending( Irp );
  2195. Status = STATUS_PENDING;
  2196. } else {
  2197. Status = STATUS_CANCELLED;
  2198. }
  2199. FsRtlCancelWaitIrp( NULL, Irp );
  2200. //
  2201. // Otherwise, we set the cancel routine and decide whether we
  2202. // are going to wait on our local event.
  2203. //
  2204. } else {
  2205. IoSetCancelRoutine( Irp, FsRtlCancelWaitIrp );
  2206. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2207. //
  2208. // If we wait on the event, we pull the return code out of
  2209. // the Irp.
  2210. //
  2211. if (!ARGUMENT_PRESENT( CompletionRoutine )) {
  2212. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  2213. AcquiredMutex = FALSE;
  2214. KeWaitForSingleObject( Event,
  2215. Executive,
  2216. KernelMode,
  2217. FALSE,
  2218. NULL );
  2219. Status = Irp->IoStatus.Status;
  2220. //
  2221. // Otherwise, we return STATUS_PENDING.
  2222. //
  2223. } else {
  2224. IoMarkIrpPending( Irp );
  2225. Status = STATUS_PENDING;
  2226. }
  2227. }
  2228. } finally {
  2229. //
  2230. // Release the Mutex if we have not done so.
  2231. //
  2232. if (AcquiredMutex) {
  2233. ExReleaseFastMutexUnsafe( Oplock->FastMutex );
  2234. }
  2235. DebugTrace( -1, Dbg, "FsRtlWaitOnIrp: Exit\n", 0 );
  2236. }
  2237. return Status;
  2238. }
  2239. //
  2240. // Local support routine.
  2241. //
  2242. VOID
  2243. FsRtlCompletionRoutinePriv (
  2244. IN PVOID Context,
  2245. IN PIRP Irp
  2246. )
  2247. /*++
  2248. Routine Description:
  2249. This routine is called when an operation must be synchronous with
  2250. respect to the oplock package. This routine will simply set the
  2251. event in the Signalled state, allowing some other thread to resume
  2252. execution.
  2253. Arguments:
  2254. Context - This is the event to signal.
  2255. Irp - Supplies a pointer to the Irp which declares the requested
  2256. operation.
  2257. Return Value:
  2258. None.
  2259. --*/
  2260. {
  2261. PAGED_CODE();
  2262. DebugTrace( +1, Dbg, "FsRtlCompletionRoutinePriv: Entered\n", 0 );
  2263. KeSetEvent( (PKEVENT)Context, 0, FALSE );
  2264. DebugTrace( -1, Dbg, "FsRtlCompletionRoutinePriv: Exit\n", 0 );
  2265. return;
  2266. UNREFERENCED_PARAMETER( Irp );
  2267. }
  2268. //
  2269. // Local support routine.
  2270. //
  2271. VOID
  2272. FsRtlCancelWaitIrp (
  2273. IN PDEVICE_OBJECT DeviceObject,
  2274. IN PIRP Irp
  2275. )
  2276. /*++
  2277. Routine Description:
  2278. This routine is called for an Irp that is placed on the waiting
  2279. Irp queue. We remove the Cancel routine from the specified Irp and
  2280. then call the completion routines for all the cancelled Irps on the
  2281. queue.
  2282. Arguments:
  2283. DeviceObject - Ignored.
  2284. Irp - Supplies the Irp being cancelled. A pointer to the
  2285. Oplock structure for the Irp is stored in the information
  2286. field of the Irp's Iosb.
  2287. Return Value:
  2288. None.
  2289. --*/
  2290. {
  2291. PNONOPAQUE_OPLOCK Oplock;
  2292. PLIST_ENTRY Links;
  2293. DebugTrace( +1, Dbg, "FsRtlCancelWaitIrp: Entered\n", 0 );
  2294. Oplock = (PNONOPAQUE_OPLOCK) Irp->IoStatus.Information;
  2295. //
  2296. // We now need to void the cancel routine and release the spinlock
  2297. //
  2298. IoSetCancelRoutine( Irp, NULL );
  2299. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2300. //
  2301. // Iterate through all of the waiting locks looking for a canceled one
  2302. // We do this under the protection of the oplock mutex.
  2303. //
  2304. ExAcquireFastMutex( Oplock->FastMutex );
  2305. try {
  2306. for (Links = Oplock->WaitingIrps.Flink;
  2307. Links != &Oplock->WaitingIrps;
  2308. Links = Links->Flink ) {
  2309. PWAITING_IRP WaitingIrp;
  2310. //
  2311. // Get a pointer to the waiting Irp record
  2312. //
  2313. WaitingIrp = CONTAINING_RECORD( Links, WAITING_IRP, Links );
  2314. DebugTrace(0, Dbg, "FsRtlCancelWaitIrp, Loop top, WaitingIrp = %08lx\n", WaitingIrp);
  2315. //
  2316. // Check if the irp has been cancelled
  2317. //
  2318. if (WaitingIrp->Irp->Cancel) {
  2319. //
  2320. // Now we need to remove this waiter and call the
  2321. // completion routine. But we must not mess up our link
  2322. // iteration so we need to back up link one step and
  2323. // then the next iteration will go to our current flink.
  2324. //
  2325. Links = Links->Blink;
  2326. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  2327. }
  2328. }
  2329. } finally {
  2330. //
  2331. // No matter how we exit we release the mutex
  2332. //
  2333. ExReleaseFastMutex( Oplock->FastMutex );
  2334. DebugTrace( -1, Dbg, "FsRtlCancelWaitIrp: Exit\n", 0 );
  2335. }
  2336. return;
  2337. UNREFERENCED_PARAMETER( DeviceObject );
  2338. }
  2339. //
  2340. // Local support routine.
  2341. //
  2342. VOID
  2343. FsRtlCancelOplockIIIrp (
  2344. IN PDEVICE_OBJECT DeviceObject,
  2345. IN PIRP Irp
  2346. )
  2347. /*++
  2348. Routine Description:
  2349. This routine is called for an Irp that is placed in the Oplock II
  2350. Irp queue. We remove the Cancel routine from the specified Irp and
  2351. then call the completion routines for all the cancelled Irps on the
  2352. queue.
  2353. Arguments:
  2354. DeviceObject - Ignored.
  2355. Irp - Supplies the Irp being cancelled. A pointer to the
  2356. Oplock structure for the Irp is stored in the information
  2357. field of the Irp's Iosb.
  2358. Return Value:
  2359. None.
  2360. --*/
  2361. {
  2362. PNONOPAQUE_OPLOCK Oplock;
  2363. BOOLEAN LevelIIIrps;
  2364. PLIST_ENTRY Links;
  2365. DebugTrace( +1, Dbg, "FsRtlCancelOplockIIIrp: Entered\n", 0 );
  2366. Oplock = (PNONOPAQUE_OPLOCK) Irp->IoStatus.Information;
  2367. //
  2368. // We now need to void the cancel routine and release the spinlock
  2369. //
  2370. IoSetCancelRoutine( Irp, NULL );
  2371. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2372. LevelIIIrps = FALSE;
  2373. //
  2374. // Iterate through all of the level II oplocks looking for a canceled one
  2375. // We do this under the protection of the oplock mutex.
  2376. //
  2377. ExAcquireFastMutex( Oplock->FastMutex );
  2378. try {
  2379. for (Links = Oplock->IrpOplocksII.Flink;
  2380. Links != &Oplock->IrpOplocksII;
  2381. Links = Links->Flink ) {
  2382. PIRP OplockIIIrp;
  2383. //
  2384. // Get a pointer to the Irp record
  2385. //
  2386. OplockIIIrp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
  2387. DebugTrace(0, Dbg, "FsRtlCancelOplockIIIrp, Loop top, Irp = %08lx\n", OplockIIIrp);
  2388. //
  2389. // Check if the irp has been cancelled
  2390. //
  2391. if (OplockIIIrp->Cancel) {
  2392. //
  2393. // Now we need to remove this waiter and call the
  2394. // completion routine. But we must not mess up our link
  2395. // iteration so we need to back up link one step and
  2396. // then the next iteration will go to our current flink.
  2397. //
  2398. Links = Links->Blink;
  2399. FsRtlRemoveAndCompleteIrp( Links->Flink );
  2400. LevelIIIrps = TRUE;
  2401. }
  2402. }
  2403. //
  2404. // If the list is now empty, change the oplock status to
  2405. // no oplocks held.
  2406. //
  2407. if (LevelIIIrps && IsListEmpty( &Oplock->IrpOplocksII )) {
  2408. Oplock->OplockState = NoOplocksHeld;
  2409. }
  2410. } finally {
  2411. //
  2412. // No matter how we exit we release the mutex
  2413. //
  2414. ExReleaseFastMutex( Oplock->FastMutex );
  2415. DebugTrace( -1, Dbg, "FsRtlCancelOplockIIIrp: Exit\n", 0 );
  2416. }
  2417. return;
  2418. UNREFERENCED_PARAMETER( DeviceObject );
  2419. }
  2420. //
  2421. // Local support routine.
  2422. //
  2423. VOID
  2424. FsRtlCancelExclusiveIrp (
  2425. IN PDEVICE_OBJECT DeviceObject,
  2426. IN PIRP Irp
  2427. )
  2428. /*++
  2429. Routine Description:
  2430. This routine is called for either an exclusive or oplock I Irp.
  2431. Arguments:
  2432. DeviceObject - Ignored.
  2433. Irp - Supplies the Irp being cancelled. A pointer to the
  2434. Oplock structure for the Irp is stored in the information
  2435. field of the Irp's Iosb.
  2436. Return Value:
  2437. None.
  2438. --*/
  2439. {
  2440. PNONOPAQUE_OPLOCK Oplock;
  2441. DebugTrace( +1, Dbg, "FsRtlCancelExclusiveIrp: Entered\n", 0 );
  2442. Oplock = (PNONOPAQUE_OPLOCK) Irp->IoStatus.Information;
  2443. //
  2444. // We now need to void the cancel routine and release the spinlock
  2445. //
  2446. IoSetCancelRoutine( Irp, NULL );
  2447. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2448. //
  2449. // Grab the synchronization object for this oplock.
  2450. //
  2451. ExAcquireFastMutex( Oplock->FastMutex );
  2452. try {
  2453. //
  2454. // We look for the exclusive Irp, if present and cancelled
  2455. // we complete it.
  2456. //
  2457. if ((Oplock->IrpExclusiveOplock != NULL) &&
  2458. (Oplock->IrpExclusiveOplock->Cancel)) {
  2459. FsRtlCompleteRequest( Oplock->IrpExclusiveOplock, STATUS_CANCELLED );
  2460. Oplock->IrpExclusiveOplock = NULL;
  2461. ObDereferenceObject( Oplock->FileObject );
  2462. Oplock->FileObject = NULL;
  2463. Oplock->OplockState = NoOplocksHeld;
  2464. //
  2465. // Complete the waiting Irps.
  2466. //
  2467. while (!IsListEmpty( &Oplock->WaitingIrps )) {
  2468. PWAITING_IRP WaitingIrp;
  2469. //
  2470. // Remove the entry found and complete the Irp.
  2471. //
  2472. WaitingIrp = CONTAINING_RECORD( Oplock->WaitingIrps.Flink,
  2473. WAITING_IRP,
  2474. Links );
  2475. FsRtlRemoveAndCompleteWaitIrp( WaitingIrp );
  2476. }
  2477. }
  2478. } finally {
  2479. //
  2480. // No matter how we exit we release the mutex
  2481. //
  2482. ExReleaseFastMutex( Oplock->FastMutex );
  2483. DebugTrace( -1, Dbg, "FsRtlCancelExclusiveIrp: Exit\n", 0 );
  2484. }
  2485. return;
  2486. UNREFERENCED_PARAMETER( DeviceObject );
  2487. }
  2488. //
  2489. // Local support routine.
  2490. //
  2491. VOID
  2492. FsRtlRemoveAndCompleteWaitIrp (
  2493. IN PWAITING_IRP WaitingIrp
  2494. )
  2495. /*++
  2496. Routine Description:
  2497. This routine is called to remove and perform any neccessary cleanup
  2498. for an Irp stored on the waiting Irp list in an oplock structure.
  2499. Arguments:
  2500. WaitingIrp - This is the auxilary structure attached to the Irp
  2501. being completed.
  2502. Return Value:
  2503. None.
  2504. --*/
  2505. {
  2506. PIRP Irp;
  2507. PAGED_CODE();
  2508. DebugTrace( +1, Dbg, "FsRtlRemoveAndCompleteWaitIrp: Entered\n", 0 );
  2509. //
  2510. // Remove the Irp from the queue.
  2511. //
  2512. RemoveEntryList( &WaitingIrp->Links );
  2513. Irp = WaitingIrp->Irp;
  2514. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  2515. IoSetCancelRoutine( Irp, NULL );
  2516. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2517. //
  2518. // Restore the information field.
  2519. //
  2520. Irp->IoStatus.Information = WaitingIrp->Information;
  2521. Irp->IoStatus.Status = (Irp->Cancel
  2522. ? STATUS_CANCELLED
  2523. : STATUS_SUCCESS);
  2524. //
  2525. // Call the completion routine in the Waiting Irp.
  2526. //
  2527. WaitingIrp->CompletionRoutine( WaitingIrp->Context, Irp );
  2528. //
  2529. // And free up pool
  2530. //
  2531. ExFreePool( WaitingIrp );
  2532. DebugTrace( -1, Dbg, "FsRtlRemoveAndCompleteWaitIrp: Exit\n", 0 );
  2533. return;
  2534. }
  2535. //
  2536. // Local support routine.
  2537. //
  2538. VOID
  2539. FsRtlNotifyCompletion (
  2540. IN PVOID Context,
  2541. IN PIRP Irp
  2542. )
  2543. /*++
  2544. Routine Description:
  2545. This is the completion routine called when a break notify Irp is to
  2546. be completed. We simply call FsRtlComplete request to dispose of the
  2547. Irp.
  2548. Arguments:
  2549. Context - Ignored.
  2550. Irp - Irp used to request break notify.
  2551. Return Value:
  2552. None.
  2553. --*/
  2554. {
  2555. PAGED_CODE();
  2556. UNREFERENCED_PARAMETER (Context);
  2557. DebugTrace( +1, Dbg, "FsRtlNotifyCompletion: Entered\n", 0 );
  2558. //
  2559. // Call FsRtlCompleteRequest using the value in the Irp.
  2560. //
  2561. FsRtlCompleteRequest( Irp, Irp->IoStatus.Status );
  2562. DebugTrace( -1, Dbg, "FsRtlNotifyCompletion: Exit\n", 0 );
  2563. return;
  2564. }