diff options
author | Pavel Shilovsky <pshilov@microsoft.com> | 2019-01-16 11:12:41 -0800 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2019-03-05 18:10:01 -0600 |
commit | 335b7b62ffb69d18055f2bb6f3a029263a07c735 (patch) | |
tree | 27d3e4a9edd427da8e4bae69a4e54b37c89d661a /fs/cifs/smb2pdu.c | |
parent | 5b964852609b2826126a526851f316fc06f5e37e (diff) | |
download | linux-stable-335b7b62ffb69d18055f2bb6f3a029263a07c735.tar.gz linux-stable-335b7b62ffb69d18055f2bb6f3a029263a07c735.tar.bz2 linux-stable-335b7b62ffb69d18055f2bb6f3a029263a07c735.zip |
CIFS: Respect reconnect in MTU credits calculations
Every time after a session reconnect we don't need to account for
credits obtained in previous sessions. Introduce new struct cifs_credits
which contains both credits value and reconnect instance of the
time those credits were taken. Modify a routine that add credits
back to handle the reconnect instance by assuming zero credits
if the reconnect happened after the credits were obtained and
before we decided to add them back due to some errors during sending.
This patch fixes the MTU credits cases. The subsequent patch
will handle non-MTU ones.
Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r-- | fs/cifs/smb2pdu.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 77f2c723befa..04581f06f29f 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -3294,9 +3294,9 @@ smb2_async_readv(struct cifs_readdata *rdata) rc = smb2_new_read_req( (void **) &buf, &total_len, &io_parms, rdata, 0, 0); if (rc) { - if (rc == -EAGAIN && rdata->credits) { + if (rc == -EAGAIN && rdata->credits.value) { /* credits was reset by reconnect */ - rdata->credits = 0; + rdata->credits.value = 0; /* reduce in_flight value since we won't send the req */ spin_lock(&server->req_lock); server->in_flight--; @@ -3313,17 +3313,26 @@ smb2_async_readv(struct cifs_readdata *rdata) shdr = (struct smb2_sync_hdr *)buf; - if (rdata->credits) { + if (rdata->credits.value > 0) { shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, SMB2_MAX_BUFFER_SIZE)); shdr->CreditRequest = cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); spin_lock(&server->req_lock); - server->credits += rdata->credits - + if (server->reconnect_instance == rdata->credits.instance) + server->credits += rdata->credits.value - le16_to_cpu(shdr->CreditCharge); + else { + spin_unlock(&server->req_lock); + cifs_dbg(VFS, "trying to return %u credits to old session\n", + rdata->credits.value + - le16_to_cpu(shdr->CreditCharge)); + rc = -EAGAIN; + goto async_readv_out; + } spin_unlock(&server->req_lock); wake_up(&server->request_q); - rdata->credits = le16_to_cpu(shdr->CreditCharge); + rdata->credits.value = le16_to_cpu(shdr->CreditCharge); flags |= CIFS_HAS_CREDITS; } @@ -3340,6 +3349,7 @@ smb2_async_readv(struct cifs_readdata *rdata) io_parms.offset, io_parms.length, rc); } +async_readv_out: cifs_small_buf_release(buf); return rc; } @@ -3508,9 +3518,9 @@ smb2_async_writev(struct cifs_writedata *wdata, rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len); if (rc) { - if (rc == -EAGAIN && wdata->credits) { + if (rc == -EAGAIN && wdata->credits.value) { /* credits was reset by reconnect */ - wdata->credits = 0; + wdata->credits.value = 0; /* reduce in_flight value since we won't send the req */ spin_lock(&server->req_lock); server->in_flight--; @@ -3603,17 +3613,26 @@ smb2_async_writev(struct cifs_writedata *wdata, req->Length = cpu_to_le32(wdata->bytes); #endif - if (wdata->credits) { + if (wdata->credits.value > 0) { shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, SMB2_MAX_BUFFER_SIZE)); shdr->CreditRequest = cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); spin_lock(&server->req_lock); - server->credits += wdata->credits - + if (server->reconnect_instance == wdata->credits.instance) + server->credits += wdata->credits.value - le16_to_cpu(shdr->CreditCharge); + else { + spin_unlock(&server->req_lock); + cifs_dbg(VFS, "trying to return %d credits to old session\n", + wdata->credits.value + - le16_to_cpu(shdr->CreditCharge)); + rc = -EAGAIN; + goto async_writev_out; + } spin_unlock(&server->req_lock); wake_up(&server->request_q); - wdata->credits = le16_to_cpu(shdr->CreditCharge); + wdata->credits.value = le16_to_cpu(shdr->CreditCharge); flags |= CIFS_HAS_CREDITS; } |