Freigeben über


Oplocks anfragen und gewähren

Wenn der Netzwerkumleiter auf Dateien auf Remoteservern zugreift, fordert er das Oplock vom Remoteserver an. Client-Anwendungen fragen Oplocks nur dann direkt an, wenn die Sperre für eine Datei auf dem lokalen Server bestimmt ist.

Oplocks werden über FSCTLs angefordert. Die folgenden FSCTLs werden für die verschiedenen Oplock-Typen verwendet, die sowohl von Benutzermodus-Anwendungen als auch von Kernel-Treibern vergeben werden können.

Anfordern eines Oplocks im Benutzermodus

Um einen Windows 7-Oplock im Benutzermodus anzufordern, rufen Sie DeviceIoControl auf:

Weitere Informationen finden Sie unter FSCTL_REQUEST_OPLOCK.

Wenn der angefragte Oplock gewährt werden kann, gibt DeviceIoControl FALSE zurück und GetLastError gibt ERROR_IO_PENDING zurück. Aus diesem Grund werden Oplocks nie für synchrone E/A gewährt. Die überlappende Operation wird erst abgeschlossen, wenn der Oplock fehlerhaft ist. Nach dem Abschluss der Operation enthält der REQUEST_OPLOCK_OUTPUT_BUFFER Informationen über die Aufhebung des Oplocks.

Wenn der Oplock nicht gewährt werden kann, gibt das Dateisystem einen entsprechenden Fehlercode zurück. Die am häufigsten zurückgegebenen Fehlercodes sind ERROR_OPLOCK_NOT_GRANTED und ERROR_INVALID_PARAMETER.

Anfordern eines Oplocks im Kernelmodus

So fragen Sie Windows 7 Oplocks im Kernel-Modus an:

Dateisystem-Minifilter

Ein Dateisystem-Minifilter muss FltAllocateCallbackData verwenden und das zugewiesene FLT_CALLBACK_DATA wie folgt ausfüllen:

  • Legen Sie das Feld Iopb->MajorFunction auf IRP_MJ_FILE_SYSETM_CONTROL fest.
  • Legen Sie sein Iopb->MinorFunction-Feld auf IRP_MN_USER_FS_REQUEST fest.
  • Legen Sie sein Mitglied Iopb->Parameters.FileSystemControl.Buffered.FsControlCode auf FSCTL_REQUEST_OPLOCK fest.
  • Weisen Sie einen Puffer zu, dessen Größe dem größeren von REQUEST_OPLOCK_INPUT_BUFFER oder REQUEST_OPLOCK_OUTPUT_BUFFERentspricht.
    • Legen Sie das Mitglied > des zugewiesenen FLT_CALLBACK_DATA so fest, dass es auf diesen Puffer zeigt.
    • Legen Sie die zugewiesenen FLT_CALLBACK_DATA-Felder Iopb->Parameters.FileSystemControl.Buffered.InputBufferLength und Iopb->Parameters.FileSystemControl.Buffered.OutputBufferLength auf die Größe dieses Puffers fest.

Lesen Sie in der Dokumentation der Struktur REQUEST_OPLOCK_INPUT_BUFFER nach, wie Sie die oplock-Anfrage formatieren.

Dann muss der Dateisystem-Minifilter FltPerformAsynchronousIoaufrufen und die zugeordnete FLT_CALLBACK_DATA als CallbackData-Parameter übergeben.

Wenn der angeforderte Oplock gewährt werden kann, gibt der Aufruf FltPerformAsynchronousIo den Status STATUS_PENDING zurück. Aus diesem Grund werden Oplocks nie für synchrone E/A gewährt. Der Vorgang wird erst abgeschlossen, wenn das Oplock aufgehoben ist. Nach dem Abschluss der Operation enthält der REQUEST_OPLOCK_OUTPUT_BUFFER Informationen über die Aufhebung des Oplocks.

Wenn der Oplock nicht gewährt werden kann, gibt das Dateisystem einen entsprechenden Fehlercode zurück. Die am häufigsten zurückgegebenen Fehlercodes sind STATUS_OPLOCK_NOT_GRANTED und STATUS_INVALID_PARAMETER.

Andere Arten von Treibern

Andere Arten von Treibern können ZwFsControlFileaufrufen:

  • Legen Sie FsControlCode auf FSCTL_REQUEST_OPLOCK fest.
  • Übergeben Sie einen Zeiger auf eine REQUEST_OPLOCK_INPUT_BUFFER-Struktur im InputBuffer-Parameter, und legen Sie den InputBufferLength-Parameter auf die Größe dieses Puffers fest.
  • Übergeben Sie einen Zeiger auf eine REQUEST_OPLOCK_OUTPUT_BUFFER-Struktur im OutputBuffer-Parameter, und legen Sie den OutputBufferLength-Parameter auf die Größe dieses Puffers fest.

Lesen Sie in der Dokumentation der Struktur REQUEST_OPLOCK_INPUT_BUFFER nach, wie Sie die oplock-Anfrage formatieren.

Wenn der angeforderte Oplock gewährt werden kann, gibt der Aufruf ZwFsControlFile STATUS_PENDING zurück. Aus diesem Grund werden Oplocks nie für synchrone E/A gewährt. Der Vorgang wird erst abgeschlossen, wenn der Oplock fehlerhaft ist. Nach dem Abschluss der Operation enthält der REQUEST_OPLOCK_OUTPUT_BUFFER Informationen über die Aufhebung des Oplocks.

Wenn der Oplock nicht gewährt werden kann, gibt das Dateisystem einen entsprechenden Fehlercode zurück. Die am häufigsten zurückgegebenen Fehlercodes sind STATUS_OPLOCK_NOT_GRANTED und STATUS_INVALID_PARAMETER.

Vermeidung von Sharing-Verstößen bei der Anfrage von Oplocks

Verwenden der Atomic-Create-With-Oplock-Methode

Die atomare create-with-oplock-Prozedur ist kein Oplock-Typ. Vielmehr handelt es sich um eine Prozedur, die offenen Vorgängen die Möglichkeit bietet, Verletzungen des Freigabemodus in der Zeitspanne zwischen dem Öffnen einer Datei und dem Erhalt eines Oplocks zu vermeiden. Bei Legacy-Oplocks sind Filter-Oplocks und das Öffnen von zwei Handles erforderlich. Bei Windows 7-Oplocks kann eine Anwendung oder ein Treiber mit dieser Prozedur eine beliebige Art von Oplock anfordern und muss nur ein Handle öffnen.

Um die atomare create-with-oplock-Prozedur durchzuführen, sollten Sie:

  1. Gegebenenfalls FltCreateFileEx2 oder ZwCreateFile verwenden, um die Datei zu öffnen. Übergeben Sie im CreateOptions-Parameter das FILE_OPEN_REQUIRING_OPLOCK-Flag. Sie können die parameter DesiredAccess und ShareAccess wie gewünscht festlegen. Legen Sie z. B. im DesiredAccess-Parameter GENERIC_READ fest, damit Sie die Datei lesen können, und im ShareAccess-Parameter die FILE_SHARE_READ | FILE_SHARE_DELETE-Flags, damit andere die Datei lesen, umbenennen und/oder zum Löschen markieren können, während Sie sie geöffnet haben.
  2. Verwenden Sie den FSCTL_REQUEST_OPLOCK-Steuercode, um ein Oplock für das resultierende Dateiobjekt oder Handle anzufordern, wie in Anfordern eines Oplock im Kernelmodusbeschrieben.

Führen Sie keine Dateisystemvorgänge für die Datei zwischen schritt 1 und 2 aus. Dies kann zu Deadlocks führen.

Der am häufigsten verwendete Oplock, der mithilfe dieser Prozedur angefordert werden kann, ist der Read-Handle-Typ. Dies bietet Ihnen die Möglichkeit, anderen Aufrufern so viel parallelen Zugriff wie möglich zu gewähren, während Sie immer noch benachrichtigt werden, wenn Sie Ihr Handle schließen müssen, um eine Verletzung der gemeinsamen Nutzung durch ein konkurrierendes Öffnen zu vermeiden.

Verwendung des veralteten Filter-Oplocks

Der veraltete Filter Oplock bietet einer Anwendung ebenfalls die Möglichkeit, ein "back out" durchzuführen, wenn andere Anwendungen/Clients versuchen, auf denselben Stream zuzugreifen, ist aber weniger flexibel als die atomare Methode create-with-oplock. Dieser Mechanismus bietet einer Anwendung die Möglichkeit, auf einen Stream zuzugreifen, ohne dass andere Accessors des Streams beim Versuch, den Stream zu öffnen, eine Verletzung der Freigabe erhalten. Um Freigabeverletzungen zu vermeiden, sollten Sie die folgende dreistufige Prozedur anwenden, um einen Filter-Oplock anzufordern:

  1. Öffnen Sie die Datei mit einer erforderlichen Zugriffsfreiheit von FILE_READ_ATTRIBUTES und einem Freigabemodus von FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE. Das in diesem Schritt geöffnete Handle führt nicht dazu, dass andere Anwendungen Freigabeverletzungen erhalten, da es nur für den Attributzugriff (FILE_READ_ATTRIBUTES) und nicht für den Datenzugriff (FILE_READ_DATA) geöffnet ist. Dieses Handle eignet sich für die Anfrage des Filter-Oplocks, aber nicht für die Durchführung der eigentlichen E/A auf dem Datenstrom.

  2. Fordern Sie ein Filter-Oplock (FSCTL_REQUEST_FILTER_OPLOCK) für das Handle aus Schritt 1 an. Der in diesem Schritt gewährte Oplock bietet dem Oplock-Inhaber die Möglichkeit, "aus dem Weg zu gehen", ohne eine Freigabeverletzung für eine andere Anwendung zu verursachen, die versucht, auf den Datenstrom zuzugreifen.

  3. Öffnen Sie die Datei erneut für den Lesezugriff. Das in diesem Schritt geöffnete Handle bietet dem Oplock-Inhaber die Möglichkeit, E/A auf dem Stream durchzuführen.

Das NTFS-Dateisystem bietet mit dem Flag für die Erstellungsoption FILE_RESERVE_OPFILTER eine Optimierung für diesen Vorgang. Wenn dieses Flag in Schritt 1 der vorherigen Prozedur angegeben ist, ermöglicht es dem Dateisystem, die Erstellungsanforderung mit dem Status STATUS_OPLOCK_NOT_GRANTED abzulehnen, falls das Dateisystem feststellen kann, dass Schritt 2 fehlschlägt. Wenn Schritt 1 erfolgreich ist, besteht keine Garantie dafür, dass Schritt 2 erfolgreich ist, auch wenn FILE_RESERVE_OPFILTER für die Erstellungsanforderung angegeben wurde.

Bedingungen für die Gewährung von Oplocks

In der folgenden Tabelle sind die Bedingungen aufgeführt, die für die Gewährung eines Oplocks erforderlich sind.

Anforderungstyp Bedingungen

Stufe 1

Filter

Batch

Wird nur gewährt, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderung gilt für einen bestimmten Datenstrom einer Datei.
    • Wenn es sich um ein Verzeichnis handelt, wird STATUS_INVALID_PARAMETER zurückgegeben.
  • Der Stream wird für den asynchronen Zugriff geöffnet.
    • Wenn für den SYNCHRONOUS-Zugriff geöffnet wurde, wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben (Oplocks werden für synchrone E/A-Anfragen nicht gewährt).
  • Es werden keine TxF-Transaktionen für einen Datenstrom der Datei ausgeführt.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es gibt keine anderen Öffnungen auf dem Stream (auch nicht von demselben Thread).
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.

Wenn der aktuelle Status des Oplocks ist:

  • Kein Oplock: Die Anfrage wird gewährt.

  • Level 2: Die ursprüngliche Level 2-Anfrage wird mit FILE_OPLOCK_BROKEN_TO_NONE fehlerhaft abgebrochen. Der angefragte exklusive Oplock wird dann gewährt.

  • Level 1, Batch, Filter, Read, Read-Handle, Read-Write oder Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED wird zurückgegeben.

Stufe 2

Wird nur gewährt, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderung gilt für einen bestimmten Datenstrom einer Datei.
    • Wenn es sich um ein Verzeichnis handelt, wird STATUS_INVALID_PARAMETER zurückgegeben.
  • Der Stream wird für den asynchronen Zugriff geöffnet.
    • Wenn für SYNCHRONOUS-Zugriff geöffnet, wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es werden keine TxF-Transaktionen für die Datei ausgeführt.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Aktuell sind keine Bytebereichssperren für den Datenstrom vorhanden.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
    • Vor Windows 7 überprüfte das Betriebssystem, ob eine Bytebereichssperre auf dem Datenstrom seit dem letzten Öffnen bestanden hatte, und lehnte den Antrag ab, falls dies der Fall war.

Wenn der aktuelle Status des Oplocks ist:

  • Kein Oplock: Die Anfrage wird gewährt.

  • Level 2- und/oder Lesezugriff: Die Anforderung wird gewährt. Sie können gleichzeitig mehrere Level 2/Read-Oplocks für denselben Stream gewähren lassen. Mehrere Level 2 (aber nicht Read) Oplocks können sogar auf demselben Handle existieren.
    • Wenn ein Read-Oplock für ein Handle angefordert wird, für das bereits ein Read-Oplock gewährt wurde, wird der IRP des ersten Read-Oplocks mit STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE abgeschlossen, bevor der zweite Read-Oplock gewährt wird.
  • Level 1, Batch, Filter, Read-Handle, Read-Write, Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED wird zurückgegeben.

Lesen

Wird nur gewährt, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderung gilt für einen bestimmten Datenstrom einer Datei.
  • Der Stream wird für den asynchronen Zugriff geöffnet.
    • Wenn für SYNCHRONOUS-Zugriff geöffnet, wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es werden keine TxF-Transaktionen für die Datei ausgeführt.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Aktuell sind keine Bytebereichssperren für den Datenstrom vorhanden.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es gibt keine beschreibbaren Benutzer-gemappten Abschnitte auf dem Stream.
    • Andernfalls wird STATUS_CANNOT_GRANT_REQUESTED_OPLOCK zurückgegeben. Im Feld REQUEST_OPLOCK_OUTPUT_BUFFER.Flags wird das Flag REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT festgelegt.

Wenn der aktuelle Status des Oplocks ist:

  • Kein Oplock: Die Anfrage wird gewährt.

  • Level 2- und/oder Lesezugriff: Die Anforderung wird gewährt. Sie können gleichzeitig mehrere Level 2/Read-Oplocks für denselben Stream gewähren lassen.
    • Wenn ein vorhandenes Oplock den gleichen Oplock-Schlüssel wie die neue Anfrage hat, wird sein IRP mit STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE abgeschlossen.
  • Read-Handle und das vorhandene Oplock haben einen anderen Oplock-Schlüssel als die neue Anfrage: Der Anfrage wird stattgegeben. Mehrere Read-Oplocks und Read-Handle-Oplocks können auf demselben Stream koexistieren (siehe den Hinweis nach dieser Tabelle).
    • Andernfalls (Oplock-Schlüssel sind identisch) wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Level 1, Batch, Filter, Read-Write, Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED wird zurückgegeben.

Read-Handle

Wird nur gewährt, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderung gilt für einen bestimmten Datenstrom einer Datei.
  • Der Stream wird für den asynchronen Zugriff geöffnet.
    • Wenn für SYNCHRONOUS-Zugriff geöffnet, wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es werden keine TxF-Transaktionen für die Datei ausgeführt.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Aktuell sind keine Bytebereichssperren für den Datenstrom vorhanden.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es gibt keine beschreibbaren Benutzer-gemappten Abschnitte auf dem Stream.
    • Andernfalls wird STATUS_CANNOT_GRANT_REQUESTED_OPLOCK zurückgegeben. Im Feld REQUEST_OPLOCK_OUTPUT_BUFFER.Flags wird das Flag REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT festgelegt.

Wenn der aktuelle Status des Oplocks ist:

  • Kein Oplock: Die Anfrage wird gewährt.

  • Lesen: der Anfrage wird stattgegeben.
    • Wenn ein bestehendes Read-Oplock denselben Oplock-Schlüssel hat wie die neue Anfrage, wird dessen IRP mit STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE abgeschlossen. Ergebnis: Der Oplock wird von „Read“ auf „Read-Handle“ aktualisiert.
    • Alle vorhandenen Read-Oplocks, die nicht über denselben Oplock-Schlüssel wie die neue Anforderung verfügen, bleiben unverändert.
  • Level 2, Level 1, Batch, Filter, Read-Write, Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED wird zurückgegeben.

Lesen/Schreiben

Wird nur gewährt, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderung gilt für einen bestimmten Datenstrom einer Datei.
    • Wenn es sich um ein Verzeichnis handelt, wird STATUS_INVALID_PARAMETER zurückgegeben.
  • Der Stream wird für den asynchronen Zugriff geöffnet.
    • Wenn für SYNCHRONOUS-Zugriff geöffnet, wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es werden keine TxF-Transaktionen für die Datei ausgeführt.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Wenn es andere Öffnungen auf dem Stream gibt (sogar durch denselben Thread), müssen diese denselben Oplock-Schlüssel haben.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es gibt keine beschreibbaren Benutzer-gemappten Abschnitte auf dem Stream.
    • Andernfalls wird STATUS_CANNOT_GRANT_REQUESTED_OPLOCK zurückgegeben. Im Feld REQUEST_OPLOCK_OUTPUT_BUFFER.Flags wird das Flag REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT festgelegt.

Wenn der aktuelle Status des Oplocks ist:

  • Kein Oplock: Die Anfrage wird gewährt.

  • Read oder Read-Write und der vorhandene Oplock hat den gleichen Oplock-Schlüssel wie die Anfrage: Der IRP des vorhandenen Oplocks wird mit STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE abgeschlossen und die Anfrage wird gewährt.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Level 2, Level 1, Batch, Filter, Read-Handle, Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED wird zurückgegeben.

Read-Write-Handle

Wird nur gewährt, wenn alle folgenden Bedingungen erfüllt sind:

  • Die Anforderung gilt für einen bestimmten Datenstrom einer Datei.
    • Wenn es sich um ein Verzeichnis handelt, wird STATUS_INVALID_PARAMETER zurückgegeben.
  • Der Stream wird für den asynchronen Zugriff geöffnet.
    • Wenn für SYNCHRONOUS-Zugriff geöffnet, wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es werden keine TxF-Transaktionen für die Datei ausgeführt.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Wenn es andere offene Anfragen an den Stream gibt, auch von demselben Thread, müssen diese denselben Oplock-Schlüssel haben.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Es gibt keine beschreibbaren Benutzer-gemappten Abschnitte auf dem Stream.
    • Andernfalls wird STATUS_CANNOT_GRANT_REQUESTED_OPLOCK zurückgegeben. Im Feld REQUEST_OPLOCK_OUTPUT_BUFFER.Flags wird das Flag REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT festgelegt.

Wenn der aktuelle Status des Oplocks ist:

  • Kein Oplock: Die Anfrage wird gewährt.

  • Read, Read-Handle, Read-Write oder Read-Write-Handle und der vorhandene Oplock hat denselben Oplock-Schlüssel wie die Anfrage: Der IRP des vorhandenen Oplocks wird mit STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE abgeschlossen und die Anfrage wird bewilligt.
    • Andernfalls wird STATUS_OPLOCK_NOT_GRANTED zurückgegeben.
  • Ebene 2, Ebene 1, Batch, Filter: STATUS_OPLOCK_NOT_GRANTED wird zurückgegeben.

Hinweis

Read-Oplocks und Level 2-Oplocks können im selben Datenstrom koexistieren. Read-Oplocks und Read-Handle-Oplocks können koexistieren, aber Level 2-Oplocks und Read-Handle-Oplocks können nicht koexistieren.