//+---------------------------------------------------------------------------- // // Copyright (C) 1992, Microsoft Corporation. // // File: CLOSE.C // // Contents: This module implements the File Close and Cleanup routines for // Dsfs called by the dispatch driver. // // Functions: DfsFsdClose - FSD entry point for Close IRP // DfsFsdCleanup - FSD entry point for Cleanup IRP // DfsFspClose - FSP entry point for Close IRP // DfsCommonClose - Common close IRP handler // // History: 12 Nov 1991 AlanW Created from CDFS souce. //----------------------------------------------------------------------------- #include "dfsprocs.h" #include "fcbsup.h" #include "mupwml.h" // // The local debug trace level // #define Dbg (DEBUG_TRACE_CLOSE) // // Local procedure prototypes // NTSTATUS DfsCommonClose ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ); VOID DfsCloseWorkInSystemContext ( PDFS_FCB pDfsFcb ); VOID DfsClosePostSystemWork( PDFS_FCB pDfsFcb ); #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, DfsFsdClose ) #pragma alloc_text( PAGE, DfsFsdCleanup ) #pragma alloc_text( PAGE, DfsFspClose ) #pragma alloc_text( PAGE, DfsCommonClose ) #endif // ALLOC_PRAGMA //+------------------------------------------------------------------- // // Function: DfsFsdClose, public // // Synopsis: This routine implements the FSD part of closing down the // last reference to a file object. // // Arguments: [DeviceObject] -- Supplies the device object where the // file being closed exists // [Irp] - Supplies the Irp being processed // // Returns: NTSTATUS - The FSD status for the IRP // // Notes: Even when the close is through the attached device // object, we need to check if the file is one of ours, // since files opened via the logical root device // object get switched over to the attached device for // local volumes. // //-------------------------------------------------------------------- NTSTATUS DfsFsdClose ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT FileObject = IrpSp->FileObject; NTSTATUS Status; PIRP_CONTEXT IrpContext; MUP_TRACE_HIGH(TRACE_IRP, DfsFsdClose_Entry, LOGPTR(DeviceObject) LOGPTR(Irp) LOGPTR(FileObject)); DfsDbgTrace(+1, Dbg, "DfsFsdClose: Entered\n", 0); ASSERT(IoIsOperationSynchronous(Irp) == TRUE); if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME) { if (DfsLookupFcb(IrpSp->FileObject) == NULL) { Status = DfsVolumePassThrough(DeviceObject, Irp); DfsDbgTrace(-1, Dbg, "DfsFsdClose: Exit -> %08lx\n", ULongToPtr(Status) ); return Status; } } // // Call the common close routine, with blocking allowed if synchronous // FsRtlEnterFileSystem(); try { IrpContext = DfsCreateIrpContext( Irp, CanFsdWait( Irp ) ); if (IrpContext == NULL) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); Status = DfsCommonClose( IrpContext, Irp ); } except(DfsExceptionFilter( IrpContext, GetExceptionCode(), GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = DfsProcessException( IrpContext, Irp, GetExceptionCode() ); } FsRtlExitFileSystem(); // // And return to our caller // DfsDbgTrace(-1, Dbg, "DfsFsdClose: Exit -> %08lx\n", ULongToPtr(Status)); MUP_TRACE_HIGH(TRACE_IRP, DfsFsdClose_Exit, LOGSTATUS(Status) LOGPTR(DeviceObject) LOGPTR(Irp) LOGPTR(FileObject)); return Status; } //+------------------------------------------------------------------- // // Function: DfsFsdCleanup, public // // Synopsis: This routine implements the FSD part of closing down the // last user handle to a file object. // // Arguments: [DeviceObject] -- Supplies the device object where the // file being closed exists // [Irp] - Supplies the Irp being processed // // Returns: NTSTATUS - The FSD status for the IRP // //-------------------------------------------------------------------- NTSTATUS DfsFsdCleanup ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS Status; PIRP_CONTEXT IrpContext; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT FileObject = IrpSp->FileObject; TYPE_OF_OPEN TypeOfOpen; PDFS_VCB Vcb; PDFS_FCB Fcb; DfsDbgTrace(+1, Dbg, "DfsFsdCleanup: Entered\n", 0); MUP_TRACE_HIGH(TRACE_IRP, DfsFsdCleanup_Entry, LOGPTR(DeviceObject) LOGPTR(FileObject) LOGPTR(Irp)); ASSERT(IoIsOperationSynchronous(Irp) == TRUE); // // Now, pass through to the device that opened the file for us if the // file was a redirected open of some kind. // if (DeviceObject->DeviceType == FILE_DEVICE_DFS) { TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb); if (TypeOfOpen == RedirectedFileOpen) { Status = DfsVolumePassThrough(DeviceObject, Irp); DfsDbgTrace(-1, Dbg, "DfsFsdCleanup: RedirectedOpen.Exit -> %08lx\n", ULongToPtr(Status) ); return Status; } } // // TypeOfOpen != RedirectedFileOpen. We do nothing special for cleanup; // everything is done in the close routine. // FsRtlEnterFileSystem(); Status = STATUS_SUCCESS; DfsCompleteRequest( NULL, Irp, Status ); FsRtlExitFileSystem(); // // And return to our caller // DfsDbgTrace(-1, Dbg, "DfsFsdCleanup: Exit -> %08lx\n", ULongToPtr(Status)); MUP_TRACE_HIGH(TRACE_IRP, DfsFsdCleanup_Exit, LOGSTATUS(Status) LOGPTR(DeviceObject) LOGPTR(FileObject) LOGPTR(Irp)); return Status; } //+------------------------------------------------------------------- // // Function: DfsFspClose, public // // Synopsis: This routine implements the FSP part of closing down the // last reference to a file object. // // Arguments: [IrpContext] -- Supplies the IRP context for the request // being processed. // [Irp] - Supplies the Irp being processed // // Returns: PDEVICE_OBJECT - Returns the volume device object // of the volume just processed by this operation. // This value is used by the Fsp dispatcher to examine // the device object's overflow queue // //-------------------------------------------------------------------- VOID DfsFspClose ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) { DfsDbgTrace(+1, Dbg, "DfsFspClose: Entered\n", 0); // // Call the common close routine. // (VOID)DfsCommonClose( IrpContext, Irp ); // // And return to our caller // DfsDbgTrace(-1, Dbg, "DfsFspClose: Exit -> VOID\n", 0); } //+------------------------------------------------------------------- // // Function: DfsCommonClose, local // // Synopsis: This is the common routine for closing a file/directory // called by both the fsd and fsp threads. // // Close is invoked whenever the last reference to a file // object is deleted. Cleanup is invoked when the last handle // to a file object is closed, and is called before close. // // The function of close is to completely tear down and // remove the DFS_FCB structures associated with the // file object. // // Arguments: [Irp] -- Supplies the Irp to process // // Returns: NTSTATUS - The return status for the operation // //-------------------------------------------------------------------- NTSTATUS DfsCommonClose ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) { NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT FileObject = IrpSp->FileObject; TYPE_OF_OPEN TypeOfOpen; PDFS_VCB Vcb; PDFS_FCB Fcb; BOOLEAN DontComplete = FALSE; BOOLEAN pktLocked; DfsDbgTrace(+1, Dbg, "DfsCommonClose: Entered\n", 0); DfsDbgTrace( 0, Dbg, "Irp = %08lx\n", Irp); DfsDbgTrace( 0, Dbg, "->FileObject = %08lx\n", FileObject); // // This action is a noop for unopened file objects. Nothing needs // to be done for FS device opens, either. // TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb); if (TypeOfOpen == UnopenedFileObject || TypeOfOpen == FilesystemDeviceOpen ) { DfsDbgTrace(-1, Dbg, "DfsCommonClose: Filesystem file object\n", 0); DfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); return STATUS_SUCCESS; } try { // // Case on the type of open that we are trying to close. // switch (TypeOfOpen) { case LogicalRootDeviceOpen: DfsDbgTrace(0, Dbg, "DfsCommonClose: Close LogicalRootDevice\n", 0); InterlockedDecrement(&Vcb->DirectAccessOpenCount); InterlockedDecrement(&Vcb->OpenFileCount); if (Vcb->VcbState & VCB_STATE_FLAG_LOCKED) { Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED; Vcb->FileObjectWithVcbLocked = NULL; } try_return( Status = STATUS_SUCCESS ); case RedirectedFileOpen: DfsDbgTrace(0, Dbg, "DfsCommonClose: File -> %wZ\n", &Fcb->FullFileName); // // Decrement the OpenFileCount for the Vcb through which this // file was opened. // InterlockedDecrement(&Vcb->OpenFileCount); // // Close the redirected file by simply passing through // to the redirected device. We detach the DFS_FCB from the // file object before the close so it cannot be looked // up in some other thread. // DfsDetachFcb( FileObject, Fcb); Status = DfsFilePassThrough(Fcb, Irp); DontComplete = TRUE; // // Post to system work here, to avoid deadlocks with RDR. // workaround for bug 20642. // DfsClosePostSystemWork( Fcb ); break; default: BugCheck("Dfs close, unexpected open type"); } try_exit: NOTHING; } finally { // // If this is a normal termination, then complete the request. // Even if we're not to complete the IRP, we still need to // delete the IRP_CONTEXT. // if (!AbnormalTermination()) { if (DontComplete) { DfsCompleteRequest( IrpContext, NULL, 0 ); } else { DfsCompleteRequest( IrpContext, Irp, Status ); } } DfsDbgTrace(-1, Dbg, "DfsCommonClose: Exit -> %08lx\n", ULongToPtr(Status)); } return Status; } VOID DfsClosePostSystemWork( PDFS_FCB pDfsFcb ) { ExInitializeWorkItem( &pDfsFcb->WorkQueueItem, DfsCloseWorkInSystemContext, pDfsFcb ); ExQueueWorkItem( &pDfsFcb->WorkQueueItem, CriticalWorkQueue ); return; } // //work around for bug 20642. // VOID DfsCloseWorkInSystemContext ( PDFS_FCB pDfsFcb ) { BOOLEAN pktLocked; // // Decrement the RefCount on the DFS_MACHINE_ENTRY through which // this file was opened // PktAcquireExclusive( TRUE, &pktLocked ); ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE ); DfsDecrementMachEntryCount(pDfsFcb->DfsMachineEntry, TRUE); ExReleaseResourceLite( &DfsData.Resource ); PktRelease(); DfsDeleteFcb( NULL, pDfsFcb ); }