CIFS: Fix credits calculation for cancelled requests
authorPavel Shilovsky <pshilov@microsoft.com>
Fri, 4 Jan 2019 00:45:27 +0000 (16:45 -0800)
committerSteve French <stfrench@microsoft.com>
Fri, 11 Jan 2019 13:14:40 +0000 (07:14 -0600)
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>
fs/cifs/cifsglob.h
fs/cifs/transport.c

index 01ded7038b19eabd2798b7cd18abf187cae4e145..770926877b7ce029690f8aeb9a4c352632c2bcd2 100644 (file)
@@ -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 */
index aaff9c5aab3d0ea77c38a5d4678d1669b0f2d10c..450c4349432488efc45b077b290b9da3604cc49d 100644 (file)
@@ -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);
                }