2.1.5.19 Server Acknowledges an Oplock Break

msdn link

The server provides:

  • Open - The Open associated with the oplock that has broken.

  • Type - As part of the acknowledgement, the server indicates a new oplock it would like in place of the one that has broken. Valid values are as follows:

    • LEVEL_NONE

    • LEVEL_TWO

    • LEVEL_GRANULAR - If this oplock type is specified, the server additionally provides:

      • RequestedOplockLevel - A combination of zero or more of the following flags:

        • READ_CACHING

        • HANDLE_CACHING

        • WRITE_CACHING

If the server requests a new oplock and it is granted, the request does not complete until the oplock is broken; the operation waits for this to happen. Processing of an oplock break is described in section 2.1.5.18.3. Whether the new oplock is granted or not, the object store MUST return:

  • Status - An NTSTATUS code indicating the result of the operation.

If the server requests a new oplock and it is granted, then when the oplock breaks and the request finally completes, the object store MUST additionally return:

  • NewOplockLevel: The type of oplock the requested oplock has been broken to. 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.18.2.

This routine uses the following local variables:

  • Boolean values (initialized to FALSE): NewOplockGranted, ReturnBreakToNone, FoundMatchingRHOplock

Pseudocode for the operation is as follows:

  • If Open.Stream.Oplock is empty, the operation MUST be failed with Status set to STATUS_INVALID_OPLOCK_PROTOCOL.

  • If Type is LEVEL_NONE or LEVEL_TWO:

    • If Open.Stream.Oplock.ExclusiveOpen is not equal to Open, the operation MUST be failed with Status set to STATUS_INVALID_OPLOCK_PROTOCOL.

    • If Type is LEVEL_TWO and Open.Stream.Oplock.State contains BREAK_TO_TWO:

      • Set Open.Stream.Oplock.State to LEVEL_TWO_OPLOCK.

      • Set NewOplockGranted to TRUE.

    • Else If Open.Stream.Oplock.State contains BREAK_TO_TWO or BREAK_TO_NONE:

      • Set Open.Stream.Oplock.State to NO_OPLOCK.

    • Else If Open.Stream.Oplock.State contains BREAK_TO_TWO_TO_NONE:

      • Set Open.Stream.Oplock.State to NO_OPLOCK.

      • Set ReturnBreakToNone to TRUE.

    • Else

      • The operation MUST be failed with Status set to STATUS_INVALID_OPLOCK_PROTOCOL.

    • EndIf

    • For each Open WaitingOpen on Open.Stream.Oplock.WaitList:

      • Indicate that the operation associated with WaitingOpen can continue according to the algorithm in section 2.1.4.12.1, setting OpenToRelease equal to WaitingOpen.

      • Remove WaitingOpen from Open.Stream.Oplock.WaitList.

    • EndFor

    • Set Open.Stream.Oplock.ExclusiveOpen to NULL.

    • If NewOplockGranted is TRUE:

      • The operation waits until the newly-granted Level 2 oplock is broken, as specified in section 2.1.5.18.3.

    • Else If ReturnBreakToNone is TRUE:

      • In this case the server was expecting the oplock to break to Level 2, but because the oplock is actually breaking to None (that is, no oplock), the object store MUST indicate an oplock break to the server according to the algorithm in section 2.1.5.18.3, setting the algorithm's parameters as follows:

        • BreakingOplockOpen equal to Open.

        • NewOplockLevel equal to LEVEL_NONE.

        • AcknowledgeRequired equal to FALSE.

        • OplockCompletionStatus equal to STATUS_SUCCESS.

      • (Because BreakingOplockOpen is equal to the passed-in Open, the operation ends at this point.)

    • Else

      • The operation MUST return Status set to STATUS_SUCCESS at this point.

    • EndIf

  • Else If Type is LEVEL_GRANULAR:

    • Let BREAK_LEVEL_MASK = (BREAK_TO_READ_CACHING | BREAK_TO_WRITE_CACHING | BREAK_TO_HANDLE_CACHING | BREAK_TO_NO_CACHING)

    • Let R_AND_RH_GRANTED = (READ_CACHING|HANDLE_CACHING|MIXED_R_AND_RH)

    • Let RH_GRANTED = (READ_CACHING|HANDLE_CACHING)

    • //  If there are no BREAK_LEVEL_MASK flags set, this is invalid, unless the

    • //  state is R_AND_RH_GRANTED or RH_GRANTED, in which case we'll need to see if

    • //  the RHBreakQueue is empty.

    • If (Open.Stream.Oplock.State does not contain any flag in BREAK_LEVEL_MASK and

      (Open.Stream.Oplock.State != R_AND_RH_GRANTED) and

      (Open.Stream.Oplock.State != RH_GRANTED)) or

      (((Open.Stream.Oplock.State == R_AND_RH_GRANTED) or

      (Open.Stream.Oplock.State == RH_GRANTED)) and

 Open.Stream.Oplock.RHBreakQueue is empty):

  • The request MUST be failed with Status set to STATUS_INVALID_OPLOCK_PROTOCOL.

  • EndIf

  • Switch Open.Stream.Oplock.State

    • Case (READ_CACHING|HANDLE_CACHING|MIXED_R_AND_RH):

    • Case (READ_CACHING|HANDLE_CACHING):

    • Case (READ_CACHING|HANDLE_CACHING|BREAK_TO_READ_CACHING):

    • Case (READ_CACHING|HANDLE_CACHING|BREAK_TO_NO_CACHING):

      • For each RHOpContext ThisContext in Open.Stream.Oplock.RHBreakQueue:

        • If ThisContext.Open equals Open:

          • Set FoundMatchingRHOplock to TRUE.

          • If ThisContext.BreakingToRead is FALSE:

            • If RequestedOplockLevel is not 0 and Open.Stream.Oplock.WaitList is not empty:

              • The object store MUST indicate an oplock break to the server according to the algorithm in section 2.1.5.18.3, setting the algorithm's parameters as follows:

                • BreakingOplockOpen equal to Open.

                • NewOplockLevel equal to LEVEL_NONE.

                • AcknowledgeRequired equal to TRUE.

                • OplockCompletionStatus equal to STATUS_CANNOT_GRANT_REQUESTED_OPLOCK.

              • (Because BreakingOplockOpen is equal to the passed-in Open, the operation ends at this point.)

            • EndIf

          • Else // ThisContext.BreakingToRead is TRUE.

            • If Open.Stream.Oplock.WaitList is not empty and (RequestedOplockLevel is (READ_CACHING|WRITE_CACHING) or (READ_CACHING|WRITE_CACHING|HANDLE_CACHING)):

              • The object store MUST indicate an oplock break to the server according to the algorithm in section 2.1.5.18.3, setting the algorithm's parameters as follows:

                • BreakingOplockOpen equal to Open.

                • NewOplockLevel equal to READ_CACHING.

                • AcknowledgeRequired equal to TRUE.

                • OplockCompletionStatus equal to STATUS_CANNOT_GRANT_REQUESTED_OPLOCK.

              • (Because BreakingOplockOpen is equal to the passed-in Open, the operation ends at this point.)

            • EndIf

          • EndIf

          • Remove ThisContext from Open.Stream.Oplock.RHBreakQueue.

          • For each Open WaitingOpen on Open.Stream.Oplock.WaitList:

            • // The operation waiting for the Read-Handle oplock to break can continue if

            • // there are no more Read-Handle oplocks outstanding, or if all the remaining

            • // Read-Handle oplocks have the same oplock key as the waiting operation.

            • If (Open.Stream.Oplock.RHBreakQueue is empty) or (all RHOpContext.Open.TargetOplockKey values on Open.Stream.Oplock.RHBreakQueue are equal to WaitingOpen.TargetOplockKey):

              • Indicate that the operation associated with WaitingOpen can continue according to the algorithm in section 2.1.4.12.1, setting OpenToRelease equal to WaitingOpen.

              • Remove WaitingOpen from Open.Stream.Oplock.WaitList.

            • EndIf

          • EndFor

          • If RequestedOplockLevel is 0 (that is, no flags):

            • Recompute Open.Stream.Oplock.State according to the algorithm in section 2.1.4.13, passing Open.Stream.Oplock as the ThisOplock parameter.

            • The algorithm MUST return Status set to STATUS_SUCCESS at this point.

          • Else If RequestedOplockLevel does not contain WRITE_CACHING:

            • The object store MUST request a shared oplock according to the algorithm in section 2.1.5.18.2, setting the algorithm's parameters as follows:

              • Pass in the current Open.

              • RequestedOplock equal to RequestedOplockLevel.

              • GrantingInAck equal to TRUE.

            • The operation MUST at this point return any status code returned by the shared oplock request algorithm.

          • Else

            • Set Open.Stream.Oplock.ExclusiveOpen to ThisContext.Open.

            • Set Open.Stream.Oplock.State to (RequestedOplockLevel|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.

          • EndIf

          • Break out of the For loop.

        • EndIf

      • EndFor

      • If FoundMatchingRHOplock is FALSE:

        • The operation MUST be failed with Status set to STATUS_INVALID_OPLOCK_PROTOCOL.

      • EndIf

      • The operation returns Status set to STATUS_SUCCESS at this point.

    • EndCase

    • Case (READ_CACHING|WRITE_CACHING|EXCLUSIVE|BREAK_TO_READ_CACHING):

    • Case (READ_CACHING|WRITE_CACHING|EXCLUSIVE|BREAK_TO_NO_CACHING):

    • Case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|BREAK_TO_READ_CACHING|BREAK_TO_WRITE_CACHING):

    • Case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|BREAK_TO_READ_CACHING|BREAK_TO_HANDLE_CACHING):

    • Case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|BREAK_TO_READ_CACHING):

    • Case (READ_CACHING|WRITE_CACHING|HANDLE_CACHING|EXCLUSIVE|BREAK_TO_NO_CACHING):

      • If Open.Stream.Oplock.ExclusiveOpen != Open:

        • The operation MUST be failed with Status set to STATUS_INVALID_OPLOCK_PROTOCOL.

      • EndIf

      • If Open.Stream.Oplock.WaitList is not empty and Open.Stream.Oplock.State does not contain HANDLE_CACHING and RequestedOplockLevel is (READ_CACHING|WRITE_CACHING|HANDLE_CACHING):

        • The object store MUST indicate an oplock break to the server according to the algorithm in section 2.1.5.18.3, setting the algorithm's parameters as follows:

          • BreakingOplockOpen equal to Open.

          • NewOplockLevel equal to:

            • (READ_CACHING|WRITE_CACHING) if Open.Stream.Oplock.State contains each of BREAK_TO_READ_CACHING and BREAK_TO_WRITE_CACHING and not BREAK_TO_HANDLE_CACHING.

            • (READ_CACHING|HANDLE_CACHING) if Open.Stream.Oplock.State contains each of BREAK_TO_READ_CACHING and BREAK_TO_HANDLE_CACHING and not BREAK_TO_WRITE_CACHING.

            • READ_CACHING if Open.Stream.Oplock.State contains BREAK_TO_READ_CACHING and neither BREAK_TO_WRITE_CACHING nor BREAK_TO_HANDLE_CACHING.

            • LEVEL_NONE if Open.Stream.Oplock.State contains BREAK_TO_NO_CACHING.

          • AcknowledgeRequired equal to TRUE.

          • OplockCompletionStatus equal to STATUS_CANNOT_GRANT_REQUESTED_OPLOCK.

        • (Because BreakingOplockOpen is equal to the passed-in Open, the operation ends at this point.)

      • Else

        • If Open.Stream.IsDeleted is TRUE and RequestedOplockLevel contains HANDLE_CACHING:

          • The object store MUST indicate an oplock break to the server according to the algorithm in section 2.1.5.18.3, setting the algorithm's parameters as follows:

            • BreakingOplockOpen equal to Open.

            • NewOplockLevel equal to RequestedOplockLevel without HANDLE_CACHING (for example if RequestedOplockLevel is (READ_CACHING|HANDLE_CACHING), then NewOplockLevel would be just READ_CACHING).

            • AcknowledgeRequired equal to TRUE.

            • OplockCompletionStatus equal to STATUS_CANNOT_GRANT_REQUESTED_OPLOCK.

          • (Because BreakingOplockOpen is equal to the passed-in Open, the operation ends at this point.)

        • EndIf

        • For each Open WaitingOpen on Open.Stream.Oplock.WaitList:

          • Indicate that the operation associated with WaitingOpen can continue according to the algorithm in section 2.1.4.12.1, setting OpenToRelease equal to WaitingOpen.

          • Remove WaitingOpen from Open.Stream.Oplock.WaitList.

        • EndFor

        • If RequestedOplockLevel does not contain WRITE_CACHING:

          • Set Open.Stream.Oplock.ExclusiveOpen to NULL.

        • EndIf

        • If RequestedOplockLevel is 0 (that is, no flags):

          • Set Open.Stream.Oplock.State to NO_OPLOCK.

          • The operation returns Status set to STATUS_SUCCESS at this point.

        • Else If RequestedOplockLevel does not contain WRITE_CACHING:

          • The object store MUST request a shared oplock according to the algorithm in section 2.1.5.18.2, setting the algorithm's parameters as follows:

            • Pass in the current Open.

            • RequestedOplock equal to RequestedOplockLevel.

            • GrantingInAck equal to TRUE.

          • The operation MUST at this point return any status code returned by the shared oplock request algorithm.

        • Else

          // Note that because this oplock is being set up as part of an acknowledgement of an exclusive oplock break, Open.Stream.Oplock.ExclusiveOpen was set at the time of the original oplock request; it contains Open.

          • Set Open.Stream.Oplock.State to (RequestedOplockLevel|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.

        • Endif

      • EndIf

    • EndCase

    • DefaultCase:

      • The operation MUST be failed with Status set to STATUS_INVALID_OPLOCK_PROTOCOL.

  • EndSwitch

  • EndIf