런다운 보호

Windows XP부터 커널 모드 드라이버에서 런다운 보호를 사용할 수 있습니다. 드라이버는 런다운 보호를 사용하여 다른 커널 모드 드라이버에서 만들고 삭제한 공유 시스템 메모리의 개체에 안전하게 액세스할 수 있습니다.

개체의 모든 미해결 액세스가 완료되고 개체에 액세스하기 위한 새 요청이 부여되지 않으면 개체가 실행 되었다고 합니다. 예를 들어 공유 개체를 삭제하고 새 개체로 바꿀 수 있도록 실행해야 할 수 있습니다.

공유 개체를 소유하는 드라이버는 다른 드라이버가 개체에 대한 런다운 보호를 획득하고 해제할 수 있도록 할 수 있습니다. 런다운 보호가 적용되는 경우 소유자가 아닌 드라이버는 액세스가 완료되기 전에 소유자가 개체를 삭제할 위험 없이 개체에 액세스할 수 있습니다. 액세스가 시작되기 전에 액세스하는 드라이버는 개체에 대한 런다운 보호를 요청합니다. 수명이 긴 개체의 경우 이 요청은 거의 항상 부여됩니다. 액세스가 완료되면 액세스하는 드라이버는 개체에서 이전에 획득한 런다운 보호를 해제합니다.

기본 런다운 보호 루틴

개체 공유를 시작하기 위해 개체를 소유한 드라이버는 ExInitializeRundownProtection 루틴을 호출하여 개체에 대한 런다운 보호를 초기화합니다. 이 호출 후에 개체에 액세스하는 다른 드라이버는 개체에 대한 런다운 보호를 획득하고 해제할 수 있습니다.

공유 개체에 액세스하는 드라이버는 ExAcquireRundownProtection 루틴을 호출하여 개체에 대한 런다운 보호를 요청합니다. 액세스가 완료되면 이 드라이버는 ExReleaseRundownProtection 루틴을 호출하여 개체에 대한 런다운 보호를 해제합니다.

소유 드라이버가 공유 개체를 삭제해야 한다고 판단하는 경우 이 드라이버는 개체의 모든 미해결 액세스가 완료될 때까지 개체 삭제를 기다립니다.

공유 개체를 삭제하기 위해 소유 드라이버는 ExWaitForRundownProtectionRelease 루틴을 호출하여 개체가 실행될 때까지 기다립니다. 이 호출 중에 ExWaitForRundownProtectionRelease 는 개체에 대해 이전에 부여한 모든 런다운 보호 인스턴스가 해제될 때까지 대기하지만 개체의 런다운 보호에 대한 새 요청이 부여되지 않도록 합니다. 마지막으로 보호된 액세스가 완료되고 모든 런다운 보호 인스턴스가 해제되면 ExWaitForRundownProtectionRelease 가 반환되고 소유 드라이버가 개체를 안전하게 삭제할 수 있습니다.

ExWaitForRundownProtectionRelease 는 공유 개체에서 런다운 보호를 유지하는 모든 드라이버가 이 보호를 해제할 때까지 호출 드라이버 스레드의 실행을 차단합니다. ExWaitForRundownProtectionRelease가 너무 오랜 기간 동안 실행을 차단하지 않도록 하려면 공유 개체에 액세스하는 드라이버 스레드가 개체에 대한 런다운 보호를 유지하는 동안 일시 중단되지 않아야 합니다. 이러한 이유로 드라이버 액세스는 중요한 지역 또는 보호된 지역 내에서 또는 IRQL = APC_LEVEL 실행하는 동안 ExAcquireRundownProtectionExReleaseRundownProtection을 호출해야 합니다.

런다운 보호 사용

런다운 보호는 거의 항상 사용할 수 있지만 경우에 따라 삭제 및 교체해야 할 수 있는 공유 개체에 대한 액세스를 제공하는 데 특히 유용합니다. 데이터에 액세스하거나 이 개체의 루틴을 호출하는 드라이버는 삭제된 후 개체에 액세스하려고 하면 안 됩니다. 그렇지 않으면 이러한 잘못된 액세스로 인해 예측할 수 없는 동작, 데이터 손상 또는 시스템 오류가 발생할 수 있습니다.

예를 들어 바이러스 백신 드라이버는 일반적으로 운영 체제가 실행될 때 메모리에 로드된 상태로 유지됩니다. 경우에 따라 이 드라이버를 언로드하고 업데이트된 드라이버 릴리스로 교체해야 할 수 있습니다. 다른 드라이버는 이 드라이버의 데이터 및 루틴에 액세스하기 위해 바이러스 백신 드라이버에 I/O 요청을 보냅니다. I/O 요청을 보내기 전에 파일 시스템 필터 관리자와 같은 커널 구성 요소는 I/O 요청을 처리하는 동안 바이러스 백신 드라이버의 조기 언로드를 방지하는 런다운 보호를 획득할 수 있습니다. I/O 요청이 완료되면 런다운 보호를 해제할 수 있습니다.

런다운 보호는 공유 개체에 대한 액세스를 직렬화하지 않습니다. 둘 이상의 액세스 드라이버가 동시에 개체에 대한 런다운 보호를 유지할 수 있고 개체에 대한 액세스를 직렬화해야 하는 경우 상호 배제 잠금과 같은 다른 메커니즘을 사용하여 액세스를 직렬화해야 합니다.

EX_RUNDOWN_REF 구조체

EX_RUNDOWN_REF 구조체는 공유 개체에 대한 런다운 보호의 상태 추적합니다. 이 구조는 드라이버에 불투명합니다. 시스템에서 제공하는 런다운 보호 루틴은 이 구조를 사용하여 현재 개체에 적용되는 런다운 보호 인스턴스 수를 계산합니다. 이러한 루틴은 또한 이 구조를 사용하여 개체가 실행 중인지 아니면 실행 중인지 추적합니다.

개체 공유를 시작하기 위해 개체를 소유하는 드라이버는 ExInitializeRundownProtection을 호출하여 개체와 연결된 EX_RUNDOWN_REF 구조를 초기화 합니다. 초기화 후 소유 드라이버는 개체에 액세스해야 하는 다른 드라이버에서 이 구조를 사용할 수 있도록 할 수 있습니다. 액세스 드라이버는 개체에 대한 런다운 보호를 획득하고 해제하는 ExAcquireRundownProtectionExReleaseRundownProtection 호출에 이 구조를 매개 변수로 전달합니다. 소유 드라이버는 안전하게 삭제할 수 있도록 개체가 실행될 때까지 기다리는 ExWaitForRundownProtectionRelease 호출에 이 구조를 매개 변수로 전달합니다.

잠금 비교

런다운 보호는 공유 개체에 대한 안전한 액세스를 보장하는 여러 가지 방법 중 하나입니다. 또 다른 방법은 상호 배제 소프트웨어 잠금을 사용하는 것입니다. 드라이버가 현재 다른 드라이버에 의해 잠겨 있는 개체에 액세스해야 하는 경우 첫 번째 드라이버는 두 번째 드라이버가 잠금을 해제할 때까지 기다려야 합니다. 그러나 잠금을 획득하고 해제하면 성능 병목 상태가 될 수 있으며 잠금은 많은 양의 메모리를 사용할 수 있습니다. 잘못 사용하면 잠금으로 인해 동일한 공유 개체에 대해 경쟁하는 드라이버가 교착 상태가 될 수 있습니다. 교착 상태를 감지하고 방지하려면 일반적으로 상당한 컴퓨팅 리소스를 전환해야 합니다.

잠금과 달리 런다운 보호에는 비교적 간단한 처리 시간과 메모리 요구 사항이 있습니다. 개체의 모든 미해결 액세스가 완료될 때까지 개체 삭제가 지연되도록 하는 간단한 참조 수가 개체와 연결됩니다. 이 방법을 사용하면 상호 배제 소프트웨어 잠금 대신 원자성 연동 하드웨어 지침을 사용하여 개체에 안전하게 액세스할 수 있습니다. 런다운 보호를 획득하고 릴리스하기 위한 호출은 일반적으로 매우 빠릅니다. 런다운 보호와 같은 경량 메커니즘을 사용하는 이점은 수명이 길고 많은 드라이버에서 공유되는 공유 개체에 중요할 수 있습니다.

기타 런다운 보호 루틴

이전에 멘션 것 외에도 몇 가지 다른 런다운 보호 루틴을 사용할 수 있습니다. 이러한 추가 루틴은 일부 드라이버에서 사용할 수 있습니다.

ExReInitializeRundownProtection 루틴을 사용하면 이전에 사용한 EX_RUNDOWN_REF 구조체를 새 개체와 연결하고 이 개체에 대한 런다운 보호를 초기화합니다.

ExRundownCompleted 루틴은 연결된 개체의 실행이 완료되었음을 나타내기 위해 EX_RUNDOWN_REF 구조를 업데이트합니다.

ExAcquireRundownProtectionEx ExReleaseRundownProtectionEx 루틴은 ExAcquireRundownProtection 및 ExReleaseRundownProtection유사합니다. 이러한 네 가지 루틴은 공유 개체에 적용되는 런다운 보호 인스턴스의 수를 증가 또는 감소합니다. ExAcquireRundownProtection 및 ExReleaseRundownProtection은 이 수를 1씩 증가 및 감소하지만 ExAcquireRundownProtectionEx ExReleaseRundownProtectionEx는 증분하고 개수를 임의의 양만큼 감소합니다.

캐시 인식 런다운 보호

런다운 참조는 작고 빠른 데이터 구조이지만 많은 프로세서가 동시에 참조를 획득하려고 할 때 캐시 경합을 일으킬 수 있습니다. 이는 드라이버의 성능 및 확장성에 영향을 줄 수 있습니다.

이 문제를 방지하려면 캐시 인식 런다운 참조를 사용하여 참조 추적을 여러 캐시 줄에 분산할 수 있습니다. 이렇게 하면 캐시 경합이 줄어들고 다중 프로세서 컴퓨터에서 드라이버의 성능이 향상됩니다.

캐시 인식 런다운 참조를 사용하려면 다음 단계를 수행합니다.

  1. 다음 중 하나를 수행하여 EX_RUNDOWN_REF_CACHE_AWARE 개체를 만듭니다.
  2. ExAcquireRundownProtectionCacheAware 루틴을 호출하여 액세스하기 전에 개체에 대한 런다운 보호를 요청합니다. 이 루틴은 요청이 부여된 경우 TRUE를 반환하고, 개체가 실행되고 있으면 FALSE를 반환합니다.
  3. ExReleaseRundownProtectionCacheAware 루틴을 호출하여 액세스한 후 개체에 대한 런다운 보호를 해제합니다.
  4. ExWaitForRundownProtectionReleaseCacheAware 루틴을 호출하여 삭제하기 전에 개체가 실행되기를 기다립니다. 이 루틴은 개체에 대한 모든 런다운 보호 인스턴스가 해제될 때까지 현재 스레드를 차단합니다.
  5. 드라이버가 ExAllocateCacheAwareRundownProtection을 이전에 호출한 경우 ExFreeCacheAwareRundownProtection을 호출하여 런다운 참조를 해제해야 합니다.

캐시 인식 런다운 참조를 다시 사용하려면 다음 단계를 수행합니다.

  1. ExWaitForRundownProtectionReleaseCacheAware를 호출한 후 ExRundownCompletedCacheAware를 호출하여 이전 개체의 실행이 완료되었음을 나타냅니다.
  2. ExReInitializeRundownProtectionCacheAware를 호출하여 연결된 개체가 실행된 후 참조를 다시 초기화합니다.
  3. 이제 드라이버는 ExAcquireRundownProtectionCacheAware를 다시 호출할 수 있습니다.

캐시 인식 런다운 참조는 특정 상황에서 더 나은 성능과 확장성의 장점이 있지만 일반 런다운 참조보다 더 많은 메모리를 사용합니다. 두 가지 유형의 런다운 참조 중에서 선택할 때 이 장차를 고려해야 합니다.