/************************************************************************* * * Function: Ext2PassDownMultiReadWriteIRP() * * Description: * pass down multiple read IRPs as Associated IRPs * * Expected Interrupt Level (for execution) : * * ? * * Return Value: STATUS_SUCCESS / STATUS_PENDING / Error * *************************************************************************/ NTSTATUS NTAPI Ext2PassDownMultiReadWriteIRP( PEXT2_IO_RUN PtrIoRuns, UINT Count, ULONG TotalReadWriteLength, PtrExt2IrpContext PtrIrpContext, PtrExt2FCB PtrFCB, BOOLEAN SynchronousIo) { PIRP PtrMasterIrp; PIRP PtrAssociatedIrp; PIO_STACK_LOCATION PtrIrpSp; PMDL PtrMdl; PtrExt2VCB PtrVCB; UINT i; ULONG BufferOffset; PEXT2_IO_CONTEXT PtrIoContext = NULL; PKEVENT PtrSyncEvent = NULL; ULONG LogicalBlockSize; ULONG ReadWriteLength; NTSTATUS RC = STATUS_SUCCESS; PtrVCB = PtrFCB->PtrVCB; PtrMasterIrp = PtrIrpContext->Irp; LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; try { if( !SynchronousIo ) { IoMarkIrpPending( PtrIrpContext->Irp ); // We will be returning STATUS_PENDING... } if( !PtrMasterIrp->MdlAddress ) { Ext2LockCallersBuffer( PtrMasterIrp, TRUE, TotalReadWriteLength ); } if( SynchronousIo ) { PtrSyncEvent = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) ); if ( !PtrSyncEvent ) { RC = STATUS_INSUFFICIENT_RESOURCES; try_return(); } KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE ); } // // Allocate and initialize a completion context // PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) ); if ( !PtrIoContext ) { RC = STATUS_INSUFFICIENT_RESOURCES; try_return(); } RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) ); PtrIoContext->Count = Count; PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT; PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT ); PtrIoContext->PtrMasterIrp = PtrMasterIrp; PtrIoContext->PtrSyncEvent = PtrSyncEvent; PtrIoContext->ReadWriteLength = TotalReadWriteLength; for( ReadWriteLength = 0, BufferOffset = 0, i = 0; i < Count; i++, BufferOffset += ReadWriteLength ) { ReadWriteLength = PtrIoRuns[ i].EndOffset - PtrIoRuns[ i].StartOffset; // // Allocating an Associated IRP... // PtrAssociatedIrp = IoMakeAssociatedIrp( PtrMasterIrp, (CCHAR) (PtrVCB->TargetDeviceObject->StackSize + 1 ) ); PtrIoRuns[ i].PtrAssociatedIrp = PtrAssociatedIrp; ASSERT ( PtrAssociatedIrp ); PtrMasterIrp->AssociatedIrp.IrpCount ++; // // Allocating a Memory Descriptor List... // PtrMdl = IoAllocateMdl( (PCHAR) PtrMasterIrp->UserBuffer + BufferOffset, // Virtual Address ReadWriteLength, FALSE, FALSE, PtrAssociatedIrp ); // // and building a partial MDL... // IoBuildPartialMdl( PtrMasterIrp->MdlAddress, PtrMdl, (PCHAR)PtrMasterIrp->UserBuffer + BufferOffset, ReadWriteLength ); // // Create an Irp stack location for ourselves... // IoSetNextIrpStackLocation( PtrAssociatedIrp ); PtrIrpSp = IoGetCurrentIrpStackLocation( PtrAssociatedIrp ); // // Setup the Stack location to describe our read. // PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) { PtrIrpSp->Parameters.Read.Length = ReadWriteLength; PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) { PtrIrpSp->Parameters.Write.Length = ReadWriteLength; PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock; // // Setup a completion routine... // IoSetCompletionRoutine( PtrAssociatedIrp, SynchronousIo ? Ext2MultiSyncCompletionRoutine : Ext2MultiAsyncCompletionRoutine, PtrIoContext, TRUE, TRUE, TRUE ); // // Initialise the next stack location for the driver below us to use... // PtrIrpSp = IoGetNextIrpStackLocation( PtrAssociatedIrp ); PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) { PtrIrpSp->Parameters.Read.Length = ReadWriteLength; PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) { PtrIrpSp->Parameters.Write.Length = ReadWriteLength; PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = // PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } for( i = 0; i < Count; i++ ) { // DbgPrint("PASSING DOWN IRP %d TO TARGET DEVICE\n", i); IoCallDriver( PtrVCB->TargetDeviceObject, PtrIoRuns[ i].PtrAssociatedIrp ); } if( SynchronousIo ) { // // Synchronous IO // Wait for the IO to complete... // DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql()); KeWaitForSingleObject( PtrSyncEvent, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); DbgPrint("DEADLY WAIT DONE\n"); try_return(); } else { // Asynchronous IO... RC = STATUS_PENDING; try_return(); } try_exit: NOTHING; } finally { if( PtrSyncEvent ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent ); ExFreePool( PtrSyncEvent ); } if( PtrIoContext && ! ( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) ) { // // This means we are getting out of // this function without doing a read // due to an error, maybe... // DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext); ExFreePool( PtrIoContext ); } } return(RC); }
NTSTATUS Ext2ReadWriteBlocks( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_EXTENT Chain, IN ULONG Length ) { PIRP Irp; PIRP MasterIrp = IrpContext->Irp; PIO_STACK_LOCATION IrpSp; PMDL Mdl; PEXT2_RW_CONTEXT pContext = NULL; PEXT2_EXTENT Extent; KEVENT Wait; NTSTATUS Status = STATUS_SUCCESS; BOOLEAN bMasterCompleted = FALSE; BOOLEAN bBugCheck = FALSE; ASSERT(MasterIrp); __try { pContext = Ext2AllocatePool(NonPagedPool, sizeof(EXT2_RW_CONTEXT), EXT2_RWC_MAGIC); if (!pContext) { DEBUG(DL_ERR, ( "Ex2ReadWriteBlocks: failed to allocate pContext.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } INC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT)); RtlZeroMemory(pContext, sizeof(EXT2_RW_CONTEXT)); pContext->Wait = Ext2CanIWait(); pContext->MasterIrp = MasterIrp; pContext->Length = Length; if (IrpContext->MajorFunction == IRP_MJ_WRITE) { SetFlag(pContext->Flags, EXT2_RW_CONTEXT_WRITE); } if (pContext->Wait) { KeInitializeEvent(&(pContext->Event), NotificationEvent, FALSE); } else if (IrpContext->Fcb->Identifier.Type == EXT2FCB) { if (IsFlagOn(MasterIrp->Flags, IRP_PAGING_IO)) { pContext->Resource = &IrpContext->Fcb->PagingIoResource; } else { pContext->Resource = &IrpContext->Fcb->MainResource; } pContext->FileObject = IrpContext->FileObject; pContext->ThreadId = ExGetCurrentResourceThread(); } if (NULL == Chain->Next && 0 == Chain->Offset) { /* we get only 1 extent to dispatch, then don't bother allocating new irps */ /* setup the Stack location to do a read from the disk driver. */ IrpSp = IoGetNextIrpStackLocation(MasterIrp); IrpSp->MajorFunction = IrpContext->MajorFunction; IrpSp->Parameters.Read.Length = Chain->Length; IrpSp->Parameters.Read.ByteOffset.QuadPart = Chain->Lba; if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { SetFlag(IrpSp->Flags, SL_WRITE_THROUGH); } if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) { SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); } IoSetCompletionRoutine( MasterIrp, Ext2CanIWait() ? Ext2ReadWriteBlockSyncCompletionRoutine : Ext2ReadWriteBlockAsyncCompletionRoutine, (PVOID) pContext, TRUE, TRUE, TRUE ); /* intialize context block */ Chain->Irp = MasterIrp; pContext->Blocks = 1; } else { for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(Vcb->TargetDeviceObject->StackSize + 1) ); if (!Irp) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer + Extent->Offset, Extent->Length, FALSE, FALSE, Irp ); if (!Mdl) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } IoBuildPartialMdl( MasterIrp->MdlAddress, Mdl, (PCHAR)MasterIrp->UserBuffer +Extent->Offset, Extent->Length ); IoSetNextIrpStackLocation(Irp); IrpSp = IoGetCurrentIrpStackLocation(Irp); IrpSp->MajorFunction = IrpContext->MajorFunction; IrpSp->Parameters.Read.Length = Extent->Length; IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba; IoSetCompletionRoutine( Irp, Ext2CanIWait() ? Ext2ReadWriteBlockSyncCompletionRoutine : Ext2ReadWriteBlockAsyncCompletionRoutine, (PVOID) pContext, TRUE, TRUE, TRUE ); IrpSp = IoGetNextIrpStackLocation(Irp); IrpSp->MajorFunction = IrpContext->MajorFunction; IrpSp->Parameters.Read.Length =Extent->Length; IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba; /* set write through flag */ if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { SetFlag( IrpSp->Flags, SL_WRITE_THROUGH ); } /* set verify flag */ if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) { SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); } Extent->Irp = Irp; pContext->Blocks += 1; } MasterIrp->AssociatedIrp.IrpCount = pContext->Blocks; if (Ext2CanIWait()) { MasterIrp->AssociatedIrp.IrpCount += 1; } } if (!Ext2CanIWait()) { /* mark MasterIrp pending */ IoMarkIrpPending(pContext->MasterIrp); } bBugCheck = TRUE; for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { Status = IoCallDriver ( Vcb->TargetDeviceObject, Extent->Irp); Extent->Irp = NULL; } if (Ext2CanIWait()) { KeWaitForSingleObject( &(pContext->Event), Executive, KernelMode, FALSE, NULL ); KeClearEvent( &(pContext->Event) ); } else { bMasterCompleted = TRUE; } } __finally { for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { if (Extent->Irp != NULL ) { if (Extent->Irp->MdlAddress != NULL) { IoFreeMdl(Extent->Irp->MdlAddress ); } IoFreeIrp(Extent->Irp); } } if (IrpContext->ExceptionInProgress) { if (bBugCheck) { Ext2BugCheck(EXT2_BUGCHK_BLOCK, 0, 0, 0); } } else { if (Ext2CanIWait()) { if (MasterIrp) { Status = MasterIrp->IoStatus.Status; } if (pContext) { Ext2FreePool(pContext, EXT2_RWC_MAGIC); DEC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT)); } } else { if (bMasterCompleted) { IrpContext->Irp = NULL; Status = STATUS_PENDING; } } } } return Status; }