共用方式為


實作 IoCompletion 常式

在專案上, IoCompletion 常式會收到 CoNtext 指標。 當分派常式呼叫 IoSetCompletionRoutine時,它可以提供 CoNtext 指標。 此指標可以參考 IoCompletion 常式處理 IRP 所需的任何驅動程式判斷內容資訊。 請注意,內容區域無法分頁,因為 IoCompletion 常式可以在 IRQL = DISPATCH_LEVEL呼叫。

請考慮下列 IoCompletion 常式的實作指導方針:

  • IoCompletion常式可以檢查 IRP 的I/O 狀態欄塊,以判斷 I/O 作業的結果。

  • 如果使用 IoAllocateIrpIoBuildAsynchronousFsdRequest來配置發送常式的輸入 IRP, IoCompletion 常式必須呼叫 IoFreeIrp 來釋放該 IRP,最好在完成原始 IRP 之前。

    • IoCompletion常式必須釋放針對驅動程式配置的 IRP 所配置之分派常式的任何每個 IRP 資源,最好在釋放對應的 IRP 之前。

      例如,如果分派常式使用 IoAllocateMdl 配置 MDL ,並針對它配置的部分傳輸 IRP 呼叫 IoBuildPartialMdlIoCompletion 常式必須使用 IoFreeMdl 釋放 MDL。 如果配置資源來維護原始 IRP 的狀態,則必須釋放這些資源,最好在呼叫具有原始 IRP 的 IoCompleteRequest 之前,一定在傳回控制權之前。

      一般而言,在釋放或完成 IRP 之前, IoCompletion 常式應該釋放分派常式所配置的任何每個 IRP 資源。 否則,驅動程式必須在其 IoCompletion 常式從完成原始要求傳回控制權之前,維護要釋放之資源的狀態。

    • 如果 IoCompletion 常式無法使用 STATUS_SUCCESS 完成原始 IRP,則必須將原始 IRP 中的 I/O 狀態欄塊設定為驅動程式配置 IRP 中傳回的值,導致 IoCompletion 常式失敗原始要求。

    • 如果 IoCompletion 常式使用 STATUS_PENDING 完成原始要求,它必須先使用原始 IRP 呼叫 IoMarkIrpPending ,才能呼叫 IoCompleteRequest

    • 如果 IoCompletion 常式必須讓原始 IRP 失敗,並出現錯誤STATUS_XXX,它可以 記錄錯誤。 不過,基礎設備磁碟機必須負責記錄任何發生的裝置 I/O 錯誤,因此 IoCompletion 常式通常不會記錄錯誤。

    • IoCompletion 常式已處理並釋放驅動程式配置的 IRP 時,常式必須傳回具有STATUS_MORE_PROCESSING_REQUIRED的控制權。

      IoCompletion 常式傳回STATUS_MORE_PROCESSING_REQUIRED,會將驅動程式配置和釋放 IRP 的 I/O 管理員完成處理。 第二次呼叫 IoCompleteRequest 會導致 I/O 管理員繼續呼叫 IRP 的完成常式,從傳回STATUS_MORE_PROCESSING_REQUIRED的常式正上方的完成常式開始。

  • 如果 IoCompletion 常式重複使用傳入的 IRP,將一或多個要求傳送至較低的驅動程式,或常式重試失敗的作業,它應該更新 IoCompletion 常式維護每個 IRP 重複使用或重試的內容。 然後,它可以再次設定下一個較低驅動程式的 I/O 堆疊位置、使用自己的進入點呼叫 IoSetCompletionRoutine ,並為 IRP 呼叫 IoCallDriver

    • IoCompletion常式不應該在每次重複使用或重試 IRP 時呼叫IoMarkIrpPending

      分派常式已將原始 IRP 標示為擱置中。 在鏈結中的所有驅動程式都使用 IoCompleteRequest完成原始 IRP 之前,它仍會擱置中。

    • 重試要求之前, IoCompletion 常式應該重設 I/O 狀態欄塊,並針對 [狀態 ] 和 [狀態] 設定為 STATUS_SUCCESS 零,可能是儲存傳回的錯誤資訊之後。

      針對每次重試, IoCompletion 常式通常會遞減分派常式所設定的重試計數。 一般而言, IoCompletion 常式必須呼叫 IoCompleteRequest ,當某些有限的重試次數失敗時,IRP 就會失敗。

    • IoCompletion常式必須在呼叫IoSetCompletionRoutineIoCallDriver且具有重複使用或重試的 IRP 之後傳回STATUS_MORE_PROCESSING_REQUIRED。

      IoCompletion 常式傳回STATUS_MORE_PROCESSING_REQUIRED,會讓 I/O 管理員完成重複使用或重試的 IRP 處理。

    • 如果 IoCompletion 常式無法使用 STATUS_SUCCESS完成原始 IRP,它必須讓較低驅動程式傳回 I/O 狀態欄塊,以便重複使用或重試作業,使 IoCompletion 常式失敗 IRP。

    • 如果 IoCompletion 常式使用 STATUS_PENDING 完成原始要求,它必須先使用原始 IRP 呼叫 IoMarkIrpPending ,才能呼叫 IoCompleteRequest

    • 如果 IoCompletion 常式必須讓原始 IRP 失敗,並出現錯誤STATUS_XXX,它可以 記錄錯誤。 不過,基礎設備磁碟機必須負責記錄任何發生的裝置 I/O 錯誤,因此 IoCompletion 常式通常不會記錄錯誤。

  • 任何在 IRP 中設定IoCompletion常式的驅動程式,然後將 IRP 向下傳遞至較低的驅動程式,都應該檢查IoCompletion常式中的IRP-PendingReturned >旗標。 如果已設定旗標, IoCompletion 常式就必須使用 IRP 呼叫 IoMarkIrpPending 。 不過請注意,將 IRP 向下傳遞,然後等候事件的驅動程式不應該標示 IRP 擱置中。 相反地,其 IoCompletion 常式應該發出訊號,並傳回STATUS_MORE_PROCESSING_REQUIRED。

  • IoCompletion常式必須釋放配置處理原始 IRP 之分派常式的任何資源,最好在IoCompletion常式呼叫IoCompleteRequest與原始 IRP 之前,且絕對在IoCompletion常式傳回控制項之前,才能完成原始 IRP。

如果任何較高層級的驅動程式已在原始 IRP 中設定其 IoCompletion 常式,則除非呼叫所有較低層級驅動程式的 IoCompletion 常式,否則不會呼叫該驅動程式的 IoCompletion 常式。

在呼叫 IoCompleteRequest 中提供優先權提升

如果最低層級設備磁碟機可以在其分派常式中完成 IRP,它會使用priorityBoost IO_NO_INCREMENT 呼叫IoCompleteRequest。 因為驅動程式可以假設原始要求者未等待其 I/O 作業完成,所以不需要增加執行時間優先順序。

否則,最低層級驅動程式會提供系統定義的裝置類型特定值,以提升要求者的執行時間優先順序,以補償要求者在其裝置 I/O 要求上等候的時間。 如需提升值,請參閱 Wdm.h 或 Ntddk.h。

較高層級的驅動程式在呼叫IoCompleteRequest時,會套用與其各自的基礎設備磁碟機相同的PriorityBoost

呼叫 IoCompleteRequest 的效果

當驅動程式呼叫 IoCompleteRequest時,I/O 管理員會在呼叫下一個較高層級驅動程式之前,以零填入該驅動程式的 I/O 堆疊位置,如果有的話,該驅動程式已設定要針對 IRP 呼叫 的 IoCompletion 常式。

較高層級驅動程式的 IoCompletion 常式只能檢查 IRP 的 I/O 狀態欄塊,以判斷所有較低驅動程式如何處理要求。

IoCompleteRequest的呼叫端不得嘗試存取剛完成的 IRP。 這類嘗試是導致系統損毀的程式設計錯誤。