範例 I/O 要求 - 詳細數據
說明開啟檔案物件的圖表顯示具有兩個 I/O 堆棧位置的 IRP,但 IRP 可以有任意數目的 I/O 堆棧位置,視有多少分層驅動程式會處理指定的要求而定。
下圖詳細說明開啟檔案物件 中的驅動程式 圖如何使用 I/O 支援例程(IoXxx 例程)來處理讀取或寫入要求的 IRP。
I/O 管理員會使用它為子系統讀取/寫入要求配置的 IRP 呼叫文件系統驅動程式 (FSD)。 FSD 會在 IRP 中存取其 I/O 堆疊位置,以判斷它應該執行的作業。
FSD 可以透過呼叫 I/O 支援例程(IoAllocateIrp)一或多次,來將原始要求分成較小的要求(可能需要用於一個以上的裝置驅動程式),以分配額外的 IRP。 其他 IRP 被傳回給 FSD,其 I/O 堆疊位置已填充為零,供較低層級驅動程式使用。 FSD 可自行選擇重新使用原始 IRP,而不是配置上圖所示的其他 IRP,方法是在原始 IRP 中設置下層驅動程式的 I/O 堆疊位置,並將其傳遞給下層驅動程式。
針對每個驅動程式配置的 IRP,上圖中的 FSD 會呼叫 I/O 支援例程來註冊 FSD 提供的完成例程;在完成例程中,FSD 可以判斷較低驅動程式是否符合要求,並在較低驅動程式完成時釋放每個驅動程式配置的 IRP。 I/O 管理員會呼叫 FSD 提供的完成程序,不論每個驅動程式配置的 IRP 是否已順利完成、是否完成但出現錯誤狀態,或被取消。 較高層級的驅動程式負責釋放其配置的任何 IRP,並且為較低層級的驅動程式自行分配和設定。 I/O 管理員會在所有驅動程式完成後釋放它們所配置的 IRP。
接下來,FSD 會呼叫 I/O 支援例程(IoGetNextIrpStackLocation),以存取下一個較低層級驅動程式的 I/O 堆棧位置,以設定下一個較低驅動程式的要求。 (在上圖中,下一個較低的驅動程式恰好是最低層級的驅動程式。FSD 接著會呼叫 I/O 支援例程(IoCallDriver),將該 IRP 傳遞給下一個較低的驅動程式。
使用 IRP 呼叫時,最低層級驅動程式會檢查其 I/O 堆疊位置,以判斷它應該在目標裝置上執行的作業(IRP_MJ_XXX 函式程式代碼所指示)。 目標裝置是由裝置物件在其指定的 I/O 堆疊位置中表示,並以 IRP 傳遞至驅動程式。 最低層級驅動程式可以假設 I/O 管理員已將 IRP 路由傳送至針對 IRP_MJ_XXX 作業定義的驅動程式進入點(這裡 IRP_MJ_READ 或 IRP_MJ_WRITE),而較高層級的驅動程式已檢查要求之其他參數的有效性。
如果沒有較高層級的驅動程式,最低層級驅動程式會檢查 IRP_MJ_XXX 作業的輸入參數是否有效。 如果是,驅動程式通常會呼叫 I/O 支援例程,告知 I/O 管理員有一個裝置操作正在 IRP 上待決,並將它排入佇列,或傳遞給另一個驅動程式提供的、用於存取目標裝置的例程(這裡的目標裝置可能是實體裝置或邏輯裝置,如磁碟或磁碟上的分區)。
I/O 管理員會判斷驅動程式是否已經在忙於處理目標裝置上的另一個 IRP,如果是,則將 IRP 排入佇列,並返回。 否則,I/O 管理器會將 IRP 路由到驅動程式提供的例程,以在其裝置上啟動 I/O 作業。 (在這個階段,上圖中的兩個驅動程式和 I/O 管理員回復控制權。)
當裝置中斷時,驅動程式的中斷服務例程(ISR)只會執行必要的工作,以停止裝置中斷並儲存作業所需的相關資訊。 ISR 接著會使用 IRP 呼叫 I/O 支援例程(IoRequestDpc),將驅動程式提供的 DPC (延遲過程調用) 例程排入佇列,以比 ISR 低的硬體優先順序來完成要求的作業。
當驅動程式的 DPC 取得控制權時,它會使用在 ISR 呼叫 IoRequestDpc中傳遞的上下文來完成 I/O 作業。 DPC 會呼叫支援例程來清除下一個 IRP(如果有的話),並將該 IRP 傳遞給驅動程式提供的例程,以在裝置上啟動 I/O 作業(請參閱步驟 5)。 DPC 接著會在 IRP 的 I/O 狀態區塊中設定剛完成作業的狀態,然後將它傳回給 I/O 管理員,同時 IoCompleteRequest。
I/O 管理員會將 IRP 中最低層級驅動程式的 I/O 堆疊位置設為零,然後呼叫文件系統已註冊的完成例程(請參閱步驟 3),使用 FSD 配置的 IRP。 此完成例程會檢查 I/O 狀態區塊,以判斷要重試要求,還是更新有關原始要求的任何內部狀態,並釋放其驅動程式配置的 IRP。 文件系統可以收集傳送至較低層級驅動程式的所有由驅動程式分配的 IRP 的狀態資訊,以便設置 I/O 狀態並完成原始 IRP。 當檔案系統完成原始 IRP 時,I/O 管理員會將 NTSTATUS 值傳回給 I/O 操作的原始要求者(該子系統的原生函式)。
如同分層驅動程式 圖中 處理 IRP 中所顯示的檔案系統驅動程式,任何新增至現有驅動程式鏈結的新驅動程式都可以執行下列所有動作:
將自己的完成例程設定為 IRP。 IoCompletion 例程會檢查 I/O 狀態區塊,以判斷較低驅動程式是否已成功地完成 IRP、取消 IRP,或完成操作但伴隨錯誤。 完成例程可以在完成 IRP 之前,更新驅動程式可能儲存的任何 IRP 特定狀態,以及釋放驅動程式可能已配置的任何作業特定資源,依此類推。 此外,完成例程可以延後 IRP 完成(藉由通知 I/O 管理員 IRP 需要更多處理),而且可以在允許 IRP 完成之前,先將另一個要求傳送至下一個較低層級的驅動程式。
在它配置的 IRP 中設定下一個較低層級驅動程式的 I/O 堆疊位置,並將要求傳送至下一個較低層級的驅動程式。
藉由在每個 IRP 中設定下一個較低驅動程式的 I/O 堆疊位置,並呼叫 IoCallDriver,將任何傳入要求傳遞至較低的驅動程式。 (請注意,對於具有主要函式程式碼 IRP_MJ_POWER的 IRP,驅動程式必須使用 PoCallDriver。
每個驅動程式建立的裝置物件都代表特定驅動程式執行 I/O 要求的實體、邏輯或虛擬設備。 如需建立和設定裝置物件的詳細資訊,請參閱 裝置物件和裝置堆疊。
如分層驅動程式中的 處理 IRP 圖所示,大多數驅動程式會透過一組由驅動程式提供的系統定義 標準例程,以階段處理每個 IRP,但鏈結中不同層級的驅動程式一定有不同的標準例程。 例如,只有最低層級的驅動程式會處理來自實體裝置的中斷,因此只有最低層級的驅動程式會有ISR和 DPC 來完成插斷驅動 I/O 作業。 另一方面,由於這類驅動程式知道當收到裝置的中斷時,I/O 已經完成,因此不需要完成例行程序。 只有較高層級的驅動程式會有一或多個完成例程,例如此圖中的 FSD。