summaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r--fs/cifs/smb2ops.c68
1 files changed, 47 insertions, 21 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index cf7eb891804f..153238fc4fa9 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -34,6 +34,7 @@
34#include "cifs_ioctl.h" 34#include "cifs_ioctl.h"
35#include "smbdirect.h" 35#include "smbdirect.h"
36 36
37/* Change credits for different ops and return the total number of credits */
37static int 38static int
38change_conf(struct TCP_Server_Info *server) 39change_conf(struct TCP_Server_Info *server)
39{ 40{
@@ -41,17 +42,15 @@ change_conf(struct TCP_Server_Info *server)
41 server->oplock_credits = server->echo_credits = 0; 42 server->oplock_credits = server->echo_credits = 0;
42 switch (server->credits) { 43 switch (server->credits) {
43 case 0: 44 case 0:
44 return -1; 45 return 0;
45 case 1: 46 case 1:
46 server->echoes = false; 47 server->echoes = false;
47 server->oplocks = false; 48 server->oplocks = false;
48 cifs_dbg(VFS, "disabling echoes and oplocks\n");
49 break; 49 break;
50 case 2: 50 case 2:
51 server->echoes = true; 51 server->echoes = true;
52 server->oplocks = false; 52 server->oplocks = false;
53 server->echo_credits = 1; 53 server->echo_credits = 1;
54 cifs_dbg(FYI, "disabling oplocks\n");
55 break; 54 break;
56 default: 55 default:
57 server->echoes = true; 56 server->echoes = true;
@@ -64,14 +63,15 @@ change_conf(struct TCP_Server_Info *server)
64 server->echo_credits = 1; 63 server->echo_credits = 1;
65 } 64 }
66 server->credits -= server->echo_credits + server->oplock_credits; 65 server->credits -= server->echo_credits + server->oplock_credits;
67 return 0; 66 return server->credits + server->echo_credits + server->oplock_credits;
68} 67}
69 68
70static void 69static void
71smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, 70smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
72 const int optype) 71 const int optype)
73{ 72{
74 int *val, rc = 0; 73 int *val, rc = -1;
74
75 spin_lock(&server->req_lock); 75 spin_lock(&server->req_lock);
76 val = server->ops->get_credits_field(server, optype); 76 val = server->ops->get_credits_field(server, optype);
77 77
@@ -101,8 +101,26 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
101 } 101 }
102 spin_unlock(&server->req_lock); 102 spin_unlock(&server->req_lock);
103 wake_up(&server->request_q); 103 wake_up(&server->request_q);
104 if (rc) 104
105 cifs_reconnect(server); 105 if (server->tcpStatus == CifsNeedReconnect)
106 return;
107
108 switch (rc) {
109 case -1:
110 /* change_conf hasn't been executed */
111 break;
112 case 0:
113 cifs_dbg(VFS, "Possible client or server bug - zero credits\n");
114 break;
115 case 1:
116 cifs_dbg(VFS, "disabling echoes and oplocks\n");
117 break;
118 case 2:
119 cifs_dbg(FYI, "disabling oplocks\n");
120 break;
121 default:
122 cifs_dbg(FYI, "add %u credits total=%d\n", add, rc);
123 }
106} 124}
107 125
108static void 126static void
@@ -136,7 +154,11 @@ smb2_get_credits(struct mid_q_entry *mid)
136{ 154{
137 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf; 155 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf;
138 156
139 return le16_to_cpu(shdr->CreditRequest); 157 if (mid->mid_state == MID_RESPONSE_RECEIVED
158 || mid->mid_state == MID_RESPONSE_MALFORMED)
159 return le16_to_cpu(shdr->CreditRequest);
160
161 return 0;
140} 162}
141 163
142static int 164static int
@@ -165,14 +187,14 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
165 187
166 scredits = server->credits; 188 scredits = server->credits;
167 /* can deadlock with reopen */ 189 /* can deadlock with reopen */
168 if (scredits == 1) { 190 if (scredits <= 8) {
169 *num = SMB2_MAX_BUFFER_SIZE; 191 *num = SMB2_MAX_BUFFER_SIZE;
170 *credits = 0; 192 *credits = 0;
171 break; 193 break;
172 } 194 }
173 195
174 /* leave one credit for a possible reopen */ 196 /* leave some credits for reopen and other ops */
175 scredits--; 197 scredits -= 8;
176 *num = min_t(unsigned int, size, 198 *num = min_t(unsigned int, size,
177 scredits * SMB2_MAX_BUFFER_SIZE); 199 scredits * SMB2_MAX_BUFFER_SIZE);
178 200
@@ -3189,11 +3211,23 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
3189 server->ops->is_status_pending(buf, server, 0)) 3211 server->ops->is_status_pending(buf, server, 0))
3190 return -1; 3212 return -1;
3191 3213
3192 rdata->result = server->ops->map_error(buf, false); 3214 /* set up first two iov to get credits */
3215 rdata->iov[0].iov_base = buf;
3216 rdata->iov[0].iov_len = 4;
3217 rdata->iov[1].iov_base = buf + 4;
3218 rdata->iov[1].iov_len =
3219 min_t(unsigned int, buf_len, server->vals->read_rsp_size) - 4;
3220 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
3221 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
3222 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
3223 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
3224
3225 rdata->result = server->ops->map_error(buf, true);
3193 if (rdata->result != 0) { 3226 if (rdata->result != 0) {
3194 cifs_dbg(FYI, "%s: server returned error %d\n", 3227 cifs_dbg(FYI, "%s: server returned error %d\n",
3195 __func__, rdata->result); 3228 __func__, rdata->result);
3196 dequeue_mid(mid, rdata->result); 3229 /* normal error on read response */
3230 dequeue_mid(mid, false);
3197 return 0; 3231 return 0;
3198 } 3232 }
3199 3233
@@ -3266,14 +3300,6 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
3266 return 0; 3300 return 0;
3267 } 3301 }
3268 3302
3269 /* set up first iov for signature check */
3270 rdata->iov[0].iov_base = buf;
3271 rdata->iov[0].iov_len = 4;
3272 rdata->iov[1].iov_base = buf + 4;
3273 rdata->iov[1].iov_len = server->vals->read_rsp_size - 4;
3274 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
3275 rdata->iov[0].iov_base, server->vals->read_rsp_size);
3276
3277 length = rdata->copy_into_pages(server, rdata, &iter); 3303 length = rdata->copy_into_pages(server, rdata, &iter);
3278 3304
3279 kfree(bvec); 3305 kfree(bvec);