/*++ 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; }