Run-Down Protection
從 Windows XP 開始,內核模式驅動程式可以使用向下執行保護。 驅動程式可以使用執行保護,安全地存取由另一個內核模式驅動程式建立和刪除的共享系統記憶體中物件。
如果物件的所有未完成存取都已完成,而且不會授與存取物件的新要求,則會執行 物件。 例如,可能需要執行共享物件,才能將其刪除並取代為新的物件。
擁有共用物件的驅動程式可讓其他驅動程式取得並釋放對象的執行保護。 當執行關閉保護生效時,擁有者以外的驅動程式可以存取物件,而不會有擁有者在存取完成之前刪除對象的風險。 存取開始之前,存取驅動程式會在物件上要求執行保護。 對於長期存留的物件,此要求幾乎一律會被授與。 存取完成之後,存取驅動程式會在 對象上釋放先前取得的 Run-down 保護。
主要執行保護例程
若要開始共享對象,擁有對象的驅動程式會呼叫 ExInitializeRundownProtection 例程,以初始化 對象的執行保護。 在此呼叫之後,存取物件的其他驅動程式可以在 物件上取得並釋放執行保護。
存取共用對象的驅動程式會呼叫 ExAcquireRundownProtection 例程,要求對象的執行保護。 存取完成之後,此驅動程式會呼叫 ExReleaseRundownProtection 例程,以釋放對象的執行保護。
如果擁有驅動程式判斷必須刪除共享物件,此驅動程式會等候刪除物件,直到物件的所有未完成存取為止。
為了準備刪除共享對象,擁有的驅動程式會呼叫 ExWaitForRundownProtectionRelease 例程,等待物件執行。 在此呼叫期間, ExWaitForRundownProtectionRelease 會等候物件上所有先前授與的 Run-down 保護實例被釋放,但會防止對物件授與執行保護的新要求。 在最後一個受保護的存取完成,並釋放所有執行保護實例之後, ExWaitForRundownProtectionRelease 會傳回,且擁有的驅動程式可以安全地刪除物件。
ExWaitForRundownProtectionRelease 會封鎖呼叫驅動程式線程的執行,直到所有在共享物件上保留 Run-down 保護的驅動程式都會釋放此保護。 為了避免 ExWaitForRundownProtectionRelease 封鎖長時間的執行,存取共用物件的驅動程式線程應該避免在物件上保留執行關閉保護時暫停。 基於這個理由,存取驅動程序應該呼叫重要區域或受防護區域內的 ExAcquireRundownProtection 和 ExReleaseRundownProtection,或在 IRQL = APC_LEVEL執行時。
用於執行保護
執行關閉保護特別適用於提供幾乎一律可用的共享物件的存取權,但有時可能需要刪除和取代。 存取資料或呼叫此物件例程的驅動程式,在刪除對象之後,不得嘗試存取該物件。 否則,這些無效的存取可能會導致無法預期的行為、數據損毀,甚至是系統失敗。
例如,當操作系統執行時,防病毒軟體驅動程式通常會保留在記憶體中。 有時候,此驅動程式可能需要卸除並取代為驅動程式的更新版本。 其他驅動程式會將 I/O 要求傳送至防毒驅動程式,以存取此驅動程式中的數據和例程。 傳送 I/O 要求之前,核心元件,例如文件系統篩選管理員,可以取得執行保護,以防止在處理 I/O 要求時過早卸載防病毒軟體驅動程式。 I/O 要求完成之後,就可以釋出執行保護。
執行保護不會將共享物件的存取串行化。 如果兩個或多個存取驅動程式可以同時在物件上保存執行保護,而且必須串行化物件的存取權,則必須使用其他一些機制,例如互斥鎖定,以串行化存取。
EX_RUNDOWN_REF結構
EX_RUNDOWN_REF結構會追蹤共享物件上執行保護的狀態。 此結構對驅動程式不透明。 系統提供的 Run-down 保護例程會使用此結構來計算目前在 物件上生效之 Run-down 保護實例的數目。 這些例程也會使用此結構來追蹤物件是否正在執行中或正在執行中。
若要開始共享對象,擁有對象的驅動程式會呼叫 ExInitializeRundownProtection ,以初始化 與對象相關聯的EX_RUNDOWN_REF 結構。 初始化之後,擁有驅動程式可以將此結構提供給需要存取物件的其他驅動程式。 存取驅動程式會將這個結構當做參數傳遞至 ExAcquireRundownProtection 和 ExReleaseRundownProtection 呼叫,以取得和釋放物件上的執行保護。 擁有的驅動程式會將這個結構當做參數傳遞至 ExWaitForRundownProtectionRelease 呼叫,以等候物件執行,以便安全地刪除它。
與鎖定的比較
執行保護是數種方式之一,可保證共享物件的安全存取。 另一種方法是使用互斥軟體鎖定。 如果驅動程式需要存取目前由另一個驅動程式鎖定的物件,則第一個驅動程式必須等候第二個驅動程序釋放鎖定。 不過,取得和釋放鎖定可能會成為效能瓶頸,而鎖定可能會耗用大量的記憶體。 如果不正確使用,鎖定可能會導致競爭相同共用對象的驅動程式變成死結。 偵測並避免死結的努力通常需要大量運算資源的轉移。
相較於鎖定,執行保護具有相對輕量型的處理時間和記憶體需求。 簡單的參考計數與 對象相關聯,以確保刪除物件會延後,直到物件的所有未完成存取為止。 透過此方法,可以使用不可部分完成、相互鎖定的硬體指令,而不是互斥軟體鎖定,以確保對物件的安全存取。 取得和發行執行保護的呼叫通常非常快速。 使用輕量型機制的優點,例如執行保護,對於具有長壽且在許多驅動程式之間共用的共享物件而言,可能相當重要。
其他執行保護例程
除了先前提到的程式之外,還有數個其他執行保護例程可供使用。 某些驅動程式可能會使用這些額外的例程。
ExReInitializeRundownProtection 例程可讓先前使用的EX_RUNDOWN_REF結構與新的對象相關聯,並初始化此對象的執行保護。
ExRundownCompleted 例程會更新 EX_RUNDOWN_REF 結構,指出相關聯對象的執行已完成。
ExAcquireRundownProtectionEx 和 ExReleaseRundownProtectionEx 例程類似於 ExAcquireRundownProtection 和 ExReleaseRundownProtection。 這四個例程會遞增或遞減在共享物件上生效之執行保護實例的計數。 ExAcquireRundownProtection 和 ExReleaseRundownProtection 遞增並遞減此計數一次,ExAcquireRundownProtectionEx 和 ExReleaseRundownProtectionEx 遞增,並依任意數量遞減計數。
快取感知的 Run-down 保護
取消參考是精簡且快速的數據結構,但是當許多處理器同時嘗試取得參考時,可能會導致快取爭用。 這可能會影響驅動程式的效能和延展性。
若要避免這個問題,您可以使用快取感知的取消參考,將參考追蹤分散到多個快取行。 這樣可減少快取爭用,並改善多處理器計算機上的驅動程式效能。
若要使用快取感知的取消參考,請遵循下列步驟:
- 執行下列其中一項動作,以建立 EX_RUNDOWN_REF_CACHE_AWARE 物件:
- 呼叫 ExAllocateCacheAwareRundownProtection。 請注意,這會負責初始化。
- 或者,若要控制記憶體配置,請呼叫 ExSizeOfRundownProtectionCacheAware、配置傳回大小的緩衝區,然後將該緩衝區和大小傳遞至 ExInitializeRundownProtectionCacheAware。
- 呼叫 ExAcquireRundownProtectionCacheAware 例程,在存取物件之前要求取消保護。 如果授與要求,則此例程會傳回 TRUE,如果物件正在執行,則傳回 FALSE。
- 藉由呼叫 ExReleaseRundownProtectionCacheAware 例程,在存取對象之後釋放物件的取消保護。
- 呼叫 ExWaitForRundownProtectionReleaseCacheAware 例程,等待對象在刪除之前執行。 此例程會封鎖目前的線程,直到釋放物件上所有取消保護實例為止。
- 如果驅動程式稍早呼叫 ExAllocateCacheAwareRundownProtection,它應該呼叫 ExFreeCacheAwareRundownProtection 以釋放取消參考。
若要重複使用快取感知的取消參考,請遵循下列步驟:
- 呼叫 ExWaitForRundownProtectionReleaseCacheAware 之後,呼叫 ExRundownCompletedCacheAware 以指出舊對象的執行已完成。
- 呼叫 ExReInitializeRundownProtectionCacheAware ,在相關聯的物件執行後重新初始化參考。
- 現在驅動程式可以再次呼叫 ExAcquireRundownProtectionCacheAware。
快取感知的取消參考在特定情況下具有較佳效能和延展性的優點,但會耗用比一般取消參考更多的記憶體。 在選擇這兩種類型的取消參考時,您應該考慮此取捨。