Здравствуйте! Пишу нечто вроде "родительского контроля". Отслеживается в том числе и содержимое Web-страниц. Так вот. Когда мой драйвер ставит IRP, который также интересен KAV (он проверяет содержимое Web), в очередь или блокирует данный запрос, возникает BSOD. Помогите, пожалуйста, помирить драйверы. Ставлю в очередь так: Код (Text): KIRQL Irql; PDRIVER_CANCEL oldCancelRoutine; KeAcquireSpinLock( &irpQueueSpinLock, &Irql ); IoMarkIrpPending( pIrp ); InsertTailList( &irpQueue, &pIrp->Tail.Overlay.ListEntry ); oldCancelRoutine = IoSetCancelRoutine(pIrp, IrpCancelRoutine); ASSERT(!oldCancelRoutine); if (pIrp->Cancel){ oldCancelRoutine = IoSetCancelRoutine(pIrp, NULL); if (oldCancelRoutine){ RemoveEntryList(&pIrp->Tail.Overlay.ListEntry); status = pIrp->IoStatus.Status = STATUS_CANCELLED; } //endif } // endif KeReleaseSpinLock(&irpQueueSpinLock, Irql); if (...){ //Отправим уведомление в приложение SendEventToGUI(); } status=STATUS_PENDING; return status; Если данные не обрабатываются антивирусом, или антивирус выгружен, все работает правильно. Иначе - вот дамп. Кто знает, помогите, пожалуйста. И еще: можно ли из драйвера гарантированно определить в каком режиме работает модем в данный момент (т.е. в режиме обработки команд или пересылки данных)? Заранее спасибо. 715978175__Mini032906_01.rar
Мда.. заморочно. Кирдык происходит слишком далеко от твоего драйвера. К тому же в моей копии xpsp2 по смещению 0x93E04 совсем другое. Так что хрен разберёшь. Если кирдык стабильно происходит, подключи SoftICE, правда я не помню перехватывает ли он IRQL_NOT_LESS_OR_EQUAL на DISPATCH_LEVEL. В любом случае KeBugCheckEx он хучит и у тебя будет возможность ещё на живой системе попытаться понять в чём дело. И настрой систему на сброс дампа ядра. Дамп получиться большой, так что анализировать придется самому. А по минидампу тут нихрена не понятно. А вот copy&paste у тя неправильно сделан Если ты дошёл до pIrp->IoStatus.Status = STATUS_CANCELLED, то должен завершить IRP, т.к. в этой точке точно известно, что IRP был отменён, но твоя IrpCancelRoutine не была вызвана, т.к. ты успел сделать IoSetCancelRoutine (Irp, NULL). Но кирдык не из-за этого, ибо на однопроцессорной машине при схваченном спинлоке мы никогда не дойдём до pIrp->IoStatus.Status = STATUS_CANCELLED, даже теоретически. В последнем тостере это делается так: Код (Text): NTSTATUS ToasterQueueRequest ( IN OUT PFDO_DATA FdoData, IN PIRP Irp ) { KIRQL oldIrql; PDRIVER_CANCEL ret; ASSERT(HoldRequests == FdoData->QueueState); IoMarkIrpPending(Irp); KeAcquireSpinLock(&FdoData->QueueLock, &oldIrql); IoSetCancelRoutine (Irp, ToasterCancelQueued); if(TRUE == Irp->Cancel) { ret = IoSetCancelRoutine (Irp, NULL); // // Initialize the driver-managed IRP queue's list head to prevent // ToasterCancelQueued from potentially causing a system crash if the system // has already called it. The list head must be initialized because the // incoming IRP is not added to the driver-managed IRP queue, but when // ToasterQueueRequest releases the spin lock, QueueLock, a different thread // attempting to execute ToasterCancelQueued might resume and attempt to // remove the IRP that is not present in the queue, resulting in a system // crash. Therefore, initializing the list head allows ToasterCancelQueued // to proceed, and not attempt to remove the IRP that is not present in the // IRP queue, without resulting in a system crash. // InitializeListHead(&Irp->Tail.Overlay.ListEntry); KeReleaseSpinLock(&FdoData->QueueLock, oldIrql); if(NULL != ret) { Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); // // Fall-through to the call to ToasterIoDecrement. ToasterQueueRequest // then returns STATUS_PENDING even though the IRP has been cancelled // because a routine must return STATUS_PENDING if it calls // IoMarkIrpPending. // } else { // // The system has already called ToasterCancelQueued. Fall-through to the // call to ToasterIoDecrement. ToasterQueueRequest then returns // STATUS_PENDING even though the IRP has been cancelled because a routine // must return STATUS_PENDING if it calls IoMarkIrpPending. // } } else { // // The incoming IRP has not been canceled, therefore add it to the end of // the driver-managed IRP queue. // InsertTailList(&FdoData->NewRequestsQueue, &Irp->Tail.Overlay.ListEntry); KeReleaseSpinLock(&FdoData->QueueLock, oldIrql); } ToasterIoDecrement(FdoData); return STATUS_PENDING; } VOID ToasterCancelQueued ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PFDO_DATA fdoData = DeviceObject->DeviceExtension; // // Instead of releasing the cancel spin lock and passing Irp->CancelIrql, this // stage of the function driver passes DISPATCH_LEVEL because ToasterCancelQueued // acquires the cancel spin lock again later. // IoReleaseCancelSpinLock(DISPATCH_LEVEL); // // Acquire the driver-managed IRP queue spinlock and take advantage of the // fact that the system calls ToasterCancelQueued at DPC level. // KeAcquireSpinLockAtDpcLevel (&fdoData->QueueLock); RemoveEntryList(&Irp->Tail.Overlay.ListEntry); // // Release the spinlock but stay at DISPATCH_LEVEL // KeReleaseSpinLockFromDpcLevel (&fdoData->QueueLock); // // Lower the system's IRQL to the level it was was before the system called // ToasterCancelQueued. // KeLowerIrql(Irp->CancelIrql); // // Note that the above two calls could also be collapsed into a single call // to KeReleaseSpinLock(&fdoData->QueueLock, Irp->CancelIrql); // Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return; } Навороты с IoReleaseCancelSpinLock(DISPATCH_LEVEL); KeAcquireSpinLockAtDpcLevel KeReleaseSpinLockFromDpcLevel KeLowerIrql это чисто для оптимизации. Если не понятно что зачем, то можно сделать как в старом тостере: Код (Text): VOID ToasterCancelQueued ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PFDO_DATA fdoData = DeviceObject->DeviceExtension; KIRQL oldIrql; IoReleaseCancelSpinLock( Irp->CancelIrql); KeAcquireSpinLock(&fdoData->QueueLock, &oldIrql); RemoveEntryList(&Irp->Tail.Overlay.ListEntry); KeReleaseSpinLock(&fdoData->QueueLock, oldIrql); Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return; }
Спасибо за ответ. Насчет МЕГАдампа () - сделаю, посмотрю. Но вот насчет операций по отмене - я не уверен, что в данном случае это влияет на ситуацию, вроде вообще это не должно выполняться (сделано на всякий пожарный). Ну, если есть неточности, посмотрю тостер. Еще раз спасибо.