Partager via


Requête et octroi d'oplocks

Lorsque le redirecteur réseau accède à des fichiers sur des serveurs distants, il demande l'oplock au serveur distant. Les applications clientes demandent directement des oplocks uniquement lorsque le verrou est destiné à un fichier sur le serveur local.

Les Oplocks sont requis par l'intermédiaire des FSCTL. Les FSCTL suivants sont utilisés pour les différents types de verrouillage d'opérations, que les applications en mode utilisateur et les pilotes en mode noyau peuvent tous deux problème.

Demande d'un oplock en mode utilisateur

Pour requêter un verrouillage Windows 7 en mode utilisateur, appelez DeviceIoControl :

  • Attribuez la valeur FSCTL_REQUEST_OPLOCK à dwIoControlCode.
  • Passez un pointeur vers une structure REQUEST_OPLOCK_INPUT_BUFFER dans le paramètre lpInBuffer.
    • Reportez-vous à la documentation de cette structure pour savoir comment formater la requête d'oplock.
  • Passez un pointeur vers une structure REQUEST_OPLOCK_OUTPUT_BUFFER dans le paramètre lpOutBuffer.

Pour plus d'informations, voir FSCTL_REQUEST_OPLOCK.

Si le verrou oplock demandé peut être accordé, DeviceIoControl renvoie FALSE et GetLastError renvoie ERROR_IO_PENDING. C'est pourquoi les oplocks ne sont jamais accordés pour les E/S synchrones. L'opération chevauchée ne se termine pas tant que l'oplock n'est pas rompu. Une fois l'opération terminée, le REQUEST_OPLOCK_OUTPUT_BUFFER contient des informations sur l'interruption de l'oplock.

Si l'oplock ne peut pas être accordé, le système de fichiers renvoie un code d'erreur approprié. Les codes d'erreur les plus fréquemment renvoyés sont ERROR_OPLOCK_NOT_GRANTED et ERROR_INVALID_PARAMETER.

Demande d’un oplock en mode noyau

Pour la requête des oplocks de Windows 7 en mode noyau :

Minifilters du système de fichiers

Un minifiltre de système de fichiers doit utiliser FltAllocateCallbackData et remplir la FLT_CALLBACK_DATA allouée comme suit :

Reportez-vous à la documentation de la structure REQUEST_OPLOCK_INPUT_BUFFER pour obtenir des informations sur le formatage de la requête oplock.

Ensuite, le minifiltre du système de fichiers doit appeler FltPerformAsynchronousIo, en passant le paramètre FLT_CALLBACK_DATA alloué comme CallbackData.

Si l'oplock demandé peut être accordé, l'appel FltPerformAsynchronousIo renvoie STATUS_PENDING. C'est pourquoi les oplocks ne sont jamais accordés pour les E/S synchrones. L'opération ne se termine pas tant que l'oplock n'est pas rompu. Une fois l'opération terminée, le REQUEST_OPLOCK_OUTPUT_BUFFER contient des informations sur l'interruption de l'oplock.

Si l'oplock ne peut pas être accordé, le système de fichiers renvoie un code d'erreur approprié. Les codes d'erreur les plus fréquemment renvoyés sont STATUS_OPLOCK_NOT_GRANTED et STATUS_INVALID_PARAMETER.

Autres types de pilotes

D’autres types de pilotes peuvent appeler ZwFsControlFile:

  • Mettez FsControlCode à FSCTL_REQUEST_OPLOCK.
  • Passez un pointeur sur une structure REQUEST_OPLOCK_INPUT_BUFFER dans le paramètre InputBuffer et fixez le paramètre InputBufferLength à la taille de ce tampon.
  • Passez un pointeur sur une structure REQUEST_OPLOCK_OUTPUT_BUFFER dans le paramètre OutputBuffer et fixez le paramètre OutputBufferLength à la taille de ce tampon.

Reportez-vous à la documentation de la structure REQUEST_OPLOCK_INPUT_BUFFER pour obtenir des informations sur le formatage de la requête oplock.

Si l'oplock demandé peut être accordé, l'appel ZwFsControlFile renvoie STATUS_PENDING. C'est pourquoi les oplocks ne sont jamais accordés pour les E/S synchrones. L'opération ne se termine pas tant que l'oplock n'est pas rompu. Une fois l'opération terminée, le REQUEST_OPLOCK_OUTPUT_BUFFER contient des informations sur l'interruption de l'oplock.

Si l'oplock ne peut pas être accordé, le système de fichiers renvoie un code d'erreur approprié. Les codes d'erreur les plus fréquemment renvoyés sont STATUS_OPLOCK_NOT_GRANTED et STATUS_INVALID_PARAMETER.

Éviter les violations de partage lors de la requête d'oplocks

Utilisation de la méthode de création atomique avec oplock

La création atomique avec oplock n'est pas un type d'oplock. Il s’agit plutôt d’une procédure qui permet aux opérations ouvertes d’éviter de provoquer des violations en mode de partage dans le temps entre l’ouverture d’un fichier et la réception d’un oplock. Avec les oplocks hérités, les oplocks de filtre et l'ouverture de deux descripteurs sont nécessaires. Avec les oplocks Windows 7, une application ou un pilote peut requêter n'importe quel type d'oplock en utilisant cette procédure et n'a besoin d'ouvrir qu'un seul descripteur.

Pour effectuer la procédure de création atomique avec oplock, vous devez :

  1. Utilisez FltCreateFileEx2 ou ZwCreateFile, selon le cas, pour ouvrir le fichier. Dans le paramètre CreateOptions, passez l'indicateur FILE_OPEN_REQUIRING_OPLOCK. Vous pouvez définir les paramètres DesiredAccess et ShareAccess comme vous le souhaitez. Par exemple, dans le paramètre DesiredAccess, définissez GENERIC_READ pour pouvoir lire le fichier, et dans le paramètre ShareAccess, définissez les indicateurs FILE_SHARE_READ | FILE_SHARE_DELETE pour permettre à d'autres personnes de lire, de renommer et/ou de marquer le fichier pour suppression pendant que vous l'avez ouvert.
  2. Utilisez le code de contrôle FSCTL_REQUEST_OPLOCK pour demander un oplock sur l’objet ou le handle de fichier résultant, comme décrit dans Demande d’oplock en mode noyau.

N’effectuez aucune opération de système de fichiers sur le fichier entre les étapes 1 et 2. Cela peut entraîner des interblocages.

L'oplock le plus courant à requêter à l'aide de cette procédure est le type Read-Handle. Cela vous permet d'autoriser autant d'accès simultanés que possible à d'autres appelants, tout en vous permettant d'être averti si vous devez fermer votre handle pour éviter de provoquer une violation de partage à un conflit d'ouverture.

Utilisation de l'ancien oplock de filtrage

L'ancien oplock Filter permet également à une application de « se retirer » lorsque d'autres applications/clients tentent d'accéder au même flux, mais il est moins souple que la méthode atomique create-with-oplock (créer avec oplock). Ce mécanisme permet à une application d'accéder à un flux sans que les autres accédants du flux ne reçoivent de violations de partage lorsqu'ils tentent d'ouvrir le flux. Pour éviter les violations de partage, la procédure suivante en trois étapes doit être utilisée pour la requête d'un oplock de filtrage :

  1. Ouvrez le fichier avec un accès requis de FILE_READ_ATTRIBUTES et un mode de partage de FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE. Le descripteur ouvert à cette étape n'entraînera pas de violations de partage pour les autres applications, car il est ouvert uniquement pour l'accès aux attributs (FILE_READ_ATTRIBUTES) et non pour l'accès aux données (FILE_READ_DATA). Cette poignée est adaptée à la requête d'un sas de filtrage, mais pas à l'exécution d'E/S sur le flux de données.

  2. Demandez un oplock de filtrage (FSCTL_REQUEST_FILTER_OPLOCK) sur le handle de l'étape 1. L'oplock accordé à cette étape permet au détenteur de l'oplock de « s'écarter du chemin » sans causer de violation de partage à une autre application qui tente d'accéder au flux.

  3. Ouvrez à nouveau le fichier pour l'accès en lecture. Le handle ouvert à cette étape permet au détenteur de l'oplock d'effectuer des entrées/sorties sur le flux.

Le système de fichiers NTFS optimise cette procédure grâce à l'indicateur d'option de création FILE_RESERVE_OPFILTER. Si cet indicateur est spécifié à l'étape 1 de la procédure précédente, il permet au système de fichiers d'échouer la requête de création avec STATUS_OPLOCK_NOT_GRANTED si le système de fichiers peut déterminer que l'étape 2 échouera. Si l'étape 1 réussit, il n'y a aucune garantie que l'étape 2 réussira, même si FILE_RESERVE_OPFILTER a été spécifié pour la requête de création.

Conditions d'octroi des oplocks

Le tableau suivant identifie les conditions nécessaires à l'octroi d'un oplock.

Type de demande Conditions

Niveau 1

Filtrer

Batch

Accordé uniquement si toutes les conditions suivantes sont remplies :

  • La requête concerne un flux donné d'un fichier.
    • Si c'est un répertoire, STATUS_INVALID_PARAMETER est retourné.
  • Le flux est ouvert pour un accès ASYNCHRONOUS.
    • S'il est ouvert pour un accès SYNCHRONIQUE, STATUS_OPLOCK_NOT_GRANTED est renvoyé (les oplocks ne sont pas accordés pour les requêtes d'E/S synchrones).
  • Il n'y a aucune transaction TxF sur aucun flux du fichier.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas d'autres ouvertures sur le flux (même par le même threading).
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.

Si l'état actuel de l'oplock est :

  • Pas d'oplock : La requête est acceptée.

  • Niveau 2 : La requête originale de niveau 2 est interrompue avec FILE_OPLOCK_BROKEN_TO_NONE. Le verrou exclusif demandé est alors accordé.

  • Niveau 1, Batch, Filter, Read, Read-Handle, Read-Write, ou Read-Write-Handle : STATUS_OPLOCK_NOT_GRANTED est renvoyé.

Niveau 2

Accordé uniquement si toutes les conditions suivantes sont remplies :

  • La requête concerne un flux donné d'un fichier.
    • Si c'est un répertoire, STATUS_INVALID_PARAMETER est retourné.
  • Le flux est ouvert pour un accès ASYNCHRONOUS.
    • S'il est ouvert pour un accès SYNCHRONIQUE, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de transactions TxF sur le fichier.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de verrou de plage d'octets en cours sur le flux.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
    • Avant Windows 7, le système d'exploitation vérifie si un verrouillage de plage d'octets a déjà existé sur le flux depuis la dernière fois qu'il a été ouvert, et rejette la requête si c'est le cas.

Si l'état actuel de l'oplock est :

  • Pas d'oplock : La requête est acceptée.

  • Niveau 2 et/ou Lecture : la requête est accordée. Vous pouvez avoir plusieurs oplocks de niveau 2/lecture accordés sur le même flux en même temps. Plusieurs verrous de niveau 2 (mais pas de lecture) peuvent même exister sur le même handle.
    • Si un oplock de lecture est requis sur un handle auquel un oplock de lecture a déjà été accordé, l'IRP du premier oplock de lecture est complétée par STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE avant que le second oplock de lecture ne soit accordé.
  • Niveau 1, Batch, Filter, Read-Handle, Read-Write, Read-Write-Handle : STATUS_OPLOCK_NOT_GRANTED est renvoyé.

Lire

Accordé uniquement si toutes les conditions suivantes sont remplies :

  • La requête concerne un flux donné d'un fichier.
  • Le flux est ouvert pour un accès ASYNCHRONOUS.
    • S'il est ouvert pour un accès SYNCHRONIQUE, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de transactions TxF sur le fichier.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de verrou de plage d'octets en cours sur le flux.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de sections accessibles en écriture mappées par l'utilisateur sur le flux.
    • Sinon, STATUS_CANNOT_GRANT_REQUESTED_OPLOCK est renvoyé. Le champ REQUEST_OPLOCK_OUTPUT_BUFFER.Flags aura l'indicateur REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT défini.

Si l'état actuel de l'oplock est :

  • Pas d'oplock : La requête est acceptée.

  • Niveau 2 et/ou Lecture : la requête est accordée. Vous pouvez avoir plusieurs oplocks de niveau 2/lecture accordés sur le même flux en même temps.
    • En outre, si un oplock existant possède la même clé d'oplock que la nouvelle requête, son IRP est complétée par STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
  • Read-Handle et l’oplock existant ont une clé d’oplock différente de celle de la nouvelle demande : la requête est accordée. Plusieurs oplocks de lecture et de lecture-maintien peuvent coexister sur le même flux (voir la note qui suit ce tableau).
    • Dans le cas contraire (clés de bloc identiques), STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Niveau 1, Batch, Filter, Read-Write, Read-Write-Handle : STATUS_OPLOCK_NOT_GRANTED est renvoyé.

Poignée de lecture

Accordé uniquement si toutes les conditions suivantes sont remplies :

  • La requête concerne un flux donné d'un fichier.
  • Le flux est ouvert pour un accès ASYNCHRONOUS.
    • S'il est ouvert pour un accès SYNCHRONIQUE, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de transactions TxF sur le fichier.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de verrou de plage d'octets en cours sur le flux.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de sections accessibles en écriture mappées par l'utilisateur sur le flux.
    • Sinon, STATUS_CANNOT_GRANT_REQUESTED_OPLOCK est renvoyé. Le champ REQUEST_OPLOCK_OUTPUT_BUFFER.Flags aura l'indicateur REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT défini.

Si l'état actuel de l'oplock est :

  • Pas de sas : la requête est acceptée.

  • Lire : la demande est acceptée.
    • Si un oplock de lecture existant possède la même clé d'oplock que la nouvelle requête, son IRP est complétée par STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE. Le résultat est que l'oplock passe de Read à Read-Handle.
    • Tout verrou de lecture existant qui n’a pas la même clé d’oplock que la nouvelle requête reste inchangé.
  • Niveau 2, Niveau 1, Batch, Filter, Read-Write, Read-Write-Handle : STATUS_OPLOCK_NOT_GRANTED est renvoyé.

Lecture-écriture

Accordé uniquement si toutes les conditions suivantes sont remplies :

  • La requête concerne un flux donné d'un fichier.
    • Si c'est un répertoire, STATUS_INVALID_PARAMETER est retourné.
  • Le flux est ouvert pour un accès ASYNCHRONOUS.
    • S'il est ouvert pour un accès SYNCHRONIQUE, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de transactions TxF sur le fichier.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • S'il y a d'autres ouvertures sur le flux (même par le même threading), elles doivent avoir la même clé oplock.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de sections accessibles en écriture mappées par l'utilisateur sur le flux.
    • Sinon, STATUS_CANNOT_GRANT_REQUESTED_OPLOCK est renvoyé. Le champ REQUEST_OPLOCK_OUTPUT_BUFFER.Flags aura l'indicateur REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT défini.

Si l'état actuel de l'oplock est :

  • Pas de sas : la requête est acceptée.

  • Lecture ou lecture-écriture et l'oplock existant a la même clé d'oplock que la requête : l'IRP de l'oplock existant est complétée avec STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE et la requête est accordée.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Niveau 2, Niveau 1, Batch, Filter, Read-Handle, Read-Write-Handle : STATUS_OPLOCK_NOT_GRANTED est renvoyé.

Lecture-écriture

Accordée uniquement si toutes les conditions suivantes sont remplies :

  • La requête concerne un flux donné d'un fichier.
    • Si c'est un répertoire, STATUS_INVALID_PARAMETER est retourné.
  • Le flux est ouvert pour un accès ASYNCHRONOUS.
    • S'il est ouvert pour un accès SYNCHRONIQUE, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de transactions TxF sur le fichier.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • S'il existe d'autres requêtes ouvertes sur le flux, même par le même threading, elles doivent avoir la même clé oplock.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n'y a pas de sections accessibles en écriture mappées par l'utilisateur sur le flux.
    • Sinon, STATUS_CANNOT_GRANT_REQUESTED_OPLOCK est renvoyé. Le champ REQUEST_OPLOCK_OUTPUT_BUFFER.Flags aura l'indicateur REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT défini.

Si l'état actuel de l'oplock est :

  • Pas de sas : la requête est acceptée.

  • Lecture, lecture-mandat, lecture-écriture ou lecture-écriture-mandat et que l'oplock existant a la même clé d'oplock que la requête : l'IRP de l'oplock existant est complétée par STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE et la requête est acceptée.
    • Sinon, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Niveau 2, Niveau 1, Batch, Filter : STATUS_OPLOCK_NOT_GRANTED est renvoyé.

Remarque

Les oplocks de lecture et de niveau 2 peuvent coexister sur le même flux, de même que les oplocks de lecture et de gestion de lecture, mais les oplocks de niveau 2 et de gestion de lecture ne peuvent pas coexister.