xref: /reactos/drivers/filesystems/cdfs/pnp.c (revision cdf90707)
1 /*++
2 
3 Copyright (c) 1997-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     Pnp.c
8 
9 Abstract:
10 
11     This module implements the Plug and Play routines for CDFS called by
12     the dispatch driver.
13 
14 
15 --*/
16 
17 #include "cdprocs.h"
18 
19 //
20 //  The Bug check file id for this module
21 //
22 
23 #define BugCheckFileId                   (CDFS_BUG_CHECK_PNP)
24 
25 _Requires_lock_held_(_Global_critical_region_)
26 _Releases_nonreentrant_lock_(CdData.DataResource)
27 NTSTATUS
28 CdPnpQueryRemove (
29     _Inout_ PIRP_CONTEXT IrpContext,
30     _Inout_ PIRP Irp,
31     _Inout_ PVCB Vcb
32     );
33 
34 _Requires_lock_held_(_Global_critical_region_)
35 _Releases_nonreentrant_lock_(CdData.DataResource)
36 NTSTATUS
37 CdPnpRemove (
38     _Inout_ PIRP_CONTEXT IrpContext,
39     _Inout_ PIRP Irp,
40     _Inout_ PVCB Vcb
41     );
42 
43 _Requires_lock_held_(_Global_critical_region_)
44 _Releases_nonreentrant_lock_(CdData.DataResource)
45 NTSTATUS
46 CdPnpSurpriseRemove (
47     _Inout_ PIRP_CONTEXT IrpContext,
48     _Inout_ PIRP Irp,
49     _Inout_ PVCB Vcb
50     );
51 
52 _Requires_lock_held_(_Global_critical_region_)
53 _Releases_nonreentrant_lock_(CdData.DataResource)
54 NTSTATUS
55 CdPnpCancelRemove (
56     _Inout_ PIRP_CONTEXT IrpContext,
57     _Inout_ PIRP Irp,
58     _Inout_ PVCB Vcb
59     );
60 
61 //  Tell prefast this is a completion routine.
62 IO_COMPLETION_ROUTINE CdPnpCompletionRoutine;
63 
64 NTSTATUS
65 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
66 CdPnpCompletionRoutine (
67     _In_ PDEVICE_OBJECT DeviceObject,
68     _In_ PIRP Irp,
69     _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
70     );
71 
72 #ifdef ALLOC_PRAGMA
73 #pragma alloc_text(PAGE, CdCommonPnp)
74 #pragma alloc_text(PAGE, CdPnpCancelRemove)
75 #pragma alloc_text(PAGE, CdPnpQueryRemove)
76 #pragma alloc_text(PAGE, CdPnpRemove)
77 #pragma alloc_text(PAGE, CdPnpSurpriseRemove)
78 #endif
79 
80 _Requires_lock_held_(_Global_critical_region_)
81 NTSTATUS
82 CdCommonPnp (
83     _Inout_ PIRP_CONTEXT IrpContext,
84     _Inout_ PIRP Irp
85     )
86 
87 /*++
88 
89 Routine Description:
90 
91     This is the common routine for doing PnP operations called
92     by both the fsd and fsp threads
93 
94 Arguments:
95 
96     Irp - Supplies the Irp to process
97 
98 Return Value:
99 
100     NTSTATUS - The return status for the operation
101 
102 --*/
103 
104 {
105     NTSTATUS Status = STATUS_SUCCESS;
106     BOOLEAN PassThrough = FALSE;
107 
108     PIO_STACK_LOCATION IrpSp;
109 
110     PVOLUME_DEVICE_OBJECT OurDeviceObject;
111     PVCB Vcb;
112 
113     PAGED_CODE();
114 
115     // Global lock object is acquired based on internal book-keeping
116     _Analysis_suppress_lock_checking_(CdData.DataResource);
117 
118     //
119     //  Get the current Irp stack location.
120     //
121 
122     IrpSp = IoGetCurrentIrpStackLocation( Irp );
123 
124     //
125     //  Find our Vcb.  This is tricky since we have no file object in the Irp.
126     //
127 
128     OurDeviceObject = (PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject;
129 
130     //
131     //  IO holds a handle reference on our VDO and holds the device lock, which
132     //  syncs us against mounts/verifies.  However we hold no reference on the
133     //  volume, which may already have been torn down (and the Vpb freed), for
134     //  example by a force dismount. Check for this condition. We must hold this
135     //  lock until the pnp worker functions take additional locks/refs on the Vcb.
136     //
137 
138     CdAcquireCdData( IrpContext);
139 
140     //
141     //  Make sure this device object really is big enough to be a volume device
142     //  object.  If it isn't, we need to get out before we try to reference some
143     //  field that takes us past the end of an ordinary device object.
144     //
145 
146 #ifdef _MSC_VER
147 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the size member is allowed")
148 #endif
149     if (OurDeviceObject->DeviceObject.Size != sizeof(VOLUME_DEVICE_OBJECT) ||
150         NodeType( &OurDeviceObject->Vcb ) != CDFS_NTC_VCB) {
151 
152         //
153         //  We were called with something we don't understand.
154         //
155 
156         Status = STATUS_INVALID_PARAMETER;
157         CdReleaseCdData( IrpContext);
158         CdCompleteRequest( IrpContext, Irp, Status );
159         return Status;
160     }
161 
162     //
163     //  Force all PnP operations to be synchronous.
164     //
165 
166     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
167 
168     Vcb = &OurDeviceObject->Vcb;
169 
170     //
171     //  Check that the Vcb hasn't already been deleted.  If so,  just pass the
172     //  request through to the driver below,  we don't need to do anything.
173     //
174 
175     if (NULL == Vcb->Vpb) {
176 
177         PassThrough = TRUE;
178     }
179     else {
180 
181         //
182         //  Case on the minor code.
183         //
184 
185         switch ( IrpSp->MinorFunction ) {
186 
187             case IRP_MN_QUERY_REMOVE_DEVICE:
188 
189                 Status = CdPnpQueryRemove( IrpContext, Irp, Vcb );
190                 break;
191 
192             case IRP_MN_SURPRISE_REMOVAL:
193 
194                 Status = CdPnpSurpriseRemove( IrpContext, Irp, Vcb );
195                 break;
196 
197             case IRP_MN_REMOVE_DEVICE:
198 
199                 Status = CdPnpRemove( IrpContext, Irp, Vcb );
200                 break;
201 
202             case IRP_MN_CANCEL_REMOVE_DEVICE:
203 
204                 Status = CdPnpCancelRemove( IrpContext, Irp, Vcb );
205                 break;
206 
207             default:
208 
209                 PassThrough = TRUE;
210                 break;
211         }
212     }
213 
214     if (PassThrough) {
215 
216         CdReleaseCdData( IrpContext);
217 
218         //
219         //  Just pass the IRP on.  As we do not need to be in the
220         //  way on return, ellide ourselves out of the stack.
221         //
222 
223         IoSkipCurrentIrpStackLocation( Irp );
224 
225         Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
226 
227         //
228         //  Cleanup our Irp Context.  The driver has completed the Irp.
229         //
230 
231         CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
232     }
233 
234     return Status;
235 }
236 
237 _Requires_lock_held_(_Global_critical_region_)
238 _Releases_nonreentrant_lock_(CdData.DataResource)
239 NTSTATUS
240 CdPnpQueryRemove (
241     _Inout_ PIRP_CONTEXT IrpContext,
242     _Inout_ PIRP Irp,
243     _Inout_ PVCB Vcb
244     )
245 
246 /*++
247 
248 Routine Description:
249 
250     This routine handles the PnP query remove operation.  The filesystem
251     is responsible for answering whether there are any reasons it sees
252     that the volume can not go away (and the device removed).  Initiation
253     of the dismount begins when we answer yes to this question.
254 
255     Query will be followed by a Cancel or Remove.
256 
257 Arguments:
258 
259     Irp - Supplies the Irp to process
260 
261     Vcb - Supplies the volume being queried.
262 
263 Return Value:
264 
265     NTSTATUS - The return status for the operation
266 
267 --*/
268 
269 {
270     NTSTATUS Status;
271     KEVENT Event;
272     BOOLEAN VcbPresent = TRUE;
273 
274     PAGED_CODE();
275 
276     ASSERT_EXCLUSIVE_CDDATA;
277 
278     //
279     //  Having said yes to a QUERY, any communication with the
280     //  underlying storage stack is undefined (and may block)
281     //  until the bounding CANCEL or REMOVE is sent.
282     //
283     //  Acquire the global resource so that we can try to vaporize the volume,
284     //  and the vcb resource itself.
285     //
286 
287     CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
288 
289     //
290     //  Drop a reference on the Vcb to keep it around after we drop the locks.
291     //
292 
293     CdLockVcb( IrpContext, Vcb);
294     Vcb->VcbReference += 1;
295     CdUnlockVcb( IrpContext, Vcb);
296 
297     CdReleaseCdData( IrpContext);
298 
299     Status = CdLockVolumeInternal( IrpContext, Vcb, NULL );
300 
301     //
302     //  Reacquire the global lock,  which means dropping the Vcb resource.
303     //
304 
305     CdReleaseVcb( IrpContext, Vcb );
306 
307     CdAcquireCdData( IrpContext );
308     CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
309 
310     //
311     //  Remove our extra reference.
312     //
313 
314     CdLockVcb( IrpContext, Vcb);
315     Vcb->VcbReference -= 1;
316     CdUnlockVcb( IrpContext, Vcb);
317 
318     if (NT_SUCCESS( Status )) {
319 
320         //
321         //  We need to pass this down before starting the dismount, which
322         //  could disconnect us immediately from the stack.
323         //
324 
325         //
326         //  Get the next stack location, and copy over the stack location
327         //
328 
329         IoCopyCurrentIrpStackLocationToNext( Irp );
330 
331         //
332         //  Set up the completion routine
333         //
334 
335         KeInitializeEvent( &Event, NotificationEvent, FALSE );
336         IoSetCompletionRoutine( Irp,
337                                 CdPnpCompletionRoutine,
338                                 &Event,
339                                 TRUE,
340                                 TRUE,
341                                 TRUE );
342 
343         //
344         //  Send the request and wait.
345         //
346 
347         Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
348 
349         if (Status == STATUS_PENDING) {
350 
351             (VOID)KeWaitForSingleObject( &Event,
352                                    Executive,
353                                    KernelMode,
354                                    FALSE,
355                                    NULL );
356 
357             Status = Irp->IoStatus.Status;
358         }
359 
360         //
361         //  Now if no one below us failed already, initiate the dismount
362         //  on this volume, make it go away.  PnP needs to see our internal
363         //  streams close and drop their references to the target device.
364         //
365         //  Since we were able to lock the volume, we are guaranteed to
366         //  move this volume into dismount state and disconnect it from
367         //  the underlying storage stack.  The force on our part is actually
368         //  unnecesary, though complete.
369         //
370         //  What is not strictly guaranteed, though, is that the closes
371         //  for the metadata streams take effect synchronously underneath
372         //  of this call.  This would leave references on the target device
373         //  even though we are disconnected!
374         //
375 
376         if (NT_SUCCESS( Status )) {
377 
378             VcbPresent = CdCheckForDismount( IrpContext, Vcb, TRUE );
379 
380             NT_ASSERT( !VcbPresent || Vcb->VcbCondition == VcbDismountInProgress );
381         }
382 
383         //
384         //  Note: Normally everything will complete and the internal streams will
385         //  vaporise.  However there is some code in the system which drops additional
386         //  references on fileobjects,  including our internal stream file objects,
387         //  for (WMI) tracing purposes.  If that happens to run concurrently with our
388         //  teardown, our internal streams will not vaporise until those references
389         //  are removed.  So it's possible that the volume still remains at this
390         //  point.  The pnp query remove will fail due to our references on the device.
391         //  To be cleaner we will return an error here.  We could pend the pnp
392         //  IRP until the volume goes away, but since we don't know when that will
393         //  be, and this is a very rare case, we'll just fail the query.
394         //
395         //  The reason this is the case is that handles/fileobjects place a reference
396         //  on the device objects they overly.  In the filesystem case, these references
397         //  are on our target devices.  PnP correcly thinks that if references remain
398         //  on the device objects in the stack that someone has a handle, and that this
399         //  counts as a reason to not succeed the query - even though every interrogated
400         //  driver thinks that it is OK.
401         //
402 
403         if (NT_SUCCESS( Status) && VcbPresent && (Vcb->VcbReference != 0)) {
404 
405             Status = STATUS_DEVICE_BUSY;
406         }
407     }
408 
409     //
410     //  Release the Vcb if it could still remain.
411     //
412 
413     if (VcbPresent) {
414 
415         CdReleaseVcb( IrpContext, Vcb );
416     }
417     else {
418         _Analysis_assume_lock_not_held_(Vcb->VcbResource);
419     }
420 
421     CdReleaseCdData( IrpContext );
422 
423     //
424     //  Cleanup our IrpContext and complete the IRP if neccesary.
425     //
426 
427     CdCompleteRequest( IrpContext, Irp, Status );
428 
429     return Status;
430 }
431 
432 _Requires_lock_held_(_Global_critical_region_)
433 _Releases_nonreentrant_lock_(CdData.DataResource)
434 NTSTATUS
435 CdPnpRemove (
436     _Inout_ PIRP_CONTEXT IrpContext,
437     _Inout_ PIRP Irp,
438     _Inout_ PVCB Vcb
439     )
440 
441 /*++
442 
443 Routine Description:
444 
445     This routine handles the PnP remove operation.  This is our notification
446     that the underlying storage device for the volume we have is gone, and
447     an excellent indication that the volume will never reappear. The filesystem
448     is responsible for initiation or completion the dismount.
449 
450 Arguments:
451 
452     Irp - Supplies the Irp to process
453 
454     Vcb - Supplies the volume being removed.
455 
456 Return Value:
457 
458     NTSTATUS - The return status for the operation
459 
460 --*/
461 
462 {
463     NTSTATUS Status;
464     KEVENT Event;
465     BOOLEAN VcbPresent = TRUE;
466 
467     PAGED_CODE();
468 
469     ASSERT_EXCLUSIVE_CDDATA;
470 
471     //
472     //  REMOVE - a storage device is now gone.  We either got
473     //  QUERY'd and said yes OR got a SURPRISE OR a storage
474     //  stack failed to spin back up from a sleep/stop state
475     //  (the only case in which this will be the first warning).
476     //
477     //  Note that it is entirely unlikely that we will be around
478     //  for a REMOVE in the first two cases, as we try to intiate
479     //  dismount.
480     //
481 
482     //
483     //  Acquire the global resource so that we can try to vaporize
484     //  the volume, and the vcb resource itself.
485     //
486 
487     CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
488 
489     //
490     //  The device will be going away.  Remove our lock and find
491     //  out if we ever had one in the first place.
492     //
493 
494     Status = CdUnlockVolumeInternal( IrpContext, Vcb, NULL );
495 
496     //
497     //  If the volume had not been locked, we must invalidate the
498     //  volume to ensure it goes away properly.  The remove will
499     //  succeed.
500     //
501 
502     if (!NT_SUCCESS( Status )) {
503 
504         CdLockVcb( IrpContext, Vcb );
505 
506         if (Vcb->VcbCondition != VcbDismountInProgress) {
507 
508             CdUpdateVcbCondition( Vcb, VcbInvalid);
509         }
510 
511         CdUnlockVcb( IrpContext, Vcb );
512 
513         Status = STATUS_SUCCESS;
514     }
515 
516     //
517     //  We need to pass this down before starting the dismount, which
518     //  could disconnect us immediately from the stack.
519     //
520 
521     //
522     //  Get the next stack location, and copy over the stack location
523     //
524 
525     IoCopyCurrentIrpStackLocationToNext( Irp );
526 
527     //
528     //  Set up the completion routine
529     //
530 
531     KeInitializeEvent( &Event, NotificationEvent, FALSE );
532     IoSetCompletionRoutine( Irp,
533                             CdPnpCompletionRoutine,
534                             &Event,
535                             TRUE,
536                             TRUE,
537                             TRUE );
538 
539     //
540     //  Send the request and wait.
541     //
542 
543     Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
544 
545     if (Status == STATUS_PENDING) {
546 
547         (VOID)KeWaitForSingleObject( &Event,
548                                Executive,
549                                KernelMode,
550                                FALSE,
551                                NULL );
552 
553         Status = Irp->IoStatus.Status;
554     }
555 
556     //
557     //  Now make our dismount happen.  This may not vaporize the
558     //  Vcb, of course, since there could be any number of handles
559     //  outstanding if we were not preceeded by a QUERY.
560     //
561     //  PnP will take care of disconnecting this stack if we
562     //  couldn't get off of it immediately.
563     //
564 
565 
566     VcbPresent = CdCheckForDismount( IrpContext, Vcb, TRUE );
567 
568     //
569     //  Release the Vcb if it could still remain.
570     //
571 
572     if (VcbPresent) {
573 
574         CdReleaseVcb( IrpContext, Vcb );
575     }
576     else {
577         _Analysis_assume_lock_not_held_(Vcb->VcbResource);
578     }
579 
580     CdReleaseCdData( IrpContext );
581 
582     //
583     //  Cleanup our IrpContext and complete the IRP.
584     //
585 
586     CdCompleteRequest( IrpContext, Irp, Status );
587 
588     return Status;
589 }
590 
591 _Requires_lock_held_(_Global_critical_region_)
592 _Releases_nonreentrant_lock_(CdData.DataResource)
593 NTSTATUS
594 CdPnpSurpriseRemove (
595     _Inout_ PIRP_CONTEXT IrpContext,
596     _Inout_ PIRP Irp,
597     _Inout_ PVCB Vcb
598     )
599 
600 /*++
601 
602 Routine Description:
603 
604     This routine handles the PnP surprise remove operation.  This is another
605     type of notification that the underlying storage device for the volume we
606     have is gone, and is excellent indication that the volume will never reappear.
607     The filesystem is responsible for initiation or completion the dismount.
608 
609     For the most part, only "real" drivers care about the distinction of a
610     surprise remove, which is a result of our noticing that a user (usually)
611     physically reached into the machine and pulled something out.
612 
613     Surprise will be followed by a Remove when all references have been shut down.
614 
615 Arguments:
616 
617     Irp - Supplies the Irp to process
618 
619     Vcb - Supplies the volume being removed.
620 
621 Return Value:
622 
623     NTSTATUS - The return status for the operation
624 
625 --*/
626 
627 {
628     NTSTATUS Status;
629     KEVENT Event;
630     BOOLEAN VcbPresent = TRUE;
631 
632     PAGED_CODE();
633 
634     ASSERT_EXCLUSIVE_CDDATA;
635 
636     //
637     //  SURPRISE - a device was physically yanked away without
638     //  any warning.  This means external forces.
639     //
640 
641     CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
642 
643     //
644     //  Invalidate the volume right now.
645     //
646     //  The intent here is to make every subsequent operation
647     //  on the volume fail and grease the rails toward dismount.
648     //  By definition there is no going back from a SURPRISE.
649     //
650 
651     CdLockVcb( IrpContext, Vcb );
652 
653     if (Vcb->VcbCondition != VcbDismountInProgress) {
654 
655         CdUpdateVcbCondition( Vcb, VcbInvalid);
656     }
657 
658     CdUnlockVcb( IrpContext, Vcb );
659 
660     //
661     //  We need to pass this down before starting the dismount, which
662     //  could disconnect us immediately from the stack.
663     //
664 
665     //
666     //  Get the next stack location, and copy over the stack location
667     //
668 
669     IoCopyCurrentIrpStackLocationToNext( Irp );
670 
671     //
672     //  Set up the completion routine
673     //
674 
675     KeInitializeEvent( &Event, NotificationEvent, FALSE );
676     IoSetCompletionRoutine( Irp,
677                             CdPnpCompletionRoutine,
678                             &Event,
679                             TRUE,
680                             TRUE,
681                             TRUE );
682 
683     //
684     //  Send the request and wait.
685     //
686 
687     Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
688 
689     if (Status == STATUS_PENDING) {
690 
691         (VOID)KeWaitForSingleObject( &Event,
692                                Executive,
693                                KernelMode,
694                                FALSE,
695                                NULL );
696 
697         Status = Irp->IoStatus.Status;
698     }
699 
700     //
701     //  Now make our dismount happen.  This may not vaporize the
702     //  Vcb, of course, since there could be any number of handles
703     //  outstanding since this is an out of band notification.
704     //
705 
706 
707     VcbPresent = CdCheckForDismount( IrpContext, Vcb, TRUE );
708 
709     //
710     //  Release the Vcb if it could still remain.
711     //
712 
713     if (VcbPresent) {
714 
715         CdReleaseVcb( IrpContext, Vcb );
716     }
717     else {
718         _Analysis_assume_lock_not_held_(Vcb->VcbResource);
719     }
720 
721     CdReleaseCdData( IrpContext );
722 
723     //
724     //  Cleanup our IrpContext and complete the IRP.
725     //
726 
727     CdCompleteRequest( IrpContext, Irp, Status );
728 
729     return Status;
730 }
731 
732 _Requires_lock_held_(_Global_critical_region_)
733 _Releases_nonreentrant_lock_(CdData.DataResource)
734 NTSTATUS
735 CdPnpCancelRemove (
736     _Inout_ PIRP_CONTEXT IrpContext,
737     _Inout_ PIRP Irp,
738     _Inout_ PVCB Vcb
739     )
740 
741 /*++
742 
743 Routine Description:
744 
745     This routine handles the PnP cancel remove operation.  This is our
746     notification that a previously proposed remove (query) was eventually
747     vetoed by a component.  The filesystem is responsible for cleaning up
748     and getting ready for more IO.
749 
750 Arguments:
751 
752     Irp - Supplies the Irp to process
753 
754     Vcb - Supplies the volume being removed.
755 
756 Return Value:
757 
758     NTSTATUS - The return status for the operation
759 
760 --*/
761 
762 {
763     NTSTATUS Status;
764 
765     PAGED_CODE();
766 
767     ASSERT_EXCLUSIVE_CDDATA;
768 
769     //
770     //  CANCEL - a previous QUERY has been rescinded as a result
771     //  of someone vetoing.  Since PnP cannot figure out who may
772     //  have gotten the QUERY (think about it: stacked drivers),
773     //  we must expect to deal with getting a CANCEL without having
774     //  seen the QUERY.
775     //
776     //  For CDFS, this is quite easy.  In fact, we can't get a
777     //  CANCEL if the underlying drivers succeeded the QUERY since
778     //  we disconnect the Vpb on our dismount initiation.  This is
779     //  actually pretty important because if PnP could get to us
780     //  after the disconnect we'd be thoroughly unsynchronized
781     //  with respect to the Vcb getting torn apart - merely referencing
782     //  the volume device object is insufficient to keep us intact.
783     //
784 
785     CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
786     CdReleaseCdData( IrpContext);
787 
788     //
789     //  Unlock the volume.  This is benign if we never had seen
790     //  a QUERY.
791     //
792 
793     (VOID) CdUnlockVolumeInternal( IrpContext, Vcb, NULL );
794 
795     CdReleaseVcb( IrpContext, Vcb );
796 
797     //
798     //  Send the request.  The underlying driver will complete the
799     //  IRP.  Since we don't need to be in the way, simply ellide
800     //  ourselves out of the IRP stack.
801     //
802 
803     IoSkipCurrentIrpStackLocation( Irp );
804 
805     Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
806 
807     CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
808 
809     return Status;
810 }
811 
812 
813 //
814 //  Local support routine
815 //
816 
817 NTSTATUS
818 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
819 CdPnpCompletionRoutine (
820     _In_ PDEVICE_OBJECT DeviceObject,
821     _In_ PIRP Irp,
822     _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
823     )
824 {
825     PKEVENT Event = (PKEVENT) Contxt;
826     _Analysis_assume_(Contxt != NULL);
827 
828     KeSetEvent( Event, 0, FALSE );
829 
830     return STATUS_MORE_PROCESSING_REQUIRED;
831 
832     UNREFERENCED_PARAMETER( DeviceObject );
833     UNREFERENCED_PARAMETER( Irp );
834     UNREFERENCED_PARAMETER( Contxt );
835 }
836 
837 
838