/*++ Copyright (c) 1991 Microsoft Corporation Module Name: DevCtrl.c Abstract: This module implements the Device Control routines for Ntfs called by the dispatch driver. Author: Gary Kimura [GaryKi] 28-May-1991 Revision History: --*/ #include "NtfsProc.h" #include // // The local debug trace level // #define Dbg (DEBUG_TRACE_DEVCTRL) // // Local procedure prototypes // NTSTATUS DeviceControlCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Contxt ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, NtfsCommonDeviceControl) #endif NTSTATUS NtfsCommonDeviceControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for Device Control called by both the fsd and fsp threads. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status = STATUS_SUCCESS; TYPE_OF_OPEN TypeOfOpen; PIO_STACK_LOCATION IrpSp; NTFS_COMPLETION_CONTEXT Context; PNTFS_COMPLETION_CONTEXT CompletionContext = NULL; LOGICAL ReleaseResources = FALSE; PVCB Vcb; PFCB Fcb; PSCB Scb; PCCB Ccb; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_IRP( Irp ); ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL )); PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsCommonDeviceControl\n") ); DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) ); DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) ); // // Extract and decode the file object // IrpSp = IoGetCurrentIrpStackLocation( Irp ); TypeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE ); // // The only type of opens we accept are user volume opens. // if (TypeOfOpen != UserVolumeOpen) { NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); DebugTrace( -1, Dbg, ("NtfsCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER) ); return STATUS_INVALID_PARAMETER; } try { // // A few IOCTLs actually require some intervention on our part // switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES: // // This is sent by the Volume Snapshot driver (Lovelace). // We flush the volume, and hold all file resources // to make sure that nothing more gets dirty. Then we wait // for the IRP to complete or cancel. // Status = NtfsCheckpointForVolumeSnapshot( IrpContext ); if (NT_SUCCESS( Status )) { ReleaseResources = TRUE; } KeInitializeEvent( &Context.Event, NotificationEvent, FALSE ); Context.IrpContext = IrpContext; CompletionContext = &Context; SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT ); break; case IOCTL_VOLSNAP_RELEASE_WRITES: // // No-op for filesystems. // break; default: break; } // // If error, complete the irp, free the IrpContext // and return to the caller. // if (!NT_SUCCESS( Status )) { NtfsCompleteRequest( NULL, Irp, Status ); leave; } // // Get the next stack location, and copy over the stack parameter // information // IoCopyCurrentIrpStackLocationToNext( Irp ); // // Set up the completion routine // IoSetCompletionRoutine( Irp, DeviceControlCompletionRoutine, CompletionContext, TRUE, TRUE, TRUE ); // // Send the request. And wait. // Status = IoCallDriver( Vcb->TargetDeviceObject, Irp ); if ((Status == STATUS_PENDING) && (CompletionContext != NULL)) { KeWaitForSingleObject( &CompletionContext->Event, Executive, KernelMode, FALSE, NULL ); } } finally { // // Release all the resources that we held because of a // VOLSNAP_FLUSH_AND_HOLD. // if (ReleaseResources && !NtfsIsVolumeReadOnly( IrpContext->Vcb )) { NtfsReleaseAllFiles( IrpContext, IrpContext->Vcb, FALSE ); NtfsReleaseVcb( IrpContext, Vcb ); } #ifdef SUPW_DBG if (AbnormalTermination()) { DbgPrint("CommonDevControl Raised: Status %8lx\n", Status); } #endif } NtfsCleanupIrpContext( IrpContext, TRUE ); DebugTrace( -1, Dbg, ("NtfsCommonDeviceControl -> %08lx\n", Status) ); return Status; } // // Local support routine // NTSTATUS DeviceControlCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Contxt ) { // // Add the hack-o-ramma to fix formats. // if (Irp->PendingReturned) { IoMarkIrpPending( Irp ); } if (Contxt) { PNTFS_COMPLETION_CONTEXT CompletionContext = (PNTFS_COMPLETION_CONTEXT)Contxt; KeSetEvent( &CompletionContext->Event, 0, FALSE ); } // // Return success always, because we want this IRP to go away for good // irrespective of the IRP completion status. // return STATUS_SUCCESS; UNREFERENCED_PARAMETER( DeviceObject ); }