NtReadFile为例,
1. 建立irp
- PIRP
- IopAllocateIrpPrivate(
- IN CCHAR StackSize,
- IN BOOLEAN ChargeQuota
- )
- //如果大小小于IopLargeIrpStackLocations,那么从prcb->PPLookasideList[number].P;这个快查表里面拿一个,如果大于这个值则构造一个
- //然后初始化
- #define IopInitializeIrp( Irp, PacketSize, StackSize ) { \
- RtlZeroMemory( (Irp), (PacketSize) ); \
- (Irp)->Type = (CSHORT) IO_TYPE_IRP; \
- (Irp)->Size = (USHORT) ((PacketSize)); \
- (Irp)->StackCount = (CCHAR) ((StackSize)); \
- (Irp)->CurrentLocation = (CCHAR) ((StackSize) + 1); \
- (Irp)->ApcEnvironment = KeGetCurrentApcEnvironment(); \
- InitializeListHead (&(Irp)->ThreadListEntry); \
- (Irp)->Tail.Overlay.CurrentStackLocation = \
- ((PIO_STACK_LOCATION) ((UCHAR *) (Irp) + \
- sizeof( IRP ) + \
- ( (StackSize) * sizeof( IO_STACK_LOCATION )))); }
PIRP
IopAllocateIrpPrivate(
IN CCHAR StackSize,
IN BOOLEAN ChargeQuota
)
//如果大小小于IopLargeIrpStackLocations,那么从prcb->PPLookasideList[number].P;这个快查表里面拿一个,如果大于这个值则构造一个
//然后初始化
#define IopInitializeIrp( Irp, PacketSize, StackSize ) { \
RtlZeroMemory( (Irp), (PacketSize) ); \
(Irp)->Type = (CSHORT) IO_TYPE_IRP; \
(Irp)->Size = (USHORT) ((PacketSize)); \
(Irp)->StackCount = (CCHAR) ((StackSize)); \
(Irp)->CurrentLocation = (CCHAR) ((StackSize) + 1); \
(Irp)->ApcEnvironment = KeGetCurrentApcEnvironment(); \
InitializeListHead (&(Irp)->ThreadListEntry); \
(Irp)->Tail.Overlay.CurrentStackLocation = \
((PIO_STACK_LOCATION) ((UCHAR *) (Irp) + \
sizeof( IRP ) + \
( (StackSize) * sizeof( IO_STACK_LOCATION )))); }
2.调用IopSynchronousServiceTail派发irp
- NTSTATUS
- IopSynchronousServiceTail(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PFILE_OBJECT FileObject,
- IN BOOLEAN DeferredIoCompletion,
- IN KPROCESSOR_MODE RequestorMode,
- IN BOOLEAN SynchronousIo,
- IN TRANSFER_TYPE TransferType
- )
- {
- NTSTATUS status;
- PAGED_CODE();
- //异步操作要插入irp的thread->irpList
- if (!SynchronousIo) {
- IopQueueThreadIrp( Irp );
- }
- //……
- //
- // 向设备发irp
- //
- status = IoCallDriver( DeviceObject, Irp );
- if (DeferredIoCompletion) {
- if (status != STATUS_PENDING) {
- PKNORMAL_ROUTINE normalRoutine;
- PVOID normalContext;
- KIRQL irql = PASSIVE_LEVEL; // Just to shut up the compiler
- ASSERT( !Irp->PendingReturned );
- if (!SynchronousIo) {
- KeRaiseIrql( APC_LEVEL, &irql );
- }
- //完成请求
- IopCompleteRequest( &Irp->Tail.Apc,
- &normalRoutine,
- &normalContext,
- (PVOID *) &FileObject,
- &normalContext );
- if (!SynchronousIo) {
- KeLowerIrql( irql );
- }
- }
- }
- //同步下等待irp完成
- if (SynchronousIo) {
- if (status == STATUS_PENDING) {
- status = KeWaitForSingleObject( &FileObject->Event,
- Executive,
- RequestorMode,
- (BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),
- (PLARGE_INTEGER) NULL );
- if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
- IopCancelAlertedRequest( &FileObject->Event, Irp );
- }
- status = FileObject->FinalStatus;
- }
- IopReleaseFileObjectLock( FileObject );
- }
- return status;
- }
NTSTATUS
IopSynchronousServiceTail(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PFILE_OBJECT FileObject,
IN BOOLEAN DeferredIoCompletion,
IN KPROCESSOR_MODE RequestorMode,
IN BOOLEAN SynchronousIo,
IN TRANSFER_TYPE TransferType
)
{
NTSTATUS status;
PAGED_CODE();
//异步操作要插入irp的thread->irpList
if (!SynchronousIo) {
IopQueueThreadIrp( Irp );
}
//……
//
// 向设备发irp
//
status = IoCallDriver( DeviceObject, Irp );
if (DeferredIoCompletion) {
if (status != STATUS_PENDING) {
PKNORMAL_ROUTINE normalRoutine;
PVOID normalContext;
KIRQL irql = PASSIVE_LEVEL; // Just to shut up the compiler
ASSERT( !Irp->PendingReturned );
if (!SynchronousIo) {
KeRaiseIrql( APC_LEVEL, &irql );
}
//完成请求
IopCompleteRequest( &Irp->Tail.Apc,
&normalRoutine,
&normalContext,
(PVOID *) &FileObject,
&normalContext );
if (!SynchronousIo) {
KeLowerIrql( irql );
}
}
}
//同步下等待irp完成
if (SynchronousIo) {
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject( &FileObject->Event,
Executive,
RequestorMode,
(BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),
(PLARGE_INTEGER) NULL );
if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
IopCancelAlertedRequest( &FileObject->Event, Irp );
}
status = FileObject->FinalStatus;
}
IopReleaseFileObjectLock( FileObject );
}
return status;
}
3.向设备派发irp
- FORCEINLINE
- IopfCallDriver(
- IN PDEVICE_OBJECT DeviceObject,
- IN OUT PIRP Irp
- )
- {
- PIO_STACK_LOCATION irpSp;
- PDRIVER_OBJECT driverObject;
- NTSTATUS status;
- //向下一层
- Irp->CurrentLocation--;
- irpSp = IoGetNextIrpStackLocation( Irp );
- //调整irpSp
- Irp->Tail.Overlay.CurrentStackLocation = irpSp;
- irpSp->DeviceObject = DeviceObject;
- driverObject = DeviceObject->DriverObject;
- status = driverObject->MajorFunction[irpSp->MajorFunction]( DeviceObject,
- Irp );
- return status;
- }
FORCEINLINE
IopfCallDriver(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
{
PIO_STACK_LOCATION irpSp;
PDRIVER_OBJECT driverObject;
NTSTATUS status;
//向下一层
Irp->CurrentLocation--;
irpSp = IoGetNextIrpStackLocation( Irp );
//调整irpSp
Irp->Tail.Overlay.CurrentStackLocation = irpSp;
irpSp->DeviceObject = DeviceObject;
driverObject = DeviceObject->DriverObject;
status = driverObject->MajorFunction[irpSp->MajorFunction]( DeviceObject,
Irp );
return status;
}
driverObject->MajorFunction[irpSp->MajorFunction]这个调用以ClassRead为例,
ClassRead调用 IoMarkIrpPending –IoStartPacket – return Status_Pending
- VOID
- IoStartPacket(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PULONG Key OPTIONAL,
- IN PDRIVER_CANCEL CancelFunction OPTIONAL
- )
- {
- KIRQL oldIrql;
- KIRQL cancelIrql = PASSIVE_LEVEL;
- BOOLEAN i;
- KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
- if (CancelFunction) {
- IoAcquireCancelSpinLock( &cancelIrql );
- Irp->CancelRoutine = CancelFunction;
- }
- //如果设备正忙,挂入设备链表队尾
- if (Key) {
- i = KeInsertByKeyDeviceQueue( &DeviceObject->DeviceQueue,
- &Irp->Tail.Overlay.DeviceQueueEntry,
- *Key );
- } else {
- i = KeInsertDeviceQueue( &DeviceObject->DeviceQueue,
- &Irp->Tail.Overlay.DeviceQueueEntry );
- }
- if (!i) {
- //不忙的话直接调用startIo处理
- DeviceObject->CurrentIrp = Irp;
- if (CancelFunction) {
- if (DeviceObject->DeviceObjectExtension->StartIoFlags & DOE_STARTIO_NO_CANCEL) {
- Irp->CancelRoutine = NULL;
- }
- IoReleaseCancelSpinLock( cancelIrql );
- }
- DeviceObject->DriverObject->DriverStartIo( DeviceObject, Irp );
- } else {
- if (CancelFunction) {
- if (Irp->Cancel) {
- Irp->CancelIrql = cancelIrql;
- Irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
- CancelFunction( DeviceObject, Irp );
- } else {
- IoReleaseCancelSpinLock( cancelIrql );
- }
- }
- }
- KeLowerIrql( oldIrql );
- }
VOID
IoStartPacket(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PULONG Key OPTIONAL,
IN PDRIVER_CANCEL CancelFunction OPTIONAL
)
{
KIRQL oldIrql;
KIRQL cancelIrql = PASSIVE_LEVEL;
BOOLEAN i;
KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
if (CancelFunction) {
IoAcquireCancelSpinLock( &cancelIrql );
Irp->CancelRoutine = CancelFunction;
}
//如果设备正忙,挂入设备链表队尾
if (Key) {
i = KeInsertByKeyDeviceQueue( &DeviceObject->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry,
*Key );
} else {
i = KeInsertDeviceQueue( &DeviceObject->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry );
}
if (!i) {
//不忙的话直接调用startIo处理
DeviceObject->CurrentIrp = Irp;
if (CancelFunction) {
if (DeviceObject->DeviceObjectExtension->StartIoFlags & DOE_STARTIO_NO_CANCEL) {
Irp->CancelRoutine = NULL;
}
IoReleaseCancelSpinLock( cancelIrql );
}
DeviceObject->DriverObject->DriverStartIo( DeviceObject, Irp );
} else {
if (CancelFunction) {
if (Irp->Cancel) {
Irp->CancelIrql = cancelIrql;
Irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
CancelFunction( DeviceObject, Irp );
} else {
IoReleaseCancelSpinLock( cancelIrql );
}
}
}
KeLowerIrql( oldIrql );
}
4.完成irp
VOID
FASTCALL
IopfCompleteRequest(
IN PIRP Irp,
IN CCHAR PriorityBoost
)
{
//…
// Irp->CurrentLocation为0时是栈底,每深入一层就减1
//循环所有已经跑过的栈对他们调用完成历程
for (stackPointer = IoGetCurrentIrpStackLocation( Irp ),
Irp->CurrentLocation++,
Irp->Tail.Overlay.CurrentStackLocation++;
Irp->CurrentLocation <= (CCHAR) (Irp->StackCount + 1);
stackPointer++,
Irp->CurrentLocation++,
Irp->Tail.Overlay.CurrentStackLocation++) {
Irp->PendingReturned = stackPointer->Control & SL_PENDING_RETURNED;
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
if (Irp->IoStatus.Status != errorStatus) {
errorStatus = Irp->IoStatus.Status;
stackPointer->Control |= SL_ERROR_RETURNED;
bottomSp->Parameters.Others.Argument4 = (PVOID)(ULONG_PTR)errorStatus;
bottomSp->Control |= SL_ERROR_RETURNED; // Mark that there is status in this location
}
}
if ( (NT_SUCCESS( Irp->IoStatus.Status ) &&
stackPointer->Control & SL_INVOKE_ON_SUCCESS) ||
(!NT_SUCCESS( Irp->IoStatus.Status ) &&
stackPointer->Control & SL_INVOKE_ON_ERROR) ||
(Irp->Cancel &&
stackPointer->Control & SL_INVOKE_ON_CANCEL)
) {
//调用完成函数
ZeroIrpStackLocation( stackPointer );
if (Irp->CurrentLocation == (CCHAR) (Irp->StackCount + 1)) {
deviceObject = NULL;
}
else {
deviceObject = IoGetCurrentIrpStackLocation( Irp )->DeviceObject;
}
status = stackPointer->CompletionRoutine( deviceObject,
Irp,
stackPointer->Context );
if (status == STATUS_MORE_PROCESSING_REQUIRED) {
//返回这个值就什么都别做了,表示完成例程在获得irp后还要做处理
//如果驱动设置了IpCompletion 例程,那么他在上一步(第
//一步)中必须使用 IoCopyCurrentIrpStackLocationToNext
return;
}
} else {
if (Irp->PendingReturned && Irp->CurrentLocation <= Irp->StackCount) {
IoMarkIrpPending( Irp );
}
ZeroIrpStackLocation( stackPointer );
}
}
//
// Check to see whether this is an associated IRP. 略
if (Irp->Flags & IRP_ASSOCIATED_IRP) { …}
//
// Check to see if we have a name junction. If so set the stage to
// transmogrify the reparse point data in IopCompleteRequest.
//
if ((Irp->IoStatus.Status == STATUS_REPARSE ) && //…略
// Check to see if this is paging I/O or a close operation. 略
//略很多
//这是一个同步操作 那么直接返回,调用方会执行IopCompleteRequest
if (Irp->Flags & IRP_DEFER_IO_COMPLETION && !Irp->PendingReturned) {
if ((Irp->IoStatus.Status == STATUS_REPARSE ) &&
(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)) {
//
// For name junctions we reinstate the address of the appropriate
// buffer. It is freed in parse.c
//
Irp->Tail.Overlay.AuxiliaryBuffer = saveAuxiliaryPointer;
}
return;
}
//
// Finally, initialize the IRP as an APC structure and queue the special
// kernel APC to the target thread.
//异步操作,向该线程投掷APC执行IopCompleteRequest
thread = Irp->Tail.Overlay.Thread;
fileObject = Irp->Tail.Overlay.OriginalFileObject;
if (!Irp->Cancel) {
KeInitializeApc( &Irp->Tail.Apc,
&thread->Tcb,
Irp->ApcEnvironment,
IopCompleteRequest,
IopAbortRequest,
(PKNORMAL_ROUTINE) NULL,
KernelMode,
(PVOID) NULL );
(VOID) KeInsertQueueApc( &Irp->Tail.Apc,
fileObject,
(PVOID) saveAuxiliaryPointer,
PriorityBoost );
}
- //IopCompleteRequest Apc
- //将缓冲区考回用户态,释放系统内存 释放mdl
- RtlCopyMemory( irp->UserBuffer,
- irp->AssociatedIrp.SystemBuffer,
- irp->IoStatus.Information );
- if (irp->MdlAddress) {
- for (mdl = irp->MdlAddress; mdl != NULL; mdl = nextMdl) {
- nextMdl = mdl->Next;
- IoFreeMdl( mdl );
- }
- }
- 异步完成,可通知应用层,插用户apc
- KeSetEvent( irp->UserEvent, 0, FALSE );
- if (irp->Overlay.AsynchronousParameters.UserApcRoutine) {
- KeInitializeApc( &irp->Tail.Apc,
- &thread->Tcb,
- CurrentApcEnvironment,
- IopUserCompletion,
- (PKRUNDOWN_ROUTINE) IopUserRundown,
- (PKNORMAL_ROUTINE) irp->Overlay.AsynchronousParameters.UserApcRoutine,
- irp->RequestorMode,
- irp->Overlay.AsynchronousParameters.UserApcContext );
- KeInsertQueueApc( &irp->Tail.Apc,
- irp->UserIosb,
- NULL,
- 2 );
- } else if (port && irp->Overlay.AsynchronousParameters.UserApcContext) {
- //
- // If there is a completion context associated w/this I/O operation,
- // send the message to the port. Tag completion packet as an Irp.
- //
- irp->Tail.CompletionKey = key;
- irp->Tail.Overlay.PacketType = IopCompletionPacketIrp;
- KeInsertQueue( (PKQUEUE) port,
- &irp->Tail.Overlay.ListEntry );
- } else {
- //
- // Free the IRP now since it is no longer needed.
- //
- IoFreeIrp( irp );
- }
//IopCompleteRequest Apc
//将缓冲区考回用户态,释放系统内存 释放mdl
RtlCopyMemory( irp->UserBuffer,
irp->AssociatedIrp.SystemBuffer,
irp->IoStatus.Information );
if (irp->MdlAddress) {
for (mdl = irp->MdlAddress; mdl != NULL; mdl = nextMdl) {
nextMdl = mdl->Next;
IoFreeMdl( mdl );
}
}
异步完成,可通知应用层,插用户apc
KeSetEvent( irp->UserEvent, 0, FALSE );
if (irp->Overlay.AsynchronousParameters.UserApcRoutine) {
KeInitializeApc( &irp->Tail.Apc,
&thread->Tcb,
CurrentApcEnvironment,
IopUserCompletion,
(PKRUNDOWN_ROUTINE) IopUserRundown,
(PKNORMAL_ROUTINE) irp->Overlay.AsynchronousParameters.UserApcRoutine,
irp->RequestorMode,
irp->Overlay.AsynchronousParameters.UserApcContext );
KeInsertQueueApc( &irp->Tail.Apc,
irp->UserIosb,
NULL,
2 );
} else if (port && irp->Overlay.AsynchronousParameters.UserApcContext) {
//
// If there is a completion context associated w/this I/O operation,
// send the message to the port. Tag completion packet as an Irp.
//
irp->Tail.CompletionKey = key;
irp->Tail.Overlay.PacketType = IopCompletionPacketIrp;
KeInsertQueue( (PKQUEUE) port,
&irp->Tail.Overlay.ListEntry );
} else {
//
// Free the IRP now since it is no longer needed.
//
IoFreeIrp( irp );
}
5.完成历程
6.取消IO
NtCancelIoFile 对thread->IrpList中的irp进行比对,凡是fileObject相符的就调用IoCancelIrp, IoCancelIrp则调用驱动注册的cancelRoutine
7.irp 完成的fix
*. tips about IpCompletion
a.如果驱动设置了IpCompletion 例程,那么他在上一步(第一步)中必须使用IoCopyCurrentIrpStackLocationToNext
b.一个IoCompletion 例程能够返回两个状态值中的任一个:
STATUS_CONTINUE_COMPLETION – 继续向上完成特定 IRP 。I/O 管理器提升IRP 栈指针,并且调用上一个驱动的 IoCompletion 例程。
STATUS_MORE_PROCESSING_REQUIRED – 中断向上完成特定 IRP 的过程,并且把IRP 栈指针留在当前位置。返回这一状态的驱动通常会在过后调用
IoCompleteRequest例程来重新开始向上完成特定 IRP 的过程