diff options
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r-- | fs/cifs/smb2ops.c | 68 |
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 */ | ||
37 | static int | 38 | static int |
38 | change_conf(struct TCP_Server_Info *server) | 39 | change_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 | ||
70 | static void | 69 | static void |
71 | smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, | 70 | smb2_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 | ||
108 | static void | 126 | static 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 | ||
142 | static int | 164 | static 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); |