IO REMOVE LOCK使用方法小結

2021-06-02 23:05:16 字數 3962 閱讀 4041

io_remove_lock(刪除鎖)的具體結構沒有公開,wdk的文件中中查不到io_remove_lock。最開始看到io_remove_lock是在wdk的例子event中。下面是參考網上的一些資料之後的一點總結,錯誤的地方請指正。

wdm 驅動程式在處理裝置刪除 irp 並釋放驅動程式分配的記憶體後可能接收到附加的 irp。在處理附加的 irp 時試圖引用已經釋放的記憶體會導致系統崩潰。驅動程式能夠接收已刪除裝置的 irp,這有兩個原因:

在裝置被刪除後,另乙個元件可以傳送 i/o。要傳送乙個 irp,元件獲取目標裝置或檔案的指標並去除該裝置物件上的引用(或者 i/o 管理器代表元件去除引用)。引用可以確保目標裝置或檔案物件的持續性,從而目標驅動程式可以訪問裝置物件和裝置擴充套件。但是,除非元件已經在目標裝置上註冊了即插即用通知,否則它不能確定裝置是否仍然存在。

在裝置刪除請求之前傳送的 i/o 請求可能在目標驅動程式處理裝置刪除請求之後到達。這種情況是否發生取決於哪個元件在傳送 i/o、目標驅動程式在裝置堆疊中的位置以及為裝置掛起的其他 i/o 請求。

通俗一點的解釋:有時候i/o管理器發出的pnp請求會與其它i/o請求(如包含讀寫的請求)同時出現。這完全有可能,例如當你處理其它irp時收到了irp_mn_remove_device請求。你必須自己避免這種麻煩產生,標準的做法是使用乙個io_remove_lock物件和幾個相關的核心模式支援例程。

防止裝置被過早地刪除的基本想法是在每一次開始處理請求時都獲取刪除鎖,處理完成後釋放刪除鎖。在你刪除你的裝置物件前,應確保刪除鎖未被使用。否則,你將等到這個鎖的所有引用都被釋放。下圖顯示了這個過程:

在驅動程式的裝置擴充套件(device_extension)中定義io_remove_lock型別的變數,並在 adddevice例程中呼叫ioinitializeremovelock對其進行初始化。

此後,無論何時,當你收到乙個i/o請求時(除了irp_mj_create),你就呼叫ioacquireremovelock。如果刪除裝置的操作正在進行,則ioacquireremovelock返回status_delete_pending。否則,該函式將獲得刪除鎖並返回status_success。一旦你完成乙個i/o操作,就呼叫ioreleaseremovelock,該函式將釋放刪除鎖以及目前未處理的刪除操作。

當處理乙個裝置刪除請求 (irp_mn_remove_device) 時,驅動程式通過呼叫 ioreleaseremovelockandwait 來釋放在其 dispatchpnp 例程中獲取的刪除鎖。這個呼叫直到與刪除鎖關聯的引用計數達到零時才返回,這表示刪除鎖的所有其他持有者都已經被釋放。在 ioreleaseremovelockandwait 返回之後,驅動程式將 irp 沿其裝置堆疊向下傳遞(如有必要),呼叫 iodetachdevice 來從裝置堆疊中刪除其裝置物件,然後釋放在其 adddevice 例程中分配的資源(例如池記憶體)。最後,驅動程式呼叫 iodeletedevice 來標記要刪除的裝置物件。

驅動程式何時應該呼叫 ioreleaseremovelock 取決於它如何處理 irp:通過將其傳遞給下一層驅動程式(不設定完成例程)、通過完成 irp 而不將其傳遞給下一層驅動程式或者通過向下傳遞 irp 並設定乙個完成例程。

如果驅動程式將 irp 傳遞給下一層驅動程式並且不設定 iocompletion 例程,那麼驅動程式應該在呼叫 iocalldriver 之後呼叫 ioreleaseremovelock 來向下傳遞irp。

ntstatus mydispatchroutine (

in pdevice_object deviceobject,

in pirp irp

) // do request-specific processing

. . .

// pass down the irp and release the lock.

ioskipcurrentirpstacklocation (irp);

status = iocalldriver (devext->nextlowerdriver, irp);

ioreleaseremovelock (&devext->removelock, irp);

return status;

}

如果驅動程式完成 irp 並且不將其傳遞給下一層驅動程式,那麼驅動程式應該在呼叫 iocompleterequest 之後呼叫 ioreleaseremovelock,如下例所示:

ntstatus mydispatchroutine (

in pdevice_object deviceobject,

in pirp irp

) // do request-specific processing

. . .

// request-specific processing is done. complete the irp

// and release the lock.

irp->iostatus.status = status;

iocompleterequest (irp, io_no_increment );

ioreleaseremovelock (&devext->removelock, irp);

return status;

}

如果驅動程式將 irp 傳遞給下一層驅動程式並設定乙個 iocompletion 例程,那麼驅動程式將從 iocompletion 例程呼叫 ioreleaseremovelock,如下所示:

ntstatus mycompletionroutine (

in pdevice_object deviceobject,

in pirp irp,

in pvoid context

)

只有在對裝置物件的所有引用都被釋放後,i/o 管理器才會真正刪除該裝置物件。因此,在驅動程式的裝置刪除處理完成之後,有效的裝置物件和裝置擴充套件可能仍然存在。但是,驅動程式已經釋放其資源,從而使得儲存在裝置擴充套件中的這些資源的指標都變得無效。

如果驅動程式在其刪除裝置處理完成之後,但是 i/o 管理器刪除裝置物件之前接收到另乙個 i/o 請求,那麼就會發生問題。當驅動程式處理請求時,它可能試圖從裝置擴充套件取消對乙個無效指標的引用,這會導致系統崩潰。

要防止這種問題,驅動程式應該為所有型別的 i/o 請求獲取刪除鎖,而不僅僅是即插即用和電源請求。大部分驅動程式已經在其 dispatchpnp 和 dispatchpower 例程中獲取了刪除鎖,從而防止在處理即插即用和電源 irp 時刪除裝置。但是,因為其他型別的 irp 可能在裝置刪除之後到達,所以驅動程式還應該在排程例程中為其他型別的 i/o 請求獲得刪除鎖。

最簡單的方法是在傳送 irp 時在 i/o 排程例程中呼叫 ioacquireremovelock。ioacquireremovelock 返回 status_delete_pending 來指示正在刪除裝置。如果 ioacquireremovelock 返回此狀態(或者除 status_success 之外的任何狀態),那麼驅動程式應該拒絕 i/o 請求。

在取消引用儲存在裝置擴充套件中的任何指標之前,通過在傳送 irp 時在 i/o 排程例程中呼叫 ioacquireremovelock 來獲得刪除鎖。

如果 ioacquireremovelock 不返回 status_success,那麼拒絕 i/o 請求。

當驅動程式完成 irp 處理時,呼叫 ioreleaseremovelock。

在裝置刪除處理期間呼叫 ioreleaseremovelockandwait,然後呼叫 iodetachdevice 和 iodeletedevice。

reference(其實基本都是轉來的,稍微整理了一下)

我的裝置不見了。為什麼我仍然收到 irp?

《programming the microsoft windows driver model》

本文首發於:程式人生 >> io_remove_lock使用方法小結 &

dbms output put line使用方法

begin dbms output.put line a end 如果你是再sql plus中,只要再環境中打出 set serveroutput on 就可以了.還有一種方法 就是使用環境中的繫結變數也可以.再環境中定義 variable name varchar2 50 然後把過程新增乙個out...

sp addlinkedserver使用方法

exec sp droplinkedsrvlogin dbvip,null exec sp dropserver dbvip exec sp addlinkedserver server dbvip 被訪問的伺服器別名 srvproduct provider sqloledb datasrc ser...

SQL Server Profiler使用方法

一 sql server profiler使用方法 1 單擊開始 程式 microsoft sql server 2005 效能工具 sql server profiler,如下圖 2 彈出sql server profiler視窗,如下圖 3 在工作視窗內,滑鼠單擊 檔案 新建跟蹤 n 彈出資料庫...