📄 deviosup.c
字号:
// Push the scratch buffer pointers forward so that we don't stomp
// on the zeroed buffer.
//
ScratchUserBuffer = Add2Ptr( CurrentUserBuffer,
CurrentByteCount,
PVOID );
ScratchUserBufferOffset += CurrentByteCount;
//
// Handle the case where this is an unaligned transfer. The
// following must all be true for this to be an aligned transfer.
//
// Disk offset on a 2048 byte boundary (Start of transfer)
//
// Byte count is a multiple of 2048 (Length of transfer)
//
// Current buffer offset is also on a 2048 byte boundary.
//
// If the ByteCount is at least one sector then do the
// unaligned transfer only for the tail. We can use the
// user's buffer for the aligned portion.
//
} else if (SectorOffset( Vcb, DiskOffset ) ||
SectorOffset( Vcb, CurrentUserBufferOffset ) ||
(SectorOffset( Vcb, CurrentByteCount ) &&
CurrentByteCount < SectorSize( Vcb ))) {
//
// If we can't wait then raise.
//
if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
}
//
// Remember the offset and the number of bytes out of
// the transfer buffer to copy into the user's buffer.
// We will truncate the current read to end on a sector
// boundary.
//
ThisIoRun->TransferBufferOffset = SectorOffset( Vcb, DiskOffset );
//
// Make sure this transfer ends on a sector boundary.
//
ThisIoRun->DiskOffset = LlSectorTruncate( Vcb, DiskOffset );
//
// Check if we can use a free portion of the user's buffer.
// If we can copy the bytes to an earlier portion of the
// buffer then read into that location and slide the bytes
// up.
//
// We can use the user's buffer if:
//
// The temporary location in the buffer is before the
// final destination.
//
// There is at least one sector of data to read.
//
if ((ScratchUserBufferOffset + ThisIoRun->TransferBufferOffset < CurrentUserBufferOffset) &&
(ThisIoRun->TransferBufferOffset + CurrentByteCount >= SectorSize( Vcb ))) {
ThisIoRun->DiskByteCount = SectorTruncate( Vcb, ThisIoRun->TransferBufferOffset + CurrentByteCount );
CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
ThisIoRun->TransferByteCount = CurrentByteCount;
//
// Point to the user's buffer and Mdl for this transfer.
//
ThisIoRun->TransferBuffer = ScratchUserBuffer;
ThisIoRun->TransferMdl = Irp->MdlAddress;
ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
ScratchUserBufferOffset,
PVOID );
ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
ThisIoRun->DiskByteCount,
PVOID );
ScratchUserBufferOffset += ThisIoRun->DiskByteCount;
//
// Otherwise we need to allocate an auxilary buffer for the next sector.
//
} else {
//
// Read up to a page containing the partial data
//
ThisIoRun->DiskByteCount = SectorAlign( Vcb, ThisIoRun->TransferBufferOffset + CurrentByteCount );
if (ThisIoRun->DiskByteCount > PAGE_SIZE) {
ThisIoRun->DiskByteCount = PAGE_SIZE;
}
if (ThisIoRun->TransferBufferOffset + CurrentByteCount > ThisIoRun->DiskByteCount) {
CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
}
ThisIoRun->TransferByteCount = CurrentByteCount;
//
// Allocate a buffer for the non-aligned transfer.
//
ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( UdfNonPagedPool,
PAGE_SIZE,
TAG_IO_BUFFER );
//
// Allocate and build the Mdl to describe this buffer.
//
ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
PAGE_SIZE,
FALSE,
FALSE,
NULL );
ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
if (ThisIoRun->TransferMdl == NULL) {
IrpContext->Irp->IoStatus.Information = 0;
UdfRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
}
MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
}
//
// Remember we found an unaligned transfer.
//
FoundUnaligned = TRUE;
//
// Otherwise we use the buffer and Mdl from the original request.
//
} else {
//
// Truncate the read length to a sector-aligned value. We know
// the length must be at least one sector or we wouldn't be
// here now.
//
CurrentByteCount = SectorTruncate( Vcb, CurrentByteCount );
//
// Read these sectors from the disk.
//
ThisIoRun->DiskOffset = DiskOffset;
ThisIoRun->DiskByteCount = CurrentByteCount;
//
// Use the user's buffer and Mdl as our transfer buffer
// and Mdl.
//
ThisIoRun->TransferBuffer = CurrentUserBuffer;
ThisIoRun->TransferMdl = Irp->MdlAddress;
ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
CurrentUserBufferOffset,
PVOID );
ScratchUserBuffer = Add2Ptr( CurrentUserBuffer,
CurrentByteCount,
PVOID );
ScratchUserBufferOffset += CurrentByteCount;
}
//
// Update our position in the transfer and the RunCount and
// ByteCount for the user.
//
RemainingByteCount -= CurrentByteCount;
//
// Break out if no more positions in the IoRuns array or
// we have all of the bytes accounted for.
//
*ThisByteCount += CurrentByteCount;
if ((RemainingByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
break;
}
//
// Update our pointers for the user's buffer.
//
ThisIoRun = IoRuns + *RunCount;
CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentByteCount, PVOID );
CurrentUserBufferOffset += CurrentByteCount;
CurrentFileOffset += CurrentByteCount;
}
return FoundUnaligned;
}
//
// Local support routine
//
BOOLEAN
UdfFinishBuffers (
IN PIRP_CONTEXT IrpContext,
IN PIO_RUN IoRuns,
IN ULONG RunCount,
IN BOOLEAN FinalCleanup
)
/*++
Routine Description:
This routine is called to perform any data transferred required for
unaligned Io or to perform the final cleanup of the IoRuns array.
In all cases this is where we will deallocate any buffer and mdl
allocated to perform the unaligned transfer. If this is not the
final cleanup then we also transfer the bytes to the user buffer
and flush the hardware cache.
We walk backwards through the run array because we may be shifting data
in the user's buffer. Typical case is where we allocated a buffer for
the first part of a read and then used the user's buffer for the
next section (but stored it at the beginning of the buffer.
Arguments:
IoRuns - Pointer to the IoRuns array.
RunCount - Number of entries in the IoRuns array filled here.
FinalCleanup - Indicates if we should be deallocating temporary buffers
(TRUE) or transferring bytes for a unaligned transfers and
deallocating the buffers (FALSE). Flush the system cache if
transferring data.
Return Value:
BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise.
--*/
{
BOOLEAN FlushIoBuffers = FALSE;
ULONG RemainingEntries = RunCount;
PIO_RUN ThisIoRun = &IoRuns[RunCount - 1];
PAGED_CODE();
//
// Walk through each entry in the IoRun array.
//
while (RemainingEntries != 0) {
//
// We only need to deal with the case of an unaligned transfer.
//
if (ThisIoRun->TransferByteCount != 0) {
//
// If not the final cleanup then transfer the data to the
// user's buffer and remember that we will need to flush
// the user's buffer to memory.
//
if (!FinalCleanup) {
//
// If we are shifting in the user's buffer then use
// MoveMemory.
//
if (ThisIoRun->TransferMdl == IrpContext->Irp->MdlAddress) {
RtlMoveMemory( ThisIoRun->UserBuffer,
Add2Ptr( ThisIoRun->TransferBuffer,
ThisIoRun->TransferBufferOffset,
PVOID ),
ThisIoRun->TransferByteCount );
} else {
RtlCopyMemory( ThisIoRun->UserBuffer,
Add2Ptr( ThisIoRun->TransferBuffer,
ThisIoRun->TransferBufferOffset,
PVOID ),
ThisIoRun->TransferByteCount );
}
FlushIoBuffers = TRUE;
}
//
// Free any Mdl we may have allocated. If the Mdl isn't
// present then we must have failed during the allocation
// phase.
//
if (ThisIoRun->TransferMdl != IrpContext->Irp->MdlAddress) {
if (ThisIoRun->TransferMdl != NULL) {
IoFreeMdl( ThisIoRun->TransferMdl );
}
//
// Now free any buffer we may have allocated. If the Mdl
// doesn't match the original Mdl then free the buffer.
//
if (ThisIoRun->TransferBuffer != NULL) {
UdfFreePool( &ThisIoRun->TransferBuffer );
}
}
}
//
// Now handle the case where we failed in the process
// of allocating associated Irps and Mdls.
//
if (ThisIoRun->SavedIrp != NULL) {
if (ThisIoRun->SavedIrp->MdlAddress != NULL) {
IoFreeMdl( ThisIoRun->SavedIrp->MdlAddress );
}
IoFreeIrp( ThisIoRun->SavedIrp );
}
//
// Move to the previous IoRun entry.
//
ThisIoRun -= 1;
RemainingEntries -= 1;
}
//
// If we copied any data then flush the Io buffers.
//
return FlushIoBuffers;
}
//
// Local support routine
//
VOID
UdfMultipleAsync (
IN PIRP_CONTEXT IrpContext,
IN ULONG RunCount,
IN PIO_RUN IoRuns
)
/*++
Routine Description:
This routine first does the initial setup required of a Master IRP that is
going to be completed using associated IRPs. This routine should not
be used if only one async request is needed, instead the single read
async routines should be called.
A context parameter is initialized, to serve as a communications area
between here and the common completion routine.
Next this routine reads or writes one or more contiguous sectors from
a device asynchronously, and is used if there are multiple reads for a
master IRP. A completion routine is used to synchronize with the
completion of all of the I/O requests started by calls to this routine.
Also, prior to calling this routine the caller must initialize the
IoStatus field in the Context, with the correct success status and byte
count which are expected if all of the parallel transfers complete
successfully. After return this status will be unchanged if all requests
were, in fact, successful. However, if one or more errors occur, the
IoStatus will be modified to reflect the error status and byte count
from the first run (by Vbo) which encountered an error. I/O status
from all subsequent runs will not be indicated.
Arguments:
RunCount - Supplies the number of multiple async requests
that will be issued against the master irp.
IoRuns - Supplies an array containing the Offset and ByteCount for the
separate requests.
Return Value:
None.
--*/
{
PIO_COMPLETION_ROUTINE CompletionRoutine;
PIO_STACK_LOCATION IrpSp;
PMDL Mdl;
PIRP Irp;
PIRP MasterIrp;
ULONG UnwindRunCount;
PAGED_CODE();
//
// Set up things according to whether this is truely async.
//
CompletionRoutine = UdfMultiSyncCompletionRoutine;
if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
CompletionRoutine = UdfMultiAsyncCompletionRoutine;
}
//
// Initialize some local variables.
//
MasterIrp = IrpContext->Irp;
//
// Itterate through the runs, doing everything that can fail.
// We let the cleanup in CdFinishBuffers clean up on error.
//
for (UnwindRunCount = 0;
UnwindRunCount < RunCount;
UnwindRunCount += 1) {
//
// Create an associated IRP, making sure there is one stack entry for
// us, as well.
//
IoRuns[UnwindRunCount].SavedIrp =
Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
if (Irp == NULL) {
IrpContext->Irp->IoStatus.Information = 0;
UdfRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
}
//
// Allocate and build a partial Mdl for the request.
//
Mdl = IoAllocateMdl( IoRuns[UnwindRunCount].TransferVirtualAddress,
IoRuns[UnwindRunCount].DiskByteCount,
FALSE,
FALSE,
Irp );
if (Mdl == NULL) {
IrpContext->Irp->IoStatus.Information = 0;
UdfRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
}
IoBuildPartialMdl( IoRuns[UnwindRunCount].TransferMdl,
Mdl,
IoRuns[UnwindRunCount].TransferVirtualAddress,
IoRuns[UnwindRunCount].DiskByteCount );
//
// Get the first IRP stack location in the associated Irp
//
IoSetNextIrpStackLocation( Irp );
IrpSp = IoGetCurrentIrpStackLocation( Irp );
//
// Setup the Stack location to describe our read.
//
IrpSp->MajorFunction = IRP_MJ_READ;
IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
//
// Set up the completion routine address in our stack frame.
//
IoSetCompletionRoutine( Irp,
CompletionRoutine,
IrpContext->IoContext,
TRUE,
TRUE,
TRUE );
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -