Compartir a través de


Protección de aislamiento

Los controladores en modo kernel pueden usar la protección de ejecución para acceder a objetos de forma segura en la memoria del sistema compartida que otro controlador en modo kernel crea y elimina.

Se dice que un objeto está apagado si se han finalizado todos los accesos pendientes del objeto y no se concederán nuevas solicitudes para acceder al objeto. Por ejemplo, es posible que un objeto compartido deba desactivarse para que se pueda eliminar y reemplazar por un nuevo objeto.

El controlador que posee el objeto compartido tiene la capacidad de permitir que otros controladores adquieran y liberen la protección contra agotamiento sobre el objeto. Cuando la protección contra desactivación está en vigor, un controlador distinto del propietario puede acceder al objeto sin riesgo de que el propietario elimine el objeto antes de que finalice el acceso. Antes de que se inicie el acceso, el controlador de acceso solicita protección de run-down sobre el objeto. Para un objeto de larga duración, esta solicitud se concede casi siempre. Una vez finalizado el acceso, el controlador de acceso libera su protección de ejecución adquirida anteriormente en el objeto .

Rutinas de protección primaria contra descarga

Para empezar a compartir un objeto, el controlador que posee el objeto llama a la rutina ExInitializeRundownProtection para inicializar la protección de ejecución en el objeto. Después de esta llamada, otros controladores que acceden al objeto pueden adquirir y liberar la protección contra degradación en el objeto.

Un controlador que tiene acceso al objeto compartido llama a la rutina ExAcquireRundownProtection para solicitar protección de ejecución en el objeto. Una vez finalizado el acceso, este controlador llama a la rutina ExReleaseRundownProtection para liberar la protección de ejecución en el objeto.

Si el controlador propietario determina que se debe eliminar el objeto compartido, este controlador espera a eliminar el objeto hasta que finalicen todos los accesos pendientes del objeto.

En preparación para borrar el objeto compartido, el controlador propietario llama a la rutina ExWaitForRundownProtectionRelease para esperar a que el objeto se detenga. Durante esta llamada, ExWaitForRundownProtectionRelease espera a que se liberen todas las instancias de protección de ejecución concedidas previamente en el objeto, pero impide que se concedan nuevas solicitudes para la protección de ejecución en el objeto. Una vez que finaliza el último acceso protegido y se liberan todas las instancias de protección de ejecución, ExWaitForRundownProtectionRelease devuelve y el controlador propietario puede eliminar el objeto de forma segura.

ExWaitForRundownProtectionRelease bloquea la ejecución del subproceso del controlador que realiza la llamada hasta que todos los controladores que contienen protección de ejecución en el objeto compartido liberan esta protección. Para evitar que ExWaitForRundownProtectionRelease bloquee la ejecución durante períodos demasiado largos, los subprocesos de controladores que acceden al objeto compartido deben evitar que se suspendan mientras mantienen la protección contra la ejecución en el objeto. Por este motivo, los controladores que acceden deben llamar a ExAcquireRundownProtection y ExReleaseRundownProtection dentro de una región crítica o protegida, o cuando se ejecuta a IRQL = APC_LEVEL.

Usos para la protección contra descarga

La protección contra el agotamiento es útil para proporcionar acceso a un objeto compartido que casi siempre está disponible, pero que en ocasiones podría necesitar ser eliminado y reemplazado. Los controladores que acceden a datos o que llaman a rutinas de este objeto no deben intentar acceder al objeto después de eliminarlos. De lo contrario, estos accesos no válidos pueden provocar un comportamiento impredecible, daños en los datos o incluso errores del sistema.

Por ejemplo, un controlador antivirus normalmente permanece cargado en memoria cuando se ejecuta el sistema operativo. En ocasiones, es posible que este controlador deba descargarse y reemplazarse por una versión actualizada del controlador. Otros controladores envían solicitudes de E/S al controlador antivirus para acceder a los datos y rutinas de este controlador. Antes de enviar una solicitud de E/S, un componente de kernel, como un administrador de filtros del sistema de archivos, puede adquirir protección de ejecución para protegerse contra la descarga prematura del controlador antivirus mientras controla la solicitud de E/S. Una vez completada la solicitud de E/S, se puede liberar la protección de ejecución.

La protección de agotamiento no serializa los accesos a un objeto compartido. Si dos o más controladores de acceso pueden contener simultáneamente la protección de ejecución en un objeto y los accesos al objeto deben serializarse, se debe usar algún otro mecanismo, como un bloqueo de exclusión mutua, para serializar los accesos.

La estructura EX_RUNDOWN_REF

Una estructura EX_RUNDOWN_REF monitorea el estado de la protección de agotamiento en un objeto compartido. Esta estructura es opaca para los controladores. Las rutinas de protección contra apagado proporcionadas por el sistema usan esta estructura para contar el número de instancias de protección contra apagado que están actualmente en vigor en el objeto. Estas rutinas también utilizan esta estructura para realizar un seguimiento de si el objeto está desactivado o en proceso de desactivación.

Para empezar a compartir un objeto, el controlador propietario del objeto llama a ExInitializeRundownProtection para inicializar la estructura de EX_RUNDOWN_REF asociada al objeto . Después de la inicialización, el controlador propietario puede hacer que esta estructura esté disponible para otros controladores que requieren acceso al objeto. Los controladores de acceso pasan esta estructura como parámetro a las llamadas ExAcquireRundownProtection y ExReleaseRundownProtection que adquieren y liberan la protección de ejecución en el objeto. El controlador propietario pasa esta estructura como parámetro a la llamada ExWaitForRundownProtectionRelease que espera a que el objeto se ejecute para que se pueda eliminar de forma segura.

Comparación con bloqueos

La protección contra agotamiento es una de las varias maneras de garantizar el acceso seguro a un objeto compartido. Otro enfoque consiste en usar un bloqueo de software de exclusión mutua. Si un controlador requiere acceso a un objeto que está bloqueado actualmente por otro controlador, el primer controlador debe esperar a que el segundo controlador libere el bloqueo. Sin embargo, la adquisición y liberación de bloqueos puede convertirse en un cuello de botella de rendimiento, y los bloqueos pueden consumir grandes cantidades de memoria. Si se usan incorrectamente, los bloqueos pueden provocar que los controladores que compiten por los mismos objetos compartidos queden bloqueados. Los esfuerzos para detectar y evitar interbloqueos normalmente requieren la desviación de recursos informáticos sustanciales.

A diferencia de los bloqueos, la protección contra el agotamiento exige requisitos de tiempo de procesamiento y memoria relativamente ligeros. Un recuento de referencia simple está asociado al objeto para asegurarse de que la eliminación del objeto se aplaza hasta que se completen todos los accesos pendientes del objeto. Con este enfoque, se pueden usar instrucciones atómicas de hardware interbloqueadas en lugar de bloqueos de software de exclusión mutua para garantizar el acceso seguro a un objeto. Las llamadas para adquirir y liberar la protección de degradación suelen ser rápidas. Las ventajas de usar un mecanismo liviano, como la protección de desmontaje, pueden ser importantes para un objeto compartido que tiene una larga vida útil y se comparte entre muchos controladores.

Otras rutinas de protección contra sobrecargas

Están disponibles otras rutinas de protección de descompuesto, además de las mencionadas anteriormente. Estas rutinas adicionales podrían ser utilizadas por algunos controladores.

La rutina ExReInitializeRundownProtection permite asociar una estructura de EX_RUNDOWN_REF usada previamente con un nuevo objeto e inicializa la protección de ejecución en este objeto.

La rutina ExRundownCompleted actualiza la estructura EX_RUNDOWN_REF para indicar que se ha completado la ejecución del objeto asociado.

Las rutinas ExAcquireRundownProtectionEx y ExReleaseRundownProtectionEx son similares a ExAcquireRundownProtection y ExReleaseRundownProtection. Estas cuatro rutinas incrementan o reducen el recuento de las instancias de protección de ejecución que están en vigor en un objeto compartido. Mientras que ExAcquireRundownProtection y ExReleaseRundownProtection incrementan y reducen este recuento en uno, ExAcquireRundownProtectionEx y ExReleaseRundownProtectionEx incrementan y reducen el recuento por cantidades arbitrarias.

Protección de degradación con reconocimiento de caché

Una referencia de rundown es una estructura de datos compacta y rápida, pero puede provocar contención de caché cuando muchos procesadores intentan adquirir la referencia al mismo tiempo. Esto puede afectar al rendimiento y la escalabilidad del controlador.

Para evitar este problema, puede usar una referencia de rundown compatible con la memoria caché para distribuir el seguimiento de referencias entre varias líneas de caché. Esto reduce la contención de caché y mejora el rendimiento del controlador en equipos con varios procesadores.

Para usar una referencia de rundown compatible con la memoria caché, siga estos pasos:

  1. Cree un objeto EX_RUNDOWN_REF_CACHE_AWARE realizando una de las acciones siguientes:
  2. Solicite protección de ejecución en el objeto antes de acceder a él llamando a la rutina ExAcquireRundownProtectionCacheAware . Esta rutina devuelve TRUE si se concede la solicitud o FALSE si el objeto se está ejecutando.
  3. Libera la protección de la ejecución en el objeto después de acceder a él llamando a la rutina ExReleaseRundownProtectionCacheAware .
  4. Espere a que el objeto finalice antes de eliminarlo, llamando a la rutina ExWaitForRundownProtectionReleaseCacheAware. Esta rutina bloquea el subproceso actual hasta que se liberan todas las instancias de protección contra el agotamiento en el objeto.
  5. Si el controlador llamó a ExAllocateCacheAwareRundownProtection anteriormente, debe llamar a ExFreeCacheAwareRundownProtection para liberar la referencia de rundown.

Para reutilizar una referencia de desglose compatible con la caché, siga estos pasos:

  1. Después de llamar a ExWaitForRundownProtectionReleaseCacheAware, llame a ExRundownCompletedCacheAware para indicar que se ha completado la ejecución del objeto anterior.
  2. Llame a ExReInitializeRundownProtectionCacheAware para reinicializar la referencia después de que se ejecute el objeto asociado.
  3. Ahora el controlador puede volver a llamar a ExAcquireRundownProtectionCacheAware.

Una referencia de finalización consciente de la memoria caché tiene la ventaja de mejorar el rendimiento y la escalabilidad en situaciones específicas, pero consume más memoria que una referencia de finalización normal. Debe tener en cuenta este equilibrio al elegir entre los dos tipos de referencias de resumen.