ReactOS  0.4.13-dev-79-gcd489d8
oplock.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: ntoskrnl/fsrtl/oplock.c
5  * PURPOSE: Provides an Opportunistic Lock for file system drivers.
6  * PROGRAMMERS: Pierre Schweitzer (pierre@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define NO_OPLOCK 0x1
16 #define LEVEL_1_OPLOCK 0x2
17 #define BATCH_OPLOCK 0x4
18 #define FILTER_OPLOCK 0x8
19 #define LEVEL_2_OPLOCK 0x10
20 
21 #define EXCLUSIVE_LOCK 0x40
22 #define PENDING_LOCK 0x80
23 
24 #define BROKEN_TO_LEVEL_2 0x100
25 #define BROKEN_TO_NONE 0x200
26 #define BROKEN_TO_NONE_FROM_LEVEL_2 0x400
27 #define BROKEN_TO_CLOSE_PENDING 0x800
28 #define BROKEN_ANY (BROKEN_TO_LEVEL_2 | BROKEN_TO_NONE | BROKEN_TO_NONE_FROM_LEVEL_2 | BROKEN_TO_CLOSE_PENDING)
29 
30 #define TAG_OPLOCK 'orSF'
31 
32 typedef struct _INTERNAL_OPLOCK
33 {
34  /* Level I IRP */
36  /* Level I FILE_OBJECT */
38  /* Level II IRPs */
40  /* IRPs waiting on level I */
45 
46 typedef struct _WAIT_CONTEXT
47 {
55 
56 VOID
57 NTAPI
59  IN PIRP Irp)
60 {
61  PAGED_CODE();
62 
63  DPRINT("FsRtlNotifyCompletion(%p, %p)\n", Context, Irp);
64 
65  /* Just complete the IRP */
67 }
68 
69 VOID
70 NTAPI
72  IN PIRP Irp)
73 {
74  PKEVENT WaitEvent;
75 
76  PAGED_CODE();
77 
78  DPRINT("FsRtlCompletionRoutinePriv(%p, %p)\n", Context, Irp);
79 
80  /* Set the event */
81  WaitEvent = (PKEVENT)Context;
82  KeSetEvent(WaitEvent, IO_NO_INCREMENT, FALSE);
83 }
84 
85 VOID
87 {
88  PIRP Irp;
89 
90  PAGED_CODE();
91 
92  DPRINT("FsRtlRemoveAndCompleteWaitIrp(%p)\n", WaitCtx);
93 
94  RemoveEntryList(&WaitCtx->WaitListEntry);
95  Irp = WaitCtx->Irp;
96 
97  /* No cancel routine anymore */
98  IoAcquireCancelSpinLock(&Irp->CancelIrql);
100  IoReleaseCancelSpinLock(Irp->CancelIrql);
101 
102  /* Set the information */
103  Irp->IoStatus.Information = WaitCtx->SavedInformation;
104  /* Set the status according to the fact it got cancel or not */
105  Irp->IoStatus.Status = (Irp->Cancel ? STATUS_CANCELLED : STATUS_SUCCESS);
106 
107  /* Call the completion routine */
108  WaitCtx->CompletionRoutine(WaitCtx->CompletionContext, Irp);
109 
110  /* And get rid of the now useless wait context */
111  ExFreePoolWithTag(WaitCtx, TAG_OPLOCK);
112 }
113 
114 VOID
115 NTAPI
117  IN PIRP Irp)
118 {
119  PINTERNAL_OPLOCK Oplock;
120  PLIST_ENTRY NextEntry;
121  PWAIT_CONTEXT WaitCtx;
122 
123  DPRINT("FsRtlCancelWaitIrp(%p, %p)\n", DeviceObject, Irp);
124 
125  /* Get the associated oplock */
126  Oplock = (PINTERNAL_OPLOCK)Irp->IoStatus.Information;
127 
128  /* Remove the cancel routine (we're being called!) */
130  /* And release the cancel spin lock (always locked when cancel routine is called) */
131  IoReleaseCancelSpinLock(Irp->CancelIrql);
132 
133  /* Now, remove and complete any associated waiter */
134  ExAcquireFastMutex(Oplock->IntLock);
135  for (NextEntry = Oplock->WaitListHead.Flink;
136  NextEntry != &Oplock->WaitListHead;
137  NextEntry = NextEntry->Flink)
138  {
139  WaitCtx = CONTAINING_RECORD(NextEntry, WAIT_CONTEXT, WaitListEntry);
140 
141  if (WaitCtx->Irp->Cancel)
142  {
144  }
145  }
146  ExReleaseFastMutex(Oplock->IntLock);
147 }
148 
149 VOID
151  IN PIRP Irp,
155  IN PKEVENT WaitEvent)
156 {
157  BOOLEAN Locked;
158  PWAIT_CONTEXT WaitCtx;
159 
160  DPRINT("FsRtlWaitOnIrp(%p, %p, %p, %p, %p, %p)\n", Oplock, Irp, CompletionContext, CompletionRoutine, PostIrpRoutine, WaitEvent);
161 
162  /* We must always be called with IntLock locked! */
163  Locked = TRUE;
164  /* Dirty check for above statement */
165  ASSERT(Oplock->IntLock->Owner == KeGetCurrentThread());
166 
167  /* Allocate a wait context for the IRP */
169  WaitCtx->Irp = Irp;
170  WaitCtx->SavedInformation = Irp->IoStatus.Information;
171  /* If caller provided everything required, us it */
172  if (CompletionRoutine != NULL)
173  {
176  }
177  /* Otherwise, put ourselves */
178  else
179  {
181  WaitCtx->CompletionContext = WaitEvent;
183  }
184 
185  /* If we got a prepost routine, call it now! */
186  if (PostIrpRoutine != NULL)
187  {
189  }
190 
191  Irp->IoStatus.Status = STATUS_SUCCESS;
192 
193  /* Queue the IRP - it's OK, we're locked */
194  InsertHeadList(&Oplock->WaitListHead, &WaitCtx->WaitListEntry);
195 
196  /* Set the oplock as information of the IRP (for the cancel routine)
197  * And lock the cancel routine lock for setting it
198  */
199  IoAcquireCancelSpinLock(&Irp->CancelIrql);
200  Irp->IoStatus.Information = (ULONG_PTR)Oplock;
201 
202  /* If there's already a cancel routine
203  * Cancel the IRP
204  */
205  if (Irp->Cancel)
206  {
207  ExReleaseFastMutexUnsafe(Oplock->IntLock);
208  Locked = FALSE;
209 
210  if (CompletionRoutine != NULL)
211  {
213  }
215  }
216  /* Otherwise, put ourselves as the cancel routine and start waiting */
217  else
218  {
220  IoReleaseCancelSpinLock(Irp->CancelIrql);
221  if (CompletionRoutine != NULL)
222  {
224  }
225  else
226  {
227  ExReleaseFastMutexUnsafe(Oplock->IntLock);
228  Locked = FALSE;
230  }
231  }
232 
233  /* If we didn't unlock yet, do it now */
234  if (Locked)
235  {
236  ExReleaseFastMutexUnsafe(Oplock->IntLock);
237  }
238 }
239 
240 NTSTATUS
242  IN PIO_STACK_LOCATION Stack,
243  IN PIRP Irp)
244 {
245  PAGED_CODE();
246 
247  DPRINT("FsRtlOplockBreakNotify(%p, %p, %p)\n", Oplock, Stack, Irp);
248 
249  /* No oplock, no break to notify */
250  if (Oplock == NULL)
251  {
252  Irp->IoStatus.Status = STATUS_SUCCESS;
254  return STATUS_SUCCESS;
255  }
256 
257  /* Notify by completing the IRP, unless we have broken to shared */
258  ExAcquireFastMutexUnsafe(Oplock->IntLock);
259  if (!BooleanFlagOn(Oplock->Flags, BROKEN_TO_LEVEL_2))
260  {
261  Irp->IoStatus.Status = STATUS_SUCCESS;
263  ExReleaseFastMutexUnsafe(Oplock->IntLock);
264  return STATUS_SUCCESS;
265  }
266 
267  /* If it's pending, just complete the IRP and get rid of the oplock */
268  if (BooleanFlagOn(Oplock->Flags, PENDING_LOCK))
269  {
270  Oplock->FileObject = NULL;
271  Oplock->Flags = NO_OPLOCK;
272  Irp->IoStatus.Status = STATUS_SUCCESS;
274  ExReleaseFastMutexUnsafe(Oplock->IntLock);
275  return STATUS_SUCCESS;
276  }
277 
278  /* Otherwise, wait on the IRP */
279  Irp->IoStatus.Status = STATUS_SUCCESS;
281  return STATUS_SUCCESS;
282 }
283 
284 VOID
286 {
287  PIO_STACK_LOCATION Stack;
288 
289  DPRINT("FsRtlRemoveAndCompleteIrp(%p)\n", Irp);
290 
292 
293  /* Remove our extra ref */
295 
296  /* Remove our cancel routine */
297  IoAcquireCancelSpinLock(&Irp->CancelIrql);
299  IoReleaseCancelSpinLock(Irp->CancelIrql);
300 
301  /* Remove the IRP from the list it may be in (wait or shared) */
302  RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
303 
304  /* And complete! */
305  Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
306  Irp->IoStatus.Status = (Irp->Cancel ? STATUS_CANCELLED : STATUS_SUCCESS);
307 
309 }
310 
311 VOID
312 NTAPI
314  IN PIRP Irp)
315 {
316  PINTERNAL_OPLOCK Oplock;
317  PLIST_ENTRY NextEntry;
318  PIRP ListIrp;
320 
321  DPRINT("FsRtlCancelOplockIIIrp(%p, %p)\n", DeviceObject, Irp);
322 
323  /* Get the associated oplock */
324  Oplock = (PINTERNAL_OPLOCK)Irp->IoStatus.Information;
325 
326  /* Remove the cancel routine (it's OK, we're the cancel routine! )*/
328  IoReleaseCancelSpinLock(Irp->CancelIrql);
329 
330  /* Nothing removed yet */
331  Removed = FALSE;
332  ExAcquireFastMutex(Oplock->IntLock);
333  /* Browse all the IRPs associated to the shared lock */
334  for (NextEntry = Oplock->SharedListHead.Flink;
335  NextEntry != &Oplock->SharedListHead;
336  NextEntry = NextEntry->Flink)
337  {
338  ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
339 
340  /* If canceled, remove it */
341  if (ListIrp->Cancel)
342  {
343  FsRtlRemoveAndCompleteIrp(ListIrp);
344  Removed = TRUE;
345  }
346  }
347 
348  /* If no IRP left, the oplock is gone */
349  if (Removed && IsListEmpty(&Oplock->SharedListHead))
350  {
351  Oplock->Flags = NO_OPLOCK;
352  }
353  /* Don't forget to release the mutex */
354  ExReleaseFastMutex(Oplock->IntLock);
355 }
356 
357 NTSTATUS
359  IN PIO_STACK_LOCATION Stack,
360  IN PIRP Irp,
361  IN BOOLEAN SwitchToLevel2)
362 {
363  PLIST_ENTRY NextEntry;
364  PWAIT_CONTEXT WaitCtx;
365  BOOLEAN Deref;
366  BOOLEAN Locked;
367 
368  DPRINT("FsRtlAcknowledgeOplockBreak(%p, %p, %p, %u)\n", Oplock, Stack, Irp, Unknown);
369 
370  /* No oplock, nothing to acknowledge */
371  if (Oplock == NULL)
372  {
373  Irp->IoStatus.Status = STATUS_INVALID_OPLOCK_PROTOCOL;
376  }
377 
378  /* Acquire oplock internal lock */
379  ExAcquireFastMutexUnsafe(Oplock->IntLock);
380  Locked = TRUE;
381  /* Does it match the file? */
382  if (Oplock->FileObject != Stack->FileObject)
383  {
384  Irp->IoStatus.Status = STATUS_INVALID_OPLOCK_PROTOCOL;
386  ExReleaseFastMutexUnsafe(Oplock->IntLock);
388  }
389 
390  /* Assume we'll have to deref our extra ref (level I) */
391  Deref = TRUE;
392 
393  /* If we got broken to level 2 and asked for a shared lock
394  * switch the oplock to shared
395  */
396  if (SwitchToLevel2 && BooleanFlagOn(Oplock->Flags, BROKEN_TO_LEVEL_2))
397  {
398  /* The IRP cannot be synchronous, we'll move it to the LEVEL_2 IRPs */
400 
401  /* Mark the IRP pending, and queue it for the shared IRPs */
403  Irp->IoStatus.Status = STATUS_SUCCESS;
404  InsertTailList(&Oplock->SharedListHead, &Irp->Tail.Overlay.ListEntry);
405 
406  /* Don't deref, we're not done yet */
407  Deref = FALSE;
408  /* And mark we've got a shared lock */
409  Oplock->Flags = LEVEL_2_OPLOCK;
410  /* To find the lock back on cancel */
411  Irp->IoStatus.Information = (ULONG_PTR)Oplock;
412 
413  /* Acquire the spinlock to set the cancel routine */
414  IoAcquireCancelSpinLock(&Irp->CancelIrql);
415  /* If IRP got canceled, call it immediately */
416  if (Irp->Cancel)
417  {
418  ExReleaseFastMutexUnsafe(Oplock->IntLock);
419  Locked = FALSE;
421  }
422  /* Otherwise, just set our cancel routine */
423  else
424  {
426  IoReleaseCancelSpinLock(Irp->CancelIrql);
427  }
428  }
429  /* If oplock got broken, remove it */
430  else if (BooleanFlagOn(Oplock->Flags, (BROKEN_TO_NONE | BROKEN_TO_LEVEL_2)))
431  {
432  Irp->IoStatus.Status = STATUS_SUCCESS;
434  Oplock->Flags = NO_OPLOCK;
435  }
436  /* Same, but precise we got broken from none to shared */
437  else if (BooleanFlagOn(Oplock->Flags, BROKEN_TO_NONE_FROM_LEVEL_2))
438  {
439  Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
440  Irp->IoStatus.Status = STATUS_SUCCESS;
442  Oplock->Flags = NO_OPLOCK;
443  }
444 
445  /* Now, complete any IRP waiting */
446  for (NextEntry = Oplock->WaitListHead.Flink;
447  NextEntry != &Oplock->WaitListHead;
448  NextEntry = NextEntry->Flink)
449  {
450  WaitCtx = CONTAINING_RECORD(NextEntry, WAIT_CONTEXT, WaitListEntry);
452  }
453 
454  /* If we dropped oplock, remove our extra ref */
455  if (Deref)
456  {
457  ObfDereferenceObject(Oplock->FileObject);
458  }
459  /* And unset FO: no oplock left or shared */
460  Oplock->FileObject = NULL;
461 
462  /* Don't leak the mutex! */
463  if (Locked)
464  {
465  ExReleaseFastMutexUnsafe(Oplock->IntLock);
466  }
467 
468  return STATUS_SUCCESS;
469 }
470 
471 NTSTATUS
473  IN PIO_STACK_LOCATION Stack,
474  IN PIRP Irp)
475 {
477  PLIST_ENTRY NextEntry;
478  PWAIT_CONTEXT WaitCtx;
479 
480  PAGED_CODE();
481 
482  DPRINT("FsRtlOpBatchBreakClosePending(%p, %p, %p)\n", Oplock, Stack, Irp);
483 
484  /* No oplock, that's not legit! */
485  if (Oplock == NULL)
486  {
487  Irp->IoStatus.Status = STATUS_INVALID_OPLOCK_PROTOCOL;
490  }
491 
493  ExAcquireFastMutexUnsafe(Oplock->IntLock);
494 
495  /* First of all, check if all conditions are met:
496  * Correct FO + broken oplock
497  */
498  if (Oplock->FileObject == Stack->FileObject && (BooleanFlagOn(Oplock->Flags, (BROKEN_TO_LEVEL_2 | BROKEN_TO_NONE | BROKEN_TO_NONE_FROM_LEVEL_2))))
499  {
500  /* If we have a pending or level 1 oplock... */
501  if (BooleanFlagOn(Oplock->Flags, (PENDING_LOCK | LEVEL_1_OPLOCK)))
502  {
503  /* Remove our extra ref from the FO */
504  if (Oplock->Flags & LEVEL_1_OPLOCK)
505  {
506  ObDereferenceObject(Oplock->FileObject);
507  }
508 
509  /* And remove the oplock */
510  Oplock->Flags = NO_OPLOCK;
511  Oplock->FileObject = NULL;
512 
513  /* Complete any waiting IRP */
514  for (NextEntry = Oplock->WaitListHead.Flink;
515  NextEntry != &Oplock->WaitListHead;
516  NextEntry = NextEntry->Flink)
517  {
518  WaitCtx = CONTAINING_RECORD(NextEntry, WAIT_CONTEXT, WaitListEntry);
520  }
521  }
522  /* Otherwise, mark the oplock as close pending */
523  else
524  {
525  ClearFlag(Oplock->Flags, BROKEN_ANY);
526  SetFlag(Oplock->Flags, BROKEN_TO_CLOSE_PENDING);
527  }
528  }
529  /* Oplock is in invalid state */
530  else
531  {
533  }
534 
535  /* And complete */
536  Irp->IoStatus.Status = Status;
538  ExReleaseFastMutexUnsafe(Oplock->IntLock);
539 
540  return Status;
541 }
542 
545 {
546  PINTERNAL_OPLOCK Oplock = NULL;
547 
548  PAGED_CODE();
549 
550  DPRINT("FsRtlAllocateOplock()\n");
551 
552  _SEH2_TRY
553  {
554  /* Allocate and initialize the oplock */
556  RtlZeroMemory(Oplock, sizeof(INTERNAL_OPLOCK));
557  /* We allocate the fast mutex separately to have it non paged (while the rest of the oplock can be paged) */
560  /* Initialize the IRP list for level 2 oplock */
562  /* And for the wait IRPs */
564  Oplock->Flags = NO_OPLOCK;
565  }
567  {
568  /* In case of abnormal termination, it means either OPLOCK or FAST_MUTEX allocation failed */
570  {
571  /* That FAST_MUTEX, free OPLOCK */
572  if (Oplock != NULL)
573  {
574  ExFreePoolWithTag(Oplock, TAG_OPLOCK);
575  Oplock = NULL;
576  }
577  }
578  }
579  _SEH2_END;
580 
581  return Oplock;
582 }
583 
584 VOID
585 NTAPI
587  IN PIRP Irp)
588 {
589  PINTERNAL_OPLOCK IntOplock;
590  PLIST_ENTRY NextEntry;
591  PWAIT_CONTEXT WaitCtx;
592 
593  DPRINT("FsRtlCancelExclusiveIrp(%p, %p)\n", DeviceObject, Irp);
594 
595  /* Get the associated oplock */
596  IntOplock = (PINTERNAL_OPLOCK)Irp->IoStatus.Information;
597 
598  /* Remove the cancel routine (us!) and release the cancel spinlock */
600  IoReleaseCancelSpinLock(Irp->CancelIrql);
601 
602  /* Acquire our internal FAST_MUTEX */
603  ExAcquireFastMutex(IntOplock->IntLock);
604  /* If we had an exclusive IRP */
605  if (IntOplock->ExclusiveIrp != NULL && IntOplock->ExclusiveIrp->Cancel)
606  {
607  /* Cancel it, and remove it from the oplock */
608  IntOplock->ExclusiveIrp->IoStatus.Status = STATUS_CANCELLED;
610  IntOplock->ExclusiveIrp = NULL;
611 
612  /* Dereference the fileobject and remove the oplock */
613  ObDereferenceObject(IntOplock->FileObject);
614  IntOplock->FileObject = NULL;
615  IntOplock->Flags = NO_OPLOCK;
616 
617  /* And complete any waiting IRP */
618  for (NextEntry = IntOplock->WaitListHead.Flink;
619  NextEntry != &IntOplock->WaitListHead;
620  NextEntry = NextEntry->Flink)
621  {
622  WaitCtx = CONTAINING_RECORD(NextEntry, WAIT_CONTEXT, WaitListEntry);
624  }
625  }
626 
627  /* Done! */
628  ExReleaseFastMutexUnsafe(IntOplock->IntLock);
629 }
630 
631 NTSTATUS
633  IN PIO_STACK_LOCATION Stack,
634  IN PIRP Irp,
635  IN ULONG Flags)
636 {
637  PINTERNAL_OPLOCK IntOplock;
638  PIRP ListIrp;
639  BOOLEAN Locked;
641 
642  DPRINT("FsRtlRequestExclusiveOplock(%p, %p, %p, %lu)\n", Oplock, Stack, Irp, Flags);
643 
644  IntOplock = *Oplock;
645  Locked = FALSE;
647 
648  /* Time to work! */
649  _SEH2_TRY
650  {
651  /* Was the oplock already allocated? If not, do it now! */
652  if (IntOplock == NULL)
653  {
654  *Oplock = FsRtlAllocateOplock();
655  IntOplock = *Oplock;
656  }
657 
658  /* Acquire our internal lock */
659  ExAcquireFastMutexUnsafe(IntOplock->IntLock);
660  Locked = TRUE;
661 
662  /* If we request exclusiveness, a filter or a pending oplock, grant it */
664  {
665  /* Either no oplock, or pending */
666  ASSERT(BooleanFlagOn(IntOplock->Flags, (NO_OPLOCK | PENDING_LOCK)));
667  IntOplock->ExclusiveIrp = Irp;
668  IntOplock->FileObject = Stack->FileObject;
669  IntOplock->Flags = (EXCLUSIVE_LOCK | PENDING_LOCK | FILTER_OPLOCK);
670  }
671  else
672  {
673  /* Otherwise, shared or no effective oplock */
675  {
676  /* The shared IRPs list should contain a single entry! */
677  if (IntOplock->Flags == LEVEL_2_OPLOCK)
678  {
679  ListIrp = CONTAINING_RECORD(IntOplock->SharedListHead.Flink, IRP, Tail.Overlay.ListEntry);
680  ASSERT(IntOplock->SharedListHead.Flink == IntOplock->SharedListHead.Blink);
681  FsRtlRemoveAndCompleteIrp(ListIrp);
682  }
683 
684  /* Set the exclusiveness */
685  IntOplock->ExclusiveIrp = Irp;
686  IntOplock->FileObject = Stack->FileObject;
687  IntOplock->Flags = Flags;
688 
689  /* Mark the IRP pending and reference our file object */
691  ObReferenceObject(Stack->FileObject);
692  Irp->IoStatus.Information = (ULONG_PTR)IntOplock;
693 
694  /* Now, set ourselves as cancel routine */
695  IoAcquireCancelSpinLock(&Irp->CancelIrql);
696  /* Unless IRP got canceled, then, just give up */
697  if (Irp->Cancel)
698  {
699  ExReleaseFastMutexUnsafe(IntOplock->IntLock);
700  Locked = FALSE;
703  }
704  else
705  {
707  IoReleaseCancelSpinLock(Irp->CancelIrql);
708  }
709  }
710  /* Cannot set exclusiveness, fail */
711  else
712  {
713  if (Irp != NULL)
714  {
715  Irp->IoStatus.Status = STATUS_OPLOCK_NOT_GRANTED;
718  }
719  }
720  }
721  }
722  /* If locked, release */
724  {
725  if (Locked)
726  {
727  ExReleaseFastMutexUnsafe(IntOplock->IntLock);
728  }
729  }
730  _SEH2_END;
731 
732  return Status;
733 }
734 
735 NTSTATUS
737  IN PIO_STACK_LOCATION Stack,
738  IN PIRP Irp)
739 {
740  BOOLEAN Locked;
742  PINTERNAL_OPLOCK IntOplock;
743 
744  DPRINT("FsRtlRequestOplockII(%p, %p, %p)\n", Oplock, Stack, Irp);
745 
746  IntOplock = *Oplock;
747  Locked = FALSE;
749 
750  _SEH2_TRY
751  {
752  /* No oplock yet? Allocate it */
753  if (IntOplock == NULL)
754  {
755  *Oplock = FsRtlAllocateOplock();
756  IntOplock = *Oplock;
757  }
758 
759  /* Acquire the oplock */
760  ExAcquireFastMutexUnsafe(IntOplock->IntLock);
761  Locked = TRUE;
762 
763  /* If already shared, or no oplock that's fine! */
764  if (BooleanFlagOn(IntOplock->Flags, (LEVEL_2_OPLOCK | NO_OPLOCK)))
765  {
767  /* Granted! */
768  Irp->IoStatus.Status = STATUS_SUCCESS;
769 
770  /* Insert in the shared list */
771  InsertTailList(&IntOplock->SharedListHead, &Irp->Tail.Overlay.ListEntry);
772 
773  /* Save the associated oplock */
774  Irp->IoStatus.Information = (ULONG_PTR)IntOplock;
775 
776  /* The oplock is shared */
777  IntOplock->Flags = LEVEL_2_OPLOCK;
778 
779  /* Reference the fileobject */
780  ObReferenceObject(Stack->FileObject);
781 
782  /* Set our cancel routine, unless the IRP got canceled in-between */
783  IoAcquireCancelSpinLock(&Irp->CancelIrql);
784  if (Irp->Cancel)
785  {
786  ExReleaseFastMutexUnsafe(IntOplock->IntLock);
787  Locked = FALSE;
790  }
791  else
792  {
794  IoReleaseCancelSpinLock(Irp->CancelIrql);
795  }
796  }
797  /* Otherwise, just fail */
798  else
799  {
800  Irp->IoStatus.Status = STATUS_OPLOCK_NOT_GRANTED;
803  }
804  }
806  {
807  if (Locked)
808  {
809  ExReleaseFastMutexUnsafe(IntOplock->IntLock);
810  }
811  }
812  _SEH2_END;
813 
814  return Status;
815 }
816 
817 VOID
819  IN PIO_STACK_LOCATION Stack)
820 {
821  PIO_STACK_LOCATION ListStack;
822  PLIST_ENTRY NextEntry;
823  PIRP ListIrp;
824  PWAIT_CONTEXT WaitCtx;
825 
826  DPRINT("FsRtlOplockCleanup(%p, %p)\n", Oplock, Stack);
827 
828  ExAcquireFastMutexUnsafe(Oplock->IntLock);
829  /* oplock cleaning only makes sense if there's an oplock */
830  if (Oplock->Flags != NO_OPLOCK)
831  {
832  /* Shared lock */
833  if (Oplock->Flags == LEVEL_2_OPLOCK)
834  {
835  /* Complete any associated IRP */
836  for (NextEntry = Oplock->SharedListHead.Flink;
837  NextEntry != &Oplock->SharedListHead;
838  NextEntry = NextEntry->Flink)
839  {
840  ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
841  ListStack = IoGetCurrentIrpStackLocation(ListIrp);
842 
843  if (Stack->FileObject == ListStack->FileObject)
844  {
845  FsRtlRemoveAndCompleteIrp(ListIrp);
846  }
847  }
848 
849  /* If, in the end, no IRP is left, then the lock is gone */
850  if (IsListEmpty(&Oplock->SharedListHead))
851  {
852  Oplock->Flags = NO_OPLOCK;
853  }
854  }
855  else
856  {
857  /* If we have matching file */
858  if (Oplock->FileObject == Stack->FileObject)
859  {
860  /* Oplock wasn't broken (still exclusive), easy case */
861  if (!BooleanFlagOn(Oplock->Flags, (BROKEN_ANY | PENDING_LOCK)))
862  {
863  /* Remove the cancel routine we set previously */
864  IoAcquireCancelSpinLock(&Oplock->ExclusiveIrp->CancelIrql);
865  IoSetCancelRoutine(Oplock->ExclusiveIrp, NULL);
866  IoReleaseCancelSpinLock(Oplock->ExclusiveIrp->CancelIrql);
867 
868  /* And return the fact we broke the oplock to no oplock */
869  Oplock->ExclusiveIrp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
870  Oplock->ExclusiveIrp->IoStatus.Status = STATUS_SUCCESS;
871 
872  /* And complete! */
873  IoCompleteRequest(Oplock->ExclusiveIrp, IO_DISK_INCREMENT);
874  Oplock->ExclusiveIrp = NULL;
875  }
876 
877  /* If no pending, we can safely dereference the file object */
878  if (!BooleanFlagOn(Oplock->Flags, PENDING_LOCK))
879  {
880  ObDereferenceObject(Oplock->FileObject);
881  }
882 
883  /* Now, remove the oplock */
884  Oplock->FileObject = NULL;
885  Oplock->Flags = NO_OPLOCK;
886 
887  /* And complete any waiting IRP */
888  for (NextEntry = Oplock->WaitListHead.Flink;
889  NextEntry != &Oplock->WaitListHead;
890  NextEntry = NextEntry->Flink)
891  {
892  WaitCtx = CONTAINING_RECORD(NextEntry, WAIT_CONTEXT, WaitListEntry);
894  }
895  }
896  }
897  }
898  ExReleaseFastMutexUnsafe(Oplock->IntLock);
899 }
900 
901 NTSTATUS
902 NTAPI
904  IN PIO_STACK_LOCATION Stack,
905  IN PIRP Irp,
906  IN PVOID Context,
909 {
910  PLIST_ENTRY NextEntry;
911  PWAIT_CONTEXT WaitCtx;
912  PIRP ListIrp;
913  KEVENT WaitEvent;
914 
915  DPRINT("FsRtlOplockBreakToNone(%p, %p, %p, %p, %p, %p)\n", Oplock, Stack, Irp, Context, CompletionRoutine, PostIrpRoutine);
916 
917  ExAcquireFastMutexUnsafe(Oplock->IntLock);
918 
919  /* No oplock to break! */
920  if (Oplock->Flags == NO_OPLOCK)
921  {
922  ExReleaseFastMutexUnsafe(Oplock->IntLock);
923  return STATUS_SUCCESS;
924  }
925 
926  /* Not broken yet, but set... Let's do it!
927  * Also, we won't break a shared oplock
928  */
929  if (!BooleanFlagOn(Oplock->Flags, (BROKEN_ANY | PENDING_LOCK | LEVEL_2_OPLOCK)))
930  {
931  /* Remove our cancel routine, no longer needed */
932  IoAcquireCancelSpinLock(&Oplock->ExclusiveIrp->CancelIrql);
933  IoSetCancelRoutine(Oplock->ExclusiveIrp, NULL);
934  IoReleaseCancelSpinLock(Oplock->ExclusiveIrp->CancelIrql);
935 
936  /* If the IRP got canceled, we need to cleanup a bit */
937  if (Oplock->ExclusiveIrp->Cancel)
938  {
939  /* Return cancelation */
940  Oplock->ExclusiveIrp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
941  Oplock->ExclusiveIrp->IoStatus.Status = STATUS_CANCELLED;
942  IoCompleteRequest(Oplock->ExclusiveIrp, IO_DISK_INCREMENT);
943 
944  /* No oplock left */
945  Oplock->Flags = NO_OPLOCK;
946  Oplock->ExclusiveIrp = NULL;
947 
948  /* No need for the FO anymore */
949  ObDereferenceObject(Oplock->FileObject);
950  Oplock->FileObject = NULL;
951 
952  /* And complete any waiting IRP */
953  for (NextEntry = Oplock->WaitListHead.Flink;
954  NextEntry != &Oplock->WaitListHead;
955  NextEntry = NextEntry->Flink)
956  {
957  WaitCtx = CONTAINING_RECORD(NextEntry, WAIT_CONTEXT, WaitListEntry);
959  }
960 
961  /* Done! */
962  ExReleaseFastMutexUnsafe(Oplock->IntLock);
963 
964  return STATUS_SUCCESS;
965  }
966 
967  /* Easier break, just complete :-) */
968  Oplock->ExclusiveIrp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
969  Oplock->ExclusiveIrp->IoStatus.Status = STATUS_SUCCESS;
970  IoCompleteRequest(Oplock->ExclusiveIrp, IO_DISK_INCREMENT);
971 
972  /* And remove our exclusive IRP */
973  Oplock->ExclusiveIrp = NULL;
974  SetFlag(Oplock->Flags, BROKEN_TO_NONE);
975  }
976  /* Shared lock */
977  else if (Oplock->Flags == LEVEL_2_OPLOCK)
978  {
979  /* Complete any IRP in the shared lock */
980  for (NextEntry = Oplock->SharedListHead.Flink;
981  NextEntry != &Oplock->SharedListHead;
982  NextEntry = NextEntry->Flink)
983  {
984  ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
985  FsRtlRemoveAndCompleteIrp(ListIrp);
986  }
987 
988  /* No lock left */
989  Oplock->Flags = NO_OPLOCK;
990 
991  /* Done */
992  ExReleaseFastMutexUnsafe(Oplock->IntLock);
993  return STATUS_SUCCESS;
994  }
995  /* If it was broken to level 2, break it to none from level 2 */
996  else if (Oplock->Flags & BROKEN_TO_LEVEL_2)
997  {
998  ClearFlag(Oplock->Flags, BROKEN_TO_LEVEL_2);
999  SetFlag(Oplock->Flags, BROKEN_TO_NONE_FROM_LEVEL_2);
1000  }
1001  /* If it was pending, just drop the lock */
1002  else if (BooleanFlagOn(Oplock->Flags, PENDING_LOCK))
1003  {
1004  Oplock->Flags = NO_OPLOCK;
1005  Oplock->FileObject = NULL;
1006 
1007  ExReleaseFastMutexUnsafe(Oplock->IntLock);
1008  return STATUS_SUCCESS;
1009  }
1010 
1011  /* If that's ours, job done */
1012  if (Oplock->FileObject == Stack->FileObject)
1013  {
1014  ExReleaseFastMutexUnsafe(Oplock->IntLock);
1015  return STATUS_SUCCESS;
1016  }
1017 
1018  /* Otherwise, wait on the IRP */
1019  if (Stack->MajorFunction != IRP_MJ_CREATE || !BooleanFlagOn(Stack->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED))
1020  {
1021  FsRtlWaitOnIrp(Oplock, Irp, Context, CompletionRoutine, PostIrpRoutine, &WaitEvent);
1022 
1023  ExReleaseFastMutexUnsafe(Oplock->IntLock);
1024 
1025  return STATUS_SUCCESS;
1026  }
1027  /* Done */
1028  else
1029  {
1030  ExReleaseFastMutexUnsafe(Oplock->IntLock);
1032  }
1033 }
1034 
1035 NTSTATUS
1036 NTAPI
1038  IN PIO_STACK_LOCATION Stack,
1039  IN PIRP Irp,
1040  IN PVOID Context,
1043 {
1044  PLIST_ENTRY NextEntry;
1045  PWAIT_CONTEXT WaitCtx;
1046  KEVENT WaitEvent;
1047 
1048  DPRINT("FsRtlOplockBreakToII(%p, %p, %p, %p, %p, %p)\n", Oplock, Stack, Irp, Context, CompletionRoutine, PostIrpRoutine);
1049 
1050  ExAcquireFastMutexUnsafe(Oplock->IntLock);
1051 
1052  /* If our lock, or if not exclusively locked, nothing to break! */
1053  if (!BooleanFlagOn(Oplock->Flags, EXCLUSIVE_LOCK) || Oplock->FileObject == Stack->FileObject)
1054  {
1055  ExReleaseFastMutexUnsafe(Oplock->IntLock);
1056  return STATUS_SUCCESS;
1057  }
1058 
1059  /* If already broken or not set yet */
1060  if (BooleanFlagOn(Oplock->Flags, (BROKEN_ANY | PENDING_LOCK)))
1061  {
1062  /* Drop oplock if pending */
1063  if (BooleanFlagOn(Oplock->Flags, PENDING_LOCK))
1064  {
1065  Oplock->Flags = NO_OPLOCK;
1066  Oplock->FileObject = NULL;
1067 
1068  ExReleaseFastMutexUnsafe(Oplock->IntLock);
1069  return STATUS_SUCCESS;
1070  }
1071 
1072  }
1073  /* To break! */
1074  else
1075  {
1076  /* Drop the cancel routine of the exclusive IRP */
1077  IoAcquireCancelSpinLock(&Oplock->ExclusiveIrp->CancelIrql);
1078  IoSetCancelRoutine(Oplock->ExclusiveIrp, NULL);
1079  IoReleaseCancelSpinLock(Oplock->ExclusiveIrp->CancelIrql);
1080 
1081  /* If it was canceled in between, break to no oplock */
1082  if (Oplock->ExclusiveIrp->Cancel)
1083  {
1084  /* Complete the IRP with cancellation */
1085  Oplock->ExclusiveIrp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
1086  Oplock->ExclusiveIrp->IoStatus.Status = STATUS_CANCELLED;
1087  IoCompleteRequest(Oplock->ExclusiveIrp, IO_DISK_INCREMENT);
1088 
1089  /* And mark we have no longer lock */
1090  Oplock->Flags = NO_OPLOCK;
1091  Oplock->ExclusiveIrp = NULL;
1092  ObDereferenceObject(Oplock->FileObject);
1093  Oplock->FileObject = NULL;
1094 
1095  /* Finally, complete any waiter */
1096  for (NextEntry = Oplock->WaitListHead.Flink;
1097  NextEntry != &Oplock->WaitListHead;
1098  NextEntry = NextEntry->Flink)
1099  {
1100  WaitCtx = CONTAINING_RECORD(NextEntry, WAIT_CONTEXT, WaitListEntry);
1102  }
1103 
1104  ExReleaseFastMutexUnsafe(Oplock->IntLock);
1105 
1106  return STATUS_SUCCESS;
1107  }
1108 
1109  /* It wasn't canceled, so break to shared unless we were alone, in that case we break to no lock! */
1110  Oplock->ExclusiveIrp->IoStatus.Status = STATUS_SUCCESS;
1111  if (BooleanFlagOn(Oplock->Flags, (BATCH_OPLOCK | LEVEL_1_OPLOCK)))
1112  {
1113  SetFlag(Oplock->Flags, BROKEN_TO_LEVEL_2);
1114  Oplock->ExclusiveIrp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_LEVEL_2;
1115  }
1116  else
1117  {
1118  SetFlag(Oplock->Flags, BROKEN_TO_NONE);
1119  Oplock->ExclusiveIrp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
1120  }
1121  /* And complete */
1122  IoCompleteRequest(Oplock->ExclusiveIrp, IO_DISK_INCREMENT);
1123  Oplock->ExclusiveIrp = NULL;
1124  }
1125 
1126  /* Wait if required */
1127  if (Stack->MajorFunction != IRP_MJ_CREATE || !BooleanFlagOn(Stack->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED))
1128  {
1129  FsRtlWaitOnIrp(Oplock, Irp, Context, CompletionRoutine, PostIrpRoutine, &WaitEvent);
1130 
1131  ExReleaseFastMutexUnsafe(Oplock->IntLock);
1132 
1133  return STATUS_SUCCESS;
1134  }
1135  else
1136  {
1137  ExReleaseFastMutexUnsafe(Oplock->IntLock);
1139  }
1140 }
1141 
1142 /* PUBLIC FUNCTIONS **********************************************************/
1143 
1144 /*++
1145  * @name FsRtlCheckOplock
1146  * @unimplemented
1147  *
1148  * FILLME
1149  *
1150  * @param Oplock
1151  * FILLME
1152  *
1153  * @param Irp
1154  * FILLME
1155  *
1156  * @param Context
1157  * FILLME
1158  *
1159  * @param CompletionRoutine
1160  * FILLME
1161  *
1162  * @param PostIrpRoutine
1163  * FILLME
1164  *
1165  * @return None
1166  *
1167  * @remarks None
1168  *
1169  *--*/
1170 NTSTATUS
1171 NTAPI
1173  IN PIRP Irp,
1174  IN PVOID Context,
1177 {
1178  PINTERNAL_OPLOCK IntOplock;
1179  PIO_STACK_LOCATION Stack;
1183 
1184 #define BreakToIIIfRequired \
1185  if (IntOplock->Flags != LEVEL_2_OPLOCK || IntOplock->FileObject != Stack->FileObject) \
1186  return FsRtlOplockBreakToII(IntOplock, Stack, Irp, Context, CompletionRoutine, PostIrpRoutine)
1187 
1188 #define BreakToNoneIfRequired \
1189  if (IntOplock->Flags == LEVEL_2_OPLOCK || IntOplock->FileObject != Stack->FileObject) \
1190  return FsRtlOplockBreakToNone(IntOplock, Stack, Irp, Context, CompletionRoutine, PostIrpRoutine)
1191 
1192  DPRINT("FsRtlCheckOplock(%p, %p, %p, %p, %p)\n", Oplock, Irp, Context, CompletionRoutine, PostIrpRoutine);
1193 
1194  IntOplock = *Oplock;
1195 
1196  /* No oplock, easy! */
1197  if (IntOplock == NULL)
1198  {
1199  return STATUS_SUCCESS;
1200  }
1201 
1202  /* No sense on paging */
1203  if (Irp->Flags & IRP_PAGING_IO)
1204  {
1205  return STATUS_SUCCESS;
1206  }
1207 
1208  /* No oplock, easy (bis!) */
1209  if (IntOplock->Flags == NO_OPLOCK)
1210  {
1211  return STATUS_SUCCESS;
1212  }
1213 
1215 
1216  /* If cleanup, cleanup the associated oplock & return */
1217  if (Stack->MajorFunction == IRP_MJ_CLEANUP)
1218  {
1219  FsRtlOplockCleanup(IntOplock, Stack);
1220  return STATUS_SUCCESS;
1221  }
1222  else if (Stack->MajorFunction == IRP_MJ_LOCK_CONTROL)
1223  {
1224  /* OK for filter */
1225  if (BooleanFlagOn(IntOplock->Flags, FILTER_OPLOCK))
1226  {
1227  return STATUS_SUCCESS;
1228  }
1229 
1230  /* Lock operation, we will have to break to no lock if shared or not us */
1232 
1233  return STATUS_SUCCESS;
1234  }
1235  else if (Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL)
1236  {
1237  /* FSCTL should be safe, unless user wants a write FSCTL */
1238  if (Stack->Parameters.FileSystemControl.FsControlCode != FSCTL_SET_ZERO_DATA)
1239  {
1240  return STATUS_SUCCESS;
1241  }
1242 
1243  /* We will have to break for write if shared or not us! */
1245 
1246  return STATUS_SUCCESS;
1247  }
1248  else if (Stack->MajorFunction == IRP_MJ_WRITE)
1249  {
1250  /* Write operation, we will have to break if shared or not us */
1252 
1253  return STATUS_SUCCESS;
1254  }
1255  else if (Stack->MajorFunction == IRP_MJ_READ)
1256  {
1257  /* If that's filter oplock, it's alright */
1258  if (BooleanFlagOn(IntOplock->Flags, FILTER_OPLOCK))
1259  {
1260  return STATUS_SUCCESS;
1261  }
1262 
1263  /* Otherwise, we need to break to shared oplock */
1265 
1266  return STATUS_SUCCESS;
1267  }
1268  else if (Stack->MajorFunction == IRP_MJ_CREATE)
1269  {
1270  DesiredAccess = Stack->Parameters.Create.SecurityContext->DesiredAccess;
1271 
1272  /* If that's just for reading, the oplock is fine */
1275  {
1276  return STATUS_SUCCESS;
1277  }
1278 
1279  /* Otherwise, check the disposition */
1280  CreateDisposition = (Stack->Parameters.Create.Options >> 24) & 0x000000FF;
1284  {
1285  /* Not us, we have to break the oplock! */
1287 
1288  return STATUS_SUCCESS;
1289  }
1290 
1291  /* It's fine, we can have the oplock shared */
1293 
1294  return STATUS_SUCCESS;
1295  }
1296  else if (Stack->MajorFunction == IRP_MJ_FLUSH_BUFFERS)
1297  {
1298  /* We need to share the lock, if not done yet! */
1300 
1301  return STATUS_SUCCESS;
1302  }
1303  else if (Stack->MajorFunction == IRP_MJ_SET_INFORMATION)
1304  {
1305  /* Only deal with really specific classes */
1306  FileInfo = Stack->Parameters.SetFile.FileInformationClass;
1309  {
1310  /* No need to break */
1311  if (!BooleanFlagOn(IntOplock->Flags, (FILTER_OPLOCK | BATCH_OPLOCK)))
1312  {
1313  return STATUS_SUCCESS;
1314  }
1315  /* Otherwise break to none */
1316  else
1317  {
1319 
1320  return STATUS_SUCCESS;
1321  }
1322  }
1323  else if (FileInfo == FileAllocationInformation)
1324  {
1326 
1327  return STATUS_SUCCESS;
1328  }
1329  else if (FileInfo == FileEndOfFileInformation)
1330  {
1331  /* Advance only, nothing to do */
1332  if (Stack->Parameters.SetFile.AdvanceOnly)
1333  {
1334  return STATUS_SUCCESS;
1335  }
1336 
1337  /* Otherwise, attempt to break to none */
1339 
1340  return STATUS_SUCCESS;
1341  }
1342  }
1343 
1344 #undef BreakToIIIfRequired
1345 #undef BreakToNoneIfRequired
1346 
1347  return STATUS_SUCCESS;
1348 }
1349 
1350 /*++
1351  * @name FsRtlCurrentBatchOplock
1352  * @implemented
1353  *
1354  * FILLME
1355  *
1356  * @param Oplock
1357  * FILLME
1358  *
1359  * @return None
1360  *
1361  * @remarks None
1362  *
1363  *--*/
1364 BOOLEAN
1365 NTAPI
1367 {
1368  PINTERNAL_OPLOCK IntOplock;
1369 
1370  PAGED_CODE();
1371 
1372  DPRINT("FsRtlCurrentBatchOplock(%p)\n", Oplock);
1373 
1374  IntOplock = *Oplock;
1375 
1376  /* Only return true if batch or filter oplock */
1377  if (IntOplock != NULL &&
1378  BooleanFlagOn(IntOplock->Flags, (FILTER_OPLOCK | BATCH_OPLOCK)))
1379  {
1380  return TRUE;
1381  }
1382 
1383  return FALSE;
1384 }
1385 
1386 /*++
1387  * @name FsRtlInitializeOplock
1388  * @implemented
1389  *
1390  * FILLME
1391  *
1392  * @param Oplock
1393  * FILLME
1394  *
1395  * @return None
1396  *
1397  * @remarks None
1398  *
1399  *--*/
1400 VOID
1401 NTAPI
1403 {
1404  PAGED_CODE();
1405 
1406  /* Nothing to do */
1407  DPRINT("FsRtlInitializeOplock(%p)\n", Oplock);
1408 }
1409 
1410 /*++
1411  * @name FsRtlOplockFsctrl
1412  * @unimplemented
1413  *
1414  * FILLME
1415  *
1416  * @param Oplock
1417  * FILLME
1418  *
1419  * @param Irp
1420  * FILLME
1421  *
1422  * @param OpenCount
1423  * FILLME
1424  *
1425  * @return None
1426  *
1427  * @remarks None
1428  *
1429  *--*/
1430 NTSTATUS
1431 NTAPI
1433  IN PIRP Irp,
1434  IN ULONG OpenCount)
1435 {
1436  PIO_STACK_LOCATION Stack;
1437  PINTERNAL_OPLOCK IntOplock;
1438 
1439  PAGED_CODE();
1440 
1441  DPRINT("FsRtlOplockFsctrl(%p, %p, %lu)\n", Oplock, Irp, OpenCount);
1442 
1443  IntOplock = *Oplock;
1445  /* Make sure it's not called on create */
1446  if (Stack->MajorFunction != IRP_MJ_CREATE)
1447  {
1448  switch (Stack->Parameters.FileSystemControl.FsControlCode)
1449  {
1451  return FsRtlOplockBreakNotify(IntOplock, Stack, Irp);
1452 
1454  return FsRtlAcknowledgeOplockBreak(IntOplock, Stack, Irp, FALSE);
1455 
1457  return FsRtlOpBatchBreakClosePending(IntOplock, Stack, Irp);
1458 
1460  /* We can only grant level 1 if synchronous, and only a single handle to it
1461  * (plus, not a paging IO - obvious, and not cleanup done...)
1462  */
1463  if (OpenCount == 1 && !IoIsOperationSynchronous(Irp) &&
1465  {
1467  }
1468  /* Not matching, fail */
1469  else
1470  {
1471  Irp->IoStatus.Status = STATUS_OPLOCK_NOT_GRANTED;
1474  }
1475 
1477  /* Shared can only be granted if no byte-range lock, and async operation
1478  * (plus, not a paging IO - obvious, and not cleanup done...)
1479  */
1480  if (OpenCount == 0 && !IoIsOperationSynchronous(Irp) &&
1482  {
1483  return FsRtlRequestOplockII(Oplock, Stack, Irp);
1484  }
1485  /* Not matching, fail */
1486  else
1487  {
1488  Irp->IoStatus.Status = STATUS_OPLOCK_NOT_GRANTED;
1491  }
1492 
1494  return FsRtlAcknowledgeOplockBreak(IntOplock, Stack, Irp, TRUE);
1495 
1497  /* Batch oplock can only be granted if there's a byte-range lock and async operation
1498  * (plus, not a paging IO - obvious, and not cleanup done...)
1499  */
1500  if (OpenCount == 1 && !IoIsOperationSynchronous(Irp) &&
1502  {
1503  return FsRtlRequestExclusiveOplock(Oplock, Stack, Irp, EXCLUSIVE_LOCK | BATCH_OPLOCK);
1504  }
1505  /* Not matching, fail */
1506  else
1507  {
1508  Irp->IoStatus.Status = STATUS_OPLOCK_NOT_GRANTED;
1511  }
1512 
1514  /* Filter oplock can only be granted if there's a byte-range lock and async operation
1515  * (plus, not a paging IO - obvious, and not cleanup done...)
1516  */
1517  if (OpenCount == 1 && !IoIsOperationSynchronous(Irp) &&
1519  {
1520  return FsRtlRequestExclusiveOplock(Oplock, Stack, Irp, EXCLUSIVE_LOCK | FILTER_OPLOCK);
1521  }
1522  /* Not matching, fail */
1523  else
1524  {
1525  Irp->IoStatus.Status = STATUS_OPLOCK_NOT_GRANTED;
1528  }
1529 
1530  default:
1531  Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1533  return STATUS_INVALID_PARAMETER;
1534  }
1535  }
1536 
1537  /* That's a create operation! Only grant exclusive if there's a single user handle opened
1538  * and we're only performing reading operations.
1539  */
1540  if (OpenCount == 1 &&
1541  !(Stack->Parameters.Create.SecurityContext->DesiredAccess & ~(FILE_READ_ATTRIBUTES | FILE_READ_DATA)) &&
1543  {
1545  }
1546 
1548 }
1549 
1550 /*++
1551  * @name FsRtlOplockIsFastIoPossible
1552  * @implemented
1553  *
1554  * FILLME
1555  *
1556  * @param Oplock
1557  * FILLME
1558  *
1559  * @return None
1560  *
1561  * @remarks None
1562  *
1563  *--*/
1564 BOOLEAN
1565 NTAPI
1567 {
1568  PINTERNAL_OPLOCK IntOplock;
1569 
1570  PAGED_CODE();
1571 
1572  DPRINT("FsRtlOplockIsFastIoPossible(%p)\n", Oplock);
1573 
1574  IntOplock = *Oplock;
1575 
1576  /* If there's a shared oplock or if it was used for write operation, deny FastIO */
1577  if (IntOplock != NULL &&
1578  BooleanFlagOn(IntOplock->Flags, (BROKEN_ANY | LEVEL_2_OPLOCK)))
1579  {
1580  return FALSE;
1581  }
1582 
1583  return TRUE;
1584 }
1585 
1586 /*++
1587  * @name FsRtlUninitializeOplock
1588  * @implemented
1589  *
1590  * FILLME
1591  *
1592  * @param Oplock
1593  * FILLME
1594  *
1595  * @return None
1596  *
1597  * @remarks None
1598  *
1599  *--*/
1600 VOID
1601 NTAPI
1603 {
1604  PINTERNAL_OPLOCK IntOplock;
1605  PLIST_ENTRY NextEntry;
1606  PWAIT_CONTEXT WaitCtx;
1607  PIRP Irp;
1608  PIO_STACK_LOCATION Stack;
1609 
1610  DPRINT("FsRtlUninitializeOplock(%p)\n", Oplock);
1611 
1612  IntOplock = *Oplock;
1613 
1614  /* No oplock, nothing to do */
1615  if (IntOplock == NULL)
1616  {
1617  return;
1618  }
1619 
1620  /* Caller won't have the oplock anymore */
1621  *Oplock = NULL;
1622 
1623  _SEH2_TRY
1624  {
1625  ExAcquireFastMutexUnsafe(IntOplock->IntLock);
1626 
1627  /* If we had IRPs waiting for the lock, complete them */
1628  for (NextEntry = IntOplock->WaitListHead.Flink;
1629  NextEntry != &IntOplock->WaitListHead;
1630  NextEntry = NextEntry->Flink)
1631  {
1632  WaitCtx = CONTAINING_RECORD(NextEntry, WAIT_CONTEXT, WaitListEntry);
1633  Irp = WaitCtx->Irp;
1634 
1635  RemoveEntryList(&WaitCtx->WaitListEntry);
1636  /* Remove the cancel routine */
1637  IoAcquireCancelSpinLock(&Irp->CancelIrql);
1639  IoReleaseCancelSpinLock(Irp->CancelIrql);
1640 
1641  /* And complete */
1642  Irp->IoStatus.Information = 0;
1643  WaitCtx->CompletionRoutine(WaitCtx->CompletionContext, WaitCtx->Irp);
1644 
1645  ExFreePoolWithTag(WaitCtx, TAG_OPLOCK);
1646  }
1647 
1648  /* If we had shared IRPs (LEVEL_2), complete them */
1649  for (NextEntry = IntOplock->SharedListHead.Flink;
1650  NextEntry != &IntOplock->SharedListHead;
1651  NextEntry = NextEntry->Flink)
1652  {
1653  Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
1654 
1655  RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
1656 
1657  /* Remvoe the cancel routine */
1658  IoAcquireCancelSpinLock(&Irp->CancelIrql);
1660  IoReleaseCancelSpinLock(Irp->CancelIrql);
1661 
1662  /* Dereference the file object */
1665 
1666  /* And complete */
1667  Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
1668  Irp->IoStatus.Status = STATUS_SUCCESS;
1670  }
1671 
1672  /* If we have an exclusive IRP, complete it */
1673  Irp = IntOplock->ExclusiveIrp;
1674  if (Irp != NULL)
1675  {
1676  /* Remvoe the cancel routine */
1677  IoAcquireCancelSpinLock(&Irp->CancelIrql);
1679  IoReleaseCancelSpinLock(Irp->CancelIrql);
1680 
1681  /* And complete */
1682  Irp->IoStatus.Information = FILE_OPLOCK_BROKEN_TO_NONE;
1683  Irp->IoStatus.Status = STATUS_SUCCESS;
1685  IntOplock->ExclusiveIrp = NULL;
1686 
1687  /* If still referenced, dereference */
1688  if (IntOplock->FileObject != NULL)
1689  {
1690  ObDereferenceObject(IntOplock->FileObject);
1691  }
1692  }
1693  }
1695  {
1696  ExReleaseFastMutexUnsafe(IntOplock->IntLock);
1697  }
1698  _SEH2_END;
1699 
1700  ExFreePoolWithTag(IntOplock->IntLock, TAG_OPLOCK);
1701  ExFreePoolWithTag(IntOplock, TAG_OPLOCK);
1702 }
1703 
PFILE_OBJECT FileObject
Definition: oplock.c:37
LONG_PTR FASTCALL ObfDereferenceObject(IN PVOID Object)
Definition: obref.c:320
PVOID CompletionContext
Definition: oplock.c:51
PFAST_MUTEX IntLock
Definition: oplock.c:43
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
struct _KEVENT * PKEVENT
#define PENDING_LOCK
Definition: oplock.c:22
#define IRP_MJ_CREATE
Definition: rdpdr.c:44
#define BATCH_OPLOCK
Definition: oplock.c:17
#define IRP_MJ_FLUSH_BUFFERS
NTSTATUS FsRtlOpBatchBreakClosePending(IN PINTERNAL_OPLOCK Oplock, IN PIO_STACK_LOCATION Stack, IN PIRP Irp)
Definition: oplock.c:472
_In_ PIRP Irp
Definition: csq.h:116
LIST_ENTRY SharedListHead
Definition: oplock.c:39
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
struct _LIST_ENTRY * Blink
Definition: typedefs.h:120
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
struct _INTERNAL_OPLOCK INTERNAL_OPLOCK
#define FILTER_OPLOCK
Definition: oplock.c:18
LONG NTSTATUS
Definition: precomp.h:26
NTSTATUS FsRtlAcknowledgeOplockBreak(IN PINTERNAL_OPLOCK Oplock, IN PIO_STACK_LOCATION Stack, IN PIRP Irp, IN BOOLEAN SwitchToLevel2)
Definition: oplock.c:358
VOID NTAPI IoAcquireCancelSpinLock(OUT PKIRQL Irql)
Definition: util.c:56
#define FILE_OPLOCK_BROKEN_TO_LEVEL_2
#define FSCTL_OPLOCK_BREAK_ACK_NO_2
Definition: nt_native.h:846
#define POOL_COLD_ALLOCATION
NTSTATUS NTAPI FsRtlOplockBreakToII(IN PINTERNAL_OPLOCK Oplock, IN PIO_STACK_LOCATION Stack, IN PIRP Irp, IN PVOID Context, IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL)
Definition: oplock.c:1037
#define FILE_OVERWRITE
Definition: from_kernel.h:57
struct _WAIT_CONTEXT * PWAIT_CONTEXT
LIST_ENTRY WaitListHead
Definition: oplock.c:41
#define STATUS_INVALID_OPLOCK_PROTOCOL
Definition: ntstatus.h:449
#define FSCTL_OPBATCH_ACK_CLOSE_PENDING
Definition: nt_native.h:830
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
#define TAG_OPLOCK
Definition: oplock.c:30
VOID NTAPI FsRtlUninitializeOplock(IN POPLOCK Oplock)
Definition: oplock.c:1602
IRP
Definition: iotypes.h:2462
BOOLEAN NTAPI IoIsOperationSynchronous(IN PIRP Irp)
Definition: irp.c:1882
#define InsertTailList(ListHead, Entry)
#define BROKEN_TO_NONE
Definition: oplock.c:25
IoSetCancelRoutine(Irp, CancelRoutine)
#define BreakToIIIfRequired
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
#define FSCTL_REQUEST_BATCH_OPLOCK
Definition: nt_native.h:828
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define FILE_RESERVE_OPFILTER
Definition: from_kernel.h:45
VOID FASTCALL ExReleaseFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:31
#define FSCTL_SET_ZERO_DATA
Definition: winioctl.h:141
#define FILE_WRITE_ATTRIBUTES
Definition: nt_native.h:649
VOID FASTCALL ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:86
#define PAGED_CODE()
Definition: video.h:57
#define FILE_SHARE_READ
Definition: compat.h:125
VOID NTAPI FsRtlCancelExclusiveIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: oplock.c:586
_SEH2_TRY
Definition: create.c:4250
ULONG_PTR SavedInformation
Definition: oplock.c:53
uint32_t ULONG_PTR
Definition: typedefs.h:63
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
NTSTATUS NTAPI FsRtlOplockFsctrl(IN POPLOCK Oplock, IN PIRP Irp, IN ULONG OpenCount)
Definition: oplock.c:1432
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define IO_DISK_INCREMENT
Definition: iotypes.h:567
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define LEVEL_2_OPLOCK
Definition: oplock.c:19
PIRP ExclusiveIrp
Definition: oplock.c:35
#define FSCTL_OPLOCK_BREAK_NOTIFY
Definition: nt_native.h:831
VOID FsRtlWaitOnIrp(IN PINTERNAL_OPLOCK Oplock, IN PIRP Irp, IN PVOID CompletionContext, IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine, IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine, IN PKEVENT WaitEvent)
Definition: oplock.c:150
_In_ PMEMORY_AREA _In_ PVOID _In_ BOOLEAN Locked
Definition: newmm.h:260
#define FILE_READ_DATA
Definition: nt_native.h:628
VOID NTAPI FsRtlCancelWaitIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: oplock.c:116
#define BROKEN_ANY
Definition: oplock.c:28
NTSTATUS FsRtlOplockBreakNotify(IN PINTERNAL_OPLOCK Oplock, IN PIO_STACK_LOCATION Stack, IN PIRP Irp)
Definition: oplock.c:241
_Unreferenced_parameter_ PVOID * CompletionContext
Definition: cdprocs.h:1130
VOID(NTAPI * POPLOCK_WAIT_COMPLETE_ROUTINE)(_In_ PVOID Context, _In_ PIRP Irp)
Definition: fsrtltypes.h:253
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define FILE_OVERWRITE_IF
Definition: from_kernel.h:58
#define _SEH2_AbnormalTermination()
Definition: pseh2_64.h:13
#define STATUS_OPLOCK_NOT_GRANTED
Definition: ntstatus.h:448
VOID FsRtlRemoveAndCompleteWaitIrp(IN PWAIT_CONTEXT WaitCtx)
Definition: oplock.c:86
#define IoCompleteRequest
Definition: irp.c:1240
void DPRINT(...)
Definition: polytest.cpp:61
NTSTATUS FsRtlRequestOplockII(IN POPLOCK Oplock, IN PIO_STACK_LOCATION Stack, IN PIRP Irp)
Definition: oplock.c:736
#define FILE_WRITE_DATA
Definition: nt_native.h:631
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
Definition: nt_native.h:829
FAST_MUTEX
Definition: extypes.h:17
VOID FsRtlOplockCleanup(IN PINTERNAL_OPLOCK Oplock, IN PIO_STACK_LOCATION Stack)
Definition: oplock.c:818
VOID FASTCALL IofCompleteRequest(IN PIRP Irp, IN CCHAR PriorityBoost)
Definition: irp.c:1308
enum _FILE_INFORMATION_CLASS FILE_INFORMATION_CLASS
Definition: directory.c:44
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
struct _INTERNAL_OPLOCK * PINTERNAL_OPLOCK
#define FSCTL_REQUEST_OPLOCK_LEVEL_2
Definition: nt_native.h:827
VOID FASTCALL ExAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:75
LIST_ENTRY WaitListEntry
Definition: oplock.c:48
struct _WAIT_CONTEXT WAIT_CONTEXT
VOID NTAPI FsRtlInitializeOplock(IN OUT POPLOCK Oplock)
Definition: oplock.c:1402
#define IRP_MJ_FILE_SYSTEM_CONTROL
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
#define BROKEN_TO_CLOSE_PENDING
Definition: oplock.c:27
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
NTSTATUS FsRtlRequestExclusiveOplock(IN POPLOCK Oplock, IN PIO_STACK_LOCATION Stack, IN PIRP Irp, IN ULONG Flags)
Definition: oplock.c:632
BOOLEAN NTAPI FsRtlCurrentBatchOplock(IN POPLOCK Oplock)
Definition: oplock.c:1366
* PFILE_OBJECT
Definition: iotypes.h:1954
#define READ_CONTROL
Definition: nt_native.h:58
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
VOID FsRtlRemoveAndCompleteIrp(IN PIRP Irp)
Definition: oplock.c:285
#define BROKEN_TO_LEVEL_2
Definition: oplock.c:24
#define FILE_EXECUTE
Definition: nt_native.h:642
#define BreakToNoneIfRequired
Definition: typedefs.h:117
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine
Definition: oplock.c:50
#define FSCTL_REQUEST_OPLOCK_LEVEL_1
Definition: nt_native.h:826
#define SYNCHRONIZE
Definition: nt_native.h:61
VOID NTAPI FsRtlCompletionRoutinePriv(IN PVOID Context, IN PIRP Irp)
Definition: oplock.c:71
ClearFlag(Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT)
#define FILE_SHARE_VALID_FLAGS
Definition: nt_native.h:683
VOID NTAPI IoReleaseCancelSpinLock(IN KIRQL Irql)
Definition: util.c:150
Status
Definition: gdiplustypes.h:24
#define NO_OPLOCK
Definition: oplock.c:15
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
#define EXCLUSIVE_LOCK
Definition: oplock.c:21
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
#define LEVEL_1_OPLOCK
Definition: oplock.c:16
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
PFILE_OBJECT FileObject
Definition: iotypes.h:2812
_SEH2_END
Definition: create.c:4424
* PFAST_MUTEX
Definition: extypes.h:17
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
VOID FASTCALL ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:23
#define FO_CLEANUP_COMPLETE
Definition: iotypes.h:1746
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG _In_ PUNICODE_STRING _In_ PACCESS_MASK DesiredAccess
Definition: create.c:4157
#define FSCTL_REQUEST_FILTER_OPLOCK
Definition: nt_native.h:849
_SEH2_FINALLY
Definition: create.c:4395
#define FILE_READ_EA
Definition: nt_native.h:638
NTSTATUS NTAPI FsRtlOplockBreakToNone(IN PINTERNAL_OPLOCK Oplock, IN PIO_STACK_LOCATION Stack, IN PIRP Irp, IN PVOID Context, IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL)
Definition: oplock.c:903
PIRP Irp
Definition: oplock.c:49
DWORD OpenCount
Definition: legacy.c:25
#define IRP_PAGING_IO
#define STATUS_OPLOCK_BREAK_IN_PROGRESS
Definition: ntstatus.h:87
#define IRP_MJ_LOCK_CONTROL
Definition: rdpdr.c:53
#define IRP_MJ_READ
Definition: rdpdr.c:46
#define IRP_MJ_CLEANUP
#define OUT
Definition: typedefs.h:39
#define ObReferenceObject
Definition: obfuncs.h:204
struct FileInfo FileInfo
_In_ PIRP _In_opt_ PVOID _In_opt_ POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine
Definition: fsrtlfuncs.h:673
#define IRP_MJ_SET_INFORMATION
Definition: rdpdr.c:49
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define BROKEN_TO_NONE_FROM_LEVEL_2
Definition: oplock.c:26
#define ULONG_PTR
Definition: config.h:101
#define IRP_MJ_WRITE
Definition: rdpdr.c:47
Definition: fbtusb.h:86
NTSTATUS NTAPI FsRtlCheckOplock(IN POPLOCK Oplock, IN PIRP Irp, IN PVOID Context, IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL)
Definition: oplock.c:1172
#define POOL_RAISE_IF_ALLOCATION_FAILURE
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define FILE_OPLOCK_BROKEN_TO_NONE
#define KeGetCurrentThread
Definition: hal.h:44
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2771
return STATUS_SUCCESS
Definition: btrfs.c:2725
VOID NTAPI FsRtlNotifyCompletion(IN PVOID Context, IN PIRP Irp)
Definition: oplock.c:58
IoMarkIrpPending(Irp)
VOID(NTAPI * POPLOCK_FS_PREPOST_IRP)(_In_ PVOID Context, _In_ PIRP Irp)
Definition: fsrtltypes.h:258
VOID NTAPI FsRtlCancelOplockIIIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: oplock.c:313
#define FILE_COMPLETE_IF_OPLOCKED
Definition: constants.h:493
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG _In_ PUNICODE_STRING _In_ PACCESS_MASK _In_ USHORT _In_ ULONG CreateDisposition
Definition: create.c:4157
HRESULT Create([out]ITransactionReceiver **ppReceiver)
ULONG ACCESS_MASK
Definition: nt_native.h:40
ULONG Reserved
Definition: oplock.c:52
_In_ PIRP _In_opt_ PVOID _In_opt_ POPLOCK_WAIT_COMPLETE_ROUTINE _In_opt_ POPLOCK_FS_PREPOST_IRP PostIrpRoutine
Definition: fsrtlfuncs.h:673
BOOLEAN NTAPI FsRtlOplockIsFastIoPossible(IN POPLOCK Oplock)
Definition: oplock.c:1566
#define IRP_SYNCHRONOUS_PAGING_IO
PINTERNAL_OPLOCK FsRtlAllocateOplock(VOID)
Definition: oplock.c:544
ULONG Flags
Definition: oplock.c:42
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68