xref: /reactos/drivers/filesystems/udfs/pnp.cpp (revision 8a978a17)
1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
7 *
8 * File: Pnp.cpp
9 *
10 * Module: UDF File System Driver (Kernel mode execution only)
11 *
12 * Description:
13 *    This module implements the Plug and Play routines for UDF called by
14 *    the dispatch driver.
15 *
16 *************************************************************************/
17 
18 #include            "udffs.h"
19 
20 // define the file specific bug-check id
21 #define         UDF_BUG_CHECK_ID                UDF_FILE_PNP
22 
23 
24 NTSTATUS
25 UDFPnpQueryRemove (
26     PtrUDFIrpContext PtrIrpContext,
27     PIRP Irp,
28     PVCB Vcb
29     );
30 
31 NTSTATUS
32 UDFPnpRemove (
33     PtrUDFIrpContext PtrIrpContext,
34     PIRP Irp,
35     PVCB Vcb
36     );
37 
38 NTSTATUS
39 UDFPnpSurpriseRemove (
40     PtrUDFIrpContext PtrIrpContext,
41     PIRP Irp,
42     PVCB Vcb
43     );
44 
45 NTSTATUS
46 UDFPnpCancelRemove (
47     PtrUDFIrpContext PtrIrpContext,
48     PIRP Irp,
49     PVCB Vcb
50     );
51 
52 NTSTATUS
53 NTAPI
54 UDFPnpCompletionRoutine (
55     IN PDEVICE_OBJECT DeviceObject,
56     IN PIRP Irp,
57     IN PVOID Contxt
58     );
59 
60 NTSTATUS
61 UDFCommonPnp (
62     PtrUDFIrpContext PtrIrpContext,
63     IN PIRP Irp
64     );
65 
66 /*
67     This routine implements the FSD part of PnP operations
68 
69 Arguments:
70 
71     VolumeDeviceObject - Supplies the volume device object where the
72         file exists
73     Irp - Supplies the Irp being processed
74 
75 Return Value:
76 
77     NTSTATUS - The FSD status for the IRP
78 
79  */
80 NTSTATUS
81 UDFPnp (
82     IN PDEVICE_OBJECT DeviceObject,
83     IN PIRP Irp
84     )
85 {
86     NTSTATUS RC;
87     PtrUDFIrpContext PtrIrpContext = NULL;
88     BOOLEAN AreWeTopLevel;
89 
90     UDFPrint(("UDFPnp\n"));
91     ASSERT(FALSE);
92 
93     FsRtlEnterFileSystem();
94     ASSERT(DeviceObject);
95     ASSERT(Irp);
96 
97     // set the top level context
98     AreWeTopLevel = UDFIsIrpTopLevel(Irp);
99 
100     _SEH2_TRY {
101         //  We expect there to never be a fileobject, in which case we will always
102         //  wait.  Since at the moment we don't have any concept of pending Pnp
103         //  operations, this is a bit nitpicky.
104 
105         // get an IRP context structure and issue the request
106         PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
107         if(PtrIrpContext) {
108             RC = UDFCommonPnp(PtrIrpContext, Irp);
109         } else {
110             RC = STATUS_INSUFFICIENT_RESOURCES;
111             Irp->IoStatus.Status = RC;
112             Irp->IoStatus.Information = 0;
113             // complete the IRP
114             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
115         }
116 
117     } _SEH2_EXCEPT(UDFExceptionFilter( PtrIrpContext, _SEH2_GetExceptionInformation() )) {
118 
119         RC = UDFExceptionHandler(PtrIrpContext, Irp);
120         UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
121     } _SEH2_END;
122 
123     if (AreWeTopLevel) {
124         IoSetTopLevelIrp(NULL);
125     }
126 
127     FsRtlExitFileSystem();
128 
129     return RC;
130 }
131 
132 /*
133     This is the common routine for doing PnP operations called
134     by both the fsd and fsp threads
135 
136 Arguments:
137 
138     Irp - Supplies the Irp to process
139 
140 Return Value:
141 
142     NTSTATUS - The return status for the operation
143  */
144 NTSTATUS
145 UDFCommonPnp (
146     PtrUDFIrpContext PtrIrpContext,
147     IN PIRP Irp
148     )
149 {
150     NTSTATUS RC;
151     PIO_STACK_LOCATION IrpSp;
152     PVCB Vcb;
153     UDFPrint(("UDFCommonPnp\n"));
154 
155     _SEH2_TRY {
156         // Get the current Irp stack location.
157         IrpSp = IoGetCurrentIrpStackLocation(Irp);
158 
159         // Make sure this device object really is big enough to be a volume device
160         // object.  If it isn't, we need to get out before we try to reference some
161         // field that takes us past the end of an ordinary device object.
162         Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension);
163 
164         if (Vcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) {
165             // We were called with something we don't understand.
166             if(Irp->Flags & IRP_INPUT_OPERATION) {
167                 Irp->IoStatus.Information = 0;
168             }
169             Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
170 
171             IoCompleteRequest( Irp, IO_DISK_INCREMENT );
172             try_return (RC = STATUS_INVALID_PARAMETER);
173         }
174 
175         // Force everything to wait.
176         PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
177 
178         // Case on the minor code.
179         switch ( IrpSp->MinorFunction ) {
180 
181             case IRP_MN_QUERY_REMOVE_DEVICE:
182                 RC = UDFPnpQueryRemove( PtrIrpContext, Irp, Vcb );
183                 break;
184 
185             case IRP_MN_SURPRISE_REMOVAL:
186                 RC = UDFPnpSurpriseRemove( PtrIrpContext, Irp, Vcb );
187                 break;
188 
189             case IRP_MN_REMOVE_DEVICE:
190                 RC = UDFPnpRemove( PtrIrpContext, Irp, Vcb );
191                 break;
192 
193 /*            case IRP_MN_CANCEL_REMOVE_DEVICE:
194                 RC = UDFPnpCancelRemove( PtrIrpContext, Irp, Vcb );
195                 break;*/
196 
197             default:
198                 UDFPrint(("UDFCommonPnp: pass through\n"));
199                 //  Just pass the IRP on.  As we do not need to be in the
200                 //  way on return, ellide ourselves out of the stack.
201                 IoSkipCurrentIrpStackLocation( Irp );
202                 RC = IoCallDriver(Vcb->TargetDeviceObject, Irp);
203                 ASSERT(RC != STATUS_PENDING);
204 
205                 break;
206         }
207 
208 try_exit:   NOTHING;
209 
210     } _SEH2_FINALLY {
211         UDFReleaseIrpContext(PtrIrpContext);
212     } _SEH2_END;
213 
214     return RC;
215 }
216 
217 
218 /*
219 Routine Description:
220     This routine handles the PnP query remove operation.  The filesystem
221     is responsible for answering whether there are any reasons it sees
222     that the volume can not go away (and the device removed).  Initiation
223     of the dismount begins when we answer yes to this question.
224 
225     Query will be followed by a Cancel or Remove.
226 
227 Arguments:
228     Irp - Supplies the Irp to process
229     Vcb - Supplies the volume being queried.
230 
231 Return Value:
232     NTSTATUS - The return status for the operation
233  */
234 NTSTATUS
235 UDFPnpQueryRemove(
236     PtrUDFIrpContext PtrIrpContext,
237     PIRP Irp,
238     PVCB Vcb
239     )
240 {
241     NTSTATUS RC;
242     KEVENT Event;
243     BOOLEAN VcbDeleted = FALSE;
244     BOOLEAN GlobalHeld = FALSE;
245     BOOLEAN VcbAcquired = FALSE;
246     PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
247 
248     //  Having said yes to a QUERY, any communication with the
249     //  underlying storage stack is undefined (and may block)
250     //  until the bounding CANCEL or REMOVE is sent.
251 
252     _SEH2_TRY {
253 
254         //  Acquire the global resource so that we can try to vaporize
255         //  the volume, and the vcb resource itself.
256         UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
257         GlobalHeld = TRUE;
258 
259         if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK))
260             UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
261 #ifdef UDF_DELAYED_CLOSE
262         UDFCloseAllDelayed(Vcb);
263 #endif //UDF_DELAYED_CLOSE
264 
265         UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE);
266         VcbAcquired = TRUE;
267 
268         Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
269         //  With the volume held locked, note that we must finalize as much
270         //  as possible right now.
271         UDFDoDismountSequence(Vcb, Buf, FALSE);
272 
273         // disable Eject Request Waiter if any
274         UDFReleaseResource( &(Vcb->VCBResource) );
275         VcbAcquired = FALSE;
276         UDFStopEjectWaiter(Vcb);
277         UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE);
278         VcbAcquired = TRUE;
279 
280         //  We need to pass this down before starting the dismount, which
281         //  could disconnect us immediately from the stack.
282 
283         //  Get the next stack location, and copy over the stack location
284         IoCopyCurrentIrpStackLocationToNext( Irp );
285 
286         //  Set up the completion routine
287         KeInitializeEvent( &Event, NotificationEvent, FALSE );
288         IoSetCompletionRoutine( Irp,
289                                 UDFPnpCompletionRoutine,
290                                 &Event,
291                                 TRUE,
292                                 TRUE,
293                                 TRUE );
294         //  Send the request and wait.
295         RC = IoCallDriver(Vcb->TargetDeviceObject, Irp);
296 
297         if (RC == STATUS_PENDING) {
298             KeWaitForSingleObject( &Event,
299                                    Executive,
300                                    KernelMode,
301                                    FALSE,
302                                    NULL );
303 
304             RC = Irp->IoStatus.Status;
305         }
306 
307         //  Now if no one below us failed already, initiate the dismount
308         //  on this volume, make it go away.  PnP needs to see our internal
309         //  streams close and drop their references to the target device.
310 
311         //  Since we were able to lock the volume, we are guaranteed to
312         //  move this volume into dismount state and disconnect it from
313         //  the underlying storage stack.  The force on our part is actually
314         //  unnecesary, though complete.
315 
316         //  What is not strictly guaranteed, though, is that the closes
317         //  for the metadata streams take effect synchronously underneath
318         //  of this call.  This would leave references on the target device
319         //  even though we are disconnected!
320         if (NT_SUCCESS( RC )) {
321             VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, TRUE );
322             ASSERT( VcbDeleted );
323         }
324 
325         //  Release the Vcb if it could still remain.
326 
327         //  Note: if everything else succeeded and the Vcb is persistent because the
328         //  internal streams did not vaporize, we really need to pend this IRP off on
329         //  the side until the dismount is completed.  I can't think of a reasonable
330         //  case (in UDF) where this would actually happen, though it might still need
331         //  to be implemented.
332         //
333         //  The reason this is the case is that handles/fileobjects place a reference
334         //  on the device objects they overly.  In the filesystem case, these references
335         //  are on our target devices.  PnP correcly thinks that if references remain
336         //  on the device objects in the stack that someone has a handle, and that this
337         //  counts as a reason to not succeed the query - even though every interrogated
338         //  driver thinks that it is OK.
339         ASSERT( !(NT_SUCCESS( RC ) && !VcbDeleted ));
340 
341     } _SEH2_FINALLY {
342 
343         if (!VcbDeleted && VcbAcquired) {
344             UDFReleaseResource( &(Vcb->VCBResource) );
345         }
346 
347         if (GlobalHeld) {
348             UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
349         }
350 
351         if (!_SEH2_AbnormalTermination()) {
352             Irp->IoStatus.Status = RC;
353             // Free up the Irp Context
354             UDFReleaseIrpContext(PtrIrpContext);
355             // complete the IRP
356             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
357         }
358     } _SEH2_END;
359 
360     return RC;
361 } // end UDFPnpQueryRemove()
362 
363 
364 /*
365 Routine Description:
366     This routine handles the PnP remove operation.  This is our notification
367     that the underlying storage device for the volume we have is gone, and
368     an excellent indication that the volume will never reappear. The filesystem
369     is responsible for initiation or completion of the dismount.
370 
371 Arguments:
372     Irp - Supplies the Irp to process
373     Vcb - Supplies the volume being removed.
374 
375 Return Value:
376     NTSTATUS - The return status for the operation
377 
378 --*/
379 NTSTATUS
380 UDFPnpRemove (
381     PtrUDFIrpContext PtrIrpContext,
382     PIRP Irp,
383     PVCB Vcb
384     )
385 {
386     NTSTATUS RC;
387     KEVENT Event;
388     BOOLEAN VcbDeleted;
389     BOOLEAN VcbAcquired;
390     PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
391 
392     //  REMOVE - a storage device is now gone.  We either got
393     //  QUERY'd and said yes OR got a SURPRISE OR a storage
394     //  stack failed to spin back up from a sleep/stop state
395     //  (the only case in which this will be the first warning).
396     //
397     //  Note that it is entirely unlikely that we will be around
398     //  for a REMOVE in the first two cases, as we try to intiate
399     //  dismount.
400 
401     //  Acquire the global resource so that we can try to vaporize
402     //  the volume, and the vcb resource itself.
403     UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
404 
405     if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK))
406         UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
407 #ifdef UDF_DELAYED_CLOSE
408     UDFCloseAllDelayed(Vcb);
409 #endif //UDF_DELAYED_CLOSE
410 
411     UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE);
412     VcbAcquired = TRUE;
413 
414     //  The device will be going away.  Remove our lock (benign
415     //  if we never had it).
416     if((Vcb->Vpb->Flags & VPB_LOCKED) ||
417        (Vcb->VolumeLockPID != (ULONG)-1) ) {
418         Vcb->Vpb->Flags &= ~VPB_LOCKED;
419         Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED;
420         Vcb->VolumeLockFileObject = NULL;
421         Vcb->VolumeLockPID = -1;
422         RC = STATUS_SUCCESS;
423     }
424 
425     //  We need to pass this down before starting the dismount, which
426     //  could disconnect us immediately from the stack.
427 
428     //  Get the next stack location, and copy over the stack location
429     IoCopyCurrentIrpStackLocationToNext( Irp );
430 
431     //  Set up the completion routine
432     KeInitializeEvent( &Event, NotificationEvent, FALSE );
433     IoSetCompletionRoutine( Irp,
434                             UDFPnpCompletionRoutine,
435                             &Event,
436                             TRUE,
437                             TRUE,
438                             TRUE );
439 
440     //  Send the request and wait.
441     RC = IoCallDriver(Vcb->TargetDeviceObject, Irp);
442 
443     if (RC == STATUS_PENDING) {
444 
445         KeWaitForSingleObject( &Event,
446                                Executive,
447                                KernelMode,
448                                FALSE,
449                                NULL );
450 
451         RC = Irp->IoStatus.Status;
452     }
453 
454     _SEH2_TRY {
455 
456         //  Knock as many files down for this volume as we can.
457 
458         //  Now make our dismount happen.  This may not vaporize the
459         //  Vcb, of course, since there could be any number of handles
460         //  outstanding if we were not preceeded by a QUERY.
461         //
462         //  PnP will take care of disconnecting this stack if we
463         //  couldn't get off of it immediately.
464         Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
465         Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
466         if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
467         UDFDoDismountSequence(Vcb, Buf, FALSE);
468         Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
469         Vcb->WriteSecurity = FALSE;
470         // disable Eject Request Waiter if any
471         UDFReleaseResource( &(Vcb->VCBResource) );
472         VcbAcquired = FALSE;
473 
474         UDFStopEjectWaiter(Vcb);
475 
476         VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, FALSE );
477 
478 try_exit:   NOTHING;
479 
480     } _SEH2_FINALLY {
481         //  Release the Vcb if it could still remain.
482         if (!VcbDeleted && VcbAcquired) {
483             UDFReleaseResource(&(Vcb->VCBResource));
484         }
485         UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
486 
487         if(Buf)
488             MyFreePool__(Buf);
489 
490         if (!_SEH2_AbnormalTermination()) {
491             Irp->IoStatus.Status = RC;
492             // Free up the Irp Context
493             UDFReleaseIrpContext(PtrIrpContext);
494             // complete the IRP
495             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
496         }
497     } _SEH2_END;
498 
499     return RC;
500 }
501 
502 
503 NTSTATUS
504 UDFPnpSurpriseRemove (
505     PtrUDFIrpContext PtrIrpContext,
506     PIRP Irp,
507     PVCB Vcb
508     )
509 
510 /*++
511 
512 Routine Description:
513 
514     This routine handles the PnP surprise remove operation.  This is another
515     type of notification that the underlying storage device for the volume we
516     have is gone, and is excellent indication that the volume will never reappear.
517     The filesystem is responsible for initiation or completion the dismount.
518 
519     For the most part, only "real" drivers care about the distinction of a
520     surprise remove, which is a result of our noticing that a user (usually)
521     physically reached into the machine and pulled something out.
522 
523     Surprise will be followed by a Remove when all references have been shut down.
524 
525 Arguments:
526 
527     Irp - Supplies the Irp to process
528 
529     Vcb - Supplies the volume being removed.
530 
531 Return Value:
532 
533     NTSTATUS - The return status for the operation
534 
535 --*/
536 
537 {
538     NTSTATUS RC;
539     KEVENT Event;
540     BOOLEAN VcbDeleted;
541     BOOLEAN VcbAcquired;
542     PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
543 
544     //  SURPRISE - a device was physically yanked away without
545     //  any warning.  This means external forces.
546 
547     UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
548 
549     if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK))
550         UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
551 #ifdef UDF_DELAYED_CLOSE
552     UDFCloseAllDelayed(Vcb);
553 #endif //UDF_DELAYED_CLOSE
554 
555     UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE);
556     VcbAcquired = TRUE;
557 
558     //  We need to pass this down before starting the dismount, which
559     //  could disconnect us immediately from the stack.
560 
561     //  Get the next stack location, and copy over the stack location
562     IoCopyCurrentIrpStackLocationToNext( Irp );
563 
564     //  Set up the completion routine
565     KeInitializeEvent( &Event, NotificationEvent, FALSE );
566     IoSetCompletionRoutine( Irp,
567                             UDFPnpCompletionRoutine,
568                             &Event,
569                             TRUE,
570                             TRUE,
571                             TRUE );
572 
573     //  Send the request and wait.
574     RC = IoCallDriver(Vcb->TargetDeviceObject, Irp);
575 
576     if (RC == STATUS_PENDING) {
577 
578         KeWaitForSingleObject( &Event,
579                                Executive,
580                                KernelMode,
581                                FALSE,
582                                NULL );
583 
584         RC = Irp->IoStatus.Status;
585     }
586 
587     _SEH2_TRY {
588         //  Knock as many files down for this volume as we can.
589         Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
590         Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
591         if(!Buf) {
592             VcbAcquired = FALSE;
593             VcbDeleted = FALSE;
594             try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
595         }
596 
597         UDFDoDismountSequence(Vcb, Buf, FALSE);
598         Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
599         Vcb->WriteSecurity = FALSE;
600 
601         UDFReleaseResource(&(Vcb->VCBResource));
602         VcbAcquired = FALSE;
603 
604         UDFStopEjectWaiter(Vcb);
605 
606         //  Now make our dismount happen.  This may not vaporize the
607         //  Vcb, of course, since there could be any number of handles
608         //  outstanding since this is an out of band notification.
609         VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, FALSE );
610 
611 try_exit:   NOTHING;
612 
613     } _SEH2_FINALLY {
614 
615         //  Release the Vcb if it could still remain.
616         if (!VcbDeleted && VcbAcquired) {
617             UDFReleaseResource(&(Vcb->VCBResource));
618         }
619         UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
620 
621         if(Buf)
622             MyFreePool__(Buf);
623 
624         if (!_SEH2_AbnormalTermination()) {
625             Irp->IoStatus.Status = RC;
626             // Free up the Irp Context
627             UDFReleaseIrpContext(PtrIrpContext);
628             // complete the IRP
629             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
630         }
631     } _SEH2_END;
632 
633     return RC;
634 }
635 
636 /*
637 NTSTATUS
638 UDFPnpCancelRemove (
639     PtrUDFIrpContext PtrIrpContext,
640     PIRP Irp,
641     PVCB Vcb
642     )
643 
644 */
645 /*++
646 
647 Routine Description:
648 
649     This routine handles the PnP cancel remove operation.  This is our
650     notification that a previously proposed remove (query) was eventually
651     vetoed by a component.  The filesystem is responsible for cleaning up
652     and getting ready for more IO.
653 
654 Arguments:
655 
656     Irp - Supplies the Irp to process
657 
658     Vcb - Supplies the volume being removed.
659 
660 Return Value:
661 
662     NTSTATUS - The return status for the operation
663 
664 --*/
665 
666 /*{
667     NTSTATUS RC;
668 
669     //  CANCEL - a previous QUERY has been rescinded as a result
670     //  of someone vetoing.  Since PnP cannot figure out who may
671     //  have gotten the QUERY (think about it: stacked drivers),
672     //  we must expect to deal with getting a CANCEL without having
673     //  seen the QUERY.
674     //
675     //  For UDF, this is quite easy.  In fact, we can't get a
676     //  CANCEL if the underlying drivers succeeded the QUERY since
677     //  we disconnect the Vpb on our dismount initiation.  This is
678     //  actually pretty important because if PnP could get to us
679     //  after the disconnect we'd be thoroughly unsynchronized
680     //  with respect to the Vcb getting torn apart - merely referencing
681     //  the volume device object is insufficient to keep us intact.
682 
683     UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE);
684 
685     //  Unlock the volume.  This is benign if we never had seen
686     //  a QUERY.
687     if(Vcb->Vpb->Flags & VPB_LOCKED) {
688         Vcb->Vpb->Flags &= ~VPB_LOCKED;
689         Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED;
690         Vcb->VolumeLockFileObject = NULL;
691         RC = STATUS_SUCCESS;
692     } else {
693         RC = STATUS_NOT_LOCKED;
694     }
695 
696     try {
697 
698         //  We must re-enable allocation support if we got through
699         //  the first stages of a QUERY_REMOVE; i.e., we decided we
700         //  could place a lock on the volume.
701         if (NT_SUCCESS( RC )) {
702             FatSetupAllocationSupport( PtrIrpContext, Vcb );
703         }
704 
705     } finally {
706         UDFReleaseResource(&(Vcb->VCBResource));
707     }
708 
709     //  Send the request.  The underlying driver will complete the
710     //  IRP.  Since we don't need to be in the way, simply ellide
711     //  ourselves out of the IRP stack.
712     IoSkipCurrentIrpStackLocation( Irp );
713 
714     RC = IoCallDriver(Vcb->TargetDeviceObject, Irp);
715 
716 //    if (!AbnormalTermination()) {
717         Irp->IoStatus.Status = RC;
718         // Free up the Irp Context
719         UDFReleaseIrpContext(PtrIrpContext);
720         // complete the IRP
721         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
722 //    }
723 
724     return RC;
725 } */
726 
727 
728 //  Local support routine
729 NTSTATUS
730 NTAPI
731 UDFPnpCompletionRoutine (
732     IN PDEVICE_OBJECT DeviceObject,
733     IN PIRP Irp,
734     IN PVOID Contxt
735     )
736 {
737     PKEVENT Event = (PKEVENT) Contxt;
738 
739     KeSetEvent( Event, 0, FALSE );
740 
741     return STATUS_MORE_PROCESSING_REQUIRED;
742 
743     UNREFERENCED_PARAMETER( DeviceObject );
744     UNREFERENCED_PARAMETER( Contxt );
745 }
746 
747 
748