Breaking Oplocks
Nachdem ein Oplockangefordert und gewährt wurde, hat der Besitzer dieses Oplocks Basierend auf dem angeforderten Oplocktyp Zugriff auf den Stream. Wenn der empfangene Vorgang nicht mit dem aktuellen Oplock kompatibel ist, unterbricht das System den Oplock.
Wenn ein Oplock gewährt wird, schreibt das System den anfordernden IRP. Wenn ein Oplock unterbrochen wird, wird die Anforderungs-IRP des pended oplock mit STATUS_SUCCESS abgeschlossen. Für Oplocks der Ebene 1, Batch und Filter wird der IoStatus.Information-Member des IRP festgelegt, um die Ebene anzugeben, auf der der Oplock unterbrochen wird. Diese Ebenen sind:
FILE_OPLOCK_BROKEN_TO_NONE: Der Oplock wurde unterbrochen, und es gibt keinen aktuellen Oplock im Stream. Der Oplock soll "zu Keine" gebrochen worden sein.
FILE_OPLOCK_BROKEN_TO_LEVEL_2: Der aktuelle Oplock (Level 1 oder Batch) wurde in einen Level 2-Oplock konvertiert. Filter-Oplocks brechen nie auf Ebene 2, sie brechen immer auf Keine.
Für Oplocks mit Lese-, Lese-, Schreib- und Lese-Schreib-Handle wird die Ebene, auf die der Oplock bricht, als Kombination aus null oder mehr der Flags OPLOCK_LEVEL_CACHE_READ, OPLOCK_LEVEL_CACHE_HANDLE oder OPLOCK_LEVEL_CACHE_WRITE im NewOplockLevel-Element der REQUEST_OPLOCK_OUTPUT_BUFFER-Struktur beschrieben, die als lpOutBuffer-Parameter von DeviceIoControl übergeben wird. Auf ähnliche Weise können FltFsControlFile und ZwFsControlFile verwendet werden, um Windows 7-Oplocks aus dem Kernelmodus anzufordern. Weitere Informationen finden Sie unter FSCTL_REQUEST_OPLOCK.
Wenn das Oplock-Paket des Systems eine Ebene 1 unterbricht, Batch, Filter, Read-Write, Read-Write-Handle oder unter bestimmten Umständen ein Read-Handle oplock:
- Das oplock-Paket schließt die IRP der pended oplock request ab.
- Der Vorgang, der den Oplock-Umbruch verursacht hat, wird selbst mit dem Stift versehen.
Wenn der Vorgang für ein synchrones Handle ausgegeben wird oder es sich um eine IRP_MJ_CREATE handelt, die immer synchron ist, bewirkt der E/A-Manager, dass der Vorgang blockiert wird, anstatt STATUS_PENDING zurückzugeben, und wartet auf eine Bestätigung des Besitzers des Oplocks, um dem oplock-Paket mitzuteilen, dass die Verarbeitung abgeschlossen ist und dass der Stiftvorgang sicher fortgesetzt werden kann. Der Zweck dieser Verzögerung besteht darin, dem Besitzer des Oplocks zu ermöglichen, den Stream wieder in einen konsistenten Zustand zu versetzen, bevor der aktuelle Vorgang fortgesetzt wird. Das System wartet ewig, bis die Bestätigung empfangen wird, da kein Timeout auftritt. Es obliegt daher dem Eigentümer des Oplocks, den Bruch rechtzeitig zu bestätigen. Der IRP des stifteten Vorgangs wird in einen abbruchfähigen Zustand festgelegt. Wenn die Anwendung oder der Treiber, der die Wartezeit ausführt, beendet, schließt das oplock-Paket sofort das IRP mit STATUS_CANCELLED ab.
Ein IRP_MJ_CREATE IRP kann die Option FILE_COMPLETE_IF_OPLOCKED Erstellen angeben, um zu vermeiden, dass im Rahmen der Oplock-Unterbrechungsbestätigung blockiert wird. Diese Option weist das oplock-Paket an, das Create-IRP erst zu blockieren, wenn die Oplock-Unterbrechungsbestätigung empfangen wird. Stattdessen darf die Erstellung fortgesetzt werden. Wenn eine erfolgreiche Erstellung zu einem Oplock-Umbruch führt, wird der Rückgabecode nicht STATUS_SUCCESS, sondern STATUS_OPLOCK_BREAK_IN_PROGRESS. Das flag FILE_COMPLETE_IF_OPLOCKED wird in der Regel verwendet, um Deadlocks zu vermeiden. Wenn beispielsweise ein Client einen Oplock für einen Stream besitzt und derselbe Client später denselben Stream öffnet, blockiert der Client das Warten auf sich selbst, um den Oplock-Umbruch zu bestätigen. In diesem Szenario vermeidet die Verwendung des flags FILE_COMPLETE_IF_OPLOCKED den Deadlock.
Da das NTFS-Dateisystem oplock-Unterbrechungen für Batch- und Filter-Oplocks initiiert, bevor auf Freigabeverletzungen überprüft wird, ist es möglich, dass eine Erstellung, die FILE_COMPLETE_IF_OPLOCKED angegeben hat, mit STATUS_SHARING_VIOLATION fehlschlägt, aber dennoch einen Batch- oder Filter-Oplock verursacht. In diesem Fall wird der Informationsmember der IO_STATUS_BLOCK-Struktur auf FILE_OPBATCH_BREAK_UNDERWAY festgelegt, damit der Aufrufer diesen Fall erkennen kann.
Für Read-Handle- und Read-Write-Handle-Oplocks wird der Oplock-Umbruch initiiert, nachdem NTFS einen Freigabeverstoß überprüft und erkannt hat. Dies gibt Inhabern dieser Oplocks die Möglichkeit, ihre Handgriffe zu schließen und aus dem Weg zu gehen, sodass die Möglichkeit besteht, den Verstoß gegen die Freigabe nicht an den Benutzer zurückzugeben. Außerdem wird vermieden, dass der Oplock bedingungslos abgebrochen wird, wenn das Handle, das der Oplock zwischenspeichert, nicht mit der neuen Erstellung in Konflikt steht.
Wenn Stufe 2, Lesen und unter bestimmten Umständen Read-Handle Oplocks unterbrochen werden, wartet das System nicht auf eine Bestätigung. Dies liegt daran, dass es keinen zwischengespeicherten Zustand für den Stream geben sollte, der in der Datei wiederhergestellt werden muss, bevor anderen Clients der Zugriff darauf gewährt wird.
Es gibt bestimmte Dateisystemvorgänge, die den aktuellen Oplock-Zustand überprüfen, um festzustellen, ob der Oplock unterbrochen werden muss. In den folgenden Artikeln werden die einzelnen Vorgänge aufgelistet und beschrieben, was einen Oplock-Umbruch auslöst, was die Ebene bestimmt, auf der der Oplock unterbrochen wird, und ob eine Bestätigung der Unterbrechung erforderlich ist:
Ein Umbruch eines Windows 7-Oplocks erfordert eine Bestätigung, wenn das REQUEST_OPLOCK_OUTPUT_FLAG_ACK_REQUIRED-Flag im Flags-Element der REQUEST_OPLOCK_OUTPUT_BUFFER-Struktur festgelegt ist, die als Ausgabeparameter von DeviceIoControl(lpOutBuffer), FltFsControlFile(OutBuffer) oder ZwFsControlFile(OutBuffer) übergeben wird. Weitere Informationen finden Sie unter FSCTL_REQUEST_OPLOCK.
In den aufgeführten Artikeln pro Vorgang werden die Details dazu beschrieben, wann ein Unterbrechung eines Read-Handle Oplocks dazu führt, dass der Vorgang aussteht, der den Oplock unterbrochen hat. Der artikel IRP_MJ_CREATE enthält beispielsweise die zugehörigen Read-Handle Details.