test: udfs/pnp.c File Reference

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# pnp.c File Reference

`#include "UdfProcs.h"`

Go to the source code of this file.

## Defines

#define | BugCheckFileId (UDFS_BUG_CHECK_PNP)

## Functions

NTSTATUS | UdfPnpQueryRemove (PIRP_CONTEXT IrpContext, PIRP Irp, PVCB Vcb)
NTSTATUS | UdfPnpRemove (PIRP_CONTEXT IrpContext, PIRP Irp, PVCB Vcb)
NTSTATUS | UdfPnpSurpriseRemove (PIRP_CONTEXT IrpContext, PIRP Irp, PVCB Vcb)
NTSTATUS | UdfPnpCancelRemove (PIRP_CONTEXT IrpContext, PIRP Irp, PVCB Vcb)
NTSTATUS | UdfPnpCompletionRoutine (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Contxt)
NTSTATUS | UdfCommonPnp (IN PIRP_CONTEXT IrpContext, IN PIRP Irp)

## Define Documentation

#define BugCheckFileId (UDFS_BUG_CHECK_PNP)

| Definition at line 28 of file udfs/pnp.c.

## Function Documentation

NTSTATUS UdfCommonPnp | ( | IN PIRP_CONTEXT | IrpContext,
|  | IN PIRP | Irp
| ) |

Definition at line 75 of file udfs/pnp.c.

References _IO_STACK_LOCATION::DeviceObject, _VOLUME_DEVICE_OBJECT::DeviceObject, IoCallDriver, IoGetCurrentIrpStackLocation, IoSkipCurrentIrpStackLocation, Irp, IRP_CONTEXT_FLAG_WAIT, IRP_MN_CANCEL_REMOVE_DEVICE, IRP_MN_QUERY_REMOVE_DEVICE, IRP_MN_REMOVE_DEVICE, IRP_MN_SURPRISE_REMOVAL, _IO_STACK_LOCATION::MinorFunction, NodeType, NTSTATUS(), NULL, SetFlag, _DEVICE_OBJECT::Size, Status, _VCB::TargetDeviceObject, UdfCompleteRequest(), UdfPnpCancelRemove(), UdfPnpQueryRemove(), UdfPnpRemove(), UdfPnpSurpriseRemove(), UDFS_NTC_VCB, and _VOLUME_DEVICE_OBJECT::Vcb.

Referenced by UdfFsdDispatch(), and UdfFspDispatch().

    00082                    :
    00083
    00084     This is the common routine for doing PnP operations called
    00085     by both the fsd and fsp threads
    00086
    00087 Arguments:
    00088
    00089     Irp - Supplies the Irp to process
    00090
    00091 Return Value:
    00092
    00093     NTSTATUS - The return status for the operation
    00094
    00095 --*/
    00096
    00097 {
    00098     NTSTATUS Status;
    00099
    00100     PIO_STACK_LOCATION IrpSp;
    00101
    00102     PVOLUME_DEVICE_OBJECT OurDeviceObject;
    00103     PVCB Vcb;
    00104
    00105     //
    00106     //  Get the current Irp stack location.
    00107     //
    00108
    00109     IrpSp = IoGetCurrentIrpStackLocation( Irp );
    00110
    00111     //
    00112     //  Find our Vcb.  This is tricky since we have no file object in the Irp.
    00113     //
    00114
    00115     OurDeviceObject = (PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject;
    00116
    00117     //
    00118     //  Make sure this device object really is big enough to be a volume device
    00119     //  object.  If it isn't, we need to get out before we try to reference some
    00120     //  field that takes us past the end of an ordinary device object.
    00121     //
    00122
    00123     if (OurDeviceObject->DeviceObject.Size != sizeof(VOLUME_DEVICE_OBJECT) ||
    00124         NodeType( &OurDeviceObject->Vcb ) != UDFS_NTC_VCB) {
    00125
    00126         //
    00127         //  We were called with something we don't understand.
    00128         //
    00129
    00130         Status = STATUS_INVALID_PARAMETER;
    00131         UdfCompleteRequest( IrpContext, Irp, Status );
    00132         return Status;
    00133     }
    00134
    00135     //
    00136     //  Force all PnP operations to be synchronous.
    00137     //
    00138
    00139     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
    00140
    00141     Vcb = &OurDeviceObject->Vcb;
    00142
    00143     //
    00144     //  Case on the minor code.
    00145     //
    00146
    00147     switch ( IrpSp->MinorFunction ) {
    00148
    00149         case IRP_MN_QUERY_REMOVE_DEVICE:
    00150
    00151             Status = UdfPnpQueryRemove( IrpContext, Irp, Vcb );
    00152             break;
    00153
    00154         case IRP_MN_SURPRISE_REMOVAL:
    00155
    00156             Status = UdfPnpSurpriseRemove( IrpContext, Irp, Vcb );
    00157             break;
    00158
    00159         case IRP_MN_REMOVE_DEVICE:
    00160
    00161             Status = UdfPnpRemove( IrpContext, Irp, Vcb );
    00162             break;
    00163
    00164         case IRP_MN_CANCEL_REMOVE_DEVICE:
    00165
    00166             Status = UdfPnpCancelRemove( IrpContext, Irp, Vcb );
    00167             break;
    00168
    00169         default:
    00170
    00171             //
    00172             //  Just pass the IRP on.  As we do not need to be in the
    00173             //  way on return, ellide ourselves out of the stack.
    00174             //
    00175
    00176             IoSkipCurrentIrpStackLocation( Irp );
    00177
    00178             Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
    00179
    00180             //
    00181             //  Cleanup our Irp Context.  The driver has completed the Irp.
    00182             //
    00183
    00184             UdfCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
    00185
    00186             break;
    00187     }
    00188
    00189     return Status;
    00190 }

NTSTATUS UdfPnpCancelRemove | ( | PIRP_CONTEXT | IrpContext,
|  | PIRP | Irp,
|  | PVCB | Vcb
| ) |

Definition at line 632 of file udfs/pnp.c.

References FALSE, IoCallDriver, IoSkipCurrentIrpStackLocation, Irp, NTSTATUS(), NULL, Status, _VCB::TargetDeviceObject, UdfAcquireVcbExclusive, UdfCompleteRequest(), UdfReleaseVcb, UdfUnlockVolumeInternal(), and VOID().

Referenced by UdfCommonPnp().

    00640                    :
    00641
    00642     This routine handles the PnP cancel remove operation.  This is our
    00643     notification that a previously proposed remove (query) was eventually
    00644     vetoed by a component.  The filesystem is responsible for cleaning up
    00645     and getting ready for more IO.
    00646
    00647 Arguments:
    00648
    00649     Irp - Supplies the Irp to process
    00650
    00651     Vcb - Supplies the volume being removed.
    00652
    00653 Return Value:
    00654
    00655     NTSTATUS - The return status for the operation
    00656
    00657 --*/
    00658
    00659 {
    00660     NTSTATUS Status;
    00661
    00662     //
    00663     //  CANCEL - a previous QUERY has been rescinded as a result
    00664     //  of someone vetoing.  Since PnP cannot figure out who may
    00665     //  have gotten the QUERY (think about it: stacked drivers),
    00666     //  we must expect to deal with getting a CANCEL without having
    00667     //  seen the QUERY.
    00668     //
    00669     //  For UDFS, this is quite easy.  In fact, we can't get a
    00670     //  CANCEL if the underlying drivers succeeded the QUERY since
    00671     //  we disconnect the Vpb on our dismount initiation.  This is
    00672     //  actually pretty important because if PnP could get to us
    00673     //  after the disconnect we'd be thoroughly unsynchronized
    00674     //  with respect to the Vcb getting torn apart - merely referencing
    00675     //  the volume device object is insufficient to keep us intact.
    00676     //
    00677
    00678     UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
    00679
    00680     //
    00681     //  Unlock the volume.  This is benign if we never had seen
    00682     //  a QUERY.
    00683     //
    00684
    00685     (VOID) UdfUnlockVolumeInternal( IrpContext, Vcb, NULL );
    00686
    00687     UdfReleaseVcb( IrpContext, Vcb );
    00688
    00689     //
    00690     //  Send the request.  The underlying driver will complete the
    00691     //  IRP.  Since we don't need to be in the way, simply ellide
    00692     //  ourselves out of the IRP stack.
    00693     //
    00694
    00695     IoSkipCurrentIrpStackLocation( Irp );
    00696
    00697     Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
    00698
    00699     UdfCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
    00700
    00701     return Status;
    00702 }

NTSTATUS UdfPnpCompletionRoutine | ( | IN PDEVICE_OBJECT | DeviceObject,
|  | IN PIRP | Irp,
|  | IN PVOID | Contxt
| ) |

Definition at line 710 of file udfs/pnp.c.

References Event(), FALSE, and KeSetEvent().

Referenced by UdfPnpQueryRemove(), UdfPnpRemove(), and UdfPnpSurpriseRemove().

    00715 {
    00716     PKEVENT Event = (PKEVENT) Contxt;
    00717
    00718     KeSetEvent( Event, 0, FALSE );
    00719
    00720     return STATUS_MORE_PROCESSING_REQUIRED;
    00721
    00722     UNREFERENCED_PARAMETER( DeviceObject );
    00723     UNREFERENCED_PARAMETER( Contxt );
    00724 }

NTSTATUS UdfPnpQueryRemove | ( | PIRP_CONTEXT | IrpContext,
|  | PIRP | Irp,
|  | PVCB | Vcb
| ) |

Definition at line 194 of file udfs/pnp.c.

References ASSERT, Event(), Executive, FALSE, IoCallDriver, IoCopyCurrentIrpStackLocationToNext, IoSetCompletionRoutine, _IRP::IoStatus, Irp, KeInitializeEvent, KernelMode, KeWaitForSingleObject(), NT_SUCCESS, NTSTATUS(), NULL, Status, _VCB::TargetDeviceObject, TRUE, UdfAcquireUdfData, UdfAcquireVcbExclusive, UdfCheckForDismount(), UdfCompleteRequest(), UdfLockVolumeInternal(), UdfPnpCompletionRoutine(), UdfReleaseUdfData, UdfReleaseVcb, _VCB::VcbCondition, VcbDismountInProgress, and _VCB::VcbReference.

Referenced by UdfCommonPnp().

    00202                    :
    00203
    00204     This routine handles the PnP query remove operation.  The filesystem
    00205     is responsible for answering whether there are any reasons it sees
    00206     that the volume can not go away (and the device removed).  Initiation
    00207     of the dismount begins when we answer yes to this question.
    00208
    00209     Query will be followed by a Cancel or Remove.
    00210
    00211 Arguments:
    00212
    00213     Irp - Supplies the Irp to process
    00214
    00215     Vcb - Supplies the volume being queried.
    00216
    00217 Return Value:
    00218
    00219     NTSTATUS - The return status for the operation
    00220
    00221 --*/
    00222
    00223 {
    00224     NTSTATUS Status;
    00225     KEVENT Event;
    00226     BOOLEAN VcbPresent = TRUE;
    00227
    00228     //
    00229     //  Having said yes to a QUERY, any communication with the
    00230     //  underlying storage stack is undefined (and may block)
    00231     //  until the bounding CANCEL or REMOVE is sent.
    00232     //
    00233
    00234     //
    00235     //  Acquire the global resource so that we can try to vaporize
    00236     //  the volume, and the vcb resource itself.
    00237     //
    00238
    00239     UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
    00240
    00241     Status = UdfLockVolumeInternal( IrpContext, Vcb, NULL );
    00242
    00243     UdfReleaseVcb( IrpContext, Vcb );
    00244     UdfAcquireUdfData( IrpContext );
    00245     UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
    00246
    00247     if (NT_SUCCESS( Status )) {
    00248
    00249         //
    00250         //  We need to pass this down before starting the dismount, which
    00251         //  could disconnect us immediately from the stack.
    00252         //
    00253
    00254         //
    00255         //  Get the next stack location, and copy over the stack location
    00256         //
    00257
    00258         IoCopyCurrentIrpStackLocationToNext( Irp );
    00259
    00260         //
    00261         //  Set up the completion routine
    00262         //
    00263
    00264         KeInitializeEvent( &Event, NotificationEvent, FALSE );
    00265         IoSetCompletionRoutine( Irp,
    00266                                 UdfPnpCompletionRoutine,
    00267                                 &Event,
    00268                                 TRUE,
    00269                                 TRUE,
    00270                                 TRUE );
    00271
    00272         //
    00273         //  Send the request and wait.
    00274         //
    00275
    00276         Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
    00277
    00278         if (Status == STATUS_PENDING) {
    00279
    00280             KeWaitForSingleObject( &Event,
    00281                                    Executive,
    00282                                    KernelMode,
    00283                                    FALSE,
    00284                                    NULL );
    00285
    00286             Status = Irp->IoStatus.Status;
    00287         }
    00288
    00289         //
    00290         //  Now if no one below us failed already, initiate the dismount
    00291         //  on this volume, make it go away.  PnP needs to see our internal
    00292         //  streams close and drop their references to the target device.
    00293         //
    00294         //  Since we were able to lock the volume, we are guaranteed to
    00295         //  move this volume into dismount state and disconnect it from
    00296         //  the underlying storage stack.  The force on our part is actually
    00297         //  unnecesary, though complete.
    00298         //
    00299         //  What is not strictly guaranteed, though, is that the closes
    00300         //  for the metadata streams take effect synchronously underneath
    00301         //  of this call.  This would leave references on the target device
    00302         //  even though we are disconnected!
    00303         //
    00304
    00305         if (NT_SUCCESS( Status )) {
    00306
    00307             VcbPresent = UdfCheckForDismount( IrpContext, Vcb, TRUE );
    00308
    00309             ASSERT( !VcbPresent || Vcb->VcbCondition == VcbDismountInProgress );
    00310         }
    00311     }
    00312
    00313     //
    00314     //  Release the Vcb if it could still remain.
    00315     //
    00316     //  Note: if everything else succeeded and the Vcb is persistent because the
    00317     //  internal streams did not vaporize, we really need to pend this IRP off on
    00318     //  the side until the dismount is completed.  I can't think of a reasonable
    00319     //  case (in UDFS) where this would actually happen, though it might still need
    00320     //  to be implemented.
    00321     //
    00322     //  The reason this is the case is that handles/fileobjects place a reference
    00323     //  on the device objects they overly.  In the filesystem case, these references
    00324     //  are on our target devices.  PnP correcly thinks that if references remain
    00325     //  on the device objects in the stack that someone has a handle, and that this
    00326     //  counts as a reason to not succeed the query - even though every interrogated
    00327     //  driver thinks that it is OK.
    00328     //
    00329
    00330     ASSERT( !(NT_SUCCESS( Status ) && VcbPresent && Vcb->VcbReference != 0));
    00331
    00332     if (VcbPresent) {
    00333
    00334         UdfReleaseVcb( IrpContext, Vcb );
    00335     }
    00336
    00337     UdfReleaseUdfData( IrpContext );
    00338
    00339     //
    00340     //  Cleanup our IrpContext and complete the IRP if neccesary.
    00341     //
    00342
    00343     UdfCompleteRequest( IrpContext, Irp, Status );
    00344
    00345     return Status;
    00346 }

NTSTATUS UdfPnpRemove | ( | PIRP_CONTEXT | IrpContext,
|  | PIRP | Irp,
|  | PVCB | Vcb
| ) |

Definition at line 350 of file udfs/pnp.c.

References Event(), Executive, FALSE, IoCallDriver, IoCopyCurrentIrpStackLocationToNext, IoSetCompletionRoutine, _IRP::IoStatus, Irp, KeInitializeEvent, KernelMode, KeWaitForSingleObject(), NT_SUCCESS, NTSTATUS(), NULL, Status, _VCB::TargetDeviceObject, TRUE, UdfAcquireUdfData, UdfAcquireVcbExclusive, UdfCheckForDismount(), UdfCompleteRequest(), UdfLockVcb, UdfPnpCompletionRoutine(), UdfReleaseUdfData, UdfReleaseVcb, UdfUnlockVcb, UdfUnlockVolumeInternal(), _VCB::VcbCondition, VcbDismountInProgress, and VcbInvalid.

Referenced by UdfCommonPnp().

    00358                    :
    00359
    00360     This routine handles the PnP remove operation.  This is our notification
    00361     that the underlying storage device for the volume we have is gone, and
    00362     an excellent indication that the volume will never reappear. The filesystem
    00363     is responsible for initiation or completion the dismount.
    00364
    00365 Arguments:
    00366
    00367     Irp - Supplies the Irp to process
    00368
    00369     Vcb - Supplies the volume being removed.
    00370
    00371 Return Value:
    00372
    00373     NTSTATUS - The return status for the operation
    00374
    00375 --*/
    00376
    00377 {
    00378     NTSTATUS Status;
    00379     KEVENT Event;
    00380     BOOLEAN VcbPresent = TRUE;
    00381
    00382     //
    00383     //  REMOVE - a storage device is now gone.  We either got
    00384     //  QUERY'd and said yes OR got a SURPRISE OR a storage
    00385     //  stack failed to spin back up from a sleep/stop state
    00386     //  (the only case in which this will be the first warning).
    00387     //
    00388     //  Note that it is entirely unlikely that we will be around
    00389     //  for a REMOVE in the first two cases, as we try to intiate
    00390     //  dismount.
    00391     //
    00392
    00393     //
    00394     //  Acquire the global resource so that we can try to vaporize
    00395     //  the volume, and the vcb resource itself.
    00396     //
    00397
    00398     UdfAcquireUdfData( IrpContext );
    00399     UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
    00400
    00401     //
    00402     //  The device will be going away.  Remove our lock and find
    00403     //  out if we ever had one in the first place.
    00404     //
    00405
    00406     Status = UdfUnlockVolumeInternal( IrpContext, Vcb, NULL );
    00407
    00408     //
    00409     //  If the volume had not been locked, we must invalidate the
    00410     //  volume to ensure it goes away properly.  The remove will
    00411     //  succeed.
    00412     //
    00413
    00414     if (!NT_SUCCESS( Status )) {
    00415
    00416         UdfLockVcb( IrpContext, Vcb );
    00417
    00418         if (Vcb->VcbCondition != VcbDismountInProgress) {
    00419             Vcb->VcbCondition = VcbInvalid;
    00420         }
    00421
    00422         UdfUnlockVcb( IrpContext, Vcb );
    00423
    00424         Status = STATUS_SUCCESS;
    00425     }
    00426
    00427     //
    00428     //  We need to pass this down before starting the dismount, which
    00429     //  could disconnect us immediately from the stack.
    00430     //
    00431
    00432     //
    00433     //  Get the next stack location, and copy over the stack location
    00434     //
    00435
    00436     IoCopyCurrentIrpStackLocationToNext( Irp );
    00437
    00438     //
    00439     //  Set up the completion routine
    00440     //
    00441
    00442     KeInitializeEvent( &Event, NotificationEvent, FALSE );
    00443     IoSetCompletionRoutine( Irp,
    00444                             UdfPnpCompletionRoutine,
    00445                             &Event,
    00446                             TRUE,
    00447                             TRUE,
    00448                             TRUE );
    00449
    00450     //
    00451     //  Send the request and wait.
    00452     //
    00453
    00454     Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
    00455
    00456     if (Status == STATUS_PENDING) {
    00457
    00458         KeWaitForSingleObject( &Event,
    00459                                Executive,
    00460                                KernelMode,
    00461                                FALSE,
    00462                                NULL );
    00463
    00464         Status = Irp->IoStatus.Status;
    00465     }
    00466
    00467     //
    00468     //  Now make our dismount happen.  This may not vaporize the
    00469     //  Vcb, of course, since there could be any number of handles
    00470     //  outstanding if we were not preceeded by a QUERY.
    00471     //
    00472     //  PnP will take care of disconnecting this stack if we
    00473     //  couldn't get off of it immediately.
    00474     //
    00475
    00476     VcbPresent = UdfCheckForDismount( IrpContext, Vcb, TRUE );
    00477
    00478     //
    00479     //  Release the Vcb if it could still remain.
    00480     //
    00481
    00482     if (VcbPresent) {
    00483
    00484         UdfReleaseVcb( IrpContext, Vcb );
    00485     }
    00486
    00487     UdfReleaseUdfData( IrpContext );
    00488
    00489     //
    00490     //  Cleanup our IrpContext and complete the IRP.
    00491     //
    00492
    00493     UdfCompleteRequest( IrpContext, Irp, Status );
    00494
    00495     return Status;
    00496 }

NTSTATUS UdfPnpSurpriseRemove | ( | PIRP_CONTEXT | IrpContext,
|  | PIRP | Irp,
|  | PVCB | Vcb
| ) |

Definition at line 500 of file udfs/pnp.c.

References Event(), Executive, FALSE, IoCallDriver, IoCopyCurrentIrpStackLocationToNext, IoSetCompletionRoutine, _IRP::IoStatus, Irp, KeInitializeEvent, KernelMode, KeWaitForSingleObject(), NTSTATUS(), NULL, Status, _VCB::TargetDeviceObject, TRUE, UdfAcquireUdfData, UdfAcquireVcbExclusive, UdfCheckForDismount(), UdfCompleteRequest(), UdfLockVcb, UdfPnpCompletionRoutine(), UdfReleaseUdfData, UdfReleaseVcb, UdfUnlockVcb, _VCB::VcbCondition, VcbDismountInProgress, and VcbInvalid.

Referenced by UdfCommonPnp().

    00508                    :
    00509
    00510     This routine handles the PnP surprise remove operation.  This is another
    00511     type of notification that the underlying storage device for the volume we
    00512     have is gone, and is excellent indication that the volume will never reappear.
    00513     The filesystem is responsible for initiation or completion the dismount.
    00514
    00515     For the most part, only "real" drivers care about the distinction of a
    00516     surprise remove, which is a result of our noticing that a user (usually)
    00517     physically reached into the machine and pulled something out.
    00518
    00519     Surprise will be followed by a Remove when all references have been shut down.
    00520
    00521 Arguments:
    00522
    00523     Irp - Supplies the Irp to process
    00524
    00525     Vcb - Supplies the volume being removed.
    00526
    00527 Return Value:
    00528
    00529     NTSTATUS - The return status for the operation
    00530
    00531 --*/
    00532
    00533 {
    00534     NTSTATUS Status;
    00535     KEVENT Event;
    00536     BOOLEAN VcbPresent = TRUE;
    00537
    00538     //
    00539     //  SURPRISE - a device was physically yanked away without
    00540     //  any warning.  This means external forces.
    00541     //
    00542
    00543     UdfAcquireUdfData( IrpContext );
    00544     UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
    00545
    00546     //
    00547     //  Invalidate the volume right now.
    00548     //
    00549     //  The intent here is to make every subsequent operation
    00550     //  on the volume fail and grease the rails toward dismount.
    00551     //  By definition there is no going back from a SURPRISE.
    00552     //
    00553
    00554     UdfLockVcb( IrpContext, Vcb );
    00555
    00556     if (Vcb->VcbCondition != VcbDismountInProgress) {
    00557         Vcb->VcbCondition = VcbInvalid;
    00558     }
    00559
    00560     UdfUnlockVcb( IrpContext, Vcb );
    00561
    00562     //
    00563     //  We need to pass this down before starting the dismount, which
    00564     //  could disconnect us immediately from the stack.
    00565     //
    00566
    00567     //
    00568     //  Get the next stack location, and copy over the stack location
    00569     //
    00570
    00571     IoCopyCurrentIrpStackLocationToNext( Irp );
    00572
    00573     //
    00574     //  Set up the completion routine
    00575     //
    00576
    00577     KeInitializeEvent( &Event, NotificationEvent, FALSE );
    00578     IoSetCompletionRoutine( Irp,
    00579                             UdfPnpCompletionRoutine,
    00580                             &Event,
    00581                             TRUE,
    00582                             TRUE,
    00583                             TRUE );
    00584
    00585     //
    00586     //  Send the request and wait.
    00587     //
    00588
    00589     Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
    00590
    00591     if (Status == STATUS_PENDING) {
    00592
    00593         KeWaitForSingleObject( &Event,
    00594                                Executive,
    00595                                KernelMode,
    00596                                FALSE,
    00597                                NULL );
    00598
    00599         Status = Irp->IoStatus.Status;
    00600     }
    00601
    00602     //
    00603     //  Now make our dismount happen.  This may not vaporize the
    00604     //  Vcb, of course, since there could be any number of handles
    00605     //  outstanding since this is an out of band notification.
    00606     //
    00607
    00608     VcbPresent = UdfCheckForDismount( IrpContext, Vcb, TRUE );
    00609
    00610     //
    00611     //  Release the Vcb if it could still remain.
    00612     //
    00613
    00614     if (VcbPresent) {
    00615
    00616         UdfReleaseVcb( IrpContext, Vcb );
    00617     }
    00618
    00619     UdfReleaseUdfData( IrpContext );
    00620
    00621     //
    00622     //  Cleanup our IrpContext and complete the IRP.
    00623     //
    00624
    00625     UdfCompleteRequest( IrpContext, Irp, Status );
    00626
    00627     return Status;
    00628 }