Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

451 lines
12 KiB

//+----------------------------------------------------------------------------
//
// 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) {
ASSERT (Vcb->FileObjectWithVcbLocked == FileObject);
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 );
}