[CIFS] Reduce CIFS tcp congestion timeout (it was too long) and backoff
[linux-2.6-block.git] / fs / cifs / transport.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/transport.c
3 *
b8643e1b 4 * Copyright (C) International Business Machines Corp., 2002,2005
1da177e4
LT
5 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <linux/fs.h>
23#include <linux/list.h>
24#include <linux/wait.h>
25#include <linux/net.h>
26#include <linux/delay.h>
27#include <asm/uaccess.h>
28#include <asm/processor.h>
29#include <linux/mempool.h>
30#include "cifspdu.h"
31#include "cifsglob.h"
32#include "cifsproto.h"
33#include "cifs_debug.h"
34
35extern mempool_t *cifs_mid_poolp;
36extern kmem_cache_t *cifs_oplock_cachep;
37
38static struct mid_q_entry *
39AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
40{
41 struct mid_q_entry *temp;
42
43 if (ses == NULL) {
275cde1a 44 cERROR(1, ("Null session passed in to AllocMidQEntry"));
1da177e4
LT
45 return NULL;
46 }
47 if (ses->server == NULL) {
48 cERROR(1, ("Null TCP session in AllocMidQEntry"));
49 return NULL;
50 }
51
d6e04ae6
SF
52 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
53 SLAB_KERNEL | SLAB_NOFS);
1da177e4
LT
54 if (temp == NULL)
55 return temp;
56 else {
57 memset(temp, 0, sizeof (struct mid_q_entry));
58 temp->mid = smb_buffer->Mid; /* always LE */
59 temp->pid = current->pid;
60 temp->command = smb_buffer->Command;
61 cFYI(1, ("For smb_command %d", temp->command));
62 do_gettimeofday(&temp->when_sent);
63 temp->ses = ses;
64 temp->tsk = current;
65 }
66
67 spin_lock(&GlobalMid_Lock);
68 list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
69 atomic_inc(&midCount);
70 temp->midState = MID_REQUEST_ALLOCATED;
71 spin_unlock(&GlobalMid_Lock);
72 return temp;
73}
74
75static void
76DeleteMidQEntry(struct mid_q_entry *midEntry)
77{
78 spin_lock(&GlobalMid_Lock);
79 midEntry->midState = MID_FREE;
80 list_del(&midEntry->qhead);
81 atomic_dec(&midCount);
82 spin_unlock(&GlobalMid_Lock);
b8643e1b
SF
83 if(midEntry->largeBuf)
84 cifs_buf_release(midEntry->resp_buf);
85 else
86 cifs_small_buf_release(midEntry->resp_buf);
1da177e4
LT
87 mempool_free(midEntry, cifs_mid_poolp);
88}
89
90struct oplock_q_entry *
91AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
92{
93 struct oplock_q_entry *temp;
94 if ((pinode== NULL) || (tcon == NULL)) {
95 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
96 return NULL;
97 }
98 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
99 SLAB_KERNEL);
100 if (temp == NULL)
101 return temp;
102 else {
103 temp->pinode = pinode;
104 temp->tcon = tcon;
105 temp->netfid = fid;
106 spin_lock(&GlobalMid_Lock);
107 list_add_tail(&temp->qhead, &GlobalOplock_Q);
108 spin_unlock(&GlobalMid_Lock);
109 }
110 return temp;
111
112}
113
114void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
115{
116 spin_lock(&GlobalMid_Lock);
117 /* should we check if list empty first? */
118 list_del(&oplockEntry->qhead);
119 spin_unlock(&GlobalMid_Lock);
120 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
121}
122
123int
124smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
125 unsigned int smb_buf_length, struct sockaddr *sin)
126{
127 int rc = 0;
128 int i = 0;
129 struct msghdr smb_msg;
130 struct kvec iov;
131 unsigned len = smb_buf_length + 4;
132
133 if(ssocket == NULL)
134 return -ENOTSOCK; /* BB eventually add reconnect code here */
135 iov.iov_base = smb_buffer;
136 iov.iov_len = len;
137
138 smb_msg.msg_name = sin;
139 smb_msg.msg_namelen = sizeof (struct sockaddr);
140 smb_msg.msg_control = NULL;
141 smb_msg.msg_controllen = 0;
142 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
143
144 /* smb header is converted in header_assemble. bcc and rest of SMB word
145 area, and byte area if necessary, is converted to littleendian in
146 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
147 Flags2 is converted in SendReceive */
148
149 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
3e84469d 150 cFYI(1, ("Sending smb of length %d", smb_buf_length));
1da177e4
LT
151 dump_smb(smb_buffer, len);
152
153 while (len > 0) {
154 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
155 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
156 i++;
3e84469d
SF
157 /* smaller timeout here than send2 since smaller size */
158 /* Although it may not be required, this also is smaller
159 oplock break time */
68058e75 160 if(i > 12) {
1da177e4 161 cERROR(1,
68058e75 162 ("sends on sock %p stuck for 7 seconds",
1da177e4
LT
163 ssocket));
164 rc = -EAGAIN;
165 break;
166 }
68058e75 167 msleep(1 << i);
1da177e4
LT
168 continue;
169 }
170 if (rc < 0)
171 break;
172 iov.iov_base += rc;
173 iov.iov_len -= rc;
174 len -= rc;
175 }
176
177 if (rc < 0) {
3e84469d 178 cERROR(1,("Error %d sending data on socket to server", rc));
1da177e4
LT
179 } else {
180 rc = 0;
181 }
182
183 return rc;
184}
185
d6e04ae6
SF
186#ifdef CONFIG_CIFS_EXPERIMENTAL
187static int
3e84469d
SF
188smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
189 struct sockaddr *sin)
1da177e4
LT
190{
191 int rc = 0;
192 int i = 0;
193 struct msghdr smb_msg;
3e84469d
SF
194 struct smb_hdr *smb_buffer = iov[0].iov_base;
195 unsigned int len = iov[0].iov_len;
196 unsigned int total_len;
197 int first_vec = 0;
d6e04ae6 198
1da177e4
LT
199 if(ssocket == NULL)
200 return -ENOTSOCK; /* BB eventually add reconnect code here */
3e84469d 201
1da177e4
LT
202 smb_msg.msg_name = sin;
203 smb_msg.msg_namelen = sizeof (struct sockaddr);
204 smb_msg.msg_control = NULL;
205 smb_msg.msg_controllen = 0;
206 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
207
208 /* smb header is converted in header_assemble. bcc and rest of SMB word
209 area, and byte area if necessary, is converted to littleendian in
210 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
211 Flags2 is converted in SendReceive */
212
3e84469d
SF
213
214 total_len = 0;
215 for (i = 0; i < n_vec; i++)
216 total_len += iov[i].iov_len;
217
1da177e4 218 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
3e84469d 219 cFYI(1, ("Sending smb: total_len %d", total_len));
1da177e4
LT
220 dump_smb(smb_buffer, len);
221
3e84469d
SF
222 while (total_len) {
223 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
224 n_vec - first_vec, total_len);
1da177e4
LT
225 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
226 i++;
68058e75 227 if(i >= 14) {
1da177e4 228 cERROR(1,
68058e75 229 ("sends on sock %p stuck for 15 seconds",
1da177e4
LT
230 ssocket));
231 rc = -EAGAIN;
232 break;
233 }
68058e75 234 msleep(1 << i);
1da177e4
LT
235 continue;
236 }
237 if (rc < 0)
238 break;
3e84469d
SF
239
240 if (rc >= total_len) {
241 WARN_ON(rc > total_len);
242 break;
243 }
244 if(rc == 0) {
245 /* should never happen, letting socket clear before
246 retrying is our only obvious option here */
04c08816 247 cERROR(1,("tcp sent no data"));
3e84469d
SF
248 msleep(500);
249 continue;
d6e04ae6 250 }
3e84469d 251 total_len -= rc;
68058e75 252 /* the line below resets i */
3e84469d
SF
253 for (i = first_vec; i < n_vec; i++) {
254 if (iov[i].iov_len) {
255 if (rc > iov[i].iov_len) {
256 rc -= iov[i].iov_len;
257 iov[i].iov_len = 0;
258 } else {
259 iov[i].iov_base += rc;
260 iov[i].iov_len -= rc;
261 first_vec = i;
262 break;
263 }
264 }
d6e04ae6 265 }
1da177e4
LT
266 }
267
268 if (rc < 0) {
3e84469d
SF
269 cERROR(1,("Error %d sending data on socket to server", rc));
270 } else
1da177e4 271 rc = 0;
1da177e4
LT
272
273 return rc;
274}
275
1da177e4 276int
d6e04ae6 277SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
3e84469d
SF
278 struct kvec *iov, int n_vec, int *pbytes_returned,
279 const int long_op)
1da177e4
LT
280{
281 int rc = 0;
d6e04ae6
SF
282 unsigned int receive_len;
283 unsigned long timeout;
284 struct mid_q_entry *midQ;
3e84469d 285 struct smb_hdr *in_buf = iov[0].iov_base;
1da177e4
LT
286
287 if (ses == NULL) {
288 cERROR(1,("Null smb session"));
289 return -EIO;
290 }
291 if(ses->server == NULL) {
292 cERROR(1,("Null tcp session"));
293 return -EIO;
294 }
1da177e4 295
d6e04ae6 296 if(ses->server->tcpStatus == CifsExiting)
31ca3bc3
SF
297 return -ENOENT;
298
1da177e4
LT
299 /* Ensure that we do not send more than 50 overlapping requests
300 to the same server. We may make this configurable later or
301 use ses->maxReq */
302 if(long_op == -1) {
303 /* oplock breaks must not be held up */
304 atomic_inc(&ses->server->inFlight);
305 } else {
306 spin_lock(&GlobalMid_Lock);
307 while(1) {
d6e04ae6
SF
308 if(atomic_read(&ses->server->inFlight) >=
309 cifs_max_pending){
1da177e4 310 spin_unlock(&GlobalMid_Lock);
131afd0b
SF
311#ifdef CONFIG_CIFS_STATS2
312 atomic_inc(&ses->server->num_waiters);
313#endif
1da177e4
LT
314 wait_event(ses->server->request_q,
315 atomic_read(&ses->server->inFlight)
316 < cifs_max_pending);
131afd0b
SF
317#ifdef CONFIG_CIFS_STATS2
318 atomic_dec(&ses->server->num_waiters);
319#endif
1da177e4
LT
320 spin_lock(&GlobalMid_Lock);
321 } else {
322 if(ses->server->tcpStatus == CifsExiting) {
323 spin_unlock(&GlobalMid_Lock);
324 return -ENOENT;
325 }
326
327 /* can not count locking commands against total since
328 they are allowed to block on server */
329
330 if(long_op < 3) {
331 /* update # of requests on the wire to server */
332 atomic_inc(&ses->server->inFlight);
333 }
334 spin_unlock(&GlobalMid_Lock);
335 break;
336 }
337 }
338 }
339 /* make sure that we sign in the same order that we send on this socket
340 and avoid races inside tcp sendmsg code that could cause corruption
341 of smb data */
342
343 down(&ses->server->tcpSem);
344
345 if (ses->server->tcpStatus == CifsExiting) {
346 rc = -ENOENT;
d6e04ae6 347 goto out_unlock2;
1da177e4
LT
348 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
349 cFYI(1,("tcp session dead - return to caller to retry"));
350 rc = -EAGAIN;
d6e04ae6 351 goto out_unlock2;
1da177e4
LT
352 } else if (ses->status != CifsGood) {
353 /* check if SMB session is bad because we are setting it up */
354 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
355 (in_buf->Command != SMB_COM_NEGOTIATE)) {
356 rc = -EAGAIN;
d6e04ae6 357 goto out_unlock2;
1da177e4
LT
358 } /* else ok - we are setting up session */
359 }
360 midQ = AllocMidQEntry(in_buf, ses);
361 if (midQ == NULL) {
362 up(&ses->server->tcpSem);
363 /* If not lock req, update # of requests on wire to server */
364 if(long_op < 3) {
365 atomic_dec(&ses->server->inFlight);
366 wake_up(&ses->server->request_q);
367 }
368 return -ENOMEM;
369 }
370
d6e04ae6 371/* BB FIXME */
4a77118c 372/* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */
1da177e4
LT
373
374 midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b
SF
375#ifdef CONFIG_CIFS_STATS2
376 atomic_inc(&ses->server->inSend);
377#endif
3e84469d 378 rc = smb_send2(ses->server->ssocket, iov, n_vec,
d6e04ae6 379 (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b
SF
380#ifdef CONFIG_CIFS_STATS2
381 atomic_dec(&ses->server->inSend);
382#endif
1da177e4
LT
383 if(rc < 0) {
384 DeleteMidQEntry(midQ);
385 up(&ses->server->tcpSem);
386 /* If not lock req, update # of requests on wire to server */
387 if(long_op < 3) {
388 atomic_dec(&ses->server->inFlight);
389 wake_up(&ses->server->request_q);
390 }
391 return rc;
392 } else
393 up(&ses->server->tcpSem);
d6e04ae6
SF
394 if (long_op == -1)
395 goto cifs_no_response_exit2;
396 else if (long_op == 2) /* writes past end of file can take loong time */
37c0eb46 397 timeout = 180 * HZ;
d6e04ae6
SF
398 else if (long_op == 1)
399 timeout = 45 * HZ; /* should be greater than
400 servers oplock break timeout (about 43 seconds) */
401 else if (long_op > 2) {
402 timeout = MAX_SCHEDULE_TIMEOUT;
403 } else
404 timeout = 15 * HZ;
405 /* wait for 15 seconds or until woken up due to response arriving or
406 due to last connection to this server being unmounted */
407 if (signal_pending(current)) {
408 /* if signal pending do not hold up user for full smb timeout
409 but we still give response a change to complete */
410 timeout = 2 * HZ;
411 }
412
413 /* No user interrupts in wait - wreaks havoc with performance */
414 if(timeout != MAX_SCHEDULE_TIMEOUT) {
415 timeout += jiffies;
416 wait_event(ses->server->response_q,
417 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
418 time_after(jiffies, timeout) ||
419 ((ses->server->tcpStatus != CifsGood) &&
420 (ses->server->tcpStatus != CifsNew)));
421 } else {
422 wait_event(ses->server->response_q,
423 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
424 ((ses->server->tcpStatus != CifsGood) &&
425 (ses->server->tcpStatus != CifsNew)));
426 }
427
428 spin_lock(&GlobalMid_Lock);
429 if (midQ->resp_buf) {
430 spin_unlock(&GlobalMid_Lock);
70ca734a 431 receive_len = midQ->resp_buf->smb_buf_length;
d6e04ae6 432 } else {
37c0eb46
SF
433 cERROR(1,("No response to cmd %d mid %d",
434 midQ->command, midQ->mid));
d6e04ae6
SF
435 if(midQ->midState == MID_REQUEST_SUBMITTED) {
436 if(ses->server->tcpStatus == CifsExiting)
437 rc = -EHOSTDOWN;
438 else {
439 ses->server->tcpStatus = CifsNeedReconnect;
440 midQ->midState = MID_RETRY_NEEDED;
441 }
442 }
443
444 if (rc != -EHOSTDOWN) {
445 if(midQ->midState == MID_RETRY_NEEDED) {
446 rc = -EAGAIN;
447 cFYI(1,("marking request for retry"));
448 } else {
449 rc = -EIO;
450 }
451 }
452 spin_unlock(&GlobalMid_Lock);
453 DeleteMidQEntry(midQ);
454 /* If not lock req, update # of requests on wire to server */
455 if(long_op < 3) {
456 atomic_dec(&ses->server->inFlight);
457 wake_up(&ses->server->request_q);
458 }
459 return rc;
460 }
461
462 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
463 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
464 receive_len, xid));
465 rc = -EIO;
466 } else { /* rcvd frame is ok */
467
468 if (midQ->resp_buf &&
469 (midQ->midState == MID_RESPONSE_RECEIVED)) {
470 in_buf->smb_buf_length = receive_len;
471 /* BB verify that length would not overrun small buf */
472 memcpy((char *)in_buf + 4,
473 (char *)midQ->resp_buf + 4,
474 receive_len);
475
476 dump_smb(in_buf, 80);
477 /* convert the length into a more usable form */
478 if((receive_len > 24) &&
479 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
480 SECMODE_SIGN_ENABLED))) {
481 rc = cifs_verify_signature(in_buf,
482 ses->server->mac_signing_key,
483 midQ->sequence_number+1);
484 if(rc) {
485 cERROR(1,("Unexpected SMB signature"));
486 /* BB FIXME add code to kill session */
487 }
488 }
489
490 *pbytes_returned = in_buf->smb_buf_length;
491
492 /* BB special case reconnect tid and uid here? */
493 rc = map_smb_to_linux_error(in_buf);
494
495 /* convert ByteCount if necessary */
496 if (receive_len >=
497 sizeof (struct smb_hdr) -
498 4 /* do not count RFC1001 header */ +
499 (2 * in_buf->WordCount) + 2 /* bcc */ )
500 BCC(in_buf) = le16_to_cpu(BCC(in_buf));
501 } else {
502 rc = -EIO;
ab2f218f 503 cFYI(1,("Bad MID state?"));
d6e04ae6
SF
504 }
505 }
506cifs_no_response_exit2:
507 DeleteMidQEntry(midQ);
508
1da177e4 509 if(long_op < 3) {
d6e04ae6 510 atomic_dec(&ses->server->inFlight);
1da177e4
LT
511 wake_up(&ses->server->request_q);
512 }
513
514 return rc;
1da177e4 515
d6e04ae6
SF
516out_unlock2:
517 up(&ses->server->tcpSem);
518 /* If not lock req, update # of requests on wire to server */
519 if(long_op < 3) {
520 atomic_dec(&ses->server->inFlight);
521 wake_up(&ses->server->request_q);
522 }
1da177e4 523
d6e04ae6
SF
524 return rc;
525}
1da177e4
LT
526#endif /* CIFS_EXPERIMENTAL */
527
528int
529SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
530 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
531 int *pbytes_returned, const int long_op)
532{
533 int rc = 0;
534 unsigned int receive_len;
535 unsigned long timeout;
536 struct mid_q_entry *midQ;
537
538 if (ses == NULL) {
539 cERROR(1,("Null smb session"));
540 return -EIO;
541 }
542 if(ses->server == NULL) {
543 cERROR(1,("Null tcp session"));
544 return -EIO;
545 }
546
31ca3bc3
SF
547 if(ses->server->tcpStatus == CifsExiting)
548 return -ENOENT;
549
1da177e4
LT
550 /* Ensure that we do not send more than 50 overlapping requests
551 to the same server. We may make this configurable later or
552 use ses->maxReq */
553 if(long_op == -1) {
554 /* oplock breaks must not be held up */
555 atomic_inc(&ses->server->inFlight);
556 } else {
557 spin_lock(&GlobalMid_Lock);
558 while(1) {
275cde1a
SF
559 if(atomic_read(&ses->server->inFlight) >=
560 cifs_max_pending){
1da177e4 561 spin_unlock(&GlobalMid_Lock);
131afd0b
SF
562#ifdef CONFIG_CIFS_STATS2
563 atomic_inc(&ses->server->num_waiters);
564#endif
1da177e4
LT
565 wait_event(ses->server->request_q,
566 atomic_read(&ses->server->inFlight)
567 < cifs_max_pending);
131afd0b
SF
568#ifdef CONFIG_CIFS_STATS2
569 atomic_dec(&ses->server->num_waiters);
570#endif
1da177e4
LT
571 spin_lock(&GlobalMid_Lock);
572 } else {
573 if(ses->server->tcpStatus == CifsExiting) {
574 spin_unlock(&GlobalMid_Lock);
575 return -ENOENT;
576 }
577
578 /* can not count locking commands against total since
579 they are allowed to block on server */
580
581 if(long_op < 3) {
582 /* update # of requests on the wire to server */
583 atomic_inc(&ses->server->inFlight);
584 }
585 spin_unlock(&GlobalMid_Lock);
586 break;
587 }
588 }
589 }
590 /* make sure that we sign in the same order that we send on this socket
591 and avoid races inside tcp sendmsg code that could cause corruption
592 of smb data */
593
594 down(&ses->server->tcpSem);
595
596 if (ses->server->tcpStatus == CifsExiting) {
597 rc = -ENOENT;
598 goto out_unlock;
599 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
600 cFYI(1,("tcp session dead - return to caller to retry"));
601 rc = -EAGAIN;
602 goto out_unlock;
603 } else if (ses->status != CifsGood) {
604 /* check if SMB session is bad because we are setting it up */
605 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
606 (in_buf->Command != SMB_COM_NEGOTIATE)) {
607 rc = -EAGAIN;
608 goto out_unlock;
609 } /* else ok - we are setting up session */
610 }
611 midQ = AllocMidQEntry(in_buf, ses);
612 if (midQ == NULL) {
613 up(&ses->server->tcpSem);
614 /* If not lock req, update # of requests on wire to server */
615 if(long_op < 3) {
616 atomic_dec(&ses->server->inFlight);
617 wake_up(&ses->server->request_q);
618 }
619 return -ENOMEM;
620 }
621
622 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
623 up(&ses->server->tcpSem);
624 cERROR(1,
625 ("Illegal length, greater than maximum frame, %d ",
626 in_buf->smb_buf_length));
627 DeleteMidQEntry(midQ);
628 /* If not lock req, update # of requests on wire to server */
629 if(long_op < 3) {
630 atomic_dec(&ses->server->inFlight);
631 wake_up(&ses->server->request_q);
632 }
633 return -EIO;
634 }
635
ad009ac9 636 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4
LT
637
638 midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b
SF
639#ifdef CONFIG_CIFS_STATS2
640 atomic_inc(&ses->server->inSend);
641#endif
1da177e4
LT
642 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
643 (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b
SF
644#ifdef CONFIG_CIFS_STATS2
645 atomic_dec(&ses->server->inSend);
646#endif
1da177e4
LT
647 if(rc < 0) {
648 DeleteMidQEntry(midQ);
649 up(&ses->server->tcpSem);
650 /* If not lock req, update # of requests on wire to server */
651 if(long_op < 3) {
652 atomic_dec(&ses->server->inFlight);
653 wake_up(&ses->server->request_q);
654 }
655 return rc;
656 } else
657 up(&ses->server->tcpSem);
658 if (long_op == -1)
659 goto cifs_no_response_exit;
275cde1a 660 else if (long_op == 2) /* writes past end of file can take loong time */
37c0eb46 661 timeout = 180 * HZ;
1da177e4
LT
662 else if (long_op == 1)
663 timeout = 45 * HZ; /* should be greater than
664 servers oplock break timeout (about 43 seconds) */
665 else if (long_op > 2) {
666 timeout = MAX_SCHEDULE_TIMEOUT;
667 } else
668 timeout = 15 * HZ;
669 /* wait for 15 seconds or until woken up due to response arriving or
670 due to last connection to this server being unmounted */
671 if (signal_pending(current)) {
672 /* if signal pending do not hold up user for full smb timeout
673 but we still give response a change to complete */
674 timeout = 2 * HZ;
675 }
676
677 /* No user interrupts in wait - wreaks havoc with performance */
678 if(timeout != MAX_SCHEDULE_TIMEOUT) {
679 timeout += jiffies;
680 wait_event(ses->server->response_q,
681 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
682 time_after(jiffies, timeout) ||
683 ((ses->server->tcpStatus != CifsGood) &&
684 (ses->server->tcpStatus != CifsNew)));
685 } else {
686 wait_event(ses->server->response_q,
687 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
688 ((ses->server->tcpStatus != CifsGood) &&
689 (ses->server->tcpStatus != CifsNew)));
690 }
691
692 spin_lock(&GlobalMid_Lock);
693 if (midQ->resp_buf) {
694 spin_unlock(&GlobalMid_Lock);
70ca734a 695 receive_len = midQ->resp_buf->smb_buf_length;
1da177e4 696 } else {
37c0eb46
SF
697 cERROR(1,("No response for cmd %d mid %d",
698 midQ->command, midQ->mid));
1da177e4
LT
699 if(midQ->midState == MID_REQUEST_SUBMITTED) {
700 if(ses->server->tcpStatus == CifsExiting)
701 rc = -EHOSTDOWN;
702 else {
703 ses->server->tcpStatus = CifsNeedReconnect;
704 midQ->midState = MID_RETRY_NEEDED;
705 }
706 }
707
708 if (rc != -EHOSTDOWN) {
709 if(midQ->midState == MID_RETRY_NEEDED) {
710 rc = -EAGAIN;
711 cFYI(1,("marking request for retry"));
712 } else {
713 rc = -EIO;
714 }
715 }
716 spin_unlock(&GlobalMid_Lock);
717 DeleteMidQEntry(midQ);
718 /* If not lock req, update # of requests on wire to server */
719 if(long_op < 3) {
720 atomic_dec(&ses->server->inFlight);
721 wake_up(&ses->server->request_q);
722 }
723 return rc;
724 }
725
726 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
ad009ac9 727 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1da177e4
LT
728 receive_len, xid));
729 rc = -EIO;
730 } else { /* rcvd frame is ok */
731
732 if (midQ->resp_buf && out_buf
733 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
734 out_buf->smb_buf_length = receive_len;
735 memcpy((char *)out_buf + 4,
736 (char *)midQ->resp_buf + 4,
737 receive_len);
738
739 dump_smb(out_buf, 92);
740 /* convert the length into a more usable form */
741 if((receive_len > 24) &&
ad009ac9
SF
742 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
743 SECMODE_SIGN_ENABLED))) {
744 rc = cifs_verify_signature(out_buf,
745 ses->server->mac_signing_key,
746 midQ->sequence_number+1);
747 if(rc) {
275cde1a
SF
748 cERROR(1,("Unexpected SMB signature"));
749 /* BB FIXME add code to kill session */
ad009ac9 750 }
1da177e4
LT
751 }
752
753 *pbytes_returned = out_buf->smb_buf_length;
754
ad009ac9 755 /* BB special case reconnect tid and uid here? */
1da177e4
LT
756 rc = map_smb_to_linux_error(out_buf);
757
758 /* convert ByteCount if necessary */
759 if (receive_len >=
760 sizeof (struct smb_hdr) -
761 4 /* do not count RFC1001 header */ +
762 (2 * out_buf->WordCount) + 2 /* bcc */ )
763 BCC(out_buf) = le16_to_cpu(BCC(out_buf));
764 } else {
765 rc = -EIO;
a5a2b489 766 cERROR(1,("Bad MID state? "));
1da177e4
LT
767 }
768 }
769cifs_no_response_exit:
770 DeleteMidQEntry(midQ);
771
772 if(long_op < 3) {
773 atomic_dec(&ses->server->inFlight);
774 wake_up(&ses->server->request_q);
775 }
776
777 return rc;
778
779out_unlock:
780 up(&ses->server->tcpSem);
781 /* If not lock req, update # of requests on wire to server */
782 if(long_op < 3) {
783 atomic_dec(&ses->server->inFlight);
784 wake_up(&ses->server->request_q);
785 }
786
787 return rc;
788}