Leer en inglés

Compartir a través de


Solicitud y concesión de bloqueos oportunistas

Cuando el redirector de red accede a archivos en servidores remotos, solicita el oplock del servidor remoto. Las aplicaciones cliente solicitan directamente los oplocks únicamente cuando el bloqueo está destinado a un archivo en el servidor local.

Los Bloqueos oportunistas se solicitan a través de FSCTL. Las siguientes FSCTL se utilizan para los distintos tipos de bloqueo oportunista, que pueden emitir tanto las aplicaciones en modo usuario como los controladores en modo kernel.

Solicitud de un bloqueo oportunista en modo usuario

Para solicitar un bloqueo oportunista de Windows 7 en modo usuario, llame a DeviceIoControl:

Para obtener más información, consulte FSCTL_REQUEST_OPLOCK.

Si se puede conceder el bloqueo oportunista solicitado, DeviceIoControl devuelve FALSE y GetLastError devuelve ERROR_IO_PENDING. Por esta razón, nunca se conceden bloqueos oportunistas para E/S sincrónica. La operación solapada no se completa hasta que se rompe el bloqueo oportunista. Una vez completada la operación, el REQUEST_OPLOCK_OUTPUT_BUFFER contendrá información sobre la rotura del bloqueo oportunista.

Si no se puede conceder el bloqueo oportunista, el sistema de archivos devuelve un código de error apropiado. Los códigos de error devueltos con más frecuencia son ERROR_OPLOCK_NOT_GRANTED y ERROR_INVALID_PARAMETER.

Solicitud de un bloqueo oportunista en modo kernel

Para solicitar bloqueos oportunistas de Windows 7 en modo kernel:

Minifiltros del sistema de archivos

Un minifiltro de sistema de ficheros debe utilizar FltAllocateCallbackData y rellenar el campo FLT_CALLBACK_DATA así:

Consulte la documentación de la estructura REQUEST_OPLOCK_INPUT_BUFFER para obtener información sobre cómo dar formato a la solicitud de bloqueo oportunista.

A continuación, el minifiltro del sistema de ficheros debe llamar a FltPerformAsynchronousIo, pasando el FLT_CALLBACK_DATA asignado como parámetro CallbackData.

Si se puede conceder el bloqueo oportunista solicitado, la llamada FltPerformAsynchronousIo devuelve STATUS_PENDING. Por esta razón, nunca se conceden bloqueos oportunistas para E/S sincrónica. La operación no se completa hasta que se rompe el bloqueo oportunista. Una vez completada la operación, el REQUEST_OPLOCK_OUTPUT_BUFFER contendrá información sobre la rotura del bloqueo oportunista.

Si no se puede conceder el bloqueo oportunista, el sistema de archivos devuelve un código de error apropiado. Los códigos de error devueltos con más frecuencia son STATUS_OPLOCK_NOT_GRANTED y STATUS_INVALID_PARAMETER.

Otros tipos de controladores

Otros tipos de controladores pueden llamar a ZwFsControlFile:

  • Establece FsControlCode a FSCTL_REQUEST_OPLOCK.
  • Pase un puntero a una estructura REQUEST_OPLOCK_INPUT_BUFFER en el parámetro InputBuffer y establezca el parámetro InputBufferLength en el tamaño de ese búfer.
  • Pasa un puntero a una estructura REQUEST_OPLOCK_OUTPUT_BUFFER en el parámetro OutputBuffer y establece el parámetro OutputBufferLength al tamaño de ese buffer.

Consulte la documentación de la estructura REQUEST_OPLOCK_INPUT_BUFFER para obtener información sobre cómo dar formato a la solicitud de bloqueo oportunista.

Si se puede conceder el bloqueo oportunista solicitado, la llamada ZwFsControlFile devuelve STATUS_PENDING. Por esta razón, nunca se conceden bloqueos oportunistas para E/S sincrónica. La operación no se completa hasta que se rompe el bloqueo oportunista. Una vez completada la operación, el REQUEST_OPLOCK_OUTPUT_BUFFER contendrá información sobre la rotura del bloqueo oportunista.

Si no se puede conceder el bloqueo oportunista, el sistema de archivos devuelve un código de error apropiado. Los códigos de error devueltos con más frecuencia son STATUS_OPLOCK_NOT_GRANTED y STATUS_INVALID_PARAMETER.

Cómo evitar violaciones de compartición al solicitar bloqueos oportunistas

Utilización del método atómico Create-With-Oplock

Atomic create-with-oplock no es un tipo de bloqueo oportunista. En su lugar, es un procedimiento que permite que las operaciones abiertas eviten provocar infracciones del modo de uso compartido en el intervalo de tiempo entre abrir un archivo y recibir un bloqueo oportunista. Con los bloqueos oportunistas heredados, se requieren bloqueos oportunistas de filtro y apertura de dos identificadores. Con los bloqueos oportunistas de Windows 7, una aplicación o controlador puede solicitar cualquier tipo de bloqueo oportunista utilizando este procedimiento y solo necesita abrir un identificador.

Para realizar el procedimiento atomic create-with-oplock, debe:

  1. Usar FltCreateFileEx2 o ZwCreateFile, según corresponda, para abrir el archivo. En el parámetro CreateOptions pasar la marca FILE_OPEN_REQUIRING_OPLOCK. Puede establecer los parámetros DesiredAccess y ShareAccess según sea necesario. Por ejemplo, en el parámetro DesiredAccess establezca GENERIC_READ para que pueda leer el archivo, y en el parámetro ShareAccess, establezca las banderas FILE_SHARE_READ | FILE_SHARE_DELETE para permitir que otros usuarios lean, cambien el nombre o marquen el archivo para su eliminación mientras lo tiene abierto.
  2. Use el código de control FSCTL_REQUEST_OPLOCK para solicitar un interbloqueo en el objeto o identificador de archivo resultante, como se describe en Solicitud de un interbloqueo en modo kernel.

No realice ninguna operación del sistema de archivos en el archivo entre los pasos 1 y 2. Si lo hace, puede provocar interbloqueos.

El bloqueo oportunista más común para solicitar usando este procedimiento es el tipo Read-Handle. Esto le permite permitir a otros llamadores tanto acceso concurrente como sea posible, mientras que todavía le permite ser notificado si necesita cerrar su identificador para evitar causar una violación de compartición a un open en conflicto.

Uso del filtro de bloqueo heredado

El bloqueo de filtro heredado también permite a una aplicación "retirarse" cuando otras aplicaciones/clientes intentan acceder al mismo flujo, pero es menos flexible que el método atómico de creación con bloqueo. Este mecanismo permite que una aplicación acceda a un flujo sin provocar que otros accesores del flujo reciban violaciones de uso compartido al intentar abrir el flujo. Para evitar violaciones de compartición, se debe utilizar el siguiente procedimiento de tres pasos para solicitar un bloqueo de filtro:

  1. Abra el archivo con un acceso requerido de FILE_READ_ATTRIBUTES y un modo compartido de FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE. El identificador abierto en este paso no hará que otras aplicaciones reciban infracciones de uso compartido porque solo está abierto para el acceso a atributos (FILE_READ_ATTRIBUTES) y no para el acceso a datos (FILE_READ_DATA). Este identificador es adecuado para solicitar el bloqueo de filtro, pero no para realizar E/S en el flujo de datos.

  2. Solicite un bloqueo oportunista de filtro (FSCTL_REQUEST_FILTER_OPLOCK) en el identificador del paso 1. El bloqueo oportunista concedido en este paso permite al poseedor del bloqueo oportunista «salir del paso» sin causar una violación de compartición a otra aplicación que intente acceder al flujo.

  3. Vuelva a abrir el archivo para el acceso de lectura. El identificador abierto en este paso permite al poseedor del bloqueo oportunista realizar E/S en el flujo.

El sistema de archivos NTFS proporciona una optimización para este procedimiento a través de la opción de creación FILE_RESERVE_OPFILTER. Si esta marca se especifica en el paso 1 del procedimiento anterior, permite que el sistema de archivos rechace la solicitud de creación con STATUS_OPLOCK_NOT_GRANTED si el sistema de archivos puede determinar que el paso 2 fallará. Si el paso 1 se realiza correctamente, no hay ninguna garantía de que el paso 2 vaya a realizar correctamente, aunque se haya especificado FILE_RESERVE_OPFILTER para la solicitud de creación.

Condiciones para conceder bloqueos oportunistas

La siguiente tabla identifica las condiciones necesarias para conceder un bloqueo oportunista.

Tipo de solicitud Condiciones

Nivel 1

Filtro

Batch

Solo se concede si se cumplen todas las condiciones siguientes:

  • La solicitud es para una secuencia determinada de un archivo.
    • Si es un directorio, se devuelve STATUS_INVALID_PARAMETER.
  • El flujo está abierto para acceso ASÍNCRONO.
    • Si está abierto para acceso SINCRÓNICO, se devuelve STATUS_OPLOCK_NOT_GRANTED (los bloqueos oportunistas no se conceden para peticiones de E/S síncronas).
  • No hay transacciones de TxF en ninguna secuencia del archivo.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay otras aperturas en el flujo (incluso por el mismo hilo).
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.

Si el estado actual del bloqueo oportunista es:

  • No bloqueo oportunista: se concede la petición.

  • Nivel 2: La petición original de Nivel 2 se rompe con FILE_OPLOCK_BROKEN_TO_NONE. A continuación, se concede el bloqueo oportunista exclusivo solicitado.

  • Nivel 1, Batch, Filter, Read, Read-Handle, Read-Write o Read-Write-Handle: Se devuelve STATUS_OPLOCK_NOT_GRANTED.

Nivel 2

Solo se concede si se cumplen todas las condiciones siguientes:

  • La solicitud es para una secuencia determinada de un archivo.
    • Si es un directorio, se devuelve STATUS_INVALID_PARAMETER.
  • El flujo está abierto para acceso ASÍNCRONO.
    • Si se abre para acceso SINCRÓNICO, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay transacciones TxF en el archivo.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • Actualmente, no existen bloqueos de rango de bytes en el flujo.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
    • Antes de Windows 7, el sistema operativo verificaba si existía un bloqueo de rango de bytes en el flujo desde la última vez que se abrió, y fallaba la petición en caso afirmativo.

Si el estado actual del bloqueo oportunista es:

  • No bloqueo oportunista: se concede la petición.

  • Nivel 2 y/o Read: Se concede la petición. Se pueden conceder varios bloqueos de nivel 2/Read en el mismo flujo al mismo tiempo. Incluso pueden existir múltiples bloqueos oportunistas de Nivel 2 (pero no de Read) en el mismo identificador.
    • Si se solicita un bloqueo oportunista de Read en un identificador que ya tiene un bloqueo oportunista de Read concedido, el IRP del primer bloqueo oportunista de Read se completa con STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE antes de que se conceda el segundo bloqueo oportunista de Read.
  • Nivel 1, Batch, Filter, Read-Handle, Read-Write, Read-Write-Handle: Se devuelve STATUS_OPLOCK_NOT_GRANTED.

Leer

Solo se concede si se cumplen todas las condiciones siguientes:

  • La solicitud es para una secuencia determinada de un archivo.
  • El flujo está abierto para acceso ASÍNCRONO.
    • Si se abre para acceso SINCRÓNICO, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay transacciones TxF en el archivo.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • Actualmente, no existen bloqueos de rango de bytes en el flujo.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay secciones asignadas al usuario que puedan escribirse en el flujo.
    • Si no, se devuelve STATUS_CANNOT_GRANT_REQUESTED_OPLOCK. El campo REQUEST_OPLOCK_OUTPUT_BUFFER.Flags tendrá la marca REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT.

Si el estado actual del bloqueo oportunista es:

  • No bloqueo oportunista: se concede la petición.

  • Nivel 2 y/o Read: Se concede la petición. Se pueden conceder varios bloqueos de nivel 2/Read en el mismo flujo al mismo tiempo.
    • Además, si un bloqueo oportunista existente tiene la misma clave de bloqueo oportunista que la nueva petición, su IRP se completa con STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
  • Read-Handle y el bloqueo oportunista existente tienen una clave de bloqueo oportunista diferente a la de la nueva petición: La solicitud se concede. Pueden coexistir múltiples bloqueos oportunistas de Read y de Read-Handle en el mismo flujo (véase la nota que sigue a esta tabla).
    • En caso contrario (las claves de los bloqueos oportunistas son las mismas) se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • Nivel 1, Batch, Filter, Read-Write, Read-Write-Handle: Se devuelve STATUS_OPLOCK_NOT_GRANTED.

Read-Handle

Solo se concede si se cumplen todas las condiciones siguientes:

  • La solicitud es para una secuencia determinada de un archivo.
  • El flujo está abierto para acceso ASÍNCRONO.
    • Si se abre para acceso SINCRÓNICO, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay transacciones TxF en el archivo.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • Actualmente, no existen bloqueos de rango de bytes en el flujo.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay secciones asignadas al usuario que puedan escribirse en el flujo.
    • Si no, se devuelve STATUS_CANNOT_GRANT_REQUESTED_OPLOCK. El campo REQUEST_OPLOCK_OUTPUT_BUFFER.Flags tendrá la marca REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT.

Si el estado actual del bloqueo oportunista es:

  • No bloqueo oportunista: se concede la petición.

  • Lectura: se concede la solicitud.
    • Si un bloqueo oportunista de Read existente tiene la misma clave de bloqueo oportunista que la nueva petición, su IRP se completa con STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE. El resultado es que el bloqueo oportunista se actualiza de Read a Read-Handle.
    • Cualquier Read oplock existente que no tenga la misma clave que la nueva solicitud permanece sin cambios.
  • Nivel 2, Nivel 1, Batch, Filtro, Read-Write, Read-Write-Handle: Se devuelve STATUS_OPLOCK_NOT_GRANTED.

Lectura y escritura

Solo se concede si se cumplen todas las condiciones siguientes:

  • La solicitud es para una secuencia determinada de un archivo.
    • Si es un directorio, se devuelve STATUS_INVALID_PARAMETER.
  • El flujo está abierto para acceso ASÍNCRONO.
    • Si se abre para acceso SINCRÓNICO, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay transacciones TxF en el archivo.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • Si hay otras aperturas en el flujo (incluso por el mismo hilo), deben tener la misma clave de bloqueo oportunista.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay secciones asignadas al usuario que puedan escribirse en el flujo.
    • Si no, se devuelve STATUS_CANNOT_GRANT_REQUESTED_OPLOCK. El campo REQUEST_OPLOCK_OUTPUT_BUFFER.Flags tendrá la marca REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT.

Si el estado actual del bloqueo oportunista es:

  • No bloqueo oportunista: se concede la petición.

  • Read o Read-Write y el bloqueo oportunista existente tiene la misma clave de bloqueo oportunista que la petición: el IRP del bloqueo oportunista existente se completa con STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE y se concede la petición.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • Nivel 2, Nivel 1, Batch, Filter, Read-Handle, Read-Write-Handle: Se devuelve STATUS_OPLOCK_NOT_GRANTED.

Read-Write-Handle

Solo se concede si se cumple lo siguiente:

  • La solicitud es para una secuencia determinada de un archivo.
    • Si es un directorio, se devuelve STATUS_INVALID_PARAMETER.
  • El flujo está abierto para acceso ASÍNCRONO.
    • Si se abre para acceso SINCRÓNICO, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay transacciones TxF en el archivo.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • Si hay otras peticiones abiertas en el flujo, incluso por el mismo hilo, deben tener la misma clave de bloqueo oportunista.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • No hay secciones asignadas al usuario que puedan escribirse en el flujo.
    • Si no, se devuelve STATUS_CANNOT_GRANT_REQUESTED_OPLOCK. El campo REQUEST_OPLOCK_OUTPUT_BUFFER.Flags tendrá la marca REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT.

Si el estado actual del bloqueo oportunista es:

  • No bloqueo oportunista: se concede la petición.

  • Read, Read-Handle, Read-Write, o Read-Write-Handle y el bloqueo oportunista existente tiene la misma clave de bloqueo oportunista que la petición: el IRP del bloqueo oportunista existente se completa con STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE y se concede la petición.
    • Si no, se devuelve STATUS_OPLOCK_NOT_GRANTED.
  • Nivel 2, Nivel 1, Batch, Filtro: Se devuelve STATUS_OPLOCK_NOT_GRANTED.

Nota

Los bloqueos oportunistas de Read y Nivel 2 pueden coexistir en el mismo flujo, y los bloqueos oportunistas de Read y Read-Handle pueden coexistir, pero los bloqueos oportunistas de Nivel 2 y Read-Handle no pueden coexistir.