2.1.5.18.1 Algorithm to Request an Exclusive Oplock
The inputs for requesting an exclusive oplock are:
Open: The Open on which the oplock is being requested.
RequestedOplock: The oplock type being requested.
On completion, the object store MUST return:
Status: An NTSTATUS code that specifies the result.
NewOplockLevel: The type of oplock that the requested oplock has been broken to. If a failure status is returned in Status, the value of this field is undefined. Valid values are as follows:
LEVEL_NONE (that is, no oplock)
LEVEL_TWO
A combination of one or more of the following flags:
READ_CACHING
HANDLE_CACHING
WRITE_CACHING
AcknowledgeRequired: A Boolean value: TRUE if the server MUST acknowledge the oplock break; FALSE if not, as specified in section 2.1.5.19. If a failure status is returned in Status, the value of this field is undefined.
The exclusive oplock request algorithm uses the following local variables:
Boolean value (initialized to FALSE): GrantExclusiveOplock
Pseudocode for the algorithm is as follows:
If Open.Stream.Oplock is empty:
Build a new Oplock object with fields initialized as follows:
Oplock.State set to NO_OPLOCK.
All other fields set to 0/empty.
Store the new Oplock object in Open.Stream.Oplock.
EndIf
If Open.Stream.Oplock.State contains LEVEL_TWO_OPLOCK or NO_OPLOCK:
If Open.Stream.Oplock.State contains LEVEL_TWO_OPLOCK and RequestedOplock contains one or more of READ_CACHING, HANDLE_CACHING, or WRITE_CACHING, the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
If Open.Stream.Oplock.State is equal to LEVEL_TWO_OPLOCK:
Remove the first Open ThisOpen from Open.Stream.Oplock.IIOplocks (there is supposed to be exactly one present), and notify the server of an oplock break according to the algorithm in section 2.1.5.18.3, setting the algorithm's parameters as follows:
BreakingOplockOpen equal to ThisOpen.
NewOplockLevel equal to LEVEL_NONE.
AcknowledgeRequired equal to FALSE.
OplockCompletionStatus equal to STATUS_SUCCESS.
(The operation does not end at this point; this call to 2.1.5.18.3 completes some earlier call to 2.1.5.18.2.)
EndIf
If Open.File.OpenList contains more than one Open whose Stream is the same as Open.Stream, and NO_OPLOCK is present in Open.Stream.Oplock.State:
The operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
EndIf
If Open.Stream.IsDeleted is TRUE and RequestedOplock contains HANDLE_CACHING:
The operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
EndIf
Set GrantExclusiveOplock to TRUE.
Else If (Open.Stream.Oplock.State contains one or more of READ_CACHING, WRITE_CACHING, or HANDLE_CACHING) and (Open.Stream.Oplock.State contains none of BREAK_TO_TWO, BREAK_TO_NONE, BREAK_TO_TWO_TO_NONE, BREAK_TO_READ_CACHING, BREAK_TO_WRITE_CACHING, BREAK_TO_HANDLE_CACHING, or BREAK_TO_NO_CACHING) and (Open.Stream.Oplock.RHBreakQueue is empty):
// This is a granular oplock and it is not breaking.
If RequestedOplock contains none of READ_CACHING, WRITE_CACHING, or HANDLE_CACHING, the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
If Open.Stream.IsDeleted is TRUE and RequestedOplock contains HANDLE_CACHING, the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
Switch (Open.Stream.Oplock.State):
Case READ_CACHING:
If RequestedOplock is neither (READ_CACHING|WRITE_CACHING) nor (READ_CACHING|WRITE_CACHING|HANDLE_CACHING), the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
For each Open ThisOpen in Open.Stream.Oplock.ROplocks:
If ThisOpen.TargetOplockKey != Open.TargetOplockKey, the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
EndFor
For each Open ThisOpen in Open.Stream.Oplock.ROplocks:
Remove ThisOpen from Open.Stream.Oplock.ROplocks.
Notify the server of an oplock break according to the algorithm in section 2.1.5.18.3, setting the algorithm's parameters as follows:
BreakingOplockOpen equal to ThisOpen.
NewOplockLevel equal to RequestedOplock.
AcknowledgeRequired equal to FALSE.
OplockCompletionStatus equal to STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
(The operation does not end at this point; this call to 2.1.5.18.3 completes some earlier call to 2.1.5.18.2.)
EndFor
Set GrantExclusiveOplock to TRUE.
EndCase
Case (READ_CACHING|HANDLE_CACHING):
If RequestedOplock is not (READ_CACHING|WRITE_CACHING|HANDLE_CACHING) or Open.Stream.Oplock.RHBreakQueue is not empty, the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
For each Open ThisOpen in Open.Stream.Oplock.RHOplocks:
If ThisOpen.TargetOplockKey != Open.TargetOplockKey, the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
EndFor
For each Open ThisOpen in Open.Stream.Oplock.RHOplocks:
Remove ThisOpen from Open.Stream.Oplock.RHOplocks.
Notify the server of an oplock break according to the algorithm in section 2.1.5.18.3, setting the algorithm's parameters as follows:
BreakingOplockOpen equal to ThisOpen.
NewOplockLevel equal to RequestedOplock.
AcknowledgeRequired equal to FALSE.
OplockCompletionStatus equal to STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
(The operation does not end at this point; this call to 2.1.5.18.3 completes some earlier call to 2.1.5.18.2.)
EndFor
Set GrantExclusiveOplock to TRUE.
EndCase
Case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE):
If RequestedOplock is not (READ_CACHING|WRITE_CACHING|HANDLE_CACHING), the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
// Deliberate FALL-THROUGH to next Case statement.
Case (READ_CACHING|WRITE_CACHING|EXCLUSIVE):
If RequestedOplock is neither (READ_CACHING|WRITE_CACHING|HANDLE_CACHING) nor (READ_CACHING|WRITE_CACHING), the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
If Open.TargetOplockKey != Open.Stream.Oplock.ExclusiveOpen.TargetOplockKey, the operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
Notify the server of an oplock break according to the algorithm in section 2.1.5.18.3, setting the algorithm's parameters as follows:
BreakingOplockOpen equal to Open.Stream.Oplock.ExclusiveOpen.
NewOplockLevel equal to RequestedOplock.
AcknowledgeRequired equal to FALSE.
OplockCompletionStatus equal to STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
(The operation does not end at this point; this call to 2.1.5.18.3 completes some earlier call to 2.1.5.18.1.)
Set Open.Stream.Oplock.ExclusiveOpen to NULL.
Set GrantExclusiveOplock to TRUE.
EndCase
DefaultCase:
The operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
EndSwitch
Else
The operation MUST be failed with Status set to STATUS_OPLOCK_NOT_GRANTED.
EndIf
If GrantExclusiveOplock is TRUE:
Set Open.Stream.Oplock.ExclusiveOpen equal to Open.
Set Open.Stream.Oplock.State equal to (RequestedOplock|EXCLUSIVE).
This operation MUST be made cancelable by inserting it into CancelableOperations.CancelableOperationList.
This operation waits until the oplock is broken or canceled, as specified in section 2.1.5.18.3. When the operation specified in section 2.1.5.18.3 is called, its following input parameters are transferred to this routine and then returned by it:
Status is set to OplockCompletionStatus from the operation specified in section 2.1.5.18.3.
NewOplockLevel is set to NewOplockLevel from the operation specified in section 2.1.5.18.3.
AcknowledgeRequired is set to AcknowledgeRequired from the operation specified in section 2.1.5.18.3.
EndIf