/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
cleanup.c
Abstract:
This module implements the file cleanup routine for Netware Redirector.
Author:
Manny Weiser (mannyw) 9-Feb-1993
Revision History:
--*/
#include "procs.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_CLEANUP)
//
// local procedure prototypes
//
NTSTATUS
NwCommonCleanup (
IN PIRP_CONTEXT IrpContext
);
NTSTATUS
NwCleanupRcb (
IN PIRP Irp,
IN PRCB Rcb
);
NTSTATUS
NwCleanupScb (
IN PIRP Irp,
IN PSCB Scb
);
NTSTATUS
NwCleanupIcb (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp,
IN PICB Icb
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, NwFsdCleanup )
#pragma alloc_text( PAGE, NwCommonCleanup )
#pragma alloc_text( PAGE, NwCleanupScb )
#ifndef QFE_BUILD
#pragma alloc_text( PAGE1, NwCleanupIcb )
#endif
#endif
#if 0 // Not pageable
NwCleanupRcb
// see ifndef QFE_BUILD above
#endif
NTSTATUS
NwFsdCleanup (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine implements the FSD part of the NtCleanupFile API calls.
Arguments:
DeviceObject - Supplies the device object to use.
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The Fsd status for the Irp
--*/
{
NTSTATUS status;
PIRP_CONTEXT IrpContext = NULL;
BOOLEAN TopLevel;
PAGED_CODE();
DebugTrace(+1, Dbg, "NwFsdCleanup\n", 0);
//
// Call the common cleanup routine.
//
TopLevel = NwIsIrpTopLevel( Irp );
FsRtlEnterFileSystem();
try {
IrpContext = AllocateIrpContext( Irp );
status = NwCommonCleanup( IrpContext );
} except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
if ( IrpContext == NULL ) {
//
// If we couldn't allocate an irp context, just complete
// irp without any fanfare.
//
status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
} else {
//
// 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 = NwProcessException( IrpContext, GetExceptionCode() );
}
}
if ( IrpContext ) {
NwCompleteRequest( IrpContext, status );
}
if ( TopLevel ) {
NwSetTopLevelIrp( NULL );
}
FsRtlExitFileSystem();
//
// Return to our caller.
//
DebugTrace(-1, Dbg, "NwFsdCleanup -> %08lx\n", status );
return status;
}
NTSTATUS
NwCommonCleanup (
IN PIRP_CONTEXT IrpContext
)
/*++
Routine Description:
This is the common routine for cleaning up a file.
Arguments:
IrpContext - Supplies the Irp to process
Return Value:
NTSTATUS - the return status for the operation
--*/
{
PIRP Irp;
PIO_STACK_LOCATION irpSp;
NTSTATUS status;
NODE_TYPE_CODE nodeTypeCode;
PVOID fsContext, fsContext2;
PAGED_CODE();
Irp = IrpContext->pOriginalIrp;
irpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NwCommonCleanup\n", 0);
DebugTrace( 0, Dbg, "IrpContext = %08lx\n", (ULONG)IrpContext);
DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp);
DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG)irpSp->FileObject);
try {
//
// Get the a referenced pointer to the node and make sure it is
// not being closed.
//
if ((nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
&fsContext,
&fsContext2 )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "The file is disconnected\n", 0);
status = STATUS_INVALID_HANDLE;
DebugTrace(-1, Dbg, "NwCommonCleanup -> %08lx\n", status );
try_return( NOTHING );
}
//
// Decide how to handle this IRP.
//
switch (nodeTypeCode) {
case NW_NTC_RCB: // Cleanup the file system
status = NwCleanupRcb( Irp, (PRCB)fsContext2 );
break;
case NW_NTC_SCB: // Cleanup the server control block
status = NwCleanupScb( Irp, (PSCB)fsContext2 );
break;
case NW_NTC_ICB: // Cleanup the remote file
case NW_NTC_ICB_SCB: // Cleanup the server
status = NwCleanupIcb( IrpContext, Irp, (PICB)fsContext2 );
break;
#ifdef NWDBG
default:
//
// This is not one of ours.
//
KeBugCheck( RDR_FILE_SYSTEM );
break;
#endif
}
try_exit: NOTHING;
} finally {
DebugTrace(-1, Dbg, "NwCommonCleanup -> %08lx\n", status);
}
return status;
}
NTSTATUS
NwCleanupRcb (
IN PIRP Irp,
IN PRCB Rcb
)
/*++
Routine Description:
The routine cleans up a RCB.
This routine grabs a spinlock so must not be paged out while running.
Do not reference the code section since this will start the timer and
we don't stop it in the rcb close path.
Arguments:
Irp - Supplies the IRP associated with the cleanup.
Rcb - Supplies the RCB for MSFS.
Return Value:
NTSTATUS - An appropriate completion status
--*/
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
PFILE_OBJECT closingFileObject;
BOOLEAN OwnRcb;
BOOLEAN OwnMessageLock = FALSE;
KIRQL OldIrql;
PLIST_ENTRY listEntry, nextListEntry;
PIRP_CONTEXT pTestIrpContext;
PIO_STACK_LOCATION pTestIrpSp;
PIRP pTestIrp;
DebugTrace(+1, Dbg, "NwCleanupRcb...\n", 0);
//
// Now acquire exclusive access to the Rcb
//
NwAcquireExclusiveRcb( Rcb, TRUE );
OwnRcb = TRUE;
status = STATUS_SUCCESS;
try {
irpSp = IoGetCurrentIrpStackLocation( Irp );
IoRemoveShareAccess( irpSp->FileObject,
&Rcb->ShareAccess );
NwReleaseRcb( Rcb );
OwnRcb = FALSE;
closingFileObject = irpSp->FileObject;
//
// Walk the message queue and complete any outstanding Get Message IRPs
//
KeAcquireSpinLock( &NwMessageSpinLock, &OldIrql );
OwnMessageLock = TRUE;
for ( listEntry = NwGetMessageList.Flink;
listEntry != &NwGetMessageList;
listEntry = nextListEntry ) {
nextListEntry = listEntry->Flink;
//
// If the file object of the queued request, matches the file object
// that is being closed, remove the IRP from the queue, and
// complete it with an error.
//
pTestIrpContext = CONTAINING_RECORD( listEntry, IRP_CONTEXT, NextRequest );
pTestIrp = pTestIrpContext->pOriginalIrp;
pTestIrpSp = IoGetCurrentIrpStackLocation( pTestIrp );
if ( pTestIrpSp->FileObject == closingFileObject ) {
RemoveEntryList( listEntry );
IoAcquireCancelSpinLock( &pTestIrp->CancelIrql );
IoSetCancelRoutine( pTestIrp, NULL );
IoReleaseCancelSpinLock( pTestIrp->CancelIrql );
NwCompleteRequest( pTestIrpContext, STATUS_INVALID_HANDLE );
}
}
KeReleaseSpinLock( &NwMessageSpinLock, OldIrql );
OwnMessageLock = FALSE;
} finally {
if ( OwnRcb ) {
NwReleaseRcb( Rcb );
}
if ( OwnMessageLock ) {
KeReleaseSpinLock( &NwMessageSpinLock, OldIrql );
}
DebugTrace(-1, Dbg, "NwCleanupRcb -> %08lx\n", status);
}
//
// And return to our caller
//
return status;
}
NTSTATUS
NwCleanupScb (
IN PIRP Irp,
IN PSCB Scb
)
/*++
Routine Description:
The routine cleans up an ICB.
Arguments:
Irp - Supplies the IRP associated with the cleanup.
Scb - Supplies the SCB to cleanup.
Return Value:
NTSTATUS - An appropriate completion status
--*/
{
NTSTATUS Status;
PAGED_CODE();
DebugTrace(+1, Dbg, "NwCleanupScb...\n", 0);
Status = STATUS_SUCCESS;
try {
//
// Ensure that this SCB is still active.
//
NwVerifyScb( Scb );
//
// Cancel any IO on this SCB.
//
} finally {
DebugTrace(-1, Dbg, "NwCleanupScb -> %08lx\n", Status);
}
//
// And return to our caller
//
return Status;
}
NTSTATUS
NwCleanupIcb (
IN PIRP_CONTEXT pIrpContext,
IN PIRP Irp,
IN PICB Icb
)
/*++
Routine Description:
The routine cleans up an ICB.
Arguments:
Irp - Supplies the IRP associated with the cleanup.
Rcb - Supplies the RCB for MSFS.
Return Value:
NTSTATUS - An appropriate completion status
--*/
{
NTSTATUS Status;
PNONPAGED_FCB NpFcb;
DebugTrace(+1, Dbg, "NwCleanupIcb...\n", 0);
Status = STATUS_SUCCESS;
try {
Icb->State = ICB_STATE_CLEANED_UP;
//
// Cancel any IO on this ICB.
//
#if 0
// HACKHACK
if ( Icb->SuperType.Fcb->NodeTypeCode == NW_NTC_DCB ) {
PLIST_ENTRY listEntry;
NwAcquireExclusiveRcb( &NwRcb, TRUE );
for ( listEntry = FnList.Flink; listEntry != &FnList ; listEntry = listEntry->Flink ) {
PIRP_CONTEXT IrpContext;
IrpContext = CONTAINING_RECORD( listEntry, IRP_CONTEXT, NextRequest );
if ( IrpContext->Icb == Icb ) {
PIRP irp = pIrpContext->pOriginalIrp;
IoAcquireCancelSpinLock( &irp->CancelIrql );
IoSetCancelRoutine( irp, NULL );
IoReleaseCancelSpinLock( irp->CancelIrql );
RemoveEntryList( &IrpContext->NextRequest );
NwCompleteRequest( IrpContext, STATUS_NOT_SUPPORTED );
break;
}
}
NwReleaseRcb( &NwRcb );
}
#endif
//
// If this is a remote file clear all the cache garbage.
//
if ( Icb->NodeTypeCode == NW_NTC_ICB ) {
if ( Icb->HasRemoteHandle ) {
//
// Free all of file lock structures that are still hanging around.
//
pIrpContext->pScb = Icb->SuperType.Fcb->Scb;
pIrpContext->pNpScb = Icb->SuperType.Fcb->Scb->pNpScb;
NwFreeLocksForIcb( pIrpContext, Icb );
NwDequeueIrpContext( pIrpContext, FALSE );
//
//
//
// If this is an executable opened over the net, then
// its possible that the executables image section
// might still be kept open.
//
// Ask MM to flush the section closed. This will fail
// if the executable in question is still running.
//
NpFcb = Icb->SuperType.Fcb->NonPagedFcb;
MmFlushImageSection(&NpFcb->SegmentObject, MmFlushForWrite);
//
// There is also a possiblity that there is a user section
// open on this file, in which case we need to force the
// section closed to make sure that they are cleaned up.
//
MmForceSectionClosed(&NpFcb->SegmentObject, TRUE);
}
//
// Remove shared access.
//
IoRemoveShareAccess(
Icb->FileObject,
&Icb->SuperType.Fcb->ShareAccess );
}
} finally {
DebugTrace(-1, Dbg, "NwCleanupIcb -> %08lx\n", Status);
}
//
// And return to our caller
//
return Status;
}