共用方式為


處理 PnP 分頁要求

儲存器篩選驅動程式必須處理 PnP 分頁要求 (IRP_MJ_PNP,且 IRP_MN_DEVICE_USAGE_NOTIFICATIONParameters.UsageNotification.Type 設為 DeviceUsageTypePaging) 如果函式驅動程式處理此 IRP。

下列項目必須新增至 Filter DO 的 DeviceExtension:

ULONG PagingCount;

KEVENT PagingCountEvent;

收到 PnP 分頁要求時,記憶體篩選驅動程式必須同時更新 PagingCount 和 Filter DO 中 DO_POWER_PAGABLE 位的設定。 DO_POWER_PAGABLE位更新的時間取決於要設定或清除位。 如果 IRP 指出應該設定位,則篩選驅動程式必須先設定它, 將 IRP 轉送至驅動程式堆疊。 但是,如果 IRP 指出應該清除位,則篩選驅動程式不應該立即清除位。 它必須先轉送 IRP,然後等候較低的驅動程式傳回其狀態,並且只有在較低的驅動程式傳回 STATUS_SUCCESS時,才清除位。

下列會追蹤記憶體篩選驅動程式所採取的動作流程。 請參閱大綱下方的虛擬程式碼範例,以查看 C 程式代碼中此大綱的表示法:

A. 確認裝置已啟動。 如果沒有,則失敗 並STATUS_DEVICE_NOT_READY

B. 同步處理 PagingCountEvent (KeWaitForSingleObject ( PagingCountEvent,...) ) 。

C. 如果移除最後一個分頁裝置 ( (! Parameters.UsageNotification.InPath && (PagingCount == 1) ) then

  1. 將本機布爾值設定為 TRUE,以及

  2. 如果未在 Filter DO 中設定 DO_POWER_INRUSH 位,請設定 DO_POWER_PAGABLE 位。

    下列說明為何 DO_POWER_PAGABLE 位必須在下移時設定,而不是在進行時:

    電源需求指出,如果任何較低的裝置物件設定 DO_POWER_PAGABLE 位,則所有較高層級的驅動程式都必須執行相同的動作。 如果篩選驅動程式無法在將分頁要求 IRP 傳送至堆疊之前設定 DO_POWER_PAGABLE 位,它可能會違反此條件,如下所示:

    假設篩選驅動程式未在其 Filter DO 中設定 DO_POWER_PAGABLE 位,然後再將分頁要求 IRP 轉送至驅動程式堆疊中的驅動程式。 接下來,假設較低的驅動程式會在自己的 DO 中設定 DO_POWER_PAGABLE 位。 最後,假設在篩選驅動程式完成 IRP 之前,就會發生電源 IRP。 此時, DO_POWER_PAGABLE 位會在 Filter DO 中清除,但會在較低層級驅動程式的 DO 中設定,導致系統當機。

    安全地在將分頁要求轉送至堆疊之前設定 DO_POWER_PAGABLE 位,因為篩選驅動程式的裝置上不再有作用中的分頁檔案,因此不會再進行分頁 I/O。 如果移除此分頁檔案的要求成功,將會完成篩選驅動程式。 如果要求失敗,篩選驅動程式只要在完成 IRP 之前清除 DO_POWER_PAGABLE 位,即可還原其旗標的原始狀態。 因為分頁檔案要求已串行化,所以自從篩選驅動程式上次修改此位之後,有些其他線程將不會有任何危險。

D. 同步將 IRP 轉送至較低的驅動程式。

E. 如果 IRP 成功完成,則

  1. 呼叫 IoAdjustPagingPathCount (&PagingCount、 Parameters.UsageNotification.InPath) 來遞增或遞減 PagingCount。 IoAdjustPagingPathCount 會根據 Parameters.UsageNotification.InPath 中的值,執行 PagingCount 的 InterlockedIncrement 或 InterlockedDecrement。 TRUE 值表示正在新增分頁檔案,因此遞增 PagingCount;FALSE 值表示正在移除分頁檔案,因此會遞減 PagingCount。

  2. 如果 Parameters.UsageNotification.InPathTRUE,則會新增分頁檔案,因此請清除 DO_POWER_PAGABLE 位。

F. 如果 IRP 失敗,則為

  1. 檢查本機布爾值,以查看 DO_POWER_PAGABLE 是否已在關閉時於 Filter DO 中設定。

  2. 如果 DO_POWER_PAGABLE 設定在關閉時,請加以清除。

G. 結束同步處理 (KeSetEvent (PagingCountEvent, ...) ) 。

虛擬程式代碼範例

下列程式代碼範例中以字母標示的區段 (AB 等 ) 會對應至上述大綱的字母。

case DeviceUsageTypePaging: { 
    BOOLEAN setPageable = FALSE; 
    BOOLEAN addPageFile = irpStack -> 
                          Parameters.UsageNotification.InPath; 
 
 // A 
    if((addPageFile) && 
        (extension -> CurrentPnpState != 
        IRP_MN_START_DEVICE)) { 
            status = STATUS_DEVICE_NOT_READY; 
            break; 
        } 
 // B 
    KeWaitForSingleObject(&commonExtension -> PagingCountEvent, 
                                    Executive, KernelMode, 
                                    FALSE, NULL); 
 // C 
    if (!addPageFile && commonExtension -> PagingCount == 1 ) { 
        // The last paging file is no longer active.
        // Set the DO_POWER_PAGABLE bit before 
        // forwarding the paging request down the 
        // stack.
        if (!(DeviceObject->Flags & DO_POWER_INRUSH)) { 
            DeviceObject->Flags |=             DO_POWER_PAGABLE; 
            setPageable = TRUE; 
        ) 
    ) 
 // D 
        status = ForwardIrpSynchronous(commonExtension, Irp); 
 // E
        if (NT_SUCCESS(status)) { 
            IoAdjustPagingPathCount(&commonExtension -> PagingCount, 
                                    addPageFile); 
        if (addPageFile && commonExtension -> PagingCount == 1) { 
            // Once the lower device objects have 
            // succeeded the addition of the paging 
            // file, it is illegal to fail the 
            // request. It is also the time to 
            // clear the Filter DO's 
            //DO_POWER_PAGABLE flag.
 
            DeviceObject->Flags &= ~DO_POWER_PAGABLE; 
            } 
        } else { 
 // F 
        if (setPageable == TRUE) { 
            DeviceObject->Flags &= ~DO_POWER_PAGABLE; 
            setPageable = FALSE; 
        } 
    } 
 // G 
        KeSetEvent(&commonExtension->PagingCountEvent, 
                                    IO_NO_INCREMENT, FALSE); 
                                    break;
    } *Do not use or delete the last paragraph mark. It maintains the template setup and formats.