aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilov@microsoft.com>2018-12-22 15:40:05 -0500
committerSteve French <stfrench@microsoft.com>2019-01-10 15:32:38 -0500
commit8544f4aa9dd19a04d1244dae10feecc813ccf175 (patch)
tree7c33803d72ea7bab9640f9e1b91cfb70172bdffa
parent33fa5c8b8a7dbe6353a56eaa654b790348890d42 (diff)
CIFS: Fix credit computation for compounded requests
In SMB3 protocol every part of the compound chain consumes credits individually, so we need to call wait_for_free_credits() for each of the PDUs in the chain. If an operation is interrupted, we must ensure we return all credits taken from the server structure back. Without this patch server can sometimes disconnect the session due to credit mismatches, especially when first operation(s) are large writes. Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com> CC: Stable <stable@vger.kernel.org>
-rw-r--r--fs/cifs/transport.c59
1 files changed, 41 insertions, 18 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 8e75d689be46..e047f06c9b4f 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -795,7 +795,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
795 int i, j, rc = 0; 795 int i, j, rc = 0;
796 int timeout, optype; 796 int timeout, optype;
797 struct mid_q_entry *midQ[MAX_COMPOUND]; 797 struct mid_q_entry *midQ[MAX_COMPOUND];
798 unsigned int credits = 0; 798 bool cancelled_mid[MAX_COMPOUND] = {false};
799 unsigned int credits[MAX_COMPOUND] = {0};
799 char *buf; 800 char *buf;
800 801
801 timeout = flags & CIFS_TIMEOUT_MASK; 802 timeout = flags & CIFS_TIMEOUT_MASK;
@@ -813,13 +814,31 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
813 return -ENOENT; 814 return -ENOENT;
814 815
815 /* 816 /*
816 * Ensure that we do not send more than 50 overlapping requests 817 * Ensure we obtain 1 credit per request in the compound chain.
817 * to the same server. We may make this configurable later or 818 * It can be optimized further by waiting for all the credits
818 * use ses->maxReq. 819 * at once but this can wait long enough if we don't have enough
820 * credits due to some heavy operations in progress or the server
821 * not granting us much, so a fallback to the current approach is
822 * needed anyway.
819 */ 823 */
820 rc = wait_for_free_request(ses->server, timeout, optype); 824 for (i = 0; i < num_rqst; i++) {
821 if (rc) 825 rc = wait_for_free_request(ses->server, timeout, optype);
822 return rc; 826 if (rc) {
827 /*
828 * We haven't sent an SMB packet to the server yet but
829 * we already obtained credits for i requests in the
830 * compound chain - need to return those credits back
831 * for future use. Note that we need to call add_credits
832 * multiple times to match the way we obtained credits
833 * in the first place and to account for in flight
834 * requests correctly.
835 */
836 for (j = 0; j < i; j++)
837 add_credits(ses->server, 1, optype);
838 return rc;
839 }
840 credits[i] = 1;
841 }
823 842
824 /* 843 /*
825 * Make sure that we sign in the same order that we send on this socket 844 * Make sure that we sign in the same order that we send on this socket
@@ -835,8 +854,10 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
835 for (j = 0; j < i; j++) 854 for (j = 0; j < i; j++)
836 cifs_delete_mid(midQ[j]); 855 cifs_delete_mid(midQ[j]);
837 mutex_unlock(&ses->server->srv_mutex); 856 mutex_unlock(&ses->server->srv_mutex);
857
838 /* Update # of requests on wire to server */ 858 /* Update # of requests on wire to server */
839 add_credits(ses->server, 1, optype); 859 for (j = 0; j < num_rqst; j++)
860 add_credits(ses->server, credits[j], optype);
840 return PTR_ERR(midQ[i]); 861 return PTR_ERR(midQ[i]);
841 } 862 }
842 863
@@ -883,17 +904,16 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
883 if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) { 904 if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
884 midQ[i]->mid_flags |= MID_WAIT_CANCELLED; 905 midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
885 midQ[i]->callback = DeleteMidQEntry; 906 midQ[i]->callback = DeleteMidQEntry;
886 spin_unlock(&GlobalMid_Lock); 907 cancelled_mid[i] = true;
887 add_credits(ses->server, 1, optype);
888 return rc;
889 } 908 }
890 spin_unlock(&GlobalMid_Lock); 909 spin_unlock(&GlobalMid_Lock);
891 } 910 }
892 } 911 }
893 912
894 for (i = 0; i < num_rqst; i++) 913 for (i = 0; i < num_rqst; i++)
895 if (midQ[i]->resp_buf) 914 if (!cancelled_mid[i] && midQ[i]->resp_buf
896 credits += ses->server->ops->get_credits(midQ[i]); 915 && (midQ[i]->mid_state == MID_RESPONSE_RECEIVED))
916 credits[i] = ses->server->ops->get_credits(midQ[i]);
897 917
898 for (i = 0; i < num_rqst; i++) { 918 for (i = 0; i < num_rqst; i++) {
899 if (rc < 0) 919 if (rc < 0)
@@ -901,8 +921,9 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
901 921
902 rc = cifs_sync_mid_result(midQ[i], ses->server); 922 rc = cifs_sync_mid_result(midQ[i], ses->server);
903 if (rc != 0) { 923 if (rc != 0) {
904 add_credits(ses->server, credits, optype); 924 /* mark this mid as cancelled to not free it below */
905 return rc; 925 cancelled_mid[i] = true;
926 goto out;
906 } 927 }
907 928
908 if (!midQ[i]->resp_buf || 929 if (!midQ[i]->resp_buf ||
@@ -949,9 +970,11 @@ out:
949 * This is prevented above by using a noop callback that will not 970 * This is prevented above by using a noop callback that will not
950 * wake this thread except for the very last PDU. 971 * wake this thread except for the very last PDU.
951 */ 972 */
952 for (i = 0; i < num_rqst; i++) 973 for (i = 0; i < num_rqst; i++) {
953 cifs_delete_mid(midQ[i]); 974 if (!cancelled_mid[i])
954 add_credits(ses->server, credits, optype); 975 cifs_delete_mid(midQ[i]);
976 add_credits(ses->server, credits[i], optype);
977 }
955 978
956 return rc; 979 return rc;
957} 980}