tony_w
驱动牛犊
驱动牛犊
  • 注册日期2007-05-14
  • 最后登录2007-10-29
  • 粉丝0
  • 关注0
  • 积分70分
  • 威望8点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
阅读:3252回复:14

Vista下磁盘过虑驱动,总是产生B8错误(ATTEMPTED_SWITCH_FROM_DPC)

楼主#
更多 发布于:2007-07-10 15:18
调试错误产生在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);
}
tony_w
驱动牛犊
驱动牛犊
  • 注册日期2007-05-14
  • 最后登录2007-10-29
  • 粉丝0
  • 关注0
  • 积分70分
  • 威望8点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-07-10 15:26
以上代码是能正常运行的,不过把注释掉的KeWaitForSingleObject等同步代码加上,就会产生B8错误。
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-07-11 12:27
首先,不能用KeWaitForSingleObject(,,UserRequest,);
其次,Vista下DiskPerfReadWrite好像可能运行在dispatch level,所以不能用KeWaitForSingleObject(,,,,NULL);
tony_w
驱动牛犊
驱动牛犊
  • 注册日期2007-05-14
  • 最后登录2007-10-29
  • 粉丝0
  • 关注0
  • 积分70分
  • 威望8点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-07-11 13:35
谢谢tooflat,不能用KeWaitForSingleObject的话,用什么方式可以代替
玄风残翼
驱动牛犊
驱动牛犊
  • 注册日期2005-10-10
  • 最后登录2015-04-07
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望172点
  • 贡献值0点
  • 好评度24点
  • 原创分0分
  • 专家分0分
地下室#
发布于: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。
玄风残翼
驱动牛犊
驱动牛犊
  • 注册日期2005-10-10
  • 最后登录2015-04-07
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望172点
  • 贡献值0点
  • 好评度24点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2007-07-11 16:58
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
谢谢tooflat,不能用KeWaitForSingleObject的话,用什么方式可以代替
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

可以用StartIO来管理IRP
tony_w
驱动牛犊
驱动牛犊
  • 注册日期2007-05-14
  • 最后登录2007-10-29
  • 粉丝0
  • 关注0
  • 积分70分
  • 威望8点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2007-07-11 17:49
谢谢玄风残翼,我今天又试了一下,确实是在IRQL为DISPATCH_LEVEL的时候出的错。
我自己写了等待函数来代替Wait,结果又出现C5错误,提示为没有权限调用ExFreePool,
这个ExFreePool是别的程序调的。

真是郁闷啊。。。
玄风残翼
驱动牛犊
驱动牛犊
  • 注册日期2005-10-10
  • 最后登录2015-04-07
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望172点
  • 贡献值0点
  • 好评度24点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2007-07-11 21:18
呵呵,用StartIO吧,详细可以看WDK帮助文档中的
Windows Driver Kit->Kernel-Mode Driver Architecture->Design Guid->Handling IRPs->Queuing and Dequeuing IRPs
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2007-07-12 10:04
引用第4楼玄风残翼于2007-07-11 14:10发表的  :
关注,
不过
其次,Vista下DiskPerfReadWrite好像可能运行在dispatch level,所以不能用KeWaitForSingleObject(,,,,NULL);
这句有误,

.......



不是最后一个参数为0,而是等待的时间为0,即
LARGE_INTEGER time;
time.QuadPart = 0;

KeWaitXXX(,,, &time);
玄风残翼
驱动牛犊
驱动牛犊
  • 注册日期2005-10-10
  • 最后登录2015-04-07
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望172点
  • 贡献值0点
  • 好评度24点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2007-07-12 10:07
啊……一时弄错了,希望大家别笑话啊,  
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2007-07-12 12:59
对dispatch level的问题,我都是通过queue workitem来解决的。
tony_w
驱动牛犊
驱动牛犊
  • 注册日期2007-05-14
  • 最后登录2007-10-29
  • 粉丝0
  • 关注0
  • 积分70分
  • 威望8点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2007-07-12 14:10
tooflat,能给我介绍一下queue workitem吗?

有人跟我说可以通过开一个线程来处理Irp,我正在改。是否和你说的是一个意思?
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2007-07-12 14:15
差不多,不过queue workitem比较简单。
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2007-07-12 14:16
用IoQueueWorkItem或者ExQueueWorkItem
tony_w
驱动牛犊
驱动牛犊
  • 注册日期2007-05-14
  • 最后登录2007-10-29
  • 粉丝0
  • 关注0
  • 积分70分
  • 威望8点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2007-07-12 16:29
谢谢tooflat和玄风残翼,问题解决了。
开了一个线程来处理Irp就没问题了。
游客

返回顶部