次の方法で共有


PnP ページング要求の処理

記憶域フィルター ドライバーは、フィルター処理している関数ドライバーがこの IRP を処理する場合、PnP ページング要求 (IRP_MN_DEVICE_USAGE_NOTIFICATIONParameters.UsageNotification.TypeDeviceUsageTypePaging に設定された IRP_MJ_PNP) を処理する必要があります。

フィルター 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. DO_POWER_INRUSH ビットが Filter DO で設定されていない場合は、DO_POWER_PAGABLE ビットを設定します。

    次に、DO_POWER_PAGABLE ビットを上りではなく、下りで設定する必要がある理由を説明します。

    電源要件では、下位のデバイス オブジェクトで DO_POWER_PAGABLE ビットが設定されている場合、上位レベルのドライバーはすべて同じ操作を行う必要があります。 フィルター ドライバーがページング要求 IRP をスタックに送信する前に DO_POWER_PAGABLE ビットを設定できない場合は、次のようにこの条件に違反する可能性があります。

    たとえば、フィルター ドライバーが、ページング要求 IRP をドライバー スタック内のドライバーに転送する前に、そのフィルター DO の DO_POWER_PAGABLE ビットを設定していないとします。 次に、下位のドライバーが独自の 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, ...))。

擬似コードの例

次のコード サンプルの文字 (//A//B など) でマークされたセクションは、上記のアウトラインの文字にマップされます。

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.