《Windows NT FileSystemInternals》学习笔记知识
原来以为完成IRP的处理仅仅是简单的调用一下IoCompleteRequest()函数而已,内部的代码应该很简单。阅读了Win2K源代码才发现,事情并不简单啊,呵呵,再一次发现Win2K源代码的价值了。
驱动必须调用IoCompleteRequest()通知I/O管理器相应的IRP已经处理完毕。IoCompleteRequest函数的处理过程如下(对应着Win2K源代码阅读,在ioStubs.c中):
IoCompleteRequest调用过程如下:
IoCompleteRequestàIofCompleteRequestàIopfCompleteRequest(不知道微软的函数调用经过这么多过程干吗)àIopCompleteRequest(由APC执行)
1. I/O管理器执行一些基本检查确保IRP在正确的状态。当前StackLocation的值必须小于等于StacksCount+1。如果该值不正确,系统返回错误码为MULTIPLE_IRP_COMPLETE_REQUEST的bugcheck。如果安装的是debug build版本的操作系统,I/O管理器将执行一些附加的Assertion,例如检查STATUS_PENDING的返回状态码,以及其他从驱动返回值,
//
// Begin by ensuring that this packet has not already been completed
// by someone.
//
if (Irp->CurrentLocation > (CCHAR) (Irp->StackCount + 1) ||
Irp->Type != IO_TYPE_IRP) {
KeBugCheckEx( MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR) Irp, __LINE__, 0, 0 );
}
//
// Ensure that the packet being completed really is still an IRP.
//
ASSERT( Irp->Type == IO_TYPE_IRP );
//
// Ensure that no one believes that this request is still in a cancelable
// state.
//
ASSERT( !Irp->CancelRoutine );
//
// Ensure that the packet is not being completed with a thoroughly
// confusing status code. Actually completing a packet with a pending
// status probably means that someone forgot to set the real status in
// the packet.
//
ASSERT( Irp->IoStatus.Status != STATUS_PENDING );
//
// Ensure that the packet is not being completed with a minus one. This
// is apparently a common problem in some drivers, and has no meaning
// as a status code.
//
ASSERT( Irp->IoStatus.Status != 0xffffffff );
//
// Ensure that if this is a paging I/O operation, and it failed, that the
// reason for the failure isn't because quota was exceeded.
//
ASSERT( !(Irp->Flags & IRP_PAGING_IO && Irp->IoStatus.Status == STATUS_QUOTA_EXCEEDED ) );
2. I/O管理器开始扫描IRP包含的所有需要调用的Completion Routine。每一个Stack Location都可以包含一个Completion Routine,这些Completion Routine可以在IRP处理返回成功、错误或者取消时调用。I/O Stack Location采用反向顺序扫描,最高StackLocation最先扫描。这样磁盘驱动(最底层)提供的Completion Routine将最先调用,而最高层驱动的Completion Routine最后调用。
Completion Routine在调用IoCompleteRequest()的线程上下文中调用,如果某个Completion Routine返回STATUS_MORE_PROCESSION_REQUIRED,I/O管理器停止IRP事后处理,将程序控制权返回调用IoCompleteRequeset()的程序。返回STATUS_MORE_PROCESSING_REQUIRED程序负责调用FreeIrp()。
//
// Now check to see whether this is the last driver that needs to be
// invoked for this packet. If not, then bump the stack and check to
// see whether the driver wishes to see the completion. As each stack
// location is examined, invoke any routine which needs to be invoked.
// If the routine returns STATUS_MORE_PROCESSING_REQUIRED, then stop the
// processing of this packet.
//
for (stackPointer = IoGetCurrentIrpStackLocation( Irp ),
Irp->CurrentLocation++,
Irp->Tail.Overlay.CurrentStackLocation++;
Irp->CurrentLocation <= (CCHAR) (Irp->StackCount + 1);
stackPointer++,
Irp->CurrentLocation++,
Irp->Tail.Overlay.CurrentStackLocation++) {
//
// A stack location was located. Check to see whether or not it
// has a completion routine and if so, whether or not it should be
// invoked.
//
// Begin by saving the pending returned flag in the current stack
// location in the fixed part of the IRP.
//
Irp->PendingReturned = stackPointer->Control & SL_PENDING_RETURNED;
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)
) {
//
// This driver has specified a completion routine. Invoke the
// routine passing it a pointer to its device object and the
// IRP that is being completed.
//
ZeroIrpStackLocation( stackPointer );
PERFINFO_DRIVER_COMPLETIONROUTINE_CALL(Irp, stackPointer);
status = stackPointer->CompletionRoutine( (PDEVICE_OBJECT) (Irp->CurrentLocation == (CCHAR) (Irp->StackCount + 1) ? (PDEVICE_OBJECT) NULL :IoGetCurrentIrpStackLocation( Irp )->DeviceObject), Irp,stackPointer->Context );
PERFINFO_DRIVER_COMPLETIONROUTINE_RETURN(Irp, stackPointer);
if (status == STATUS_MORE_PROCESSING_REQUIRED) {
//
// Note: Notice that if the driver has returned the above
// status value, it may have already DEALLOCATED the
// packet! Therefore, do NOT touch any part of the
// IRP in the following code.
//
return;
}
}
else
{
if (Irp->PendingReturned && Irp->CurrentLocation <= Irp->StackCount)
{
IoMarkIrpPending( Irp );
}
ZeroIrpStackLocation( stackPointer );
}
}
3. 如果IRP有相应的Associated IRP,I/O管理器将递减AssociatedIrp.IrpCount字段的值,接着调用IopFreeIrpAndMdls()释放Associated IRP占用的内存和为它分配的MDL结构。如果是Master IRP的最后一个Associated IRP,I/O管理器直接对IRP本身调用IoCompleteRequest()函数。
//
// Check to see whether this is an associated IRP. If so, then decrement
// the count in the master IRP. If the count is decremented to zero,
// then complete the master packet as well.
//
本文地址:http://www.45fan.com/dnjc/72122.html