CIFS Oplock File Locking
Opportunistic locking (oplock) is a mechanism that allows a server to tell a client process that a requested file is only being used by that process. The client can safely do read-ahead and write-behind as well as local caching, knowing that the file will not be accessed or changed in any way by another process while the opportunistic lock is in effect. The server notifies the client when a second process attempts to open or modify the locked file.
SMB dialects including and newer than the "LANMAN1.0" dialect support oplocks.
Note An implementation, even of later dialects, can implement oplocks trivially by always refusing to grant them.
A client requests an oplock in the NT_CREATE_ANDX or NT_TRANSACT_CREATE request when the file is being opened in a mode which is not exclusive. The server returns an indication of whether the oplock was granted. The OplockLevel field indicates the type of oplock the client now owns. If OplockLevel is 0, the client possesses no oplocks on the file at all; if OplockLevel is 1, the client possesses a Level II oplock. The following list describes the types of oplock that a client may hold:
Level II oplock
Informs a client that there are multiple concurrent clients of a file, and none have yet modified it. It allows the client to perform read operations and file attribute fetches using cached or read-ahead local information, but all other requests have to be sent to the server.
Exclusive oplock
Informs a client that it is the only one to have a file open. It allows the client to perform all file operations using cached or read-ahead local information until it closes the file, at which time the server has to be updated with any changes made to the state of the file (contents and attributes).
Batch oplock
Informs a client that it is the only one to have a file open. It allows the client to perform all file operations on cached or read-ahead local information (including open and close operations).
If a client holds no oplocks, all requests other than read must be sent to the server. Read operations may be performed using cached or read-ahead data as long as the byte range has been locked by the client; otherwise, they too must be sent to the server.
When a client opens a file, it may request that the server grant it an exclusive or batch oplock on the file. The response from the server indicates the type of oplock granted to the client. If cached or read-ahead information was retained after the file was last closed, the client must verify that the last modified time is unchanged when the file is reopened before using the retained information.
Releasing Oplocks
The client is expected to flush any dirty buffers to the server, submit any file locks and respond to the server with either an SMB_LOCKING_ANDX command having the LOCKING_ANDX_OPLOCK_RELEASE flag set, or with a file close request if the file is no longer in use by the client. The SMB_LOCKING_ANDX command is used to convey oplock break requests and acknowledgements (as well as lock and unlock requests). If the client sends an SMB_LOCKING_ANDX command with the LOCKING_ANDX_OPLOCK_RELEASE flag set and NumberOfLocks is zero, the server does not send a response.
When another user attempts to open or otherwise modify the file which a client has oplocked, the server delays the second attempt and notifies the client using the command SMB_LOCKING_ANDX asynchronously sent from the server to the client. This message has the LOCKING_ANDX_OPLOCK_RELEASE flag set, indicating to the client that the oplock is being broken.
Level II Oplock Command Sequence
Client A | Client B | Server |
---|---|---|
Open("abc") | ||
Open OK. Exclusive oplock granted | ||
Read | ||
Data | ||
Open("abc") | ||
Break Level II oplock request to A | ||
Lock(s) | ||
Lock response(s) | ||
Oplock ack | ||
Open OK. Level II oplock granted to B |
Exclusive Oplock Command Sequence
When client A opens the file, it can request an exclusive oplock. Provided no one else has the file open on the server, then the server may grant the oplock to client A.
If, at some point in the future, another client, such as client B, requests an open of the same file, or requests a path-based operation on the file, then the server must tell client A to relinquish its exclusive oplock. If client B's request will not modify the state of the file, the server may tell client A that its exclusive oplock has been replaced by a level II oplock.
When a client's exclusive oplock is broken, it must synchronize the server to the local state of the file (contents and attributes) and any locks it holds on the file, and then acknowledge the oplock break request. After the server receives the acknowledgement, it can process client B's request.
Client A | Client B | Server |
---|---|---|
Open("abc") | ||
Open OK. Exclusive oplock granted | ||
<Locks, Writes> | ||
Read (large) | ||
Read data | ||
<Reads from read-ahead> | ||
Open("abc") | ||
Oplock break to A | ||
Lock(s) | ||
Lock response(s) | ||
Write(s) | ||
Write response(s) | ||
Close or oplock ack | ||
Open response to B |
Batch Oplock Command Sequence
When client A opens the file, it can request a batch oplock. Provided no one else has the file open on the server, then the server may grant the oplock to client A.
If, at some point in the future, another client, such as client B, requests any operation on the same file, then the server must tell client A to relinquish its batch oplock. If client B's request will not modify the state of the file (or rename it), the server may tell client A that its batch oplock has been replaced by a level II oplock.
If client A has the file open at the time the oplock break request is received, client actions will be the same as if it had an exclusive oplock. If client A does not have the file open at the time the oplock break request is received, it sends a close request to the server. When the file is actually closed at the server, client B's open request can be processed.
Client A | Client B | Server |
---|---|---|
Open("abc") | ||
Open OK. Batch oplock granted | ||
Read | ||
Read data | ||
<Close> | ||
<Open> | ||
<Seek> | ||
<Read> | ||
Data | ||
Open("abc") | ||
Oplock break to A | ||
Close | ||
Close OK to A | ||
Open OK to B |