KeRemoveEntryDeviceQueue引发蓝屏的问题?
蓝屏后用windbg打开dump 发现KeRemoveEntryDeviceQueue引发蓝屏 不知道怎么解决 大家帮忙看看 谢谢
如果在应用程序中不调用CancelIo 则不会引发蓝屏
这个程序大致情况是这样:应用程序创建2个线程 两个线程函数是一样的 都是readFile 然后read是异步的 read以后就是 CancelIo 然后是等待
驱动程序里边 对IRP进行了队列化
驱动代码如下:
#pragma LOCKEDCODE
VOID MyStartIo( IN PDEVICE_OBJECT DeviceObject,IN PIRP pFistIrp)
{
KdPrint(("Enter MyStartIo\n"));
KIRQLoldirql;
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
DeviceObject->DeviceExtension;
PKDEVICE_QUEUE_ENTRY device_entry;
//获取cancel自旋锁
IoAcquireCancelSpinLock(&oldirql);
if(pFirstIrp!=pDevExt->pCurrentIRP||pFirstIrp->Cancel)
{
IoReleaseCancelSpinLock(oldirql);
return;
}else
{
IoSetCancelRoutine(pFirstIrp, NULL);
IoReleaseCancelSpinLock(oldirql);
}
PIRP Irp = pFistIrp;
do
{
KEVENT event;
KeInitializeEvent(&event,NotificationEvent,FALSE);
//等3秒
LARGE_INTEGER timeout;
timeout.QuadPart = -3*1000*1000*10;
//定义一个3秒的延时,主要是为了模拟该IRP操作需要大概3秒左右时间
KeWaitForSingleObject(&event,Executive,KernelMode,FALSE,&timeout);
KdPrint(("Complete a irp:%x\n",Irp));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;// no bytes xfered
IoCompleteRequest(Irp,IO_NO_INCREMENT);
device_entry=KeRemoveDeviceQueue(&pDevExt->device_queue);
KdPrint(("device_entry:%x\n",device_entry));
if (device_entry==NULL)
{
break;
}
Irp = CONTAINING_RECORD(device_entry, IRP, Tail.Overlay.DeviceQueueEntry);
}while(1);
KdPrint(("Leave MyStartIo\n"));
}
VOID OnCancelIRP(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
KdPrint(("Enter CancelReadIRP\n"));
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
if(pdx->pCurrentIRP == Irp)
{
//释放Cancel自旋锁
IoReleaseCancelSpinLock(Irp->CancelIrql);
//从IRP队列取出下一个IRP 并将它送给startIO
IoStartNextPacket(DeviceObject, TRUE);
KeLowerIrql(Irp->CancelIrql);
}else
{
//把IRP从队列中删除 但是并不影响IRP 本身
KeRemoveEntryDeviceQueue(&pdx->device_queue, &Irp->Tail.Overlay.DeviceQueueEntry);
//释放Cancel自旋锁
IoReleaseCancelSpinLock(Irp->CancelIrql);
}
//设置完成状态为STATUS_CANCELLED
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;// bytes xfered
IoCompleteRequest( Irp, IO_NO_INCREMENT );
KdPrint(("Leave CancelReadIRP\n"));
}
NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{
KdPrint(("Enter HelloDDKRead\n"));
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
//将IRP设置为挂起
IoMarkIrpPending(pIrp);
IoSetCancelRoutine(pIrp,OnCancelIRP);
KIRQL oldirql;
//提升IRP至DISPATCH_LEVEL
KeRaiseIrql(DISPATCH_LEVEL, &oldirql);
KdPrint(("HelloDDKRead irp :%x\n",pIrp));
KdPrint(("DeviceQueueEntry:%x\n",&pIrp->Tail.Overlay.DeviceQueueEntry));
if (!KeInsertDeviceQueue(&pDevExt->device_queue, &pIrp->Tail.Overlay.DeviceQueueEntry))
MyStartIo(pDevObj,pIrp);
//将IRP降至原来IRQL
KeLowerIrql(oldirql);
KdPrint(("Leave HelloDDKRead\n"));
//返回pending状态
return STATUS_PENDING;
}
#pragma INITCODE
extern "C" NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath)
{
NTSTATUS status;
//设置卸载函数 设置派遣函数 创建驱动设备对象
return status;
}
#pragma PAGEDCODE
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
{ ........}
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp)
{ ........ }
应用代码
_Threadprocuses ebx esi edi,_lParam
.......
invokeCreateEvent,NULL,FALSE,FALSE,NULL
movstOverlap.hEvent,eax
invokeReadFile,_lParam,offset szReadBuffer,10,offset dwBytes,offset stOverlap
invokeCancelIo,_lParam
invokeWaitForSingleObject,stOverlap.hEvent,INFINITE;
ret
_Threadendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
.......
invokeCreateThread,NULL,0,offset _Thread,hDevice,0,offset dwThreadId
movhThread,eax
invokeCreateThread,NULL,0,offset _Thread,hDevice,0,offset dwThreadId
movdword ptr [hThread+4],eax
invokeWaitForMultipleObjects,2,offset hThread,TRUE,INFINITE
.......
_Ret:
invokeExitProcess,NULL
endstart
[解决办法]
1. 蓝屏代码是什么?请把蓝屏信息完整贴出来。
2. 是不是Irp = CONTAINING_RECORD(device_entry, IRP, Tail.Overlay.DeviceQueueEntry);
返回的Irp已经被Cancel过了?是不是需要加入一些判断保护后,在进入下一次While循环?
3. pDevExt->pCurrentIRP是在哪赋值的?想达到什么目的啊?