共用方式為


保證 I/O 作業的向前進度

某些驅動程式,例如系統分頁裝置的儲存體驅動程式,必須至少執行其中一些支援的 I/O 作業,而不會失敗,以避免遺失重要的系統資料。 驅動程式失敗的其中一個可能原因是記憶體不足的情況。 如果架構或驅動程式無法配置足夠的記憶體來處理 I/O 要求,其中一個或另一個可能必須透過錯誤狀態值 來完成 I/O 要求失敗。

在 1.9 版之前的 KMDF 版本中,如果架構無法為 I/O 要求封包配置架構要求物件,則架構一律會失敗, (IRP) I/O 管理員已傳送至驅動程式。 為了提供驅動程式在低記憶體情況下處理 I/O 要求的能力,架構 1.9 版和更新版本可為 I/O 佇列提供 保證的向前進度 功能。

此功能可讓架構和驅動程式分別預先配置要求物件集和要求相關驅動程式內容緩衝區的記憶體。 只有當系統記憶體數量不足時,架構和驅動程式才會使用此預先配置的記憶體。

保證向前進度的功能

藉由使用架構的 I/O 佇列保證向前進度,驅動程式可以:

  • 要求架構預先配置一組要求物件,以在低記憶體情況下搭配特定 I/O 佇列使用。

  • 提供回呼函式,此函式會在低記憶體情況下從架構接收預先配置的要求物件時,預先配置驅動程式可使用的要求特定資源。

  • 提供另一個回呼函式,以在 偵測 到低記憶體狀況時,為 I/O 要求配置驅動程式特定資源。 如果這個回呼函式的配置因為記憶體不足的情況而失敗,它可以指出架構是否應該使用其中一個預先配置的要求物件。

  • 指定哪些 I/O 要求需要使用預先配置的要求物件。 選項包括針對所有 IRP 使用預先配置的物件,只有在分頁 I/O 作業正在進行時使用它們,或讓額外的驅動程式回呼函式檢查每個 IRP,以判斷是否要使用預先配置的物件。

如果您的驅動程式為一或多個 I/O 佇列實作保證的向前進度,則驅動程式在低記憶體情況下能夠順利 處理 I/O 要求 。 您可以針對裝置的預設 I/O 佇列,以及驅動程式呼叫 WdfDeviceConfigureRequestDispatching來設定的任何 I/O 佇列實作保證的向前進度。

只有當驅動程式和驅動程式 的 I/O 目標 都實作保證向前進度時,架構的向前進度功能才適用于您的驅動程式。 換句話說,如果驅動程式為裝置實作保證的向前進度,裝置驅動程式堆疊中的所有較低層級驅動程式也必須實作保證的向前進度。

啟用 I/O 佇列的保證向前進度

若要為 I/O 佇列啟用保證的向前進度,驅動程式會初始化 WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY 結構,然後呼叫 WdfIoQueueAssignForwardProgressPolicy 方法。 如果驅動程式呼叫 WdfDeviceConfigureRequestDispatching 來設定 I/O 佇列,則必須先這麼做,才能呼叫 WdfIoQueueAssignForwardProgressPolicy

當驅動程式呼叫 WdfIoQueueAssignForwardProgressPolicy時,它可以指定下列三個事件回呼函式,全部都是選擇性的:

EvtIoAllocateResourcesForReservedRequest
驅動程式的 EvtIoAllocateResourcesForReservedRequest 回呼函式會配置並儲存架構為低記憶體情況保留的要求物件要求特定資源。

架構會在每次建立保留要求物件時呼叫這個回呼函式。 驅動程式應該為一個 I/O 要求配置要求特定資源,通常是使用保留的要求物件 內容空間

EvtIoAllocateRequestResources
驅動程式的 EvtIoAllocateRequestRequestResources 回呼函式會配置要求特定資源以供立即使用。 它會在架構收到 IRP 並建立 IRP 的要求物件之後立即呼叫。

如果回呼函式嘗試配置資源失敗,回呼函式會傳回錯誤狀態值。 架構接著會刪除新建立的要求物件,並使用其中一個保留的要求物件。 接著,驅動程式 的要求處理常式 會使用先前配置的 EvtIoAllocateRequestResources 回呼函式的要求特定資源。

EvtIoWdmIrpForForwardProgress
驅動程式的 EvtIoWdmIrpForForwardProgress 回呼函式會檢查 IRP,並告知架構是否要使用 IRP 的保留要求物件,或藉由以錯誤狀態值完成 I/O 要求來失敗。

只有當架構無法建立新的要求物件,而且您已在驅動程式的 WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY結構中 設定旗標,) 您希望驅動程式在低記憶體情況下檢查 IRP 時 (,才會呼叫此回呼函式。 換句話說,您的驅動程式可以評估每個 IRP,並決定它是否必須是必須在低記憶體情況下處理的 IRP。

當您的驅動程式呼叫 WdfIoQueueAssignForwardProgressPolicy時,也會指定您想要架構預先配置給低記憶體情況的保留要求物件數目。 您可以選擇適合您裝置和驅動程式的要求物件數目。 為避免效能降低,您的驅動程式通常應該指定一個數位,以近似驅動程式和裝置可以平行處理的 I/O 要求數目。

不過,如果您的驅動程式呼叫 WdfIoQueueAssignForwardProgressPolicy 及其 EvtIoAllocateResourcesForReservedRequest 回呼函式預先配置太多保留要求物件或太多要求特定資源記憶體,您的驅動程式實際上可以參與您嘗試處理的低記憶體情況。 您應該測試驅動程式和裝置的效能,並包含低記憶體模擬,以判斷要選擇的最佳數位。

在 WdfIoQueueAssignForwardProgressPolicy傳回之前,架構會建立並保留驅動程式已指定的要求物件數目。 每次保留要求物件時,架構都會立即呼叫驅動程式的 EvtIoAllocateResourcesForReservedRequest 回呼函式,讓驅動程式可以配置及儲存要求特定資源,以防架構實際使用保留的要求物件。

當其中一個驅動程式 的要求處理常式 從 I/O 佇列收到 I/O 要求時,它可以呼叫 WdfRequestIsReserved 方法,以判斷要求物件是否為架構預先配置給低記憶體情況的要求物件。 如果此方法傳回 TRUE,驅動程式應該使用其 EvtIoAllocateResourcesForReservedRequest 回呼函式保留的資源。

如果架構使用其中一個保留的要求物件,它會在驅動程式完成要求之後,將 物件傳回至其保留物件集。 架構會儲存要求物件,以及呼叫 WdfDeviceInitSetRequestAttributesWdfObjectAllocateCoNtext所建立驅動程式所建立的任何內容空間,以便在發生另一個低記憶體情況時重複使用。

架構和驅動程式如何保證向前進度

以下是驅動程式和架構執行以支援 I/O 佇列保證向前進度的步驟:

  1. 驅動程式會呼叫 WdfIoQueueAssignForwardProgressPolicy

    為了回應,架構會配置並儲存驅動程式所指定的要求物件數目。 如果驅動程式先前稱為 WdfDeviceInitSetRequestAttributes,則每個配置都包含 指定 WdfDeviceInitSetRequestAttributes 的內容空間。

    此外,如果驅動程式已提供 EvtIoAllocateResourcesForReservedRequest 回呼函式,則架構會在每次配置並儲存要求物件時呼叫回呼函式。

  2. 架構會收到 I/O 要求封包 (IRP) I/O 管理員傳送至驅動程式。

    架構會嘗試為 IRP 配置要求物件。 如果驅動程式為要求類型建立的 I/O 佇列支援保證向前進度,下一個步驟取決於配置是否成功或失敗:

    • 要求物件配置成功。

      如果驅動程式提供 EvtIoAllocateRequestResources 回呼函式,架構會呼叫它。 如果回呼函式傳回STATUS_SUCCESS,架構會將要求新增至 I/O 佇列。 如果回呼函式傳回錯誤狀態值,架構會刪除剛建立的要求物件,並使用其中一個預先配置的要求物件。 當驅動程式的要求處理常式收到要求物件時,它會判斷要求物件是否已預先配置,因此是否應該使用驅動程式預先配置的資源。

      如果驅動程式 提供 EvtIoAllocateRequestResources 回呼函式,架構會將要求新增至 I/O 佇列,就像驅動程式尚未啟用保證向前進度一樣。

    • 要求物件配置失敗。

      架構接下來的動作取決於驅動程式針對WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY結構之ForwardProgressReservedPolicy成員所提供的值。 此成員會通知架構何時使用保留要求:一律,只有在 I/O 要求是分頁 I/O 作業時,或只有在 EvtIoWdmIrpForForwardProgress 回呼函式指出應該使用保留要求時。

    在所有情況下,驅動程式的要求處理常式都可以呼叫 WdfRequestIsReserved 來判斷架構是否使用保留的要求物件。 如果是,驅動程式應該使用其 EvtIoAllocateResourcesForReservedRequest 回呼函式所配置的要求資源。

保證向前進度案例

您正在為可能包含系統分頁檔案的存放裝置撰寫驅動程式。 讀取作業和將作業寫入至分頁檔案很重要。

您決定為讀取和寫入作業建立個別的 I/O 佇列,並針對這兩個 I/O 佇列啟用保證的向前進度。 您決定為所有其他要求類型建立第三個 I/O 佇列,而不啟用保證的向前進度。

驅動程式堆疊和裝置能夠平行處理四個寫入作業,因此您會在呼叫WdfIoQueueAssignForwardProgressPolicy之前,將WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY結構的TotalForwardProgressRequests成員設定為 4。

您決定只有在驅動程式的裝置是分頁裝置時,才決定保證向前進度很重要,因此您的驅動程式會將 WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY 結構的 ForwardProgressReservedPolicy 成員設定為 WdfIoForwardProgressReservedPolicyPagingIO

因為您的驅動程式需要每個讀取要求和每個寫入要求的架構記憶體物件,所以您決定驅動程式應該在低記憶體情況下預先配置一些記憶體物件,以用於對 WdfIoTargetFormatRequestForReadWdfIoTargetFormatRequestForWrite 的呼叫。

因此,驅動程式會為讀取佇列提供 EvtIoAllocateResourcesForReservedRequest 回呼函式,並為寫入佇列提供另一個回呼函式。 每次架構呼叫其中一個回呼函式時,回呼函式都會呼叫 WdfMemoryCreate ,並儲存傳回的物件控制碼以用於低記憶體情況。 因為回呼函式會接收預先配置的要求物件的控制碼,所以它可以將記憶體物件父代給要求物件。 (DMA 裝置的驅動程式也可能預先配置 架構 DMA 物件。)

讀取和寫入佇列 的要求處理常式 必須判斷每個收到的要求物件是否為針對低記憶體情況保留的架構。 要求處理常式可以呼叫 WdfRequestIsReserved,也可以比較要求物件控制碼與先前收到的 EvtIoAllocateResourcesForReservedRequest 回呼函式。

驅動程式也會為讀取佇列提供 EvtIoAllocateRequestRequestResources 回呼函式,並為寫入佇列提供另一個回呼函式。 當架構從 I/O 管理員收到讀取或寫入要求,並成功建立要求物件時,架構會呼叫其中一個回呼函式。 每個回呼函式都會呼叫 WdfMemoryCreate 來配置要求的記憶體物件。 如果配置失敗,回呼函式會傳回錯誤狀態值,通知架構剛發生記憶體不足的情況。 架構會偵測錯誤傳回值,刪除它剛才建立的要求物件,並使用其中一個預先配置的物件。

此驅動程式不提供 EvtIoWdmIrpForForwardProgress 回呼函式,因為它不需要在架構將它們新增至 I/O 佇列之前檢查個別的讀取或寫入 IRP。

請記住,當驅動程式為裝置實作保證的向前進度時,裝置驅動程式堆疊中的所有較低層級驅動程式也必須實作保證的向前進度。