summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilov@microsoft.com>2019-01-03 16:45:27 -0800
committerSteve French <stfrench@microsoft.com>2019-01-11 07:14:40 -0600
commit8a26f0f781f56d3016b34a2217e346973d067e7b (patch)
treebde15d0af3ad8c84e5a539a4d5ed2dc28d3317fa
parentb9a74cde94957d82003fb9f7ab4777938ca851cd (diff)
downloadlinux-0-day-8a26f0f781f56d3016b34a2217e346973d067e7b.tar.gz
linux-0-day-8a26f0f781f56d3016b34a2217e346973d067e7b.tar.xz
CIFS: Fix credits calculation for cancelled requests
If a request is cancelled, we can't assume that the server returns 1 credit back. Instead we need to wait for a response and process the number of credits granted by the server. Create a separate mid callback for cancelled request, parse the number of credits in a response buffer and add them to the client's credits. If the didn't get a response (no response buffer available) assume 0 credits granted. The latter most probably happens together with session reconnect, so the client's credits are adjusted anyway. Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/transport.c28
2 files changed, 27 insertions, 2 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 01ded7038b19e..770926877b7ce 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1438,6 +1438,7 @@ struct mid_q_entry {
int mid_state; /* wish this were enum but can not pass to wait_event */
unsigned int mid_flags;
__le16 command; /* smb command code */
+ unsigned int optype; /* operation type */
bool large_buf:1; /* if valid response, is pointer to large buf */
bool multiRsp:1; /* multiple trans2 responses for one request */
bool multiEnd:1; /* both received */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index aaff9c5aab3d0..450c434943248 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -787,6 +787,24 @@ cifs_noop_callback(struct mid_q_entry *mid)
{
}
+static void
+cifs_cancelled_callback(struct mid_q_entry *mid)
+{
+ struct TCP_Server_Info *server = mid->server;
+ unsigned int optype = mid->optype;
+ unsigned int credits_received = 0;
+
+ if (mid->mid_state == MID_RESPONSE_RECEIVED) {
+ if (mid->resp_buf)
+ credits_received = server->ops->get_credits(mid);
+ else
+ cifs_dbg(FYI, "Bad state for cancelled MID\n");
+ }
+
+ DeleteMidQEntry(mid);
+ add_credits(server, credits_received, optype);
+}
+
int
compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
const int flags, const int num_rqst, struct smb_rqst *rqst,
@@ -862,6 +880,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
}
midQ[i]->mid_state = MID_REQUEST_SUBMITTED;
+ midQ[i]->optype = optype;
/*
* We don't invoke the callback compounds unless it is the last
* request.
@@ -896,15 +915,20 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
for (i = 0; i < num_rqst; i++) {
rc = wait_for_response(ses->server, midQ[i]);
- if (rc != 0) {
+ if (rc != 0)
+ break;
+ }
+ if (rc != 0) {
+ for (; i < num_rqst; i++) {
cifs_dbg(VFS, "Cancelling wait for mid %llu cmd: %d\n",
midQ[i]->mid, le16_to_cpu(midQ[i]->command));
send_cancel(ses->server, &rqst[i], midQ[i]);
spin_lock(&GlobalMid_Lock);
if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
- midQ[i]->callback = DeleteMidQEntry;
+ midQ[i]->callback = cifs_cancelled_callback;
cancelled_mid[i] = true;
+ credits[i] = 0;
}
spin_unlock(&GlobalMid_Lock);
}