Partager via


Requête et octroi d'oplocks

Lorsque le redirecteur réseau accède aux fichiers sur des serveurs distants, il demande l’oplock à partir du 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 fichiers FSCTL suivants sont utilisés pour les différents types d’oplocks , que les applications en mode utilisateur et les pilotes en mode noyau peuvent émettre.

Requête d'un Oplock en mode utilisateur

Pour demander un oplock 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 plus d’informations sur la mise en forme de la demande 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 l’oplock demandé peut être accordé, DeviceIoControl retourne FALSE et GetLastError retourne 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 retourne un code d’erreur approprié. Les codes d’erreur les plus couramment retournés sont ERROR_OPLOCK_NOT_GRANTED et ERROR_INVALID_PARAMETER.

Requête 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 retourne un code d’erreur approprié. Les codes d’erreur les plus couramment retourné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 plus d’informations sur le formatage de la requête d'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 retourne un code d’erreur approprié. Les codes d’erreur les plus couramment retourné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 Atomic Create-With-Oplock

Atomic create-with-oplock n’est pas un type oplock, il s’agit d’une procédure qui permet aux opérations ouvertes d’éviter de provoquer des violations en mode partage dans le temps entre l’ouverture d’un fichier et la réception d’un oplock. Avec les anciens oplocks, cela n'est possible qu'avec les oplocks de filtrage et nécessite l'ouverture de deux handles. Avec windows 7 oplocks, une application ou un pilote peut demander n’importe quel type d’oplock à l’aide de cette procédure et n’a besoin d’ouvrir qu’un seul handle.

Pour exécuter la procédure atomique de création avec oplock, vous devez procéder comme suit :

  1. Utilisez fltCreateFileEx2 ou ZwCreateFile, le cas échéant, 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 ci-dessus dans la section Demander un oplock en mode noyau.

Remarque

Vous ne devez effectuer 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 à demander à l’aide de cette procédure est le type Read-Handle. Cela vous permet d'accorder aux autres appelants autant d'accès simultanés que possible, tout en vous permettant d'être averti si vous devez fermer votre handle pour éviter de causer une violation de partage à un open conflictuel.

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 provoquer d’autres accesseurs du flux à recevoir des violations de partage lors de la tentative d’ouverture du 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 obligatoire de FILE_READ_ATTRIBUTES et un mode de partage de FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE. Le handle ouvert dans cette étape n’entraîne pas que d’autres applications reçoivent des violations de partage, car elles sont ouvertes 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 demande 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’existe aucune garantie que l’étape 2 réussit, même si FILE_RESERVE_OPFILTER a été spécifiée pour la demande de création.

Conditions d'octroi des oplocks

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

Type de requête Conditions

Niveau 1

Filtre

Batch

Accordé uniquement si toutes les conditions suivantes sont remplies :

  • La demande 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’existe aucune transaction TxF sur n’importe quel flux de 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 demande concerne un flux donné d’un fichier.
    • Si l'objet est un répertoire, STATUS_INVALID_PARAMETER est retourné.
  • Le flux est ouvert pour l'accès asynchrone.
    • S'il est ouvert pour un accès SYNCHRONIQUE, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n’existe aucune transaction 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 verrou de plage d’octets existait déjà sur le flux depuis la dernière ouverture et échoue la demande le cas échéant.

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

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

  • Niveau 2 et/ou lecture : la demande 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 demande 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’existe aucune transaction 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 demande 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 demande 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’existe aucune transaction 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 demande 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’existe aucune transaction 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é uniquement si toutes les valeurs suivantes sont vraies :

  • La demande 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 asynchrone.
    • S'il est ouvert pour un accès SYNCHRONIQUE, STATUS_OPLOCK_NOT_GRANTED est renvoyé.
  • Il n’existe aucune transaction 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.