Understanding SMB2 Credits, from the client perspective
This is mostly copied from MS-SMB2. Search for "credit" in the pdf for more details.
credit: A value that is granted to an SMB 2 Protocol client by an SMB 2 Protocol server that limits the number of outstanding requests that a client can send to a server.
Credits are "builtin", but there is also a multi-credit capability which can be negotiated.
SMB2_GLOBAL_CAP_LARGE_MTU: When set, indicates that the client supports multi-credit operations.
- Each SMB2 header has a CreditCharge and CreditRequest field.
CreditCharge (2 bytes): In the SMB 2.0.2 dialect, this field MUST NOT be used and MUST be reserved. The sender MUST set this to 0, and the receiver MUST ignore it. In all other dialects, this field indicates the number of credits that this request consumes.
CreditRequest/CreditResponse (2 bytes): On a request, this field indicates the number of credits the client is requesting. On a response, it indicates the number of credits granted to the client.
Calculating the CreditCharge
From MS-SMB2 18.104.22.168:
The CreditCharge of an SMB2 operation is computed from the payload size (the size of the data within the variable-length field of the request) or the maximum size of the response.CreditCharge = (max(SendPayloadSize, Expected ResponsePayloadSize) – 1) / 65536 + 1
Requesting Credits from Server when sending
From MS-SMB2 22.214.171.124.2:
The number of outstanding simultaneous requests that the client can have on a particular connection is determined by the number of credits granted to the client by the server. To maintain its current number of credits, the client MUST set CreditRequest to the number of credits that it will consume in sending this request, as specified in sections 126.96.36.199.5 and 188.8.131.52.6 (below). To increase or decrease this number, the client MUST request the server to grant more or fewer credits than will be consumed by the current request. The client MUST NOT decrease its credits to zero, and SHOULD request a sufficient number of credits to support implementation-defined local requirements (Windows-based clients require a minimum of 4 credits).
Management of credits is initiated by the client and controlled by the server. Specific mechanisms for credit management are implementation defined.
The Windows-based client will request credits up to a configurable maximum of 128 by default. A Windows-based client sends a CreditRequest value of 0 for an SMB2 NEGOTIATE Request and expects the server to grant at least 1 credit. In subsequent requests, the client will request credits sufficient to maintain its total outstanding limit at the configured maximum.
Sending Multi-Credit Requests
From MS-SMB2 184.108.40.206.5:
If Connection.SupportsMultiCredit is TRUE,
- For READ, WRITE, IOCTL, and QUERY_DIRECTORY requests, CreditCharge field in the SMB2 header SHOULD<87> be set to a value greater than or equal to the value computed in section 220.127.116.11.
- For all other requests, the client MUST set CreditCharge to 1, even if the payload size of a request or the anticipated response is greater than 65536.
If the client implements the SMB 2.1 dialect or SMB 3.x dialect family and Connection.SupportsMultiCredit is FALSE, CreditCharge SHOULD<88> be set to 0 and the payload size of a request or the maximum size of a response MUST be a maximum of 65536. Otherwise, the CreditCharge field MUST be set to 0 and the payload size of a request or the maximum size of a response MUST be a maximum of 65536. Before sending a multi-credit request, the client MUST consume the calculated number of consecutive MessageIds from Connection.SequenceWindow.
Application requests reading/writing from a file or named pipe, enumerating a directory
From MS-SMB2 18.104.22.168.5:
If a client requests reading from a file, Connection.Dialect is not "2.0.2", and if Connection.SupportsMultiCredit is TRUE, the CreditCharge field in the SMB2 header MUST be set to( 1 + (Length – 1) / 65536 )
Receiving any message
Unless specifically noted in a subsequent section, the following logic MUST be applied to any response message that is received from the server by the client. If the status code in the SMB2 header is not equal to STATUS_SUCCESS, the client SHOULD<137> retry the operation, in an implementation- specific manner, on the same or different channel. The client MUST ignore the CreditCharge field in the SMB2 header.
If the message size received exceeds Connection.MaxTransactSize, the client MUST disconnect the connection.
Granting Message Credits
If CreditResponse is greater than 0, the client MUST insert the newly granted credits into the Connection.SequenceWindow. For each credit that is granted, the client MUST insert the next highest value into the sequence window, as specified in section 22.214.171.124.6. The client MUST then signal any requests that were waiting for available message identifiers to continue processing.
Server algorithm for the granting of credits
The server MUST implement an algorithm for granting credits to the client. Each credit provides the client the capability to send a request to the server. Multiple credits allow for multiple simultaneous requests. The algorithm MUST meet the following conditions:
- The number of credits held by the client MUST be considered as 1 when the connection is established.
- The server MUST ensure that the number of credits held by the client is never reduced to zero. If the condition occurs, there is no way for the client to send subsequent requests for more credits.
- The server MAY<160> grant any number of credits up to that which the client requests, or more if required by the preceding rule.
- The server SHOULD<161> grant the client a non-zero value of credits in response to any non-zero value requested, within administratively configured limits. The server MUST grant the client at least 1 credit when responding to SMB2 NEGOTIATE.
- The server MAY<162> vary the number of credits granted to different clients based on quality of service features, such as identity, behavior, or administrator configuration.
The server MAY<186> grant credits separately on each response in the compounded chain. Then the entire response chain MUST be sent to the client as a single submission to the underlying transport.