IRP 的創建

 
1. 有四種方法來創建IRP
Ø IoBuildAsynchronousFsdRequest
創建異步IRP,不需要等待其完成;
Ø IoBuildSynchronousFsdRequest
創建同步IRP, 需要等待其完成,這種方法和上面的只能創建某些特定類型IRP
Ø IoBuildDeviceIoCtontrolRequest
創建一個類型爲 IRP_MJ_DEVICE_CONTROL 或者
IRP_MJ_DEVICE_CONTROL 的同步IRP.
Ø IoAllocateIrp
創建任何類型的異步IRP
2. 創建同步IRP
 I/O管理器認爲新創建的IRP是屬於創建IRP時所處的那個線程,這樣,如果這個線程結束了,I/O管理器會自動取消屬於它的還處在PENDING狀態的IRP.所以,不要在任意上下文狀態創建一個IRP,否則,IRP可能被意外的取消了。創建同步IRP時,需要用戶提供一個事件對象,要保證在I/O管理器設置該事件對象的信號時,該事件對象還在內存中。只能在PASSIVE_LEVEL 上調用創建同步IRP的函數,因爲當IRP完成時,系統派遣一個APC來置位提供的那個事件,以下的code有問題:
PIRP irp = IoBuildSynchronousFsdRequest(...);
ExAcquireFastMutex(...);
NTSTATUS status = IoCallDriver(...);
if (status == STATUS_PENDING)
{
 KeWaitForSingleObject(...); 
}
ExReleaseFastMutex(...);
紅色部分會導致死鎖,當IRP被完成時,IoCompleteRequest會派遣一個該線程的APC,這個APC會設置用戶等待的事件,但是由於開始調用了ExAcquireFastMutex,從而使得該段code處在APC_LEVEL上,這樣APC就沒法執行了。
有三種方案解決這個問題:
Ø 使用常規互斥對象代替快速互斥對象;
Ø 使用KeEnterCriticalRegion,它不會阻止APC的運行,然後使用ExAcquireFastMutexUnsafe 來獲得互斥對象
Ø 創建異步IRP來代替
3.創建異步IRP
可以在非任意上下文和任意上下文中創建異步IRP, 需要提供一個完成回調例程做IRP
的清理工作和調用IoFreeIrp.可以在IRQL <= DISPATCH_LEVEL 的級別來創建
4 派遣IRP
創建完IRP後,使用IoGetNextIrpStackLocation函數來獲得第一個堆棧單元的指針,然後初始化這個IRP。
5. 不要以STATUS_PENDING 的狀態完成一個IRP, 調用 IoCompleteRequest之前要保證IRP的取消例程爲空。把IRP向下層驅動傳遞的時候,也要保證IRP的取消例程爲空。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章