diff options
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r-- | fs/cifs/transport.c | 95 |
1 files changed, 55 insertions, 40 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 9e8e85a8d186..38b3b2463ae4 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -147,16 +147,19 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
147 | Flags2 is converted in SendReceive */ | 147 | Flags2 is converted in SendReceive */ |
148 | 148 | ||
149 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 149 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
150 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 150 | cFYI(1, ("Sending smb of length %d", smb_buf_length)); |
151 | dump_smb(smb_buffer, len); | 151 | dump_smb(smb_buffer, len); |
152 | 152 | ||
153 | while (len > 0) { | 153 | while (len > 0) { |
154 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); | 154 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); |
155 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 155 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
156 | i++; | 156 | i++; |
157 | if(i > 60) { | 157 | /* smaller timeout here than send2 since smaller size */ |
158 | /* Although it may not be required, this also is smaller | ||
159 | oplock break time */ | ||
160 | if(i > 30) { | ||
158 | cERROR(1, | 161 | cERROR(1, |
159 | ("sends on sock %p stuck for 30 seconds", | 162 | ("sends on sock %p stuck for 15 seconds", |
160 | ssocket)); | 163 | ssocket)); |
161 | rc = -EAGAIN; | 164 | rc = -EAGAIN; |
162 | break; | 165 | break; |
@@ -172,7 +175,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
172 | } | 175 | } |
173 | 176 | ||
174 | if (rc < 0) { | 177 | if (rc < 0) { |
175 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 178 | cERROR(1,("Error %d sending data on socket to server", rc)); |
176 | } else { | 179 | } else { |
177 | rc = 0; | 180 | rc = 0; |
178 | } | 181 | } |
@@ -182,22 +185,20 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
182 | 185 | ||
183 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 186 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
184 | static int | 187 | static int |
185 | smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer, | 188 | smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, |
186 | unsigned int smb_hdr_length, const char * data, unsigned int datalen, | 189 | struct sockaddr *sin) |
187 | struct sockaddr *sin) | ||
188 | { | 190 | { |
189 | int rc = 0; | 191 | int rc = 0; |
190 | int i = 0; | 192 | int i = 0; |
191 | struct msghdr smb_msg; | 193 | struct msghdr smb_msg; |
192 | struct kvec iov[2]; | 194 | struct smb_hdr *smb_buffer = iov[0].iov_base; |
193 | unsigned len = smb_hdr_length + 4; | 195 | unsigned int len = iov[0].iov_len; |
196 | unsigned int total_len; | ||
197 | int first_vec = 0; | ||
194 | 198 | ||
195 | if(ssocket == NULL) | 199 | if(ssocket == NULL) |
196 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 200 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
197 | iov[0].iov_base = smb_buffer; | 201 | |
198 | iov[0].iov_len = len; | ||
199 | iov[1].iov_base = data; | ||
200 | iov[1].iov_len = datalen; | ||
201 | smb_msg.msg_name = sin; | 202 | smb_msg.msg_name = sin; |
202 | smb_msg.msg_namelen = sizeof (struct sockaddr); | 203 | smb_msg.msg_namelen = sizeof (struct sockaddr); |
203 | smb_msg.msg_control = NULL; | 204 | smb_msg.msg_control = NULL; |
@@ -209,18 +210,23 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
209 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send | 210 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send |
210 | Flags2 is converted in SendReceive */ | 211 | Flags2 is converted in SendReceive */ |
211 | 212 | ||
213 | |||
214 | total_len = 0; | ||
215 | for (i = 0; i < n_vec; i++) | ||
216 | total_len += iov[i].iov_len; | ||
217 | |||
212 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 218 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
213 | cFYI(1, ("Sending smb: hdrlen %d datalen %d", | 219 | cFYI(1, ("Sending smb: total_len %d", total_len)); |
214 | smb_hdr_length,datalen)); | ||
215 | dump_smb(smb_buffer, len); | 220 | dump_smb(smb_buffer, len); |
216 | 221 | ||
217 | while (len + datalen > 0) { | 222 | while (total_len) { |
218 | rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len); | 223 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], |
224 | n_vec - first_vec, total_len); | ||
219 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 225 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
220 | i++; | 226 | i++; |
221 | if(i > 60) { | 227 | if(i > 40) { |
222 | cERROR(1, | 228 | cERROR(1, |
223 | ("sends on sock %p stuck for 30 seconds", | 229 | ("sends on sock %p stuck for 20 seconds", |
224 | ssocket)); | 230 | ssocket)); |
225 | rc = -EAGAIN; | 231 | rc = -EAGAIN; |
226 | break; | 232 | break; |
@@ -230,43 +236,52 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
230 | } | 236 | } |
231 | if (rc < 0) | 237 | if (rc < 0) |
232 | break; | 238 | break; |
233 | if(iov[0].iov_len > 0) { | 239 | |
234 | if(rc >= len) { | 240 | if (rc >= total_len) { |
235 | iov[0].iov_len = 0; | 241 | WARN_ON(rc > total_len); |
236 | rc -= len; | 242 | break; |
237 | len = 0; | 243 | } |
238 | } else { /* some of hdr was not sent */ | 244 | if(rc == 0) { |
239 | len -= rc; | 245 | /* should never happen, letting socket clear before |
240 | iov[0].iov_len -= rc; | 246 | retrying is our only obvious option here */ |
241 | iov[0].iov_base += rc; | 247 | cERROR(1,("tcp sent no data"); |
242 | continue; | 248 | msleep(500); |
243 | } | 249 | continue; |
244 | } | 250 | } |
245 | if((iov[0].iov_len == 0) && (rc > 0)){ | 251 | total_len -= rc; |
246 | iov[1].iov_base += rc; | 252 | for (i = first_vec; i < n_vec; i++) { |
247 | iov[1].iov_len -= rc; | 253 | if (iov[i].iov_len) { |
248 | datalen -= rc; | 254 | if (rc > iov[i].iov_len) { |
255 | rc -= iov[i].iov_len; | ||
256 | iov[i].iov_len = 0; | ||
257 | } else { | ||
258 | iov[i].iov_base += rc; | ||
259 | iov[i].iov_len -= rc; | ||
260 | first_vec = i; | ||
261 | break; | ||
262 | } | ||
263 | } | ||
249 | } | 264 | } |
250 | } | 265 | } |
251 | 266 | ||
252 | if (rc < 0) { | 267 | if (rc < 0) { |
253 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 268 | cERROR(1,("Error %d sending data on socket to server", rc)); |
254 | } else { | 269 | } else |
255 | rc = 0; | 270 | rc = 0; |
256 | } | ||
257 | 271 | ||
258 | return rc; | 272 | return rc; |
259 | } | 273 | } |
260 | 274 | ||
261 | int | 275 | int |
262 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 276 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
263 | struct smb_hdr *in_buf, int hdrlen, const char * data, | 277 | struct kvec *iov, int n_vec, int *pbytes_returned, |
264 | int datalen, int *pbytes_returned, const int long_op) | 278 | const int long_op) |
265 | { | 279 | { |
266 | int rc = 0; | 280 | int rc = 0; |
267 | unsigned int receive_len; | 281 | unsigned int receive_len; |
268 | unsigned long timeout; | 282 | unsigned long timeout; |
269 | struct mid_q_entry *midQ; | 283 | struct mid_q_entry *midQ; |
284 | struct smb_hdr *in_buf = iov[0].iov_base; | ||
270 | 285 | ||
271 | if (ses == NULL) { | 286 | if (ses == NULL) { |
272 | cERROR(1,("Null smb session")); | 287 | cERROR(1,("Null smb session")); |
@@ -364,7 +379,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
364 | /* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */ | 379 | /* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */ |
365 | 380 | ||
366 | midQ->midState = MID_REQUEST_SUBMITTED; | 381 | midQ->midState = MID_REQUEST_SUBMITTED; |
367 | rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen, | 382 | rc = smb_send2(ses->server->ssocket, iov, n_vec, |
368 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 383 | (struct sockaddr *) &(ses->server->addr.sockAddr)); |
369 | if(rc < 0) { | 384 | if(rc < 0) { |
370 | DeleteMidQEntry(midQ); | 385 | DeleteMidQEntry(midQ); |