阅读:3252回复:14
Vista下磁盘过虑驱动,总是产生B8错误(ATTEMPTED_SWITCH_FROM_DPC)
调试错误产生在KeWaitForSingleObject里面
于是我将代码简化,发现只要增加KeWaitForSingleObject就出错,去掉则一切正常。 哪位大侠知道原因啊?另外原来的代码在XP下都是好的。 附代码 NTSTATUS RWSectorsComp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { KIRQL currentIrql = KeGetCurrentIrql(); PIO_STACK_LOCATION currentSp = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status; PIRP OriginalIrp; UNREFERENCED_PARAMETER(Context); OriginalIrp = Context; if ( !NT_SUCCESS( Irp->IoStatus.Status)) { OriginalIrp->IoStatus.Status = Irp->IoStatus.Status; } if (OriginalIrp->PendingReturned) { IoMarkIrpPending(OriginalIrp); } OriginalIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(OriginalIrp, IO_DISK_INCREMENT); if(Irp->MdlAddress) { IoFreeMdl(Irp->MdlAddress); IoFreeIrp(Irp); } return STATUS_MORE_PROCESSING_REQUIRED; } void RWSectors( IN PDEVICE_OBJECT TargetDevice, IN PIRP Irp, IN BOOLEAN bIsLastProcess, IN DWORD AbsSector, IN DWORD SectorNumbers, IN OUT PVOID pReadWriteBuffer ) { NTSTATUS ntstatus; PDEVICE_EXTENSION deviceExtension = TargetDevice->DeviceExtension; PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); IN LARGE_INTEGER startSectors; //bytes PMDL NewMdl; KIRQL currentIrql; PIO_STACK_LOCATION NextIrpStack; CONTEXT_STRUC context; PIRP NewIrp; PIO_STACK_LOCATION NewIrpSp; startSectors.QuadPart = AbsSector; startSectors.QuadPart *= HD_BYTEPERSECT; SectorNumbers = SectorNumbers * HD_BYTEPERSECT; NewIrp = IoAllocateIrp(deviceExtension->DeviceObject->StackSize, FALSE); NewMdl = IoAllocateMdl(pReadWriteBuffer, SectorNumbers, FALSE, FALSE, NewIrp); // 放弃操作或者资源分配失败, 释放各种已分配的资源, 并返回 if ( NewMdl == NULL || NewIrp == NULL ) { // 返回状态中存储失败原因 Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return; } MmBuildMdlForNonPagedPool(NewMdl); NewIrpSp = IoGetNextIrpStackLocation( NewIrp );// 函数获得该IRP第一个堆栈单元的指针 NewIrpSp->MajorFunction = currentIrpStack->MajorFunction; NewIrpSp->Parameters.Read.Length = SectorNumbers ; NewIrpSp->Parameters.Read.ByteOffset = startSectors; //---置新构造的IRP包各页参数 NewIrpSp->CompletionRoutine = RWSectorsComp;// 置完成例程 NewIrpSp->Context = Irp;// 将原始IRP传下去,置完成例程的参数 NewIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL; // KeResetEvent(&kRequestEvent); ntstatus = IoCallDriver(deviceExtension->DeviceObject, NewIrp); if( !NT_SUCCESS(ntstatus) ) ASSERT(0); /* ntstatus = KeWaitForSingleObject( &kRequestEvent, Suspended, KernelMode, FALSE, NULL ); if( ntstatus != STATUS_SUCCESS ) ASSERT(0); */ return ; } void TestProcess( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, LPRETURN_STATUS lpReturnStatus ) { KIRQL TempCurrentIrql; PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION pTempNextIrpStack = IoGetNextIrpStackLocation(Irp); BYTE * pBuffer; lpReturnStatus->cReturn = TRUE; ASSERT (KeGetCurrentIrql() <= DISPATCH_LEVEL); if (g_dwStartSect == 0 && g_dwSectCount == 1) { g_dwStartSect = 11; currentIrpStack->Parameters.Read.ByteOffset.QuadPart = 512 * 11; } pBuffer = (BYTE *)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority); RWSectors(deviceExtension->TargetDeviceObject, Irp, TRUE, g_dwStartSect, g_dwSectCount, pBuffer); } NTSTATUS DiskPerfReadWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ULONG processor = (ULONG) KeGetCurrentProcessorNumber(); //PDISK_PERFORMANCE partitionCounters = NULL; LONG queueLen; PLARGE_INTEGER timeStamp; //Tony add{{ PIO_STACK_LOCATION pTempCurrentIrpStack = currentIrpStack; PIO_STACK_LOCATION pTempNextIrpStack = IoGetNextIrpStackLocation(Irp); DWORD dwTempNumber; DWORD dwTempStartAddress; KIRQL TempCurrentIrql; RETURN_STATUS TempReturnStatus; NTSTATUS TempNTStatus; //}} DWORD *pdwTemp; DWORD dwNum; //Tony add if(cInitCardOkFlag) { IoMarkIrpPending(Irp); /* TempNTStatus = KeWaitForSingleObject( &kReadFormatSemaphore, UserRequest, KernelMode, FALSE, NULL ); */ TestProcess(DeviceObject, Irp, &TempReturnStatus); ASSERT (KeGetCurrentIrql() <= DISPATCH_LEVEL); /* KeReleaseSemaphore( &kReadFormatSemaphore, 0, 1, FALSE );*/ if(TRUE == TempReturnStatus.cReturn) return STATUS_PENDING; else { KeAcquireSpinLock(&kIrpSpinlock, &TempCurrentIrql); *pTempNextIrpStack = *pTempCurrentIrpStack; pTempCurrentIrpStack->Parameters.Read.ByteOffset = KeQueryPerformanceCounter((PVOID)NULL); } } else { KeAcquireSpinLock(&kIrpSpinlock, &TempCurrentIrql); *pTempNextIrpStack = *pTempCurrentIrpStack; pTempCurrentIrpStack->Parameters.Read.ByteOffset = KeQueryPerformanceCounter((PVOID)NULL); } IoSetCompletionRoutine(Irp, DiskPerfIoCompletion, DeviceObject, TRUE, TRUE, TRUE); KeReleaseSpinLock(&kIrpSpinlock, TempCurrentIrql); return IoCallDriver(deviceExtension->TargetDeviceObject, Irp); } |
|
沙发#
发布于:2007-07-10 15:26
以上代码是能正常运行的,不过把注释掉的KeWaitForSingleObject等同步代码加上,就会产生B8错误。
|
|
板凳#
发布于:2007-07-11 12:27
首先,不能用KeWaitForSingleObject(,,UserRequest,);
其次,Vista下DiskPerfReadWrite好像可能运行在dispatch level,所以不能用KeWaitForSingleObject(,,,,NULL); |
|
地板#
发布于:2007-07-11 13:35
谢谢tooflat,不能用KeWaitForSingleObject的话,用什么方式可以代替
|
|
地下室#
发布于:2007-07-11 14:10
关注,
不过 其次,Vista下DiskPerfReadWrite好像可能运行在dispatch level,所以不能用KeWaitForSingleObject(,,,,NULL); 这句有误, Callers of KeWaitForSingleObject must be running at IRQL <= DISPATCH_LEVEL. However, if Timeout <> 0, the caller must be running at IRQL <= APC_LEVEL and in a nonarbitrary thread context. 所以KeWaitForSingleObject可以在DISPATCH_LEVEL上用,只是最后一个参数必须为0。 |
|
5楼#
发布于:2007-07-11 16:58
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
谢谢tooflat,不能用KeWaitForSingleObject的话,用什么方式可以代替 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 可以用StartIO来管理IRP |
|
6楼#
发布于:2007-07-11 17:49
谢谢玄风残翼,我今天又试了一下,确实是在IRQL为DISPATCH_LEVEL的时候出的错。
我自己写了等待函数来代替Wait,结果又出现C5错误,提示为没有权限调用ExFreePool, 这个ExFreePool是别的程序调的。 真是郁闷啊。。。 |
|
7楼#
发布于:2007-07-11 21:18
呵呵,用StartIO吧,详细可以看WDK帮助文档中的
Windows Driver Kit->Kernel-Mode Driver Architecture->Design Guid->Handling IRPs->Queuing and Dequeuing IRPs |
|
8楼#
发布于:2007-07-12 10:04
引用第4楼玄风残翼于2007-07-11 14:10发表的 : 不是最后一个参数为0,而是等待的时间为0,即 LARGE_INTEGER time; time.QuadPart = 0; KeWaitXXX(,,, &time); |
|
9楼#
发布于:2007-07-12 10:07
啊……一时弄错了,希望大家别笑话啊,
![]() |
|
10楼#
发布于:2007-07-12 12:59
对dispatch level的问题,我都是通过queue workitem来解决的。
|
|
11楼#
发布于:2007-07-12 14:10
tooflat,能给我介绍一下queue workitem吗?
有人跟我说可以通过开一个线程来处理Irp,我正在改。是否和你说的是一个意思? |
|
12楼#
发布于:2007-07-12 14:15
差不多,不过queue workitem比较简单。
|
|
13楼#
发布于:2007-07-12 14:16
用IoQueueWorkItem或者ExQueueWorkItem
|
|
14楼#
发布于:2007-07-12 16:29
谢谢tooflat和玄风残翼,问题解决了。
开了一个线程来处理Irp就没问题了。 |
|