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 }


Generated on Sat May 15 19:45:09 2004 for test by doxygen 1.3.7